COFFObjectFile.cpp revision 218885
1218885Sdim//===- COFFObjectFile.cpp - COFF object file implementation -----*- C++ -*-===// 2218885Sdim// 3218885Sdim// The LLVM Compiler Infrastructure 4218885Sdim// 5218885Sdim// This file is distributed under the University of Illinois Open Source 6218885Sdim// License. See LICENSE.TXT for details. 7218885Sdim// 8218885Sdim//===----------------------------------------------------------------------===// 9218885Sdim// 10218885Sdim// This file declares the COFFObjectFile class. 11218885Sdim// 12218885Sdim//===----------------------------------------------------------------------===// 13218885Sdim 14218885Sdim#include "llvm/ADT/StringSwitch.h" 15218885Sdim#include "llvm/ADT/Triple.h" 16218885Sdim#include "llvm/Object/ObjectFile.h" 17218885Sdim#include "llvm/Support/COFF.h" 18218885Sdim#include "llvm/Support/Endian.h" 19218885Sdim 20218885Sdimusing namespace llvm; 21218885Sdimusing namespace object; 22218885Sdim 23218885Sdimnamespace { 24218885Sdimusing support::ulittle8_t; 25218885Sdimusing support::ulittle16_t; 26218885Sdimusing support::ulittle32_t; 27218885Sdimusing support::little16_t; 28218885Sdim} 29218885Sdim 30218885Sdimnamespace { 31218885Sdimstruct coff_file_header { 32218885Sdim ulittle16_t Machine; 33218885Sdim ulittle16_t NumberOfSections; 34218885Sdim ulittle32_t TimeDateStamp; 35218885Sdim ulittle32_t PointerToSymbolTable; 36218885Sdim ulittle32_t NumberOfSymbols; 37218885Sdim ulittle16_t SizeOfOptionalHeader; 38218885Sdim ulittle16_t Characteristics; 39218885Sdim}; 40218885Sdim} 41218885Sdim 42218885Sdimextern char coff_file_header_layout_static_assert 43218885Sdim [sizeof(coff_file_header) == 20 ? 1 : -1]; 44218885Sdim 45218885Sdimnamespace { 46218885Sdimstruct coff_symbol { 47218885Sdim struct StringTableOffset { 48218885Sdim ulittle32_t Zeroes; 49218885Sdim ulittle32_t Offset; 50218885Sdim }; 51218885Sdim 52218885Sdim union { 53218885Sdim char ShortName[8]; 54218885Sdim StringTableOffset Offset; 55218885Sdim } Name; 56218885Sdim 57218885Sdim ulittle32_t Value; 58218885Sdim little16_t SectionNumber; 59218885Sdim 60218885Sdim struct { 61218885Sdim ulittle8_t BaseType; 62218885Sdim ulittle8_t ComplexType; 63218885Sdim } Type; 64218885Sdim 65218885Sdim ulittle8_t StorageClass; 66218885Sdim ulittle8_t NumberOfAuxSymbols; 67218885Sdim}; 68218885Sdim} 69218885Sdim 70218885Sdimextern char coff_coff_symbol_layout_static_assert 71218885Sdim [sizeof(coff_symbol) == 18 ? 1 : -1]; 72218885Sdim 73218885Sdimnamespace { 74218885Sdimstruct coff_section { 75218885Sdim char Name[8]; 76218885Sdim ulittle32_t VirtualSize; 77218885Sdim ulittle32_t VirtualAddress; 78218885Sdim ulittle32_t SizeOfRawData; 79218885Sdim ulittle32_t PointerToRawData; 80218885Sdim ulittle32_t PointerToRelocations; 81218885Sdim ulittle32_t PointerToLinenumbers; 82218885Sdim ulittle16_t NumberOfRelocations; 83218885Sdim ulittle16_t NumberOfLinenumbers; 84218885Sdim ulittle32_t Characteristics; 85218885Sdim}; 86218885Sdim} 87218885Sdim 88218885Sdimextern char coff_coff_section_layout_static_assert 89218885Sdim [sizeof(coff_section) == 40 ? 1 : -1]; 90218885Sdim 91218885Sdimnamespace { 92218885Sdimclass COFFObjectFile : public ObjectFile { 93218885Sdimprivate: 94218885Sdim const coff_file_header *Header; 95218885Sdim const coff_section *SectionTable; 96218885Sdim const coff_symbol *SymbolTable; 97218885Sdim const char *StringTable; 98218885Sdim 99218885Sdim const coff_section *getSection(std::size_t index) const; 100218885Sdim const char *getString(std::size_t offset) const; 101218885Sdim 102218885Sdimprotected: 103218885Sdim virtual SymbolRef getSymbolNext(DataRefImpl Symb) const; 104218885Sdim virtual StringRef getSymbolName(DataRefImpl Symb) const; 105218885Sdim virtual uint64_t getSymbolAddress(DataRefImpl Symb) const; 106218885Sdim virtual uint64_t getSymbolSize(DataRefImpl Symb) const; 107218885Sdim virtual char getSymbolNMTypeChar(DataRefImpl Symb) const; 108218885Sdim virtual bool isSymbolInternal(DataRefImpl Symb) const; 109218885Sdim 110218885Sdim virtual SectionRef getSectionNext(DataRefImpl Sec) const; 111218885Sdim virtual StringRef getSectionName(DataRefImpl Sec) const; 112218885Sdim virtual uint64_t getSectionAddress(DataRefImpl Sec) const; 113218885Sdim virtual uint64_t getSectionSize(DataRefImpl Sec) const; 114218885Sdim virtual StringRef getSectionContents(DataRefImpl Sec) const; 115218885Sdim virtual bool isSectionText(DataRefImpl Sec) const; 116218885Sdim 117218885Sdimpublic: 118218885Sdim COFFObjectFile(MemoryBuffer *Object); 119218885Sdim virtual symbol_iterator begin_symbols() const; 120218885Sdim virtual symbol_iterator end_symbols() const; 121218885Sdim virtual section_iterator begin_sections() const; 122218885Sdim virtual section_iterator end_sections() const; 123218885Sdim 124218885Sdim virtual uint8_t getBytesInAddress() const; 125218885Sdim virtual StringRef getFileFormatName() const; 126218885Sdim virtual unsigned getArch() const; 127218885Sdim}; 128218885Sdim} // end namespace 129218885Sdim 130218885SdimSymbolRef COFFObjectFile::getSymbolNext(DataRefImpl Symb) const { 131218885Sdim const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 132218885Sdim symb += 1 + symb->NumberOfAuxSymbols; 133218885Sdim Symb.p = reinterpret_cast<intptr_t>(symb); 134218885Sdim return SymbolRef(Symb, this); 135218885Sdim} 136218885Sdim 137218885SdimStringRef COFFObjectFile::getSymbolName(DataRefImpl Symb) const { 138218885Sdim const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 139218885Sdim // Check for string table entry. First 4 bytes are 0. 140218885Sdim if (symb->Name.Offset.Zeroes == 0) { 141218885Sdim uint32_t Offset = symb->Name.Offset.Offset; 142218885Sdim return StringRef(getString(Offset)); 143218885Sdim } 144218885Sdim 145218885Sdim if (symb->Name.ShortName[7] == 0) 146218885Sdim // Null terminated, let ::strlen figure out the length. 147218885Sdim return StringRef(symb->Name.ShortName); 148218885Sdim // Not null terminated, use all 8 bytes. 149218885Sdim return StringRef(symb->Name.ShortName, 8); 150218885Sdim} 151218885Sdim 152218885Sdimuint64_t COFFObjectFile::getSymbolAddress(DataRefImpl Symb) const { 153218885Sdim const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 154218885Sdim const coff_section *Section = getSection(symb->SectionNumber); 155218885Sdim char Type = getSymbolNMTypeChar(Symb); 156218885Sdim if (Type == 'U' || Type == 'w') 157218885Sdim return UnknownAddressOrSize; 158218885Sdim if (Section) 159218885Sdim return Section->VirtualAddress + symb->Value; 160218885Sdim return symb->Value; 161218885Sdim} 162218885Sdim 163218885Sdimuint64_t COFFObjectFile::getSymbolSize(DataRefImpl Symb) const { 164218885Sdim // FIXME: Return the correct size. This requires looking at all the symbols 165218885Sdim // in the same section as this symbol, and looking for either the next 166218885Sdim // symbol, or the end of the section. 167218885Sdim const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 168218885Sdim const coff_section *Section = getSection(symb->SectionNumber); 169218885Sdim char Type = getSymbolNMTypeChar(Symb); 170218885Sdim if (Type == 'U' || Type == 'w') 171218885Sdim return UnknownAddressOrSize; 172218885Sdim if (Section) 173218885Sdim return Section->SizeOfRawData - symb->Value; 174218885Sdim return 0; 175218885Sdim} 176218885Sdim 177218885Sdimchar COFFObjectFile::getSymbolNMTypeChar(DataRefImpl Symb) const { 178218885Sdim const coff_symbol *symb = reinterpret_cast<const coff_symbol*>(Symb.p); 179218885Sdim char ret = StringSwitch<char>(getSymbolName(Symb)) 180218885Sdim .StartsWith(".debug", 'N') 181218885Sdim .StartsWith(".sxdata", 'N') 182218885Sdim .Default('?'); 183218885Sdim 184218885Sdim if (ret != '?') 185218885Sdim return ret; 186218885Sdim 187218885Sdim uint32_t Characteristics = 0; 188218885Sdim uint32_t PointerToRawData = 0; 189218885Sdim const coff_section *Section = getSection(symb->SectionNumber); 190218885Sdim if (Section) { 191218885Sdim Characteristics = Section->Characteristics; 192218885Sdim PointerToRawData = Section->PointerToRawData; 193218885Sdim } 194218885Sdim 195218885Sdim switch (symb->SectionNumber) { 196218885Sdim case COFF::IMAGE_SYM_UNDEFINED: 197218885Sdim // Check storage classes. 198218885Sdim if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL) 199218885Sdim return 'w'; // Don't do ::toupper. 200218885Sdim else 201218885Sdim ret = 'u'; 202218885Sdim break; 203218885Sdim case COFF::IMAGE_SYM_ABSOLUTE: 204218885Sdim ret = 'a'; 205218885Sdim break; 206218885Sdim case COFF::IMAGE_SYM_DEBUG: 207218885Sdim ret = 'n'; 208218885Sdim break; 209218885Sdim default: 210218885Sdim // Check section type. 211218885Sdim if (Characteristics & COFF::IMAGE_SCN_CNT_CODE) 212218885Sdim ret = 't'; 213218885Sdim else if ( Characteristics & COFF::IMAGE_SCN_MEM_READ 214218885Sdim && ~Characteristics & COFF::IMAGE_SCN_MEM_WRITE) // Read only. 215218885Sdim ret = 'r'; 216218885Sdim else if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) 217218885Sdim ret = 'd'; 218218885Sdim else if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) 219218885Sdim ret = 'b'; 220218885Sdim else if (Characteristics & COFF::IMAGE_SCN_LNK_INFO) 221218885Sdim ret = 'i'; 222218885Sdim 223218885Sdim // Check for section symbol. 224218885Sdim else if ( symb->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC 225218885Sdim && symb->Value == 0) 226218885Sdim ret = 's'; 227218885Sdim } 228218885Sdim 229218885Sdim if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL) 230218885Sdim ret = ::toupper(ret); 231218885Sdim 232218885Sdim return ret; 233218885Sdim} 234218885Sdim 235218885Sdimbool COFFObjectFile::isSymbolInternal(DataRefImpl Symb) const { 236218885Sdim return false; 237218885Sdim} 238218885Sdim 239218885SdimSectionRef COFFObjectFile::getSectionNext(DataRefImpl Sec) const { 240218885Sdim const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 241218885Sdim sec += 1; 242218885Sdim Sec.p = reinterpret_cast<intptr_t>(sec); 243218885Sdim return SectionRef(Sec, this); 244218885Sdim} 245218885Sdim 246218885SdimStringRef COFFObjectFile::getSectionName(DataRefImpl Sec) const { 247218885Sdim const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 248218885Sdim StringRef name; 249218885Sdim if (sec->Name[7] == 0) 250218885Sdim // Null terminated, let ::strlen figure out the length. 251218885Sdim name = sec->Name; 252218885Sdim else 253218885Sdim // Not null terminated, use all 8 bytes. 254218885Sdim name = StringRef(sec->Name, 8); 255218885Sdim 256218885Sdim // Check for string table entry. First byte is '/'. 257218885Sdim if (name[0] == '/') { 258218885Sdim uint32_t Offset; 259218885Sdim name.getAsInteger(10, Offset); 260218885Sdim return StringRef(getString(Offset)); 261218885Sdim } 262218885Sdim 263218885Sdim // It's just a normal name. 264218885Sdim return name; 265218885Sdim} 266218885Sdim 267218885Sdimuint64_t COFFObjectFile::getSectionAddress(DataRefImpl Sec) const { 268218885Sdim const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 269218885Sdim return sec->VirtualAddress; 270218885Sdim} 271218885Sdim 272218885Sdimuint64_t COFFObjectFile::getSectionSize(DataRefImpl Sec) const { 273218885Sdim const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 274218885Sdim return sec->SizeOfRawData; 275218885Sdim} 276218885Sdim 277218885SdimStringRef COFFObjectFile::getSectionContents(DataRefImpl Sec) const { 278218885Sdim const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 279218885Sdim return StringRef(reinterpret_cast<const char *>(base + sec->PointerToRawData), 280218885Sdim sec->SizeOfRawData); 281218885Sdim} 282218885Sdim 283218885Sdimbool COFFObjectFile::isSectionText(DataRefImpl Sec) const { 284218885Sdim const coff_section *sec = reinterpret_cast<const coff_section*>(Sec.p); 285218885Sdim return sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE; 286218885Sdim} 287218885Sdim 288218885SdimCOFFObjectFile::COFFObjectFile(MemoryBuffer *Object) 289218885Sdim : ObjectFile(Object) { 290218885Sdim Header = reinterpret_cast<const coff_file_header *>(base); 291218885Sdim SectionTable = 292218885Sdim reinterpret_cast<const coff_section *>( base 293218885Sdim + sizeof(coff_file_header) 294218885Sdim + Header->SizeOfOptionalHeader); 295218885Sdim SymbolTable = 296218885Sdim reinterpret_cast<const coff_symbol *>(base + Header->PointerToSymbolTable); 297218885Sdim 298218885Sdim // Find string table. 299218885Sdim StringTable = reinterpret_cast<const char *>(base) 300218885Sdim + Header->PointerToSymbolTable 301218885Sdim + Header->NumberOfSymbols * 18; 302218885Sdim} 303218885Sdim 304218885SdimObjectFile::symbol_iterator COFFObjectFile::begin_symbols() const { 305218885Sdim DataRefImpl ret; 306218885Sdim ret.p = reinterpret_cast<intptr_t>(SymbolTable); 307218885Sdim return symbol_iterator(SymbolRef(ret, this)); 308218885Sdim} 309218885Sdim 310218885SdimObjectFile::symbol_iterator COFFObjectFile::end_symbols() const { 311218885Sdim // The symbol table ends where the string table begins. 312218885Sdim DataRefImpl ret; 313218885Sdim ret.p = reinterpret_cast<intptr_t>(StringTable); 314218885Sdim return symbol_iterator(SymbolRef(ret, this)); 315218885Sdim} 316218885Sdim 317218885SdimObjectFile::section_iterator COFFObjectFile::begin_sections() const { 318218885Sdim DataRefImpl ret; 319218885Sdim ret.p = reinterpret_cast<intptr_t>(SectionTable); 320218885Sdim return section_iterator(SectionRef(ret, this)); 321218885Sdim} 322218885Sdim 323218885SdimObjectFile::section_iterator COFFObjectFile::end_sections() const { 324218885Sdim DataRefImpl ret; 325218885Sdim ret.p = reinterpret_cast<intptr_t>(SectionTable + Header->NumberOfSections); 326218885Sdim return section_iterator(SectionRef(ret, this)); 327218885Sdim} 328218885Sdim 329218885Sdimuint8_t COFFObjectFile::getBytesInAddress() const { 330218885Sdim return getArch() == Triple::x86_64 ? 8 : 4; 331218885Sdim} 332218885Sdim 333218885SdimStringRef COFFObjectFile::getFileFormatName() const { 334218885Sdim switch(Header->Machine) { 335218885Sdim case COFF::IMAGE_FILE_MACHINE_I386: 336218885Sdim return "COFF-i386"; 337218885Sdim case COFF::IMAGE_FILE_MACHINE_AMD64: 338218885Sdim return "COFF-x86-64"; 339218885Sdim default: 340218885Sdim return "COFF-<unknown arch>"; 341218885Sdim } 342218885Sdim} 343218885Sdim 344218885Sdimunsigned COFFObjectFile::getArch() const { 345218885Sdim switch(Header->Machine) { 346218885Sdim case COFF::IMAGE_FILE_MACHINE_I386: 347218885Sdim return Triple::x86; 348218885Sdim case COFF::IMAGE_FILE_MACHINE_AMD64: 349218885Sdim return Triple::x86_64; 350218885Sdim default: 351218885Sdim return Triple::UnknownArch; 352218885Sdim } 353218885Sdim} 354218885Sdim 355218885Sdimconst coff_section *COFFObjectFile::getSection(std::size_t index) const { 356218885Sdim if (index > 0 && index <= Header->NumberOfSections) 357218885Sdim return SectionTable + (index - 1); 358218885Sdim return 0; 359218885Sdim} 360218885Sdim 361218885Sdimconst char *COFFObjectFile::getString(std::size_t offset) const { 362218885Sdim const ulittle32_t *StringTableSize = 363218885Sdim reinterpret_cast<const ulittle32_t *>(StringTable); 364218885Sdim if (offset < *StringTableSize) 365218885Sdim return StringTable + offset; 366218885Sdim return 0; 367218885Sdim} 368218885Sdim 369218885Sdimnamespace llvm { 370218885Sdim 371218885Sdim ObjectFile *ObjectFile::createCOFFObjectFile(MemoryBuffer *Object) { 372218885Sdim return new COFFObjectFile(Object); 373218885Sdim } 374218885Sdim 375218885Sdim} // end namespace llvm 376