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         for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx)
207         {
208             if (GetArchitectureAtIndex (arch_idx, curr_arch))
209             {
210                 if (arch == curr_arch)
211                 {
212                     return ObjectFile::FindPlugin (module_sp,
213                                                    file,
214                                                    m_offset + m_fat_archs[arch_idx].offset,
215                                                    m_fat_archs[arch_idx].size,
216                                                    m_data.GetSharedDataBuffer());
217                 }
218             }
219         }
220     }
221     return ObjectFileSP();
222 }
223 
224 
225 //------------------------------------------------------------------
226 // PluginInterface protocol
227 //------------------------------------------------------------------
228 const char *
229 ObjectContainerUniversalMachO::GetPluginName()
230 {
231     return "ObjectContainerUniversalMachO";
232 }
233 
234 const char *
235 ObjectContainerUniversalMachO::GetShortPluginName()
236 {
237     return GetPluginNameStatic();
238 }
239 
240 uint32_t
241 ObjectContainerUniversalMachO::GetPluginVersion()
242 {
243     return 1;
244 }
245 
246 
247