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 moveToNextSymbol(DataRefImpl &DRI) const; 72 void getSection(DataRefImpl DRI, InMemoryStruct<macho::Section> &Res) const; 73 }; 74 75 ObjectFile *ObjectFile::createMachOObjectFile(MemoryBuffer *Buffer) { 76 error_code ec; 77 std::string Err; 78 MachOObject *MachOObj = MachOObject::LoadFromBuffer(Buffer, &Err); 79 if (!MachOObj) 80 return NULL; 81 return new MachOObjectFile(Buffer, MachOObj, ec); 82 } 83 84 /*===-- Symbols -----------------------------------------------------------===*/ 85 86 void MachOObjectFile::moveToNextSymbol(DataRefImpl &DRI) const { 87 uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; 88 while (DRI.d.a < LoadCommandCount) { 89 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 90 if (LCI.Command.Type == macho::LCT_Symtab) { 91 InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; 92 MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); 93 if (DRI.d.b < SymtabLoadCmd->NumSymbolTableEntries) 94 return; 95 } 96 97 DRI.d.a++; 98 DRI.d.b = 0; 99 } 100 } 101 102 void MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI, 103 InMemoryStruct<macho::SymbolTableEntry> &Res) const { 104 InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; 105 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 106 MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); 107 108 if (RegisteredStringTable != DRI.d.a) { 109 MachOObj->RegisterStringTable(*SymtabLoadCmd); 110 RegisteredStringTable = DRI.d.a; 111 } 112 113 MachOObj->ReadSymbolTableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, 114 Res); 115 } 116 117 118 error_code MachOObjectFile::getSymbolNext(DataRefImpl DRI, 119 SymbolRef &Result) const { 120 DRI.d.b++; 121 moveToNextSymbol(DRI); 122 Result = SymbolRef(DRI, this); 123 return object_error::success; 124 } 125 126 error_code MachOObjectFile::getSymbolName(DataRefImpl DRI, 127 StringRef &Result) const { 128 InMemoryStruct<macho::SymbolTableEntry> Entry; 129 getSymbolTableEntry(DRI, Entry); 130 Result = MachOObj->getStringAtIndex(Entry->StringIndex); 131 return object_error::success; 132 } 133 134 error_code MachOObjectFile::getSymbolAddress(DataRefImpl DRI, 135 uint64_t &Result) const { 136 InMemoryStruct<macho::SymbolTableEntry> Entry; 137 getSymbolTableEntry(DRI, Entry); 138 Result = Entry->Value; 139 return object_error::success; 140 } 141 142 error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI, 143 uint64_t &Result) const { 144 Result = UnknownAddressOrSize; 145 return object_error::success; 146 } 147 148 error_code MachOObjectFile::getSymbolNMTypeChar(DataRefImpl DRI, 149 char &Result) const { 150 InMemoryStruct<macho::SymbolTableEntry> Entry; 151 getSymbolTableEntry(DRI, Entry); 152 153 char Char; 154 switch (Entry->Type & macho::STF_TypeMask) { 155 case macho::STT_Undefined: 156 Char = 'u'; 157 break; 158 case macho::STT_Absolute: 159 case macho::STT_Section: 160 Char = 's'; 161 break; 162 default: 163 Char = '?'; 164 break; 165 } 166 167 if (Entry->Flags & (macho::STF_External | macho::STF_PrivateExtern)) 168 Char = toupper(Char); 169 Result = Char; 170 return object_error::success; 171 } 172 173 error_code MachOObjectFile::isSymbolInternal(DataRefImpl DRI, 174 bool &Result) const { 175 InMemoryStruct<macho::SymbolTableEntry> Entry; 176 getSymbolTableEntry(DRI, Entry); 177 Result = Entry->Flags & macho::STF_StabsEntryMask; 178 return object_error::success; 179 } 180 181 ObjectFile::symbol_iterator MachOObjectFile::begin_symbols() const { 182 // DRI.d.a = segment number; DRI.d.b = symbol index. 183 DataRefImpl DRI; 184 DRI.d.a = DRI.d.b = 0; 185 moveToNextSymbol(DRI); 186 return symbol_iterator(SymbolRef(DRI, this)); 187 } 188 189 ObjectFile::symbol_iterator MachOObjectFile::end_symbols() const { 190 DataRefImpl DRI; 191 DRI.d.a = MachOObj->getHeader().NumLoadCommands; 192 DRI.d.b = 0; 193 return symbol_iterator(SymbolRef(DRI, this)); 194 } 195 196 197 /*===-- Sections ----------------------------------------------------------===*/ 198 199 void MachOObjectFile::moveToNextSection(DataRefImpl &DRI) const { 200 uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands; 201 while (DRI.d.a < LoadCommandCount) { 202 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 203 if (LCI.Command.Type == macho::LCT_Segment) { 204 InMemoryStruct<macho::SegmentLoadCommand> SegmentLoadCmd; 205 MachOObj->ReadSegmentLoadCommand(LCI, SegmentLoadCmd); 206 if (DRI.d.b < SegmentLoadCmd->NumSections) 207 return; 208 } else if (LCI.Command.Type == macho::LCT_Segment64) { 209 InMemoryStruct<macho::Segment64LoadCommand> Segment64LoadCmd; 210 MachOObj->ReadSegment64LoadCommand(LCI, Segment64LoadCmd); 211 if (DRI.d.b < Segment64LoadCmd->NumSections) 212 return; 213 } 214 215 DRI.d.a++; 216 DRI.d.b = 0; 217 } 218 } 219 220 error_code MachOObjectFile::getSectionNext(DataRefImpl DRI, 221 SectionRef &Result) const { 222 DRI.d.b++; 223 moveToNextSection(DRI); 224 Result = SectionRef(DRI, this); 225 return object_error::success; 226 } 227 228 void 229 MachOObjectFile::getSection(DataRefImpl DRI, 230 InMemoryStruct<macho::Section> &Res) const { 231 InMemoryStruct<macho::SegmentLoadCommand> SLC; 232 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 233 MachOObj->ReadSegmentLoadCommand(LCI, SLC); 234 MachOObj->ReadSection(LCI, DRI.d.b, Res); 235 } 236 237 error_code MachOObjectFile::getSectionName(DataRefImpl DRI, 238 StringRef &Result) const { 239 InMemoryStruct<macho::SegmentLoadCommand> SLC; 240 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 241 MachOObj->ReadSegmentLoadCommand(LCI, SLC); 242 InMemoryStruct<macho::Section> Sect; 243 MachOObj->ReadSection(LCI, DRI.d.b, Sect); 244 245 static char result[34]; 246 strcpy(result, SLC->Name); 247 strcat(result, ","); 248 strcat(result, Sect->Name); 249 Result = StringRef(result); 250 return object_error::success; 251 } 252 253 error_code MachOObjectFile::getSectionAddress(DataRefImpl DRI, 254 uint64_t &Result) const { 255 InMemoryStruct<macho::Section> Sect; 256 getSection(DRI, Sect); 257 Result = Sect->Address; 258 return object_error::success; 259 } 260 261 error_code MachOObjectFile::getSectionSize(DataRefImpl DRI, 262 uint64_t &Result) const { 263 InMemoryStruct<macho::Section> Sect; 264 getSection(DRI, Sect); 265 Result = Sect->Size; 266 return object_error::success; 267 } 268 269 error_code MachOObjectFile::getSectionContents(DataRefImpl DRI, 270 StringRef &Result) const { 271 InMemoryStruct<macho::Section> Sect; 272 getSection(DRI, Sect); 273 Result = MachOObj->getData(Sect->Offset, Sect->Size); 274 return object_error::success; 275 } 276 277 error_code MachOObjectFile::isSectionText(DataRefImpl DRI, 278 bool &Result) const { 279 InMemoryStruct<macho::SegmentLoadCommand> SLC; 280 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 281 MachOObj->ReadSegmentLoadCommand(LCI, SLC); 282 Result = !strcmp(SLC->Name, "__TEXT"); 283 return object_error::success; 284 } 285 286 ObjectFile::section_iterator MachOObjectFile::begin_sections() const { 287 DataRefImpl DRI; 288 DRI.d.a = DRI.d.b = 0; 289 moveToNextSection(DRI); 290 return section_iterator(SectionRef(DRI, this)); 291 } 292 293 ObjectFile::section_iterator MachOObjectFile::end_sections() const { 294 DataRefImpl DRI; 295 DRI.d.a = MachOObj->getHeader().NumLoadCommands; 296 DRI.d.b = 0; 297 return section_iterator(SectionRef(DRI, this)); 298 } 299 300 /*===-- Miscellaneous -----------------------------------------------------===*/ 301 302 uint8_t MachOObjectFile::getBytesInAddress() const { 303 return MachOObj->is64Bit() ? 8 : 4; 304 } 305 306 StringRef MachOObjectFile::getFileFormatName() const { 307 if (!MachOObj->is64Bit()) { 308 switch (MachOObj->getHeader().CPUType) { 309 case llvm::MachO::CPUTypeI386: 310 return "Mach-O 32-bit i386"; 311 case llvm::MachO::CPUTypeARM: 312 return "Mach-O arm"; 313 case llvm::MachO::CPUTypePowerPC: 314 return "Mach-O 32-bit ppc"; 315 default: 316 assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 0 && 317 "64-bit object file when we're not 64-bit?"); 318 return "Mach-O 32-bit unknown"; 319 } 320 } 321 322 switch (MachOObj->getHeader().CPUType) { 323 case llvm::MachO::CPUTypeX86_64: 324 return "Mach-O 64-bit x86-64"; 325 case llvm::MachO::CPUTypePowerPC64: 326 return "Mach-O 64-bit ppc64"; 327 default: 328 assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 1 && 329 "32-bit object file when we're 64-bit?"); 330 return "Mach-O 64-bit unknown"; 331 } 332 } 333 334 unsigned MachOObjectFile::getArch() const { 335 switch (MachOObj->getHeader().CPUType) { 336 case llvm::MachO::CPUTypeI386: 337 return Triple::x86; 338 case llvm::MachO::CPUTypeX86_64: 339 return Triple::x86_64; 340 case llvm::MachO::CPUTypeARM: 341 return Triple::arm; 342 case llvm::MachO::CPUTypePowerPC: 343 return Triple::ppc; 344 case llvm::MachO::CPUTypePowerPC64: 345 return Triple::ppc64; 346 default: 347 return Triple::UnknownArch; 348 } 349 } 350 351 } // end namespace llvm 352 353