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