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