1 //===- COFFObjectFile.cpp - COFF object file implementation -----*- 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 declares the COFFObjectFile class. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/ADT/StringSwitch.h" 15 #include "llvm/ADT/Triple.h" 16 #include "llvm/Object/ObjectFile.h" 17 #include "llvm/Support/COFF.h" 18 #include "llvm/Support/Endian.h" 19 20 using namespace llvm; 21 using namespace object; 22 23 namespace { 24 using support::ulittle8_t; 25 using support::ulittle16_t; 26 using support::ulittle32_t; 27 using support::little16_t; 28 } 29 30 namespace { 31 struct coff_file_header { 32 ulittle16_t Machine; 33 ulittle16_t NumberOfSections; 34 ulittle32_t TimeDateStamp; 35 ulittle32_t PointerToSymbolTable; 36 ulittle32_t NumberOfSymbols; 37 ulittle16_t SizeOfOptionalHeader; 38 ulittle16_t Characteristics; 39 }; 40 } 41 42 extern char coff_file_header_layout_static_assert 43 [sizeof(coff_file_header) == 20 ? 1 : -1]; 44 45 namespace { 46 struct coff_symbol { 47 struct StringTableOffset { 48 ulittle32_t Zeroes; 49 ulittle32_t Offset; 50 }; 51 52 union { 53 char ShortName[8]; 54 StringTableOffset Offset; 55 } Name; 56 57 ulittle32_t Value; 58 little16_t SectionNumber; 59 60 struct { 61 ulittle8_t BaseType; 62 ulittle8_t ComplexType; 63 } Type; 64 65 ulittle8_t StorageClass; 66 ulittle8_t NumberOfAuxSymbols; 67 }; 68 } 69 70 extern char coff_coff_symbol_layout_static_assert 71 [sizeof(coff_symbol) == 18 ? 1 : -1]; 72 73 namespace { 74 struct coff_section { 75 char Name[8]; 76 ulittle32_t VirtualSize; 77 ulittle32_t VirtualAddress; 78 ulittle32_t SizeOfRawData; 79 ulittle32_t PointerToRawData; 80 ulittle32_t PointerToRelocations; 81 ulittle32_t PointerToLinenumbers; 82 ulittle16_t NumberOfRelocations; 83 ulittle16_t NumberOfLinenumbers; 84 ulittle32_t Characteristics; 85 }; 86 } 87 88 extern char coff_coff_section_layout_static_assert 89 [sizeof(coff_section) == 40 ? 1 : -1]; 90 91 namespace { 92 class COFFObjectFile : public ObjectFile { 93 private: 94 const coff_file_header *Header; 95 const coff_section *SectionTable; 96 const coff_symbol *SymbolTable; 97 const char *StringTable; 98 99 const coff_section *getSection(std::size_t index) const; 100 const char *getString(std::size_t offset) const; 101 102 protected: 103 virtual SymbolRef getSymbolNext(DataRefImpl Symb) const; 104 virtual StringRef getSymbolName(DataRefImpl Symb) const; 105 virtual uint64_t getSymbolAddress(DataRefImpl Symb) const; 106 virtual uint64_t getSymbolSize(DataRefImpl Symb) const; 107 virtual char getSymbolNMTypeChar(DataRefImpl Symb) const; 108 virtual bool isSymbolInternal(DataRefImpl Symb) const; 109 110 virtual SectionRef getSectionNext(DataRefImpl Sec) const; 111 virtual StringRef getSectionName(DataRefImpl Sec) const; 112 virtual uint64_t getSectionAddress(DataRefImpl Sec) const; 113 virtual uint64_t getSectionSize(DataRefImpl Sec) const; 114 virtual StringRef getSectionContents(DataRefImpl Sec) const; 115 virtual bool isSectionText(DataRefImpl Sec) const; 116 117 public: 118 COFFObjectFile(MemoryBuffer *Object); 119 virtual symbol_iterator begin_symbols() const; 120 virtual symbol_iterator end_symbols() const; 121 virtual section_iterator begin_sections() const; 122 virtual section_iterator end_sections() const; 123 124 virtual uint8_t getBytesInAddress() const; 125 virtual StringRef getFileFormatName() const; 126 virtual unsigned getArch() const; 127 }; 128 } // end namespace 129 130 SymbolRef COFFObjectFile::getSymbolNext(DataRefImpl Symb) const { 131 const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 132 symb += 1 + symb->NumberOfAuxSymbols; 133 Symb.p = reinterpret_cast<intptr_t>(symb); 134 return SymbolRef(Symb, this); 135 } 136 137 StringRef COFFObjectFile::getSymbolName(DataRefImpl Symb) const { 138 const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 139 // Check for string table entry. First 4 bytes are 0. 140 if (symb->Name.Offset.Zeroes == 0) { 141 uint32_t Offset = symb->Name.Offset.Offset; 142 return StringRef(getString(Offset)); 143 } 144 145 if (symb->Name.ShortName[7] == 0) 146 // Null terminated, let ::strlen figure out the length. 147 return StringRef(symb->Name.ShortName); 148 // Not null terminated, use all 8 bytes. 149 return StringRef(symb->Name.ShortName, 8); 150 } 151 152 uint64_t COFFObjectFile::getSymbolAddress(DataRefImpl Symb) const { 153 const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 154 const coff_section *Section = getSection(symb->SectionNumber); 155 char Type = getSymbolNMTypeChar(Symb); 156 if (Type == 'U' || Type == 'w') 157 return UnknownAddressOrSize; 158 if (Section) 159 return Section->VirtualAddress + symb->Value; 160 return symb->Value; 161 } 162 163 uint64_t COFFObjectFile::getSymbolSize(DataRefImpl Symb) const { 164 // FIXME: Return the correct size. This requires looking at all the symbols 165 // in the same section as this symbol, and looking for either the next 166 // symbol, or the end of the section. 167 const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 168 const coff_section *Section = getSection(symb->SectionNumber); 169 char Type = getSymbolNMTypeChar(Symb); 170 if (Type == 'U' || Type == 'w') 171 return UnknownAddressOrSize; 172 if (Section) 173 return Section->SizeOfRawData - symb->Value; 174 return 0; 175 } 176 177 char COFFObjectFile::getSymbolNMTypeChar(DataRefImpl Symb) const { 178 const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 179 char ret = StringSwitch<char>(getSymbolName(Symb)) 180 .StartsWith(".debug", 'N') 181 .StartsWith(".sxdata", 'N') 182 .Default('?'); 183 184 if (ret != '?') 185 return ret; 186 187 uint32_t Characteristics = 0; 188 uint32_t PointerToRawData = 0; 189 const coff_section *Section = getSection(symb->SectionNumber); 190 if (Section) { 191 Characteristics = Section->Characteristics; 192 PointerToRawData = Section->PointerToRawData; 193 } 194 195 switch (symb->SectionNumber) { 196 case COFF::IMAGE_SYM_UNDEFINED: 197 // Check storage classes. 198 if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL) 199 return 'w'; // Don't do ::toupper. 200 else 201 ret = 'u'; 202 break; 203 case COFF::IMAGE_SYM_ABSOLUTE: 204 ret = 'a'; 205 break; 206 case COFF::IMAGE_SYM_DEBUG: 207 ret = 'n'; 208 break; 209 default: 210 // Check section type. 211 if (Characteristics & COFF::IMAGE_SCN_CNT_CODE) 212 ret = 't'; 213 else if ( Characteristics & COFF::IMAGE_SCN_MEM_READ 214 && ~Characteristics & COFF::IMAGE_SCN_MEM_WRITE) // Read only. 215 ret = 'r'; 216 else if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) 217 ret = 'd'; 218 else if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) 219 ret = 'b'; 220 else if (Characteristics & COFF::IMAGE_SCN_LNK_INFO) 221 ret = 'i'; 222 223 // Check for section symbol. 224 else if ( symb->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC 225 && symb->Value == 0) 226 ret = 's'; 227 } 228 229 if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL) 230 ret = ::toupper(ret); 231 232 return ret; 233 } 234 235 bool COFFObjectFile::isSymbolInternal(DataRefImpl Symb) const { 236 return false; 237 } 238 239 SectionRef COFFObjectFile::getSectionNext(DataRefImpl Sec) const { 240 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 241 sec += 1; 242 Sec.p = reinterpret_cast<intptr_t>(sec); 243 return SectionRef(Sec, this); 244 } 245 246 StringRef COFFObjectFile::getSectionName(DataRefImpl Sec) const { 247 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 248 StringRef name; 249 if (sec->Name[7] == 0) 250 // Null terminated, let ::strlen figure out the length. 251 name = sec->Name; 252 else 253 // Not null terminated, use all 8 bytes. 254 name = StringRef(sec->Name, 8); 255 256 // Check for string table entry. First byte is '/'. 257 if (name[0] == '/') { 258 uint32_t Offset; 259 name.getAsInteger(10, Offset); 260 return StringRef(getString(Offset)); 261 } 262 263 // It's just a normal name. 264 return name; 265 } 266 267 uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Sec) const { 268 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 269 return sec->VirtualAddress; 270 } 271 272 uint64_t COFFObjectFile::getSectionSize(DataRefImpl Sec) const { 273 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 274 return sec->SizeOfRawData; 275 } 276 277 StringRef COFFObjectFile::getSectionContents(DataRefImpl Sec) const { 278 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 279 return StringRef(reinterpret_cast<const char *>(base + sec->PointerToRawData), 280 sec->SizeOfRawData); 281 } 282 283 bool COFFObjectFile::isSectionText(DataRefImpl Sec) const { 284 const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 285 return sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE; 286 } 287 288 COFFObjectFile::COFFObjectFile(MemoryBuffer *Object) 289 : ObjectFile(Object) { 290 Header = reinterpret_cast<const coff_file_header *>(base); 291 SectionTable = 292 reinterpret_cast<const coff_section *>( base 293 + sizeof(coff_file_header) 294 + Header->SizeOfOptionalHeader); 295 SymbolTable = 296 reinterpret_cast<const coff_symbol *>(base + Header->PointerToSymbolTable); 297 298 // Find string table. 299 StringTable = reinterpret_cast<const char *>(base) 300 + Header->PointerToSymbolTable 301 + Header->NumberOfSymbols * 18; 302 } 303 304 ObjectFile::symbol_iterator COFFObjectFile::begin_symbols() const { 305 DataRefImpl ret; 306 ret.p = reinterpret_cast<intptr_t>(SymbolTable); 307 return symbol_iterator(SymbolRef(ret, this)); 308 } 309 310 ObjectFile::symbol_iterator COFFObjectFile::end_symbols() const { 311 // The symbol table ends where the string table begins. 312 DataRefImpl ret; 313 ret.p = reinterpret_cast<intptr_t>(StringTable); 314 return symbol_iterator(SymbolRef(ret, this)); 315 } 316 317 ObjectFile::section_iterator COFFObjectFile::begin_sections() const { 318 DataRefImpl ret; 319 ret.p = reinterpret_cast<intptr_t>(SectionTable); 320 return section_iterator(SectionRef(ret, this)); 321 } 322 323 ObjectFile::section_iterator COFFObjectFile::end_sections() const { 324 DataRefImpl ret; 325 ret.p = reinterpret_cast<intptr_t>(SectionTable + Header->NumberOfSections); 326 return section_iterator(SectionRef(ret, this)); 327 } 328 329 uint8_t COFFObjectFile::getBytesInAddress() const { 330 return getArch() == Triple::x86_64 ? 8 : 4; 331 } 332 333 StringRef COFFObjectFile::getFileFormatName() const { 334 switch(Header->Machine) { 335 case COFF::IMAGE_FILE_MACHINE_I386: 336 return "COFF-i386"; 337 case COFF::IMAGE_FILE_MACHINE_AMD64: 338 return "COFF-x86-64"; 339 default: 340 return "COFF-<unknown arch>"; 341 } 342 } 343 344 unsigned COFFObjectFile::getArch() const { 345 switch(Header->Machine) { 346 case COFF::IMAGE_FILE_MACHINE_I386: 347 return Triple::x86; 348 case COFF::IMAGE_FILE_MACHINE_AMD64: 349 return Triple::x86_64; 350 default: 351 return Triple::UnknownArch; 352 } 353 } 354 355 const coff_section *COFFObjectFile::getSection(std::size_t index) const { 356 if (index > 0 && index <= Header->NumberOfSections) 357 return SectionTable + (index - 1); 358 return 0; 359 } 360 361 const char *COFFObjectFile::getString(std::size_t offset) const { 362 const ulittle32_t *StringTableSize = 363 reinterpret_cast<const ulittle32_t *>(StringTable); 364 if (offset < *StringTableSize) 365 return StringTable + offset; 366 return 0; 367 } 368 369 namespace llvm { 370 371 ObjectFile *ObjectFile::createCOFFObjectFile(MemoryBuffer *Object) { 372 return new COFFObjectFile(Object); 373 } 374 375 } // end namespace llvm 376