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