Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /****************************   coff.cpp   ***********************************
  2. * Author:        Agner Fog
  3. * Date created:  2006-07-15
  4. * Last modified: 2009-01-22
  5. * Project:       objconv
  6. * Module:        coff.cpp
  7. * Description:
  8. * Module for reading PE/COFF files
  9. *
  10. * Class CCOFF is used for reading, interpreting and dumping PE/COFF files.
  11. *
  12. * Copyright 2006-2009 GNU General Public License http://www.gnu.org/licenses
  13. *****************************************************************************/
  14. #include "stdafx.h"
  15.  
  16. // Relocation type names
  17.  
  18. SIntTxt COFF32RelNames[] = {
  19.    {COFF32_RELOC_ABS,     "Absolute"},         // Ignored
  20.    {COFF32_RELOC_DIR32,   "Direct32"},         // 32-bit absolute virtual address
  21.    {COFF32_RELOC_IMGREL,  "Image relative"},   // 32-bit image relative virtual address
  22.    {COFF32_RELOC_SECTION, "Section16"},        // 16-bit section index in file
  23.    {COFF32_RELOC_SECREL,  "Section relative"}, // 32-bit section-relative
  24.    {COFF32_RELOC_SECREL7, "7 bit section relative"}, // 7-bit section-relative
  25.    {COFF32_RELOC_TOKEN,   "CLR token"},        // CLR token
  26.    {COFF32_RELOC_REL32,   "EIP relative"}      // 32-bit relative to end of address field
  27. };
  28.  
  29. SIntTxt COFF64RelNames[] = {
  30.    {COFF64_RELOC_ABS,     "Ignore"},           // Ignored
  31.    {COFF64_RELOC_ABS64,   "64 bit absolute"},  // 64 bit absolute virtual address
  32.    {COFF64_RELOC_ABS32,   "32 bit absolute"},  // 32 bit absolute virtual address
  33.    {COFF64_RELOC_IMGREL,  "Image relative"},   // 32 bit image-relative
  34.    {COFF64_RELOC_REL32,   "RIP relative"},     // 32 bit, RIP-relative
  35.    {COFF64_RELOC_REL32_1, "RIP relative-1"},   // 32 bit, relative to RIP - 1. For instruction with immediate byte operand
  36.    {COFF64_RELOC_REL32_2, "RIP relative-2"},   // 32 bit, relative to RIP - 2. For instruction with immediate word operand
  37.    {COFF64_RELOC_REL32_3, "RIP relative-3"},   // 32 bit, relative to RIP - 3. Useless
  38.    {COFF64_RELOC_REL32_4, "RIP relative-4"},   // 32 bit, relative to RIP - 4. For instruction with immediate dword operand
  39.    {COFF64_RELOC_REL32_5, "RIP relative-5"},   // 32 bit, relative to RIP - 5. Useless
  40.    {COFF32_RELOC_SECTION, "Section index"},    // 16-bit section index in file
  41.    {COFF64_RELOC_SECREL,  "Section relative"}, // 32-bit section-relative
  42.    {COFF64_RELOC_SECREL7, "7 bit section rel"},//  7-bit section-relative
  43.    {COFF64_RELOC_TOKEN,   "CLR token"},        // 64 bit absolute virtual address without inline addend
  44.    {COFF64_RELOC_SREL32,  "32b span dependent"},        //
  45.    {COFF64_RELOC_PAIR,    "pair after span dependent"}, //
  46.    {COFF64_RELOC_PPC_REFHI,"high 16 of 32 bit abs"},    //
  47.    {COFF64_RELOC_PPC_REFLO,"low 16 of 32 bit abs"},     //
  48.    {COFF64_RELOC_PPC_PAIR, "pair after high 16"},       //
  49.    {COFF64_RELOC_PPC_SECRELO,"low 16 of 32 bit section relative"},
  50.    {COFF64_RELOC_PPC_GPREL,  "16 bit GP relative"},     //
  51.    {COFF64_RELOC_PPC_TOKEN,  "CLR token"}               //
  52. };
  53.  
  54. // Machine names
  55.  
  56. SIntTxt COFFMachineNames[] = {
  57.    {0,     "Any/unknown"},     // Any machine/unknown
  58.    {0x184, "Alpha"},           // Alpha AXP
  59.    {0x1C0, "Arm"},             // Arm
  60.    {0x284, "Alpha 64 bit"},    // Alpha AXP 64 bit
  61.    {0x14C, "I386"},            // x86, 32 bit
  62.    {0x200, "IA64"},            // Intel Itanium
  63.    {0x268, "Motorola68000"},   // Motorola 68000 series
  64.    {0x266, "MIPS16"},  
  65.    {0x366, "MIPSwFPU"},
  66.    {0x466, "MIPS16wFPU"},
  67.    {0x1F0, "PowerPC"},
  68.    {0x1F1, "PowerPC"},
  69.    {0x162, "R3000"},
  70.    {0x166, "R4000MIPS"},
  71.    {0x168, "R10000"},
  72.    {0x1A2, "SH3"},
  73.    {0x1A6, "SH4"},
  74.    {0x1C2, "Thumb"},
  75.    {0x8664, "x86-64"}      // x86-64 / AMD64 / Intel EM64T
  76. };
  77.  
  78. // Storage class names
  79. SIntTxt COFFStorageClassNames[] = {
  80.    {COFF_CLASS_END_OF_FUNCTION, "EndOfFunc"},
  81.    {COFF_CLASS_AUTOMATIC, "AutoVariable"},
  82.    {COFF_CLASS_EXTERNAL, "External/Public"},
  83.    {COFF_CLASS_STATIC, "Static/Nonpublic"},
  84.    {COFF_CLASS_REGISTER, "Register"},
  85.    {COFF_CLASS_EXTERNAL_DEF, "ExternalDef"},
  86.    {COFF_CLASS_LABEL, "Label"},
  87.    {COFF_CLASS_UNDEFINED_LABEL, "UndefLabel"},
  88.    {COFF_CLASS_MEMBER_OF_STRUCTURE, "StructMem"},
  89.    {COFF_CLASS_ARGUMENT, "FuncArgument"},
  90.    {COFF_CLASS_STRUCTURE_TAG, "StructTag"},
  91.    {COFF_CLASS_MEMBER_OF_UNION, "UnionMember"},
  92.    {COFF_CLASS_UNION_TAG, "UnionTag"},
  93.    {COFF_CLASS_TYPE_DEFINITION, "TypeDef"},
  94.    {COFF_CLASS_UNDEFINED_STATIC, "UndefStatic"},
  95.    {COFF_CLASS_ENUM_TAG, "EnumTag"},
  96.    {COFF_CLASS_MEMBER_OF_ENUM, "EnumMem"},
  97.    {COFF_CLASS_REGISTER_PARAM, "RegisterParameter"},
  98.    {COFF_CLASS_BIT_FIELD, "BitField"},
  99.    {COFF_CLASS_AUTO_ARGUMENT, "AutoArgument"},
  100.    {COFF_CLASS_LASTENTRY, "DummyLastEntry"},
  101.    {COFF_CLASS_BLOCK, "bb/eb_block"},
  102.    {COFF_CLASS_FUNCTION, "Function_bf/ef"},
  103.    {COFF_CLASS_END_OF_STRUCT, "EndOfStruct"},
  104.    {COFF_CLASS_FILE, "FileName"},
  105.    {COFF_CLASS_LINE, "LineNumber"},
  106.    {COFF_CLASS_SECTION, "SectionLineNumber"},
  107.    {COFF_CLASS_ALIAS, "Alias"},
  108.    {COFF_CLASS_WEAK_EXTERNAL, "WeakExternal"},
  109.    {COFF_CLASS_HIDDEN, "Hidden"}
  110. };
  111.  
  112. // Names of section characteristics
  113. SIntTxt COFFSectionFlagNames[] = {
  114.    {PE_SCN_CNT_CODE,        "Text"},
  115.    {PE_SCN_CNT_INIT_DATA,   "Data"},
  116.    {PE_SCN_CNT_UNINIT_DATA, "BSS"},
  117.    {PE_SCN_LNK_INFO,        "Comments"},
  118.    {PE_SCN_LNK_REMOVE,      "Remove"},
  119.    {PE_SCN_LNK_COMDAT,      "Comdat"},
  120. /* {PE_SCN_ALIGN_1,         "Align by 1"},
  121.    {PE_SCN_ALIGN_2,         "Align by 2"},
  122.    {PE_SCN_ALIGN_4,         "Align by 4"},
  123.    {PE_SCN_ALIGN_8,         "Align by 8"},
  124.    {PE_SCN_ALIGN_16,        "Align by 16"},
  125.    {PE_SCN_ALIGN_32,        "Align by 32"},
  126.    {PE_SCN_ALIGN_64,        "Align by 64"},
  127.    {PE_SCN_ALIGN_128,       "Align by 128"},
  128.    {PE_SCN_ALIGN_256,       "Align by 256"},
  129.    {PE_SCN_ALIGN_512,       "Align by 512"},
  130.    {PE_SCN_ALIGN_1024,      "Align by 1024"},
  131.    {PE_SCN_ALIGN_2048,      "Align by 2048"},
  132.    {PE_SCN_ALIGN_4096,      "Align by 4096"},
  133.    {PE_SCN_ALIGN_8192,      "Align by 8192"}, */
  134.    {PE_SCN_LNK_NRELOC_OVFL, "extended relocations"},
  135.    {PE_SCN_MEM_DISCARDABLE, "Discardable"},
  136.    {PE_SCN_MEM_NOT_CACHED,  "Cannot be cached"},
  137.    {PE_SCN_MEM_NOT_PAGED,   "Not pageable"},
  138.    {PE_SCN_MEM_SHARED,      "Can be shared"},
  139.    {PE_SCN_MEM_EXECUTE,     "Executable"},
  140.    {PE_SCN_MEM_READ,        "Readable"},
  141.    {PE_SCN_MEM_WRITE,       "Writeable"}
  142. };
  143.  
  144. // Names of image data directories in optional header
  145. SIntTxt COFFImageDirNames[] = {
  146.    {0,   "Export_table"},
  147.    {1,   "Import_table"},
  148.    {2,   "Resource_table"},
  149.    {3,   "Exception_table"},
  150.    {4,   "Certificate_table"},
  151.    {5,   "Base_relocation_table"},
  152.    {6,   "Debug_table"},
  153.    {7,   "Architecture_table"},
  154.    {8,   "Global_pointer"},
  155.    {9,   "Thread_local_storage_table"},
  156.    {10,  "Load_configuration_table"},
  157.    {11,  "Bound_import_table"},
  158.    {12,  "Import_address_table"},
  159.    {13,  "Delay_import_descriptor"},
  160.    {14,  "Common_language_runtime_header"},
  161.    {15,  "Reserved_table"}
  162. };
  163.  
  164. // Class CCOFF members:
  165. // Constructor
  166. CCOFF::CCOFF() {
  167.    // Set everything to zero
  168.    memset(this, 0, sizeof(*this));
  169. }
  170.  
  171. void CCOFF::ParseFile(){
  172.    // Load and parse file buffer
  173.    // Get offset to file header
  174.    uint32 FileHeaderOffset = 0;
  175.    if ((Get<uint16>(0) & 0xFFF9) == 0x5A49) {
  176.       // File has DOS stub
  177.       uint32 Signature = Get<uint32>(0x3C);
  178.       if (Signature + 8 < DataSize && Get<uint16>(Signature) == 0x4550) {
  179.          // Executable PE file
  180.          FileHeaderOffset = Signature + 4;
  181.       }
  182.       else {
  183.          err.submit(9000);
  184.          return;
  185.       }
  186.    }
  187.    // Find file header
  188.    FileHeader = &Get<SCOFF_FileHeader>(FileHeaderOffset);
  189.    NSections = FileHeader->NumberOfSections;
  190.  
  191.    // check header integrity
  192.    if ((uint64)FileHeader->PSymbolTable + FileHeader->NumberOfSymbols * SIZE_SCOFF_SymTableEntry > GetDataSize()) err.submit(2035);
  193.  
  194.    // Find optional header if executable file
  195.    if (FileHeader->SizeOfOptionalHeader && FileHeaderOffset) {
  196.       OptionalHeader = &Get<SCOFF_OptionalHeader>(FileHeaderOffset + sizeof(SCOFF_FileHeader));
  197.       // Find image data directories
  198.       if (OptionalHeader) {
  199.          if (OptionalHeader->h64.Magic == COFF_Magic_PE64) {
  200.             // 64 bit version
  201.             pImageDirs = &(OptionalHeader->h64.ExportTable);
  202.             NumImageDirs = OptionalHeader->h64.NumberOfRvaAndSizes;
  203.             EntryPoint = OptionalHeader->h64.AddressOfEntryPoint;
  204.             ImageBase = OptionalHeader->h64.ImageBase;
  205.          }
  206.          else {
  207.             // 32 bit version
  208.             pImageDirs = &(OptionalHeader->h32.ExportTable);
  209.             NumImageDirs = OptionalHeader->h32.NumberOfRvaAndSizes;
  210.             EntryPoint = OptionalHeader->h32.AddressOfEntryPoint;
  211.             ImageBase = OptionalHeader->h32.ImageBase;
  212.          }
  213.       }
  214.    }
  215.  
  216.    // Allocate buffer for section headers
  217.    SectionHeaders.SetNum(NSections);
  218.    SectionHeaders.SetZero();
  219.  
  220.    // Find section headers
  221.    uint32 SectionOffset = FileHeaderOffset + sizeof(SCOFF_FileHeader) + FileHeader->SizeOfOptionalHeader;
  222.    for (int i = 0; i < NSections; i++) {
  223.       SectionHeaders[i] = Get<SCOFF_SectionHeader>(SectionOffset);
  224.       SectionOffset += sizeof(SCOFF_SectionHeader);
  225.       // Check for _ILDATA section
  226.       if (strcmp(SectionHeaders[i].Name, "_ILDATA") == 0) {
  227.          // This is an intermediate file for Intel compiler
  228.          err.submit(2114);
  229.       }
  230.    }
  231.    if (SectionOffset > GetDataSize()) {
  232.       err.submit(2110);  return;             // Section table points to outside file
  233.    }
  234.    // Find symbol table
  235.    SymbolTable = &Get<SCOFF_SymTableEntry>(FileHeader->PSymbolTable);
  236.    NumberOfSymbols = FileHeader->NumberOfSymbols;
  237.  
  238.    // Find string table
  239.    StringTable = (Buf() + FileHeader->PSymbolTable + NumberOfSymbols * SIZE_SCOFF_SymTableEntry);
  240.    StringTableSize = *(int*)StringTable; // First 4 bytes of string table contains its size
  241. }
  242.  
  243. // Debug dump
  244. void CCOFF::Dump(int options) {
  245.    uint32 i, j;
  246.  
  247.    if (options & DUMP_FILEHDR) {
  248.       // File header
  249.       printf("\nDump of PE/COFF file %s", FileName);
  250.       printf("\n-----------------------------------------------");
  251.       printf("\nFile size: %i", GetDataSize());
  252.       printf("\nFile header:");
  253.       printf("\nMachine: %s", Lookup(COFFMachineNames,FileHeader->Machine));
  254.       printf("\nTimeDate: 0x%08X", FileHeader->TimeDateStamp);
  255.       printf(" - %s", timestring(FileHeader->TimeDateStamp));
  256.       printf("\nNumber of sections: %2i", FileHeader->NumberOfSections);
  257.       printf("\nNumber of symbols:  %2i", FileHeader->NumberOfSymbols);
  258.       printf("\nOptional header size: %i", FileHeader->SizeOfOptionalHeader);
  259.       printf("\nFlags: 0x%04X", FileHeader->Flags);
  260.  
  261.       // May be removed:
  262.       printf("\nSymbol table offset: 0x%X", FileHeader->PSymbolTable);
  263.       printf("\nString table offset: 0x%X", FileHeader->PSymbolTable + FileHeader->NumberOfSymbols * SIZE_SCOFF_SymTableEntry);
  264.       printf("\nSection headers offset: 0x%X", (uint32)sizeof(SCOFF_FileHeader) + FileHeader->SizeOfOptionalHeader);
  265.  
  266.       // Optional header
  267.       if (OptionalHeader) {
  268.          printf("\n\nOptional header:");
  269.          if (OptionalHeader->h32.Magic != COFF_Magic_PE64) {
  270.             // 32 bit optional header
  271.             printf("\nMagic number: 0x%X", OptionalHeader->h32.Magic);
  272.             printf("\nSize of code: 0x%X", OptionalHeader->h32.SizeOfCode);
  273.             printf("\nSize of uninitialized data: 0x%X", OptionalHeader->h32.SizeOfInitializedData);
  274.             printf("\nAddress of entry point: 0x%X", OptionalHeader->h32.AddressOfEntryPoint);
  275.             printf("\nBase of code: 0x%X", OptionalHeader->h32.BaseOfCode);
  276.             printf("\nBase of data: 0x%X", OptionalHeader->h32.BaseOfData);
  277.             printf("\nImage base: 0x%X", OptionalHeader->h32.ImageBase);
  278.             printf("\nSection alignment: 0x%X", OptionalHeader->h32.SectionAlignment);
  279.             printf("\nFile alignment: 0x%X", OptionalHeader->h32.FileAlignment);
  280.             printf("\nSize of image: 0x%X", OptionalHeader->h32.SizeOfImage);
  281.             printf("\nSize of headers: 0x%X", OptionalHeader->h32.SizeOfHeaders);
  282.             printf("\nDll characteristics: 0x%X", OptionalHeader->h32.DllCharacteristics);
  283.             printf("\nSize of stack reserve: 0x%X", OptionalHeader->h32.SizeOfStackReserve);
  284.             printf("\nSize of stack commit: 0x%X", OptionalHeader->h32.SizeOfStackCommit);
  285.             printf("\nSize of heap reserve: 0x%X", OptionalHeader->h32.SizeOfHeapReserve);
  286.             printf("\nSize of heap commit: 0x%X", OptionalHeader->h32.SizeOfHeapCommit);
  287.          }
  288.          else {
  289.             // 64 bit optional header
  290.             printf("\nMagic number: 0x%X", OptionalHeader->h64.Magic);
  291.             printf("\nSize of code: 0x%X", OptionalHeader->h64.SizeOfCode);
  292.             printf("\nSize of uninitialized data: 0x%X", OptionalHeader->h64.SizeOfInitializedData);
  293.             printf("\nAddress of entry point: 0x%X", OptionalHeader->h64.AddressOfEntryPoint);
  294.             printf("\nBase of code: 0x%X", OptionalHeader->h64.BaseOfCode);
  295.             printf("\nImage base: 0x%08X%08X", HighDWord(OptionalHeader->h64.ImageBase), uint32(OptionalHeader->h64.ImageBase));
  296.             printf("\nSection alignment: 0x%X", OptionalHeader->h64.SectionAlignment);
  297.             printf("\nFile alignment: 0x%X", OptionalHeader->h64.FileAlignment);
  298.             printf("\nSize of image: 0x%X", OptionalHeader->h64.SizeOfImage);
  299.             printf("\nSize of headers: 0x%X", OptionalHeader->h64.SizeOfHeaders);
  300.             printf("\nDll characteristics: 0x%X", OptionalHeader->h64.DllCharacteristics);
  301.             printf("\nSize of stack reserve: 0x%08X%08X", HighDWord(OptionalHeader->h64.SizeOfStackReserve), uint32(OptionalHeader->h64.SizeOfStackReserve));
  302.             printf("\nSize of stack commit: 0x%08X%08X", HighDWord(OptionalHeader->h64.SizeOfStackCommit), uint32(OptionalHeader->h64.SizeOfStackCommit));
  303.             printf("\nSize of heap reserve: 0x%08X%08X", HighDWord(OptionalHeader->h64.SizeOfHeapReserve), uint32(OptionalHeader->h64.SizeOfHeapReserve));
  304.             printf("\nSize of heap commit: 0x%08X%08X", HighDWord(OptionalHeader->h64.SizeOfHeapCommit), uint32(OptionalHeader->h64.SizeOfHeapCommit));
  305.          }
  306.          // Data directories
  307.          SCOFF_ImageDirAddress dir;
  308.  
  309.          for (i = 0; i < NumImageDirs; i++) {
  310.             if (GetImageDir(i, &dir)) {
  311.                printf("\nDirectory %2i, %s:\n  Address 0x%04X, Size 0x%04X, Section %i, Offset 0x%04X",
  312.                   i, dir.Name,
  313.                   dir.VirtualAddress, dir.Size, dir.Section, dir.SectionOffset);
  314.             }
  315.          }
  316.       }
  317.    }
  318.  
  319.    if ((options & DUMP_STRINGTB) && FileHeader->PSymbolTable && StringTableSize > 4) {
  320.       // String table
  321.       char * p = StringTable + 4;
  322.       uint32 nread = 4, len;
  323.       printf("\n\nString table:");
  324.       while (nread < StringTableSize) {
  325.          len = (int)strlen(p);
  326.          if (len > 0) {
  327.             printf("\n>>%s<<", p);
  328.             nread += len + 1;
  329.             p += len + 1;
  330.          }
  331.       }
  332.    }
  333.    // Symbol tables
  334.    if (options & DUMP_SYMTAB) {
  335.       // Symbol table (object file)
  336.       if (NumberOfSymbols) PrintSymbolTable(-1);
  337.  
  338.       // Import and export tables (executable file)
  339.       if (OptionalHeader) PrintImportExport();
  340.    }
  341.  
  342.    // Section headers
  343.    if (options & (DUMP_SECTHDR | DUMP_SYMTAB | DUMP_RELTAB)) {
  344.       for (j = 0; j < (uint32)NSections; j++) {
  345.          SCOFF_SectionHeader * SectionHeader = &SectionHeaders[j];
  346.          printf("\n\n%2i Section %s", j+1, GetSectionName(SectionHeader->Name));
  347.  
  348.          //printf("\nFile offset of header: 0x%X", (int)((int8*)SectionHeader-buffer));
  349.          printf("\nVirtual size: 0x%X", SectionHeader->VirtualSize);
  350.          if (SectionHeader->VirtualAddress) {
  351.             printf("\nVirtual address: 0x%X", SectionHeader->VirtualAddress);}
  352.          if (SectionHeader->PRawData || SectionHeader->SizeOfRawData) {
  353.             printf("\nSize of raw data: 0x%X", SectionHeader->SizeOfRawData);
  354.             printf("\nRaw data pointer: 0x%X", SectionHeader->PRawData);
  355.          }
  356.          printf("\nCharacteristics: ");
  357.          PrintSegmentCharacteristics(SectionHeader->Flags);
  358.  
  359.          // print relocations
  360.          if ((options & DUMP_RELTAB) && SectionHeader->NRelocations > 0) {
  361.             printf("\nRelocation entries: %i", SectionHeader->NRelocations);
  362.             printf("\nRelocation entries pointer: 0x%X", SectionHeader->PRelocations);
  363.  
  364.             // Pointer to relocation entry
  365.             union {
  366.                SCOFF_Relocation * p;  // pointer to record
  367.                int8 * b;              // used for address calculation and incrementing
  368.             } Reloc;
  369.             Reloc.b = Buf() + SectionHeader->PRelocations;
  370.  
  371.             printf("\nRelocations:");
  372.             for (i = 0; i < SectionHeader->NRelocations; i++) {
  373.                printf("\nAddr: 0x%X, symi: %i, type: %s",
  374.                   Reloc.p->VirtualAddress,
  375.                   Reloc.p->SymbolTableIndex,
  376.                   (WordSize == 32) ? Lookup(COFF32RelNames,Reloc.p->Type) : Lookup(COFF64RelNames,Reloc.p->Type));
  377.                if (Reloc.p->Type < COFF32_RELOC_SEG12)
  378.                {
  379.                   // Check if address is within file
  380.                   if (SectionHeader->PRawData + Reloc.p->VirtualAddress < GetDataSize()) {
  381.                      int32 addend = *(int32*)(Buf() + SectionHeader->PRawData + Reloc.p->VirtualAddress);
  382.                      if (addend) printf(", Implicit addend: %i", addend);
  383.                   }
  384.                   else {
  385.                      printf(". Error: Address is outside file");
  386.                   }
  387.                }
  388.                
  389.                PrintSymbolTable(Reloc.p->SymbolTableIndex);
  390.                Reloc.b += SIZE_SCOFF_Relocation; // Next relocation record
  391.             }
  392.          }
  393.          // print line numbers
  394.          if (SectionHeader->NLineNumbers > 0) {
  395.             printf("\nLine number entries: %i", SectionHeader->NLineNumbers);
  396.             printf("  Line number pointer: %i\nLines:", SectionHeader->PLineNumbers);
  397.            
  398.             // Pointer to line number entry
  399.             union {
  400.                SCOFF_LineNumbers * p;  // pointer to record
  401.                int8 * b;              // used for address calculation and incrementing
  402.             } Linnum;
  403.             Linnum.b = Buf() + SectionHeader->PLineNumbers;
  404.             for (i = 0; i < SectionHeader->NLineNumbers; i++) {
  405.                if (Linnum.p->Line) {  // Record contains line number
  406.                   printf(" %i:%i", Linnum.p->Line, Linnum.p->Addr);
  407.                }
  408.                else { // Record contains function name
  409.                }
  410.                Linnum.b += SIZE_SCOFF_LineNumbers;  // Next line number record
  411.             }        
  412.          }
  413.       }
  414.    }
  415. }
  416.  
  417.  
  418. char const * CCOFF::GetSymbolName(int8* Symbol) {
  419.    // Get symbol name from 8 byte entry
  420.    static char text[16];
  421.    if (*(uint32*)Symbol != 0) {
  422.       // Symbol name not more than 8 bytes
  423.       memcpy(text, Symbol, 8);   // Copy to local buffer
  424.       text[8] = 0;                    // Append terminating zero
  425.       return text;                    // Return text
  426.    }
  427.    else {
  428.       // Longer than 8 bytes. Get offset into string table
  429.       uint32 offset = *(uint32*)(Symbol + 4);
  430.       if (offset >= StringTableSize || offset >= GetDataSize()) {err.submit(2035); return "";}
  431.       char * s = StringTable + offset;
  432.       if (*s) return s;               // Return string table entry
  433.    }
  434.    return "NULL";                     // String table entry was empty
  435. }
  436.  
  437.  
  438. char const * CCOFF::GetSectionName(int8* Symbol) {
  439.    // Get section name from 8 byte entry
  440.    static char text[16];
  441.    memcpy(text, Symbol, 8);        // Copy to local buffer
  442.    text[8] = 0;                    // Append terminating zero
  443.    if (text[0] == '/') {
  444.       // Long name is in string table.
  445.       // Convert decimal ASCII number to string table index
  446.       uint32 sindex = atoi(text + 1);
  447.       // Get name from string table
  448.       if (sindex < StringTableSize) {
  449.          char * s = StringTable + sindex;
  450.          if (*s) return s;}                 // Return string table entry
  451.    }
  452.    else {
  453.       // Short name is in text buffer
  454.       return text;
  455.    }
  456.    return "NULL";                           // In case of error
  457. }
  458.  
  459. char const * CCOFF::GetStorageClassName(uint8 sc) {
  460.    // Get storage class name
  461.    return Lookup(COFFStorageClassNames, sc);
  462. }
  463.  
  464. void CCOFF::PrintSegmentCharacteristics(uint32 flags) {
  465.    // Print segment characteristics
  466.    int n = 0;
  467.    // Loop through all bits of integer
  468.    for (uint32 i = 1; i != 0; i <<= 1) {
  469.       if (i & flags & ~PE_SCN_ALIGN_MASK) {
  470.          if (n++) printf(", ");
  471.          printf("%s", Lookup(COFFSectionFlagNames, i));
  472.       }
  473.    }
  474.    if (flags & PE_SCN_ALIGN_MASK) {
  475.       int a = 1 << (((flags & PE_SCN_ALIGN_MASK) / PE_SCN_ALIGN_1) - 1);
  476.       printf(", Align by 0x%X", a); n++;
  477.    }
  478.    if (n == 0) printf("None");
  479. }
  480.  
  481. const char * CCOFF::GetFileName(SCOFF_SymTableEntry * syme) {
  482.    // Get file name from records in symbol table
  483.    if (syme->s.NumAuxSymbols < 1 || syme->s.StorageClass != COFF_CLASS_FILE) {
  484.       return ""; // No file name found
  485.    }
  486.    // Set limit to file name length = 576
  487.    const uint32 MAXCOFFFILENAMELENGTH = 32 * SIZE_SCOFF_SymTableEntry;
  488.    // Buffer to store file name. Must be static
  489.    static char text[MAXCOFFFILENAMELENGTH+1];
  490.    // length of name in record
  491.    uint32 len = syme->s.NumAuxSymbols * SIZE_SCOFF_SymTableEntry;
  492.    if (len > MAXCOFFFILENAMELENGTH) len = MAXCOFFFILENAMELENGTH;
  493.    // copy name from auxiliary records
  494.    memcpy(text, (int8*)syme + SIZE_SCOFF_SymTableEntry, len);
  495.    // Terminate string
  496.    text[len] = 0;
  497.    // Return name
  498.    return text;
  499. }
  500.  
  501. const char * CCOFF::GetShortFileName(SCOFF_SymTableEntry * syme) {
  502.    // Same as above. Strips path before filename
  503.    // Full file name
  504.    const char * fullname = GetFileName(syme);
  505.    // Length
  506.    uint32 len = (uint32)strlen(fullname);
  507.    if (len < 1) return fullname;
  508.    // Scan backwards for '/', '\', ':'
  509.    for (int scan = len-2; scan >= 0; scan--) {
  510.       char c = fullname[scan];
  511.       if (c == '/' || c == '\\' || c == ':') {
  512.          // Path found. Short name starts after this character
  513.          return fullname + scan + 1;
  514.       }
  515.    }
  516.    // No path found. Return full name
  517.    return fullname;
  518. }
  519.  
  520. void CCOFF::PrintSymbolTable(int symnum) {
  521.    // Print one or all public symbols for object file.
  522.    // Dump symbol table if symnum = -1, or
  523.    // Dump symbol number symnum (zero based) when symnum >= 0
  524.    int isym = 0;  // current symbol table entry
  525.    int jsym = 0;  // auxiliary entry number
  526.    union {        // Pointer to symbol table
  527.       SCOFF_SymTableEntry * p;  // Normal pointer
  528.       int8 * b;                 // Used for address calculation
  529.    } Symtab;
  530.  
  531.    Symtab.p = SymbolTable;      // Set pointer to begin of SymbolTable
  532.    if (symnum == -1) printf("\n\nSymbol table:");
  533.    if (symnum >= 0) {
  534.       // Print one symbol only
  535.       if (symnum >= NumberOfSymbols) {
  536.          printf("\nSymbol %i not found", symnum);
  537.          return;
  538.       }
  539.       isym = symnum;
  540.       Symtab.b += SIZE_SCOFF_SymTableEntry * isym;
  541.    }
  542.    while (isym < NumberOfSymbols) {
  543.       // Print symbol table entry
  544.       SCOFF_SymTableEntry *s0;
  545.       printf("\n");
  546.       if (symnum >= 0) printf("  ");
  547.       printf("Symbol %i - Name: %s\n  Value=%i, ",
  548.          isym, GetSymbolName(Symtab.p->s.Name), Symtab.p->s.Value);
  549.       if (Symtab.p->s.SectionNumber > 0) {
  550.          printf("Section=%i", Symtab.p->s.SectionNumber);
  551.       }
  552.       else { // Special section numbers
  553.          switch (Symtab.p->s.SectionNumber) {
  554.          case COFF_SECTION_UNDEF:
  555.             printf("External"); break;
  556.          case COFF_SECTION_ABSOLUTE:
  557.             printf("Absolute"); break;
  558.          case COFF_SECTION_DEBUG:
  559.             printf("Debug"); break;
  560.          case COFF_SECTION_N_TV:
  561.             printf("Preload transfer"); break;
  562.          case COFF_SECTION_P_TV:
  563.             printf("Postload transfer"); break;
  564.          }
  565.       }
  566.       printf(", Type=0x%X, StorClass=%s, NumAux=%i",
  567.          Symtab.p->s.Type,
  568.          GetStorageClassName(Symtab.p->s.StorageClass), Symtab.p->s.NumAuxSymbols);
  569.       if (Symtab.p->s.StorageClass == COFF_CLASS_FILE && Symtab.p->s.NumAuxSymbols > 0) {
  570.          printf("\n  File name: %s", GetFileName(Symtab.p));
  571.       }
  572.       // Increment point
  573.       s0 = Symtab.p;
  574.       Symtab.b += SIZE_SCOFF_SymTableEntry;
  575.       isym++;  jsym = 0;
  576.       // Get auxiliary records
  577.       while (jsym < s0->s.NumAuxSymbols && isym + jsym < NumberOfSymbols) {
  578.          // Print auxiliary symbol table entry
  579.          SCOFF_SymTableEntry * sa = Symtab.p;
  580.          // Detect auxiliary entry type
  581.          if (s0->s.StorageClass == COFF_CLASS_EXTERNAL
  582.             && s0->s.Type == COFF_TYPE_FUNCTION
  583.             && s0->s.SectionNumber > 0) {
  584.             // This is a function definition aux record
  585.             printf("\n  Aux function definition:");
  586.             printf("\n  .bf_tag_index: 0x%X, code_size: %i, PLineNumRec: %i, PNext: %i",
  587.                sa->func.TagIndex, sa->func.TotalSize, sa->func.PointerToLineNumber,
  588.                sa->func.PointerToNextFunction);
  589.          }
  590.          else if (strcmp(s0->s.Name,".bf")==0 || strcmp(s0->s.Name,".ef")==0) {
  591.             // This is a .bf or .ef aux record
  592.             printf("\n  Aux .bf/.ef definition:");
  593.             printf("\n  Source line number: %i",
  594.                sa->bfef.SourceLineNumber);
  595.             if (strcmp(s0->s.Name,".bf")==0 ) {
  596.                printf(", PNext: %i", sa->bfef.PointerToNextFunction);
  597.             }
  598.          }
  599.          else if (s0->s.StorageClass == COFF_CLASS_EXTERNAL &&
  600.             s0->s.SectionNumber == COFF_SECTION_UNDEF &&
  601.             s0->s.Value == 0) {
  602.             // This is a Weak external aux record
  603.             printf("\n  Aux Weak external definition:");
  604.             printf("\n  Symbol2 index: %i, Characteristics: 0x%X",
  605.                sa->weak.TagIndex, sa->weak.Characteristics);
  606.             }
  607.          else if (s0->s.StorageClass == COFF_CLASS_FILE) {
  608.             // This is filename aux record. Contents has already been printed
  609.          }
  610.          else if (s0->s.StorageClass == COFF_CLASS_STATIC) {
  611.             // This is section definition aux record
  612.             printf("\n  Aux section definition record:");
  613.             printf("\n  Length: %i, Num. relocations: %i, Num linenums: %i, checksum 0x%X,"
  614.                "\n  Number: %i, Selection: %i",
  615.                sa->section.Length, sa->section.NumberOfRelocations, sa->section.NumberOfLineNumbers,
  616.                sa->section.CheckSum, sa->section.Number, sa->section.Selection);
  617.          }
  618.          else if (s0->s.StorageClass == COFF_CLASS_ALIAS) {
  619.             // This is section definition aux record
  620.             printf("\n  Aux alias definition record:");
  621.             printf("\n  symbol index: %i, ", sa->weak.TagIndex);
  622.             switch (sa->weak.Characteristics) {
  623.             case IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY:
  624.                 printf("no library search"); break;
  625.             case IMAGE_WEAK_EXTERN_SEARCH_LIBRARY:
  626.                 printf("library search"); break;
  627.             case IMAGE_WEAK_EXTERN_SEARCH_ALIAS:
  628.                 printf("alias symbol"); break;
  629.             default:
  630.                 printf("unknown characteristics 0x%X", sa->weak.Characteristics);
  631.             }
  632.          }        
  633.          else {
  634.             // Unknown aux record type
  635.             printf("\n  Unknown Auxiliary record type %i", s0->s.StorageClass);
  636.          }
  637.          Symtab.b += SIZE_SCOFF_SymTableEntry;
  638.          jsym++;
  639.       }
  640.       isym += jsym;
  641.       if (symnum >= 0) break;
  642.    }
  643. }
  644.  
  645. void CCOFF::PublicNames(CMemoryBuffer * Strings, CSList<SStringEntry> * Index, int m) {
  646.    // Make list of public names in object file
  647.    // Strings will receive ASCIIZ strings
  648.    // Index will receive records of type SStringEntry with Member = m
  649.  
  650.    // Interpret header:
  651.    ParseFile();
  652.  
  653.    int isym = 0;  // current symbol table entry
  654.    union {        // Pointer to symbol table
  655.       SCOFF_SymTableEntry * p;  // Normal pointer
  656.       int8 * b;                 // Used for address calculation
  657.    } Symtab;
  658.  
  659.    // Loop through symbol table
  660.    Symtab.p = SymbolTable;
  661.    while (isym < NumberOfSymbols) {
  662.       // Check within buffer
  663.       if (Symtab.b >= Buf() + DataSize) {
  664.          err.submit(2040);
  665.          break;
  666.       }
  667.  
  668.       // Search for public symbol
  669.       if (Symtab.p->s.SectionNumber > 0 && Symtab.p->s.StorageClass == COFF_CLASS_EXTERNAL) {
  670.          // Public symbol found
  671.          SStringEntry se;
  672.          se.Member = m;
  673.  
  674.          // Store name
  675.          se.String = Strings->PushString(GetSymbolName(Symtab.p->s.Name));
  676.          // Store name index
  677.          Index->Push(se);
  678.       }
  679.       if ((int8)Symtab.p->s.NumAuxSymbols < 0) Symtab.p->s.NumAuxSymbols = 0;
  680.  
  681.       // Increment point
  682.       isym += Symtab.p->s.NumAuxSymbols + 1;
  683.       Symtab.b += (1 + Symtab.p->s.NumAuxSymbols) * SIZE_SCOFF_SymTableEntry;
  684.    }
  685. }
  686.  
  687. int CCOFF::GetImageDir(uint32 n, SCOFF_ImageDirAddress * dir) {
  688.    // Find address of image directory for executable files
  689.    int32  Section;
  690.    uint32 FileOffset;
  691.  
  692.    if (pImageDirs == 0 || n >= NumImageDirs || dir == 0) {
  693.       // Failure
  694.       return 0;
  695.    }
  696.    // Get virtual address and size of directory
  697.    dir->VirtualAddress = pImageDirs[n].VirtualAddress;
  698.    dir->Size           = pImageDirs[n].Size;
  699.    dir->Name           = Lookup(COFFImageDirNames, n);
  700.  
  701.    // Check if nonzero
  702.    if (dir->VirtualAddress == 0 || dir->Size == 0) {
  703.       // Empty
  704.       return 0;
  705.    }
  706.  
  707.    // Search for section containing this address
  708.    for (Section = 0; Section < NSections; Section++) {
  709.       if (dir->VirtualAddress >= SectionHeaders[Section].VirtualAddress
  710.       && dir->VirtualAddress < SectionHeaders[Section].VirtualAddress + SectionHeaders[Section].SizeOfRawData) {
  711.          // Found section
  712.          dir->Section = Section + 1;
  713.          // Section-relative offset
  714.          dir->SectionOffset = dir->VirtualAddress - SectionHeaders[Section].VirtualAddress;
  715.          // Calculate file offset
  716.          FileOffset = SectionHeaders[Section].PRawData + dir->SectionOffset;
  717.          if (FileOffset == 0 || FileOffset >= DataSize) {
  718.             // points outside file
  719.             err.submit(2035);
  720.             return 0;
  721.          }
  722.          // FileOffset is within range
  723.          dir->FileOffset = FileOffset;
  724.  
  725.          // Maximum allowed offset
  726.          dir->MaxOffset = SectionHeaders[Section].SizeOfRawData - dir->SectionOffset;
  727.  
  728.          // Return success
  729.          return Section;
  730.       }
  731.    }
  732.    // Import section not found
  733.    return 0;
  734. }
  735.  
  736. void CCOFF::PrintImportExport() {
  737.    // Print imported and exported symbols
  738.  
  739.    // Table directory address
  740.    SCOFF_ImageDirAddress dir;
  741.  
  742.    uint32 i;                                     // Index into OrdinalTable and NamePointerTable
  743.    uint32 Ordinal;                               // Index into ExportAddressTable
  744.    uint32 Address;                               // Virtual address of exported symbol
  745.    uint32 NameOffset;                            // Section offset of symbol name
  746.    uint32 SectionOffset;                         // Section offset of table
  747.    const char * Name;                            // Name of symbol
  748.  
  749.    // Check if 64 bit
  750.    int Is64bit = OptionalHeader->h64.Magic == COFF_Magic_PE64;
  751.  
  752.    // Exported names
  753.    if (GetImageDir(0, &dir)) {
  754.  
  755.       // Beginning of export section is export directory
  756.       SCOFF_ExportDirectory * pExportDirectory = &Get<SCOFF_ExportDirectory>(dir.FileOffset);
  757.  
  758.       // Find ExportAddressTable
  759.       SectionOffset = pExportDirectory->ExportAddressTableRVA - dir.VirtualAddress;
  760.       if (SectionOffset == 0 || SectionOffset >= dir.MaxOffset) {
  761.          // Points outside section
  762.          err.submit(2035);  return;
  763.       }
  764.       uint32 * pExportAddressTable = &Get<uint32>(dir.FileOffset + SectionOffset);
  765.  
  766.       // Find ExportNameTable
  767.       SectionOffset = pExportDirectory->NamePointerTableRVA - dir.VirtualAddress;
  768.       if (SectionOffset == 0 || SectionOffset >= dir.MaxOffset) {
  769.          // Points outside section
  770.          err.submit(2035);  return;
  771.       }
  772.       uint32 * pExportNameTable = &Get<uint32>(dir.FileOffset + SectionOffset);
  773.  
  774.       // Find ExportOrdinalTable
  775.       SectionOffset = pExportDirectory->OrdinalTableRVA - dir.VirtualAddress;
  776.       if (SectionOffset == 0 || SectionOffset >= dir.MaxOffset) {
  777.          // Points outside section
  778.          err.submit(2035);  return;
  779.       }
  780.       uint16 * pExportOrdinalTable = &Get<uint16>(dir.FileOffset + SectionOffset);
  781.  
  782.       // Get further properties
  783.       uint32 NumExports = pExportDirectory->AddressTableEntries;
  784.       uint32 NumExportNames = pExportDirectory->NamePointerEntries;
  785.       uint32 OrdinalBase = pExportDirectory->OrdinalBase;
  786.  
  787.       // Print exported names
  788.       printf("\n\nExported symbols:");
  789.  
  790.       // Loop through export tables
  791.       for (i = 0; i < NumExports; i++) {
  792.  
  793.          Address = 0;
  794.          Name = "(None)";
  795.  
  796.          // Get ordinal from table
  797.          Ordinal = pExportOrdinalTable[i];
  798.          // Address table is indexed by ordinal
  799.          if (Ordinal < NumExports) {
  800.             Address = pExportAddressTable[Ordinal];
  801.          }
  802.          // Find name if there is a name list entry
  803.          if (i < NumExportNames) {
  804.             NameOffset = pExportNameTable[i] - dir.VirtualAddress;
  805.             if (NameOffset && NameOffset < dir.MaxOffset) {
  806.                Name = &Get<char>(dir.FileOffset + NameOffset);
  807.             }
  808.          }
  809.          // Print ordinal, address and name
  810.          printf("\n  Ordinal %3i, Address %6X, Name %s",
  811.             Ordinal + OrdinalBase, Address, Name);
  812.       }
  813.    }
  814.    // Imported names
  815.    if (GetImageDir(1, &dir)) {
  816.  
  817.       // Print imported names
  818.       printf("\n\nImported symbols:");
  819.  
  820.       // Pointer to current import directory entry
  821.       SCOFF_ImportDirectory * ImportEntry = &Get<SCOFF_ImportDirectory>(dir.FileOffset);
  822.       // Pointer to current import lookup table entry
  823.       int32 * LookupEntry = 0;
  824.       // Pointer to current hint/name table entry
  825.       SCOFF_ImportHintName * HintNameEntry;
  826.  
  827.       // Loop through import directory until null entry
  828.       while (ImportEntry->DLLNameRVA) {
  829.          // Get DLL name
  830.          NameOffset = ImportEntry->DLLNameRVA - dir.VirtualAddress;
  831.          if (NameOffset < dir.MaxOffset) {
  832.             Name = &Get<char>(dir.FileOffset + NameOffset);
  833.          }
  834.          else {
  835.             Name = "Error";
  836.          }
  837.          // Print DLL name
  838.          printf("\nFrom %s", Name);
  839.  
  840.          // Get lookup table
  841.          SectionOffset = ImportEntry->ImportLookupTableRVA;
  842.          if (SectionOffset == 0) SectionOffset = ImportEntry->ImportAddressTableRVA;
  843.          if (SectionOffset == 0) continue;
  844.          SectionOffset -= dir.VirtualAddress;
  845.          if (SectionOffset >= dir.MaxOffset) break;  // Out of range
  846.          LookupEntry = &Get<int32>(dir.FileOffset + SectionOffset);
  847.  
  848.          // Loop through lookup table
  849.          while (LookupEntry[0]) {
  850.             if (LookupEntry[Is64bit] < 0) {
  851.                // Imported by ordinal
  852.                printf("\n  Ordinal %i", uint16(LookupEntry[0]));
  853.             }
  854.             else {
  855.                // Find entry in hint/name table
  856.                SectionOffset = (LookupEntry[0] & 0x7FFFFFFF) - dir.VirtualAddress;;
  857.                if (SectionOffset >= dir.MaxOffset) continue;  // Out of range
  858.                HintNameEntry = &Get<SCOFF_ImportHintName>(dir.FileOffset + SectionOffset);
  859.  
  860.                // Print name
  861.                printf("\n  %04X  %s", HintNameEntry->Hint, HintNameEntry->Name);
  862.  
  863.                // Check if exported
  864.                if (HintNameEntry->Hint) {
  865.                  // printf(",  Export entry %i", HintNameEntry->Hint);
  866.                }
  867.             }
  868.             // Loop next
  869.             LookupEntry += Is64bit ? 2 : 1;
  870.          }
  871.  
  872.          // Loop next
  873.          ImportEntry++;
  874.       }  
  875.    }
  876. }
  877.  
  878. // Functions for manipulating COFF files
  879.  
  880. uint32 COFF_PutNameInSymbolTable(SCOFF_SymTableEntry & sym, const char * name, CMemoryBuffer & StringTable) {
  881.    // Function to put a name into SCOFF_SymTableEntry.
  882.    // Put name in string table if longer than 8 characters.
  883.    // Returns index into StringTable if StringTable used
  884.    int len = (int)strlen(name);                  // Length of name
  885.    if (len <= 8) {
  886.       // Short name. store in section header
  887.       memcpy(sym.s.Name, name, len);
  888.       // Pad with zeroes
  889.       for (; len < 8; len++) sym.s.Name[len] = 0;
  890.    }
  891.    else {
  892.       // Long name. store in string table
  893.       sym.stringindex.zeroes = 0;
  894.       sym.stringindex.offset = StringTable.PushString(name);     // Second integer = entry into string table
  895.       return sym.stringindex.offset;
  896.    }
  897.    return 0;
  898. }
  899.  
  900. void COFF_PutNameInSectionHeader(SCOFF_SectionHeader & sec, const char * name, CMemoryBuffer & StringTable) {
  901.    // Function to put a name into SCOFF_SectionHeader.
  902.    // Put name in string table if longer than 8 characters
  903.    int len = (int)strlen(name);                  // Length of name
  904.    if (len <= 8) {
  905.       // Short name. store in section header
  906.       memcpy(sec.Name, name, len);
  907.       // Pad with zeroes
  908.       for (; len < 8; len++) sec.Name[len] = 0;
  909.    }
  910.    else {
  911.       // Long name. store in string table
  912.       sprintf(sec.Name, "/%i", StringTable.PushString(name));
  913.    }
  914. }
  915.