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