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