MachOObjectFile.cpp revision 291e767dcf19d60b8e774114efc6e10f2e022844
1//===- MachOObjectFile.cpp - Mach-O object file binding ---------*- 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// This file defines the MachOObjectFile class, which binds the MachOObject 11// class to the generic ObjectFile wrapper. 12// 13//===----------------------------------------------------------------------===// 14 15#include "llvm/ADT/Triple.h" 16#include "llvm/Object/MachOFormat.h" 17#include "llvm/Object/MachOObject.h" 18#include "llvm/Object/ObjectFile.h" 19#include "llvm/Support/MemoryBuffer.h" 20#include "llvm/Support/MachO.h" 21 22#include <cctype> 23#include <cstring> 24#include <limits> 25 26using namespace llvm; 27using namespace object; 28 29namespace llvm { 30 31typedef MachOObject::LoadCommandInfo LoadCommandInfo; 32 33class MachOObjectFile : public ObjectFile { 34public: 35 MachOObjectFile(MemoryBuffer *Object, MachOObject *MOO, error_code &ec) 36 : ObjectFile(Binary::isMachO, Object, ec), 37 MachOObj(MOO), 38 RegisteredStringTable(std::numeric_limits<uint32_t>::max()) {} 39 40 virtual symbol_iterator begin_symbols() const; 41 virtual symbol_iterator end_symbols() const; 42 virtual section_iterator begin_sections() const; 43 virtual section_iterator end_sections() const; 44 45 virtual uint8_t getBytesInAddress() const; 46 virtual StringRef getFileFormatName() const; 47 virtual unsigned getArch() const; 48 49protected: 50 virtual error_code getSymbolNext(DataRefImpl Symb, SymbolRef &Res) const; 51 virtual error_code getSymbolName(DataRefImpl Symb, StringRef &Res) const; 52 virtual error_code getSymbolAddress(DataRefImpl Symb, uint64_t &Res) const; 53 virtual error_code getSymbolSize(DataRefImpl Symb, uint64_t &Res) const; 54 virtual error_code getSymbolNMTypeChar(DataRefImpl Symb, char &Res) const; 55 virtual error_code isSymbolInternal(DataRefImpl Symb, bool &Res) const; 56 57 virtual error_code getSectionNext(DataRefImpl Sec, SectionRef &Res) const; 58 virtual error_code getSectionName(DataRefImpl Sec, StringRef &Res) const; 59 virtual error_code getSectionAddress(DataRefImpl Sec, uint64_t &Res) const; 60 virtual error_code getSectionSize(DataRefImpl Sec, uint64_t &Res) const; 61 virtual error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const; 62 virtual error_code isSectionText(DataRefImpl Sec, bool &Res) const; 63 64private: 65 MachOObject *MachOObj; 66 mutable uint32_t RegisteredStringTable; 67 68 void moveToNextSection(DataRefImpl &DRI) const; 69 void getSymbolTableEntry(DataRefImpl DRI, 70 InMemoryStruct<macho::SymbolTableEntry> &Res) const; 71 void moveToNextSymbol(DataRefImpl &DRI) const; 72 void getSection(DataRefImpl DRI, InMemoryStruct<macho::Section> &Res) const; 73 void getSection64(DataRefImpl DRI, 74 InMemoryStruct<macho::Section64> &Res) const; 75}; 76 77ObjectFile *ObjectFile::createMachOObjectFile(MemoryBuffer *Buffer) { 78 error_code ec; 79 std::string Err; 80 MachOObject *MachOObj = MachOObject::LoadFromBuffer(Buffer, &Err); 81 if (!MachOObj) 82 return NULL; 83 return new MachOObjectFile(Buffer, MachOObj, ec); 84} 85 86/*===-- Symbols -----------------------------------------------------------===*/ 87 88void MachOObjectFile::moveToNextSymbol(DataRefImpl &DRI) const { 89 uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; 90 while (DRI.d.a < LoadCommandCount) { 91 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 92 if (LCI.Command.Type == macho::LCT_Symtab) { 93 InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; 94 MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); 95 if (DRI.d.b < SymtabLoadCmd->NumSymbolTableEntries) 96 return; 97 } 98 99 DRI.d.a++; 100 DRI.d.b = 0; 101 } 102} 103 104void MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI, 105 InMemoryStruct<macho::SymbolTableEntry> &Res) const { 106 InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; 107 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 108 MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); 109 110 if (RegisteredStringTable != DRI.d.a) { 111 MachOObj->RegisterStringTable(*SymtabLoadCmd); 112 RegisteredStringTable = DRI.d.a; 113 } 114 115 MachOObj->ReadSymbolTableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, 116 Res); 117} 118 119 120error_code MachOObjectFile::getSymbolNext(DataRefImpl DRI, 121 SymbolRef &Result) const { 122 DRI.d.b++; 123 moveToNextSymbol(DRI); 124 Result = SymbolRef(DRI, this); 125 return object_error::success; 126} 127 128error_code MachOObjectFile::getSymbolName(DataRefImpl DRI, 129 StringRef &Result) const { 130 InMemoryStruct<macho::SymbolTableEntry> Entry; 131 getSymbolTableEntry(DRI, Entry); 132 Result = MachOObj->getStringAtIndex(Entry->StringIndex); 133 return object_error::success; 134} 135 136error_code MachOObjectFile::getSymbolAddress(DataRefImpl DRI, 137 uint64_t &Result) const { 138 InMemoryStruct<macho::SymbolTableEntry> Entry; 139 getSymbolTableEntry(DRI, Entry); 140 Result = Entry->Value; 141 return object_error::success; 142} 143 144error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI, 145 uint64_t &Result) const { 146 Result = UnknownAddressOrSize; 147 return object_error::success; 148} 149 150error_code MachOObjectFile::getSymbolNMTypeChar(DataRefImpl DRI, 151 char &Result) const { 152 InMemoryStruct<macho::SymbolTableEntry> Entry; 153 getSymbolTableEntry(DRI, Entry); 154 155 char Char; 156 switch (Entry->Type & macho::STF_TypeMask) { 157 case macho::STT_Undefined: 158 Char = 'u'; 159 break; 160 case macho::STT_Absolute: 161 case macho::STT_Section: 162 Char = 's'; 163 break; 164 default: 165 Char = '?'; 166 break; 167 } 168 169 if (Entry->Flags & (macho::STF_External | macho::STF_PrivateExtern)) 170 Char = toupper(Char); 171 Result = Char; 172 return object_error::success; 173} 174 175error_code MachOObjectFile::isSymbolInternal(DataRefImpl DRI, 176 bool &Result) const { 177 InMemoryStruct<macho::SymbolTableEntry> Entry; 178 getSymbolTableEntry(DRI, Entry); 179 Result = Entry->Flags & macho::STF_StabsEntryMask; 180 return object_error::success; 181} 182 183ObjectFile::symbol_iterator MachOObjectFile::begin_symbols() const { 184 // DRI.d.a = segment number; DRI.d.b = symbol index. 185 DataRefImpl DRI; 186 DRI.d.a = DRI.d.b = 0; 187 moveToNextSymbol(DRI); 188 return symbol_iterator(SymbolRef(DRI, this)); 189} 190 191ObjectFile::symbol_iterator MachOObjectFile::end_symbols() const { 192 DataRefImpl DRI; 193 DRI.d.a = MachOObj->getHeader().NumLoadCommands; 194 DRI.d.b = 0; 195 return symbol_iterator(SymbolRef(DRI, this)); 196} 197 198 199/*===-- Sections ----------------------------------------------------------===*/ 200 201void MachOObjectFile::moveToNextSection(DataRefImpl &DRI) const { 202 uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; 203 while (DRI.d.a < LoadCommandCount) { 204 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 205 if (LCI.Command.Type == macho::LCT_Segment) { 206 InMemoryStruct<macho::SegmentLoadCommand> SegmentLoadCmd; 207 MachOObj->ReadSegmentLoadCommand(LCI, SegmentLoadCmd); 208 if (DRI.d.b < SegmentLoadCmd->NumSections) 209 return; 210 } else if (LCI.Command.Type == macho::LCT_Segment64) { 211 InMemoryStruct<macho::Segment64LoadCommand> Segment64LoadCmd; 212 MachOObj->ReadSegment64LoadCommand(LCI, Segment64LoadCmd); 213 if (DRI.d.b < Segment64LoadCmd->NumSections) 214 return; 215 } 216 217 DRI.d.a++; 218 DRI.d.b = 0; 219 } 220} 221 222error_code MachOObjectFile::getSectionNext(DataRefImpl DRI, 223 SectionRef &Result) const { 224 DRI.d.b++; 225 moveToNextSection(DRI); 226 Result = SectionRef(DRI, this); 227 return object_error::success; 228} 229 230void 231MachOObjectFile::getSection(DataRefImpl DRI, 232 InMemoryStruct<macho::Section> &Res) const { 233 InMemoryStruct<macho::SegmentLoadCommand> SLC; 234 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 235 MachOObj->ReadSegmentLoadCommand(LCI, SLC); 236 MachOObj->ReadSection(LCI, DRI.d.b, Res); 237} 238 239void 240MachOObjectFile::getSection64(DataRefImpl DRI, 241 InMemoryStruct<macho::Section64> &Res) const { 242 InMemoryStruct<macho::Segment64LoadCommand> SLC; 243 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 244 MachOObj->ReadSegment64LoadCommand(LCI, SLC); 245 MachOObj->ReadSection64(LCI, DRI.d.b, Res); 246} 247 248static bool is64BitLoadCommand(const MachOObject *MachOObj, DataRefImpl DRI) { 249 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 250 if (LCI.Command.Type == macho::LCT_Segment64) 251 return true; 252 assert(LCI.Command.Type == macho::LCT_Segment && "Unexpected Type."); 253 return false; 254} 255 256error_code MachOObjectFile::getSectionName(DataRefImpl DRI, 257 StringRef &Result) const { 258 // FIXME: thread safety. 259 static char result[34]; 260 if (is64BitLoadCommand(MachOObj, DRI)) { 261 InMemoryStruct<macho::Segment64LoadCommand> SLC; 262 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 263 MachOObj->ReadSegment64LoadCommand(LCI, SLC); 264 InMemoryStruct<macho::Section64> Sect; 265 MachOObj->ReadSection64(LCI, DRI.d.b, Sect); 266 267 strcpy(result, Sect->SegmentName); 268 strcat(result, ","); 269 strcat(result, Sect->Name); 270 } else { 271 InMemoryStruct<macho::SegmentLoadCommand> SLC; 272 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 273 MachOObj->ReadSegmentLoadCommand(LCI, SLC); 274 InMemoryStruct<macho::Section> Sect; 275 MachOObj->ReadSection(LCI, DRI.d.b, Sect); 276 277 strcpy(result, Sect->SegmentName); 278 strcat(result, ","); 279 strcat(result, Sect->Name); 280 } 281 Result = StringRef(result); 282 return object_error::success; 283} 284 285error_code MachOObjectFile::getSectionAddress(DataRefImpl DRI, 286 uint64_t &Result) const { 287 if (is64BitLoadCommand(MachOObj, DRI)) { 288 InMemoryStruct<macho::Section64> Sect; 289 getSection64(DRI, Sect); 290 Result = Sect->Address; 291 } else { 292 InMemoryStruct<macho::Section> Sect; 293 getSection(DRI, Sect); 294 Result = Sect->Address; 295 } 296 return object_error::success; 297} 298 299error_code MachOObjectFile::getSectionSize(DataRefImpl DRI, 300 uint64_t &Result) const { 301 if (is64BitLoadCommand(MachOObj, DRI)) { 302 InMemoryStruct<macho::Section64> Sect; 303 getSection64(DRI, Sect); 304 Result = Sect->Size; 305 } else { 306 InMemoryStruct<macho::Section> Sect; 307 getSection(DRI, Sect); 308 Result = Sect->Size; 309 } 310 return object_error::success; 311} 312 313error_code MachOObjectFile::getSectionContents(DataRefImpl DRI, 314 StringRef &Result) const { 315 if (is64BitLoadCommand(MachOObj, DRI)) { 316 InMemoryStruct<macho::Section64> Sect; 317 getSection64(DRI, Sect); 318 Result = MachOObj->getData(Sect->Offset, Sect->Size); 319 } else { 320 InMemoryStruct<macho::Section> Sect; 321 getSection(DRI, Sect); 322 Result = MachOObj->getData(Sect->Offset, Sect->Size); 323 } 324 return object_error::success; 325} 326 327error_code MachOObjectFile::isSectionText(DataRefImpl DRI, 328 bool &Result) const { 329 if (is64BitLoadCommand(MachOObj, DRI)) { 330 InMemoryStruct<macho::Section64> Sect; 331 getSection64(DRI, Sect); 332 Result = !strcmp(Sect->Name, "__text"); 333 } else { 334 InMemoryStruct<macho::Section> Sect; 335 getSection(DRI, Sect); 336 Result = !strcmp(Sect->Name, "__text"); 337 } 338 return object_error::success; 339} 340 341ObjectFile::section_iterator MachOObjectFile::begin_sections() const { 342 DataRefImpl DRI; 343 DRI.d.a = DRI.d.b = 0; 344 moveToNextSection(DRI); 345 return section_iterator(SectionRef(DRI, this)); 346} 347 348ObjectFile::section_iterator MachOObjectFile::end_sections() const { 349 DataRefImpl DRI; 350 DRI.d.a = MachOObj->getHeader().NumLoadCommands; 351 DRI.d.b = 0; 352 return section_iterator(SectionRef(DRI, this)); 353} 354 355/*===-- Miscellaneous -----------------------------------------------------===*/ 356 357uint8_t MachOObjectFile::getBytesInAddress() const { 358 return MachOObj->is64Bit() ? 8 : 4; 359} 360 361StringRef MachOObjectFile::getFileFormatName() const { 362 if (!MachOObj->is64Bit()) { 363 switch (MachOObj->getHeader().CPUType) { 364 case llvm::MachO::CPUTypeI386: 365 return "Mach-O 32-bit i386"; 366 case llvm::MachO::CPUTypeARM: 367 return "Mach-O arm"; 368 case llvm::MachO::CPUTypePowerPC: 369 return "Mach-O 32-bit ppc"; 370 default: 371 assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 0 && 372 "64-bit object file when we're not 64-bit?"); 373 return "Mach-O 32-bit unknown"; 374 } 375 } 376 377 switch (MachOObj->getHeader().CPUType) { 378 case llvm::MachO::CPUTypeX86_64: 379 return "Mach-O 64-bit x86-64"; 380 case llvm::MachO::CPUTypePowerPC64: 381 return "Mach-O 64-bit ppc64"; 382 default: 383 assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 1 && 384 "32-bit object file when we're 64-bit?"); 385 return "Mach-O 64-bit unknown"; 386 } 387} 388 389unsigned MachOObjectFile::getArch() const { 390 switch (MachOObj->getHeader().CPUType) { 391 case llvm::MachO::CPUTypeI386: 392 return Triple::x86; 393 case llvm::MachO::CPUTypeX86_64: 394 return Triple::x86_64; 395 case llvm::MachO::CPUTypeARM: 396 return Triple::arm; 397 case llvm::MachO::CPUTypePowerPC: 398 return Triple::ppc; 399 case llvm::MachO::CPUTypePowerPC64: 400 return Triple::ppc64; 401 default: 402 return Triple::UnknownArch; 403 } 404} 405 406} // end namespace llvm 407 408