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