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     Module* module,
54     DataBufferSP& dataSP,
55     const FileSpec *file,
56     addr_t offset,
57     addr_t length
58 )
59 {
60     if (ObjectContainerUniversalMachO::MagicBytesMatch(dataSP))
61     {
62         std::auto_ptr<ObjectContainerUniversalMachO> container_ap(new ObjectContainerUniversalMachO (module, dataSP, file, offset, length));
63         if (container_ap->ParseHeader())
64         {
65             return container_ap.release();
66         }
67     }
68     return NULL;
69 }
70 
71 
72 
73 bool
74 ObjectContainerUniversalMachO::MagicBytesMatch (DataBufferSP& dataSP)
75 {
76     DataExtractor data(dataSP, lldb::endian::InlHostByteOrder(), 4);
77     uint32_t offset = 0;
78     uint32_t magic = data.GetU32(&offset);
79     return magic == UniversalMagic || magic == UniversalMagicSwapped;
80 }
81 
82 ObjectContainerUniversalMachO::ObjectContainerUniversalMachO
83 (
84     Module* module,
85     DataBufferSP& dataSP,
86     const FileSpec *file,
87     addr_t offset,
88     addr_t length
89 ) :
90     ObjectContainer (module, file, offset, length, dataSP),
91     m_header(),
92     m_fat_archs()
93 {
94     memset(&m_header, 0, sizeof(m_header));
95 }
96 
97 
98 ObjectContainerUniversalMachO::~ObjectContainerUniversalMachO()
99 {
100 }
101 
102 bool
103 ObjectContainerUniversalMachO::ParseHeader ()
104 {
105     // Store the file offset for this universal file as we could have a universal .o file
106     // in a BSD archive, or be contained in another kind of object.
107     uint32_t offset = 0;
108     // Universal mach-o files always have their headers in big endian.
109     m_data.SetByteOrder (eByteOrderBig);
110     m_header.magic = m_data.GetU32(&offset);
111 
112     if (m_header.magic == UniversalMagic)
113     {
114         m_data.SetAddressByteSize(4);
115 
116         m_header.nfat_arch = m_data.GetU32(&offset);
117 
118         const size_t nfat_arch_size = sizeof(fat_arch) * m_header.nfat_arch;
119         // See if the current data we have is enough for all of the fat headers?
120         if (!m_data.ValidOffsetForDataOfSize(offset, nfat_arch_size))
121         {
122             // The fat headers are larger than the number of bytes we have been
123             // given when this class was constructed. We will read the exact number
124             // of bytes that we need.
125             DataBufferSP data_sp(m_file.ReadFileContents(m_offset, nfat_arch_size + sizeof(fat_header)));
126             m_data.SetData (data_sp);
127         }
128 
129         // Now we should have enough data for all of the fat headers, so lets index
130         // them so we know how many architectures that this universal binary contains.
131         uint32_t arch_idx = 0;
132         for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx)
133         {
134             if (m_data.ValidOffsetForDataOfSize(offset, sizeof(fat_arch)))
135             {
136                 fat_arch arch;
137                 if (m_data.GetU32(&offset, &arch, sizeof(fat_arch)/sizeof(uint32_t)))
138                 {
139                     m_fat_archs.push_back(arch);
140                 }
141             }
142         }
143         // Now that we have indexed the universal headers, we no longer need any cached data.
144         m_data.Clear();
145 
146         return true;
147     }
148     else
149     {
150         memset(&m_header, 0, sizeof(m_header));
151     }
152 
153     return false;
154 }
155 
156 void
157 ObjectContainerUniversalMachO::Dump (Stream *s) const
158 {
159     s->Printf("%p: ", this);
160     s->Indent();
161     const size_t num_archs = GetNumArchitectures();
162     const size_t num_objects = GetNumObjects();
163     s->Printf("ObjectContainerUniversalMachO, num_archs = %lu, num_objects = %lu", num_archs, num_objects);
164     uint32_t i;
165     ArchSpec arch;
166     s->IndentMore();
167     for (i=0; i<num_archs; i++)
168     {
169         s->Indent();
170         GetArchitectureAtIndex(i, arch);
171         s->Printf("arch[%u] = %s\n", i, arch.GetArchitectureName());
172     }
173     for (i=0; i<num_objects; i++)
174     {
175         s->Indent();
176         s->Printf("object[%u] = %s\n", i, GetObjectNameAtIndex (i));
177     }
178     s->IndentLess();
179     s->EOL();
180 }
181 
182 size_t
183 ObjectContainerUniversalMachO::GetNumArchitectures () const
184 {
185     return m_header.nfat_arch;
186 }
187 
188 bool
189 ObjectContainerUniversalMachO::GetArchitectureAtIndex (uint32_t idx, ArchSpec& arch) const
190 {
191     if (idx < m_header.nfat_arch)
192     {
193         arch.SetArchitecture (eArchTypeMachO, m_fat_archs[idx].cputype, m_fat_archs[idx].cpusubtype);
194         return true;
195     }
196     return false;
197 }
198 
199 ObjectFileSP
200 ObjectContainerUniversalMachO::GetObjectFile (const FileSpec *file)
201 {
202     uint32_t arch_idx = 0;
203     ArchSpec arch;
204     // If the module hasn't specified an architecture yet, set it to the default
205     // architecture:
206     if (!m_module->GetArchitecture().IsValid())
207     {
208         arch = Target::GetDefaultArchitecture ();
209         if (!arch.IsValid())
210             arch.SetTriple (LLDB_ARCH_DEFAULT, NULL);
211     }
212     else
213         arch = m_module->GetArchitecture();
214 
215     ArchSpec curr_arch;
216     for (arch_idx = 0; arch_idx < m_header.nfat_arch; ++arch_idx)
217     {
218         if (GetArchitectureAtIndex (arch_idx, curr_arch))
219         {
220             if (arch == curr_arch)
221             {
222                 return ObjectFile::FindPlugin (m_module,
223                                                file,
224                                                m_offset + m_fat_archs[arch_idx].offset,
225                                                m_fat_archs[arch_idx].size);
226             }
227         }
228     }
229     return ObjectFileSP();
230 }
231 
232 
233 //------------------------------------------------------------------
234 // PluginInterface protocol
235 //------------------------------------------------------------------
236 const char *
237 ObjectContainerUniversalMachO::GetPluginName()
238 {
239     return "ObjectContainerUniversalMachO";
240 }
241 
242 const char *
243 ObjectContainerUniversalMachO::GetShortPluginName()
244 {
245     return GetPluginNameStatic();
246 }
247 
248 uint32_t
249 ObjectContainerUniversalMachO::GetPluginVersion()
250 {
251     return 1;
252 }
253 
254 
255