1 //===-- ObjectContainerUniversalMachO.cpp ---------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "ObjectContainerUniversalMachO.h"
10 #include "lldb/Core/Module.h"
11 #include "lldb/Core/ModuleSpec.h"
12 #include "lldb/Core/PluginManager.h"
13 #include "lldb/Symbol/ObjectFile.h"
14 #include "lldb/Target/Target.h"
15 #include "lldb/Utility/ArchSpec.h"
16 #include "lldb/Utility/DataBuffer.h"
17 #include "lldb/Utility/Stream.h"
18 
19 using namespace lldb;
20 using namespace lldb_private;
21 using namespace llvm::MachO;
22 
LLDB_PLUGIN_DEFINE_ADV(ObjectContainerUniversalMachO,ObjectContainerMachOArchive)23 LLDB_PLUGIN_DEFINE_ADV(ObjectContainerUniversalMachO,
24                        ObjectContainerMachOArchive)
25 
26 void ObjectContainerUniversalMachO::Initialize() {
27   PluginManager::RegisterPlugin(GetPluginNameStatic(),
28                                 GetPluginDescriptionStatic(), CreateInstance,
29                                 GetModuleSpecifications);
30 }
31 
Terminate()32 void ObjectContainerUniversalMachO::Terminate() {
33   PluginManager::UnregisterPlugin(CreateInstance);
34 }
35 
GetPluginNameStatic()36 lldb_private::ConstString ObjectContainerUniversalMachO::GetPluginNameStatic() {
37   static ConstString g_name("mach-o");
38   return g_name;
39 }
40 
GetPluginDescriptionStatic()41 const char *ObjectContainerUniversalMachO::GetPluginDescriptionStatic() {
42   return "Universal mach-o object container reader.";
43 }
44 
CreateInstance(const lldb::ModuleSP & module_sp,DataBufferSP & data_sp,lldb::offset_t data_offset,const FileSpec * file,lldb::offset_t file_offset,lldb::offset_t length)45 ObjectContainer *ObjectContainerUniversalMachO::CreateInstance(
46     const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
47     lldb::offset_t data_offset, const FileSpec *file,
48     lldb::offset_t file_offset, lldb::offset_t length) {
49   // We get data when we aren't trying to look for cached container
50   // information, so only try and look for an architecture slice if we get data
51   if (data_sp) {
52     DataExtractor data;
53     data.SetData(data_sp, data_offset, length);
54     if (ObjectContainerUniversalMachO::MagicBytesMatch(data)) {
55       std::unique_ptr<ObjectContainerUniversalMachO> container_up(
56           new ObjectContainerUniversalMachO(module_sp, data_sp, data_offset,
57                                             file, file_offset, length));
58       if (container_up->ParseHeader()) {
59         return container_up.release();
60       }
61     }
62   }
63   return nullptr;
64 }
65 
MagicBytesMatch(const DataExtractor & data)66 bool ObjectContainerUniversalMachO::MagicBytesMatch(const DataExtractor &data) {
67   lldb::offset_t offset = 0;
68   uint32_t magic = data.GetU32(&offset);
69   return magic == FAT_MAGIC || magic == FAT_CIGAM;
70 }
71 
ObjectContainerUniversalMachO(const lldb::ModuleSP & module_sp,DataBufferSP & data_sp,lldb::offset_t data_offset,const FileSpec * file,lldb::offset_t file_offset,lldb::offset_t length)72 ObjectContainerUniversalMachO::ObjectContainerUniversalMachO(
73     const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
74     lldb::offset_t data_offset, const FileSpec *file,
75     lldb::offset_t file_offset, lldb::offset_t length)
76     : ObjectContainer(module_sp, file, file_offset, length, data_sp,
77                       data_offset),
78       m_header(), m_fat_archs() {
79   memset(&m_header, 0, sizeof(m_header));
80 }
81 
~ObjectContainerUniversalMachO()82 ObjectContainerUniversalMachO::~ObjectContainerUniversalMachO() {}
83 
ParseHeader()84 bool ObjectContainerUniversalMachO::ParseHeader() {
85   bool success = ParseHeader(m_data, m_header, m_fat_archs);
86   // We no longer need any data, we parsed all we needed to parse and cached it
87   // in m_header and m_fat_archs
88   m_data.Clear();
89   return success;
90 }
91 
ParseHeader(lldb_private::DataExtractor & data,llvm::MachO::fat_header & header,std::vector<llvm::MachO::fat_arch> & fat_archs)92 bool ObjectContainerUniversalMachO::ParseHeader(
93     lldb_private::DataExtractor &data, llvm::MachO::fat_header &header,
94     std::vector<llvm::MachO::fat_arch> &fat_archs) {
95   bool success = false;
96   // Store the file offset for this universal file as we could have a universal
97   // .o file in a BSD archive, or be contained in another kind of object.
98   // Universal mach-o files always have their headers in big endian.
99   lldb::offset_t offset = 0;
100   data.SetByteOrder(eByteOrderBig);
101   header.magic = data.GetU32(&offset);
102   fat_archs.clear();
103 
104   if (header.magic == FAT_MAGIC) {
105 
106     data.SetAddressByteSize(4);
107 
108     header.nfat_arch = data.GetU32(&offset);
109 
110     // Now we should have enough data for all of the fat headers, so lets index
111     // them so we know how many architectures that this universal binary
112     // contains.
113     uint32_t arch_idx = 0;
114     for (arch_idx = 0; arch_idx < header.nfat_arch; ++arch_idx) {
115       if (data.ValidOffsetForDataOfSize(offset, sizeof(fat_arch))) {
116         fat_arch arch;
117         if (data.GetU32(&offset, &arch, sizeof(fat_arch) / sizeof(uint32_t)))
118           fat_archs.push_back(arch);
119       }
120     }
121     success = true;
122   } else {
123     memset(&header, 0, sizeof(header));
124   }
125   return success;
126 }
127 
Dump(Stream * s) const128 void ObjectContainerUniversalMachO::Dump(Stream *s) const {
129   s->Printf("%p: ", static_cast<const void *>(this));
130   s->Indent();
131   const size_t num_archs = GetNumArchitectures();
132   const size_t num_objects = GetNumObjects();
133   s->Printf("ObjectContainerUniversalMachO, num_archs = %zu, num_objects = %zu",
134             num_archs, num_objects);
135   uint32_t i;
136   ArchSpec arch;
137   s->IndentMore();
138   for (i = 0; i < num_archs; i++) {
139     s->Indent();
140     GetArchitectureAtIndex(i, arch);
141     s->Printf("arch[%u] = %s\n", i, arch.GetArchitectureName());
142   }
143   for (i = 0; i < num_objects; i++) {
144     s->Indent();
145     s->Printf("object[%u] = %s\n", i, GetObjectNameAtIndex(i));
146   }
147   s->IndentLess();
148   s->EOL();
149 }
150 
GetNumArchitectures() const151 size_t ObjectContainerUniversalMachO::GetNumArchitectures() const {
152   return m_header.nfat_arch;
153 }
154 
GetArchitectureAtIndex(uint32_t idx,ArchSpec & arch) const155 bool ObjectContainerUniversalMachO::GetArchitectureAtIndex(
156     uint32_t idx, ArchSpec &arch) const {
157   if (idx < m_header.nfat_arch) {
158     arch.SetArchitecture(eArchTypeMachO, m_fat_archs[idx].cputype,
159                          m_fat_archs[idx].cpusubtype);
160     return true;
161   }
162   return false;
163 }
164 
165 ObjectFileSP
GetObjectFile(const FileSpec * file)166 ObjectContainerUniversalMachO::GetObjectFile(const FileSpec *file) {
167   uint32_t arch_idx = 0;
168   ArchSpec arch;
169   // If the module hasn't specified an architecture yet, set it to the default
170   // architecture:
171   ModuleSP module_sp(GetModule());
172   if (module_sp) {
173     if (!module_sp->GetArchitecture().IsValid()) {
174       arch = Target::GetDefaultArchitecture();
175       if (!arch.IsValid())
176         arch.SetTriple(LLDB_ARCH_DEFAULT);
177     } else
178       arch = module_sp->GetArchitecture();
179 
180     ArchSpec curr_arch;
181     // First, try to find an exact match for the Arch of the Target.
182     for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx) {
183       if (GetArchitectureAtIndex(arch_idx, curr_arch) &&
184           arch.IsExactMatch(curr_arch))
185         break;
186     }
187 
188     // Failing an exact match, try to find a compatible Arch of the Target.
189     if (arch_idx >= m_header.nfat_arch) {
190       for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx) {
191         if (GetArchitectureAtIndex(arch_idx, curr_arch) &&
192             arch.IsCompatibleMatch(curr_arch))
193           break;
194       }
195     }
196 
197     if (arch_idx < m_header.nfat_arch) {
198       DataBufferSP data_sp;
199       lldb::offset_t data_offset = 0;
200       return ObjectFile::FindPlugin(
201           module_sp, file, m_offset + m_fat_archs[arch_idx].offset,
202           m_fat_archs[arch_idx].size, data_sp, data_offset);
203     }
204   }
205   return ObjectFileSP();
206 }
207 
208 // PluginInterface protocol
GetPluginName()209 lldb_private::ConstString ObjectContainerUniversalMachO::GetPluginName() {
210   return GetPluginNameStatic();
211 }
212 
GetPluginVersion()213 uint32_t ObjectContainerUniversalMachO::GetPluginVersion() { return 1; }
214 
GetModuleSpecifications(const lldb_private::FileSpec & file,lldb::DataBufferSP & data_sp,lldb::offset_t data_offset,lldb::offset_t file_offset,lldb::offset_t file_size,lldb_private::ModuleSpecList & specs)215 size_t ObjectContainerUniversalMachO::GetModuleSpecifications(
216     const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
217     lldb::offset_t data_offset, lldb::offset_t file_offset,
218     lldb::offset_t file_size, lldb_private::ModuleSpecList &specs) {
219   const size_t initial_count = specs.GetSize();
220 
221   DataExtractor data;
222   data.SetData(data_sp, data_offset, data_sp->GetByteSize());
223 
224   if (ObjectContainerUniversalMachO::MagicBytesMatch(data)) {
225     llvm::MachO::fat_header header;
226     std::vector<llvm::MachO::fat_arch> fat_archs;
227     if (ParseHeader(data, header, fat_archs)) {
228       for (const llvm::MachO::fat_arch &fat_arch : fat_archs) {
229         const lldb::offset_t slice_file_offset = fat_arch.offset + file_offset;
230         if (fat_arch.offset < file_size && file_size > slice_file_offset) {
231           ObjectFile::GetModuleSpecifications(
232               file, slice_file_offset, file_size - slice_file_offset, specs);
233         }
234       }
235     }
236   }
237   return specs.GetSize() - initial_count;
238 }
239