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