kolibrios/programs/develop/objconv/coff.cpp

915 lines
37 KiB
C++
Raw Normal View History

/**************************** coff.cpp ***********************************
* Author: Agner Fog
* Date created: 2006-07-15
* Last modified: 2009-01-22
* Project: objconv
* Module: coff.cpp
* Description:
* Module for reading PE/COFF files
*
* Class CCOFF is used for reading, interpreting and dumping PE/COFF files.
*
* Copyright 2006-2009 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"
// Relocation type names
SIntTxt COFF32RelNames[] = {
{COFF32_RELOC_ABS, "Absolute"}, // Ignored
{COFF32_RELOC_DIR32, "Direct32"}, // 32-bit absolute virtual address
{COFF32_RELOC_IMGREL, "Image relative"}, // 32-bit image relative virtual address
{COFF32_RELOC_SECTION, "Section16"}, // 16-bit section index in file
{COFF32_RELOC_SECREL, "Section relative"}, // 32-bit section-relative
{COFF32_RELOC_SECREL7, "7 bit section relative"}, // 7-bit section-relative
{COFF32_RELOC_TOKEN, "CLR token"}, // CLR token
{COFF32_RELOC_REL32, "EIP relative"} // 32-bit relative to end of address field
};
SIntTxt COFF64RelNames[] = {
{COFF64_RELOC_ABS, "Ignore"}, // Ignored
{COFF64_RELOC_ABS64, "64 bit absolute"}, // 64 bit absolute virtual address
{COFF64_RELOC_ABS32, "32 bit absolute"}, // 32 bit absolute virtual address
{COFF64_RELOC_IMGREL, "Image relative"}, // 32 bit image-relative
{COFF64_RELOC_REL32, "RIP relative"}, // 32 bit, RIP-relative
{COFF64_RELOC_REL32_1, "RIP relative-1"}, // 32 bit, relative to RIP - 1. For instruction with immediate byte operand
{COFF64_RELOC_REL32_2, "RIP relative-2"}, // 32 bit, relative to RIP - 2. For instruction with immediate word operand
{COFF64_RELOC_REL32_3, "RIP relative-3"}, // 32 bit, relative to RIP - 3. Useless
{COFF64_RELOC_REL32_4, "RIP relative-4"}, // 32 bit, relative to RIP - 4. For instruction with immediate dword operand
{COFF64_RELOC_REL32_5, "RIP relative-5"}, // 32 bit, relative to RIP - 5. Useless
{COFF32_RELOC_SECTION, "Section index"}, // 16-bit section index in file
{COFF64_RELOC_SECREL, "Section relative"}, // 32-bit section-relative
{COFF64_RELOC_SECREL7, "7 bit section rel"},// 7-bit section-relative
{COFF64_RELOC_TOKEN, "CLR token"}, // 64 bit absolute virtual address without inline addend
{COFF64_RELOC_SREL32, "32b span dependent"}, //
{COFF64_RELOC_PAIR, "pair after span dependent"}, //
{COFF64_RELOC_PPC_REFHI,"high 16 of 32 bit abs"}, //
{COFF64_RELOC_PPC_REFLO,"low 16 of 32 bit abs"}, //
{COFF64_RELOC_PPC_PAIR, "pair after high 16"}, //
{COFF64_RELOC_PPC_SECRELO,"low 16 of 32 bit section relative"},
{COFF64_RELOC_PPC_GPREL, "16 bit GP relative"}, //
{COFF64_RELOC_PPC_TOKEN, "CLR token"} //
};
// Machine names
SIntTxt COFFMachineNames[] = {
{0, "Any/unknown"}, // Any machine/unknown
{0x184, "Alpha"}, // Alpha AXP
{0x1C0, "Arm"}, // Arm
{0x284, "Alpha 64 bit"}, // Alpha AXP 64 bit
{0x14C, "I386"}, // x86, 32 bit
{0x200, "IA64"}, // Intel Itanium
{0x268, "Motorola68000"}, // Motorola 68000 series
{0x266, "MIPS16"},
{0x366, "MIPSwFPU"},
{0x466, "MIPS16wFPU"},
{0x1F0, "PowerPC"},
{0x1F1, "PowerPC"},
{0x162, "R3000"},
{0x166, "R4000MIPS"},
{0x168, "R10000"},
{0x1A2, "SH3"},
{0x1A6, "SH4"},
{0x1C2, "Thumb"},
{0x8664, "x86-64"} // x86-64 / AMD64 / Intel EM64T
};
// Storage class names
SIntTxt COFFStorageClassNames[] = {
{COFF_CLASS_END_OF_FUNCTION, "EndOfFunc"},
{COFF_CLASS_AUTOMATIC, "AutoVariable"},
{COFF_CLASS_EXTERNAL, "External/Public"},
{COFF_CLASS_STATIC, "Static/Nonpublic"},
{COFF_CLASS_REGISTER, "Register"},
{COFF_CLASS_EXTERNAL_DEF, "ExternalDef"},
{COFF_CLASS_LABEL, "Label"},
{COFF_CLASS_UNDEFINED_LABEL, "UndefLabel"},
{COFF_CLASS_MEMBER_OF_STRUCTURE, "StructMem"},
{COFF_CLASS_ARGUMENT, "FuncArgument"},
{COFF_CLASS_STRUCTURE_TAG, "StructTag"},
{COFF_CLASS_MEMBER_OF_UNION, "UnionMember"},
{COFF_CLASS_UNION_TAG, "UnionTag"},
{COFF_CLASS_TYPE_DEFINITION, "TypeDef"},
{COFF_CLASS_UNDEFINED_STATIC, "UndefStatic"},
{COFF_CLASS_ENUM_TAG, "EnumTag"},
{COFF_CLASS_MEMBER_OF_ENUM, "EnumMem"},
{COFF_CLASS_REGISTER_PARAM, "RegisterParameter"},
{COFF_CLASS_BIT_FIELD, "BitField"},
{COFF_CLASS_AUTO_ARGUMENT, "AutoArgument"},
{COFF_CLASS_LASTENTRY, "DummyLastEntry"},
{COFF_CLASS_BLOCK, "bb/eb_block"},
{COFF_CLASS_FUNCTION, "Function_bf/ef"},
{COFF_CLASS_END_OF_STRUCT, "EndOfStruct"},
{COFF_CLASS_FILE, "FileName"},
{COFF_CLASS_LINE, "LineNumber"},
{COFF_CLASS_SECTION, "SectionLineNumber"},
{COFF_CLASS_ALIAS, "Alias"},
{COFF_CLASS_WEAK_EXTERNAL, "WeakExternal"},
{COFF_CLASS_HIDDEN, "Hidden"}
};
// Names of section characteristics
SIntTxt COFFSectionFlagNames[] = {
{PE_SCN_CNT_CODE, "Text"},
{PE_SCN_CNT_INIT_DATA, "Data"},
{PE_SCN_CNT_UNINIT_DATA, "BSS"},
{PE_SCN_LNK_INFO, "Comments"},
{PE_SCN_LNK_REMOVE, "Remove"},
{PE_SCN_LNK_COMDAT, "Comdat"},
/* {PE_SCN_ALIGN_1, "Align by 1"},
{PE_SCN_ALIGN_2, "Align by 2"},
{PE_SCN_ALIGN_4, "Align by 4"},
{PE_SCN_ALIGN_8, "Align by 8"},
{PE_SCN_ALIGN_16, "Align by 16"},
{PE_SCN_ALIGN_32, "Align by 32"},
{PE_SCN_ALIGN_64, "Align by 64"},
{PE_SCN_ALIGN_128, "Align by 128"},
{PE_SCN_ALIGN_256, "Align by 256"},
{PE_SCN_ALIGN_512, "Align by 512"},
{PE_SCN_ALIGN_1024, "Align by 1024"},
{PE_SCN_ALIGN_2048, "Align by 2048"},
{PE_SCN_ALIGN_4096, "Align by 4096"},
{PE_SCN_ALIGN_8192, "Align by 8192"}, */
{PE_SCN_LNK_NRELOC_OVFL, "extended relocations"},
{PE_SCN_MEM_DISCARDABLE, "Discardable"},
{PE_SCN_MEM_NOT_CACHED, "Cannot be cached"},
{PE_SCN_MEM_NOT_PAGED, "Not pageable"},
{PE_SCN_MEM_SHARED, "Can be shared"},
{PE_SCN_MEM_EXECUTE, "Executable"},
{PE_SCN_MEM_READ, "Readable"},
{PE_SCN_MEM_WRITE, "Writeable"}
};
// Names of image data directories in optional header
SIntTxt COFFImageDirNames[] = {
{0, "Export_table"},
{1, "Import_table"},
{2, "Resource_table"},
{3, "Exception_table"},
{4, "Certificate_table"},
{5, "Base_relocation_table"},
{6, "Debug_table"},
{7, "Architecture_table"},
{8, "Global_pointer"},
{9, "Thread_local_storage_table"},
{10, "Load_configuration_table"},
{11, "Bound_import_table"},
{12, "Import_address_table"},
{13, "Delay_import_descriptor"},
{14, "Common_language_runtime_header"},
{15, "Reserved_table"}
};
// Class CCOFF members:
// Constructor
CCOFF::CCOFF() {
// Set everything to zero
memset(this, 0, sizeof(*this));
}
void CCOFF::ParseFile(){
// Load and parse file buffer
// Get offset to file header
uint32 FileHeaderOffset = 0;
if ((Get<uint16>(0) & 0xFFF9) == 0x5A49) {
// File has DOS stub
uint32 Signature = Get<uint32>(0x3C);
if (Signature + 8 < DataSize && Get<uint16>(Signature) == 0x4550) {
// Executable PE file
FileHeaderOffset = Signature + 4;
}
else {
err.submit(9000);
return;
}
}
// Find file header
FileHeader = &Get<SCOFF_FileHeader>(FileHeaderOffset);
NSections = FileHeader->NumberOfSections;
// check header integrity
if ((uint64)FileHeader->PSymbolTable + FileHeader->NumberOfSymbols * SIZE_SCOFF_SymTableEntry > GetDataSize()) err.submit(2035);
// Find optional header if executable file
if (FileHeader->SizeOfOptionalHeader && FileHeaderOffset) {
OptionalHeader = &Get<SCOFF_OptionalHeader>(FileHeaderOffset + sizeof(SCOFF_FileHeader));
// Find image data directories
if (OptionalHeader) {
if (OptionalHeader->h64.Magic == COFF_Magic_PE64) {
// 64 bit version
pImageDirs = &(OptionalHeader->h64.ExportTable);
NumImageDirs = OptionalHeader->h64.NumberOfRvaAndSizes;
EntryPoint = OptionalHeader->h64.AddressOfEntryPoint;
ImageBase = OptionalHeader->h64.ImageBase;
}
else {
// 32 bit version
pImageDirs = &(OptionalHeader->h32.ExportTable);
NumImageDirs = OptionalHeader->h32.NumberOfRvaAndSizes;
EntryPoint = OptionalHeader->h32.AddressOfEntryPoint;
ImageBase = OptionalHeader->h32.ImageBase;
}
}
}
// Allocate buffer for section headers
SectionHeaders.SetNum(NSections);
SectionHeaders.SetZero();
// Find section headers
uint32 SectionOffset = FileHeaderOffset + sizeof(SCOFF_FileHeader) + FileHeader->SizeOfOptionalHeader;
for (int i = 0; i < NSections; i++) {
SectionHeaders[i] = Get<SCOFF_SectionHeader>(SectionOffset);
SectionOffset += sizeof(SCOFF_SectionHeader);
// Check for _ILDATA section
if (strcmp(SectionHeaders[i].Name, "_ILDATA") == 0) {
// This is an intermediate file for Intel compiler
err.submit(2114);
}
}
if (SectionOffset > GetDataSize()) {
err.submit(2110); return; // Section table points to outside file
}
// Find symbol table
SymbolTable = &Get<SCOFF_SymTableEntry>(FileHeader->PSymbolTable);
NumberOfSymbols = FileHeader->NumberOfSymbols;
// Find string table
StringTable = (Buf() + FileHeader->PSymbolTable + NumberOfSymbols * SIZE_SCOFF_SymTableEntry);
StringTableSize = *(int*)StringTable; // First 4 bytes of string table contains its size
}
// Debug dump
void CCOFF::Dump(int options) {
uint32 i, j;
if (options & DUMP_FILEHDR) {
// File header
printf("\nDump of PE/COFF file %s", FileName);
printf("\n-----------------------------------------------");
printf("\nFile size: %i", GetDataSize());
printf("\nFile header:");
printf("\nMachine: %s", Lookup(COFFMachineNames,FileHeader->Machine));
printf("\nTimeDate: 0x%08X", FileHeader->TimeDateStamp);
printf(" - %s", timestring(FileHeader->TimeDateStamp));
printf("\nNumber of sections: %2i", FileHeader->NumberOfSections);
printf("\nNumber of symbols: %2i", FileHeader->NumberOfSymbols);
printf("\nOptional header size: %i", FileHeader->SizeOfOptionalHeader);
printf("\nFlags: 0x%04X", FileHeader->Flags);
// May be removed:
printf("\nSymbol table offset: 0x%X", FileHeader->PSymbolTable);
printf("\nString table offset: 0x%X", FileHeader->PSymbolTable + FileHeader->NumberOfSymbols * SIZE_SCOFF_SymTableEntry);
printf("\nSection headers offset: 0x%X", (uint32)sizeof(SCOFF_FileHeader) + FileHeader->SizeOfOptionalHeader);
// Optional header
if (OptionalHeader) {
printf("\n\nOptional header:");
if (OptionalHeader->h32.Magic != COFF_Magic_PE64) {
// 32 bit optional header
printf("\nMagic number: 0x%X", OptionalHeader->h32.Magic);
printf("\nSize of code: 0x%X", OptionalHeader->h32.SizeOfCode);
printf("\nSize of uninitialized data: 0x%X", OptionalHeader->h32.SizeOfInitializedData);
printf("\nAddress of entry point: 0x%X", OptionalHeader->h32.AddressOfEntryPoint);
printf("\nBase of code: 0x%X", OptionalHeader->h32.BaseOfCode);
printf("\nBase of data: 0x%X", OptionalHeader->h32.BaseOfData);
printf("\nImage base: 0x%X", OptionalHeader->h32.ImageBase);
printf("\nSection alignment: 0x%X", OptionalHeader->h32.SectionAlignment);
printf("\nFile alignment: 0x%X", OptionalHeader->h32.FileAlignment);
printf("\nSize of image: 0x%X", OptionalHeader->h32.SizeOfImage);
printf("\nSize of headers: 0x%X", OptionalHeader->h32.SizeOfHeaders);
printf("\nDll characteristics: 0x%X", OptionalHeader->h32.DllCharacteristics);
printf("\nSize of stack reserve: 0x%X", OptionalHeader->h32.SizeOfStackReserve);
printf("\nSize of stack commit: 0x%X", OptionalHeader->h32.SizeOfStackCommit);
printf("\nSize of heap reserve: 0x%X", OptionalHeader->h32.SizeOfHeapReserve);
printf("\nSize of heap commit: 0x%X", OptionalHeader->h32.SizeOfHeapCommit);
}
else {
// 64 bit optional header
printf("\nMagic number: 0x%X", OptionalHeader->h64.Magic);
printf("\nSize of code: 0x%X", OptionalHeader->h64.SizeOfCode);
printf("\nSize of uninitialized data: 0x%X", OptionalHeader->h64.SizeOfInitializedData);
printf("\nAddress of entry point: 0x%X", OptionalHeader->h64.AddressOfEntryPoint);
printf("\nBase of code: 0x%X", OptionalHeader->h64.BaseOfCode);
printf("\nImage base: 0x%08X%08X", HighDWord(OptionalHeader->h64.ImageBase), uint32(OptionalHeader->h64.ImageBase));
printf("\nSection alignment: 0x%X", OptionalHeader->h64.SectionAlignment);
printf("\nFile alignment: 0x%X", OptionalHeader->h64.FileAlignment);
printf("\nSize of image: 0x%X", OptionalHeader->h64.SizeOfImage);
printf("\nSize of headers: 0x%X", OptionalHeader->h64.SizeOfHeaders);
printf("\nDll characteristics: 0x%X", OptionalHeader->h64.DllCharacteristics);
printf("\nSize of stack reserve: 0x%08X%08X", HighDWord(OptionalHeader->h64.SizeOfStackReserve), uint32(OptionalHeader->h64.SizeOfStackReserve));
printf("\nSize of stack commit: 0x%08X%08X", HighDWord(OptionalHeader->h64.SizeOfStackCommit), uint32(OptionalHeader->h64.SizeOfStackCommit));
printf("\nSize of heap reserve: 0x%08X%08X", HighDWord(OptionalHeader->h64.SizeOfHeapReserve), uint32(OptionalHeader->h64.SizeOfHeapReserve));
printf("\nSize of heap commit: 0x%08X%08X", HighDWord(OptionalHeader->h64.SizeOfHeapCommit), uint32(OptionalHeader->h64.SizeOfHeapCommit));
}
// Data directories
SCOFF_ImageDirAddress dir;
for (i = 0; i < NumImageDirs; i++) {
if (GetImageDir(i, &dir)) {
printf("\nDirectory %2i, %s:\n Address 0x%04X, Size 0x%04X, Section %i, Offset 0x%04X",
i, dir.Name,
dir.VirtualAddress, dir.Size, dir.Section, dir.SectionOffset);
}
}
}
}
if ((options & DUMP_STRINGTB) && FileHeader->PSymbolTable && StringTableSize > 4) {
// String table
char * p = StringTable + 4;
uint32 nread = 4, len;
printf("\n\nString table:");
while (nread < StringTableSize) {
len = (int)strlen(p);
if (len > 0) {
printf("\n>>%s<<", p);
nread += len + 1;
p += len + 1;
}
}
}
// Symbol tables
if (options & DUMP_SYMTAB) {
// Symbol table (object file)
if (NumberOfSymbols) PrintSymbolTable(-1);
// Import and export tables (executable file)
if (OptionalHeader) PrintImportExport();
}
// Section headers
if (options & (DUMP_SECTHDR | DUMP_SYMTAB | DUMP_RELTAB)) {
for (j = 0; j < (uint32)NSections; j++) {
SCOFF_SectionHeader * SectionHeader = &SectionHeaders[j];
printf("\n\n%2i Section %s", j+1, GetSectionName(SectionHeader->Name));
//printf("\nFile offset of header: 0x%X", (int)((int8*)SectionHeader-buffer));
printf("\nVirtual size: 0x%X", SectionHeader->VirtualSize);
if (SectionHeader->VirtualAddress) {
printf("\nVirtual address: 0x%X", SectionHeader->VirtualAddress);}
if (SectionHeader->PRawData || SectionHeader->SizeOfRawData) {
printf("\nSize of raw data: 0x%X", SectionHeader->SizeOfRawData);
printf("\nRaw data pointer: 0x%X", SectionHeader->PRawData);
}
printf("\nCharacteristics: ");
PrintSegmentCharacteristics(SectionHeader->Flags);
// print relocations
if ((options & DUMP_RELTAB) && SectionHeader->NRelocations > 0) {
printf("\nRelocation entries: %i", SectionHeader->NRelocations);
printf("\nRelocation entries pointer: 0x%X", SectionHeader->PRelocations);
// Pointer to relocation entry
union {
SCOFF_Relocation * p; // pointer to record
int8 * b; // used for address calculation and incrementing
} Reloc;
Reloc.b = Buf() + SectionHeader->PRelocations;
printf("\nRelocations:");
for (i = 0; i < SectionHeader->NRelocations; i++) {
printf("\nAddr: 0x%X, symi: %i, type: %s",
Reloc.p->VirtualAddress,
Reloc.p->SymbolTableIndex,
(WordSize == 32) ? Lookup(COFF32RelNames,Reloc.p->Type) : Lookup(COFF64RelNames,Reloc.p->Type));
if (Reloc.p->Type < COFF32_RELOC_SEG12)
{
// Check if address is within file
if (SectionHeader->PRawData + Reloc.p->VirtualAddress < GetDataSize()) {
int32 addend = *(int32*)(Buf() + SectionHeader->PRawData + Reloc.p->VirtualAddress);
if (addend) printf(", Implicit addend: %i", addend);
}
else {
printf(". Error: Address is outside file");
}
}
PrintSymbolTable(Reloc.p->SymbolTableIndex);
Reloc.b += SIZE_SCOFF_Relocation; // Next relocation record
}
}
// print line numbers
if (SectionHeader->NLineNumbers > 0) {
printf("\nLine number entries: %i", SectionHeader->NLineNumbers);
printf(" Line number pointer: %i\nLines:", SectionHeader->PLineNumbers);
// Pointer to line number entry
union {
SCOFF_LineNumbers * p; // pointer to record
int8 * b; // used for address calculation and incrementing
} Linnum;
Linnum.b = Buf() + SectionHeader->PLineNumbers;
for (i = 0; i < SectionHeader->NLineNumbers; i++) {
if (Linnum.p->Line) { // Record contains line number
printf(" %i:%i", Linnum.p->Line, Linnum.p->Addr);
}
else { // Record contains function name
}
Linnum.b += SIZE_SCOFF_LineNumbers; // Next line number record
}
}
}
}
}
char const * CCOFF::GetSymbolName(int8* Symbol) {
// Get symbol name from 8 byte entry
static char text[16];
if (*(uint32*)Symbol != 0) {
// Symbol name not more than 8 bytes
memcpy(text, Symbol, 8); // Copy to local buffer
text[8] = 0; // Append terminating zero
return text; // Return text
}
else {
// Longer than 8 bytes. Get offset into string table
uint32 offset = *(uint32*)(Symbol + 4);
if (offset >= StringTableSize || offset >= GetDataSize()) {err.submit(2035); return "";}
char * s = StringTable + offset;
if (*s) return s; // Return string table entry
}
return "NULL"; // String table entry was empty
}
char const * CCOFF::GetSectionName(int8* Symbol) {
// Get section name from 8 byte entry
static char text[16];
memcpy(text, Symbol, 8); // Copy to local buffer
text[8] = 0; // Append terminating zero
if (text[0] == '/') {
// Long name is in string table.
// Convert decimal ASCII number to string table index
uint32 sindex = atoi(text + 1);
// Get name from string table
if (sindex < StringTableSize) {
char * s = StringTable + sindex;
if (*s) return s;} // Return string table entry
}
else {
// Short name is in text buffer
return text;
}
return "NULL"; // In case of error
}
char const * CCOFF::GetStorageClassName(uint8 sc) {
// Get storage class name
return Lookup(COFFStorageClassNames, sc);
}
void CCOFF::PrintSegmentCharacteristics(uint32 flags) {
// Print segment characteristics
int n = 0;
// Loop through all bits of integer
for (uint32 i = 1; i != 0; i <<= 1) {
if (i & flags & ~PE_SCN_ALIGN_MASK) {
if (n++) printf(", ");
printf("%s", Lookup(COFFSectionFlagNames, i));
}
}
if (flags & PE_SCN_ALIGN_MASK) {
int a = 1 << (((flags & PE_SCN_ALIGN_MASK) / PE_SCN_ALIGN_1) - 1);
printf(", Align by 0x%X", a); n++;
}
if (n == 0) printf("None");
}
const char * CCOFF::GetFileName(SCOFF_SymTableEntry * syme) {
// Get file name from records in symbol table
if (syme->s.NumAuxSymbols < 1 || syme->s.StorageClass != COFF_CLASS_FILE) {
return ""; // No file name found
}
// Set limit to file name length = 576
const uint32 MAXCOFFFILENAMELENGTH = 32 * SIZE_SCOFF_SymTableEntry;
// Buffer to store file name. Must be static
static char text[MAXCOFFFILENAMELENGTH+1];
// length of name in record
uint32 len = syme->s.NumAuxSymbols * SIZE_SCOFF_SymTableEntry;
if (len > MAXCOFFFILENAMELENGTH) len = MAXCOFFFILENAMELENGTH;
// copy name from auxiliary records
memcpy(text, (int8*)syme + SIZE_SCOFF_SymTableEntry, len);
// Terminate string
text[len] = 0;
// Return name
return text;
}
const char * CCOFF::GetShortFileName(SCOFF_SymTableEntry * syme) {
// Same as above. Strips path before filename
// Full file name
const char * fullname = GetFileName(syme);
// Length
uint32 len = (uint32)strlen(fullname);
if (len < 1) return fullname;
// Scan backwards for '/', '\', ':'
for (int scan = len-2; scan >= 0; scan--) {
char c = fullname[scan];
if (c == '/' || c == '\\' || c == ':') {
// Path found. Short name starts after this character
return fullname + scan + 1;
}
}
// No path found. Return full name
return fullname;
}
void CCOFF::PrintSymbolTable(int symnum) {
// Print one or all public symbols for object file.
// Dump symbol table if symnum = -1, or
// Dump symbol number symnum (zero based) when symnum >= 0
int isym = 0; // current symbol table entry
int jsym = 0; // auxiliary entry number
union { // Pointer to symbol table
SCOFF_SymTableEntry * p; // Normal pointer
int8 * b; // Used for address calculation
} Symtab;
Symtab.p = SymbolTable; // Set pointer to begin of SymbolTable
if (symnum == -1) printf("\n\nSymbol table:");
if (symnum >= 0) {
// Print one symbol only
if (symnum >= NumberOfSymbols) {
printf("\nSymbol %i not found", symnum);
return;
}
isym = symnum;
Symtab.b += SIZE_SCOFF_SymTableEntry * isym;
}
while (isym < NumberOfSymbols) {
// Print symbol table entry
SCOFF_SymTableEntry *s0;
printf("\n");
if (symnum >= 0) printf(" ");
printf("Symbol %i - Name: %s\n Value=%i, ",
isym, GetSymbolName(Symtab.p->s.Name), Symtab.p->s.Value);
if (Symtab.p->s.SectionNumber > 0) {
printf("Section=%i", Symtab.p->s.SectionNumber);
}
else { // Special section numbers
switch (Symtab.p->s.SectionNumber) {
case COFF_SECTION_UNDEF:
printf("External"); break;
case COFF_SECTION_ABSOLUTE:
printf("Absolute"); break;
case COFF_SECTION_DEBUG:
printf("Debug"); break;
case COFF_SECTION_N_TV:
printf("Preload transfer"); break;
case COFF_SECTION_P_TV:
printf("Postload transfer"); break;
}
}
printf(", Type=0x%X, StorClass=%s, NumAux=%i",
Symtab.p->s.Type,
GetStorageClassName(Symtab.p->s.StorageClass), Symtab.p->s.NumAuxSymbols);
if (Symtab.p->s.StorageClass == COFF_CLASS_FILE && Symtab.p->s.NumAuxSymbols > 0) {
printf("\n File name: %s", GetFileName(Symtab.p));
}
// Increment point
s0 = Symtab.p;
Symtab.b += SIZE_SCOFF_SymTableEntry;
isym++; jsym = 0;
// Get auxiliary records
while (jsym < s0->s.NumAuxSymbols && isym + jsym < NumberOfSymbols) {
// Print auxiliary symbol table entry
SCOFF_SymTableEntry * sa = Symtab.p;
// Detect auxiliary entry type
if (s0->s.StorageClass == COFF_CLASS_EXTERNAL
&& s0->s.Type == COFF_TYPE_FUNCTION
&& s0->s.SectionNumber > 0) {
// This is a function definition aux record
printf("\n Aux function definition:");
printf("\n .bf_tag_index: 0x%X, code_size: %i, PLineNumRec: %i, PNext: %i",
sa->func.TagIndex, sa->func.TotalSize, sa->func.PointerToLineNumber,
sa->func.PointerToNextFunction);
}
else if (strcmp(s0->s.Name,".bf")==0 || strcmp(s0->s.Name,".ef")==0) {
// This is a .bf or .ef aux record
printf("\n Aux .bf/.ef definition:");
printf("\n Source line number: %i",
sa->bfef.SourceLineNumber);
if (strcmp(s0->s.Name,".bf")==0 ) {
printf(", PNext: %i", sa->bfef.PointerToNextFunction);
}
}
else if (s0->s.StorageClass == COFF_CLASS_EXTERNAL &&
s0->s.SectionNumber == COFF_SECTION_UNDEF &&
s0->s.Value == 0) {
// This is a Weak external aux record
printf("\n Aux Weak external definition:");
printf("\n Symbol2 index: %i, Characteristics: 0x%X",
sa->weak.TagIndex, sa->weak.Characteristics);
}
else if (s0->s.StorageClass == COFF_CLASS_FILE) {
// This is filename aux record. Contents has already been printed
}
else if (s0->s.StorageClass == COFF_CLASS_STATIC) {
// This is section definition aux record
printf("\n Aux section definition record:");
printf("\n Length: %i, Num. relocations: %i, Num linenums: %i, checksum 0x%X,"
"\n Number: %i, Selection: %i",
sa->section.Length, sa->section.NumberOfRelocations, sa->section.NumberOfLineNumbers,
sa->section.CheckSum, sa->section.Number, sa->section.Selection);
}
else if (s0->s.StorageClass == COFF_CLASS_ALIAS) {
// This is section definition aux record
printf("\n Aux alias definition record:");
printf("\n symbol index: %i, ", sa->weak.TagIndex);
switch (sa->weak.Characteristics) {
case IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY:
printf("no library search"); break;
case IMAGE_WEAK_EXTERN_SEARCH_LIBRARY:
printf("library search"); break;
case IMAGE_WEAK_EXTERN_SEARCH_ALIAS:
printf("alias symbol"); break;
default:
printf("unknown characteristics 0x%X", sa->weak.Characteristics);
}
}
else {
// Unknown aux record type
printf("\n Unknown Auxiliary record type %i", s0->s.StorageClass);
}
Symtab.b += SIZE_SCOFF_SymTableEntry;
jsym++;
}
isym += jsym;
if (symnum >= 0) break;
}
}
void CCOFF::PublicNames(CMemoryBuffer * Strings, CSList<SStringEntry> * Index, int m) {
// Make list of public names in object file
// Strings will receive ASCIIZ strings
// Index will receive records of type SStringEntry with Member = m
// Interpret header:
ParseFile();
int isym = 0; // current symbol table entry
union { // Pointer to symbol table
SCOFF_SymTableEntry * p; // Normal pointer
int8 * b; // Used for address calculation
} Symtab;
// Loop through symbol table
Symtab.p = SymbolTable;
while (isym < NumberOfSymbols) {
// Check within buffer
if (Symtab.b >= Buf() + DataSize) {
err.submit(2040);
break;
}
// Search for public symbol
if (Symtab.p->s.SectionNumber > 0 && Symtab.p->s.StorageClass == COFF_CLASS_EXTERNAL) {
// Public symbol found
SStringEntry se;
se.Member = m;
// Store name
se.String = Strings->PushString(GetSymbolName(Symtab.p->s.Name));
// Store name index
Index->Push(se);
}
if ((int8)Symtab.p->s.NumAuxSymbols < 0) Symtab.p->s.NumAuxSymbols = 0;
// Increment point
isym += Symtab.p->s.NumAuxSymbols + 1;
Symtab.b += (1 + Symtab.p->s.NumAuxSymbols) * SIZE_SCOFF_SymTableEntry;
}
}
int CCOFF::GetImageDir(uint32 n, SCOFF_ImageDirAddress * dir) {
// Find address of image directory for executable files
int32 Section;
uint32 FileOffset;
if (pImageDirs == 0 || n >= NumImageDirs || dir == 0) {
// Failure
return 0;
}
// Get virtual address and size of directory
dir->VirtualAddress = pImageDirs[n].VirtualAddress;
dir->Size = pImageDirs[n].Size;
dir->Name = Lookup(COFFImageDirNames, n);
// Check if nonzero
if (dir->VirtualAddress == 0 || dir->Size == 0) {
// Empty
return 0;
}
// Search for section containing this address
for (Section = 0; Section < NSections; Section++) {
if (dir->VirtualAddress >= SectionHeaders[Section].VirtualAddress
&& dir->VirtualAddress < SectionHeaders[Section].VirtualAddress + SectionHeaders[Section].SizeOfRawData) {
// Found section
dir->Section = Section + 1;
// Section-relative offset
dir->SectionOffset = dir->VirtualAddress - SectionHeaders[Section].VirtualAddress;
// Calculate file offset
FileOffset = SectionHeaders[Section].PRawData + dir->SectionOffset;
if (FileOffset == 0 || FileOffset >= DataSize) {
// points outside file
err.submit(2035);
return 0;
}
// FileOffset is within range
dir->FileOffset = FileOffset;
// Maximum allowed offset
dir->MaxOffset = SectionHeaders[Section].SizeOfRawData - dir->SectionOffset;
// Return success
return Section;
}
}
// Import section not found
return 0;
}
void CCOFF::PrintImportExport() {
// Print imported and exported symbols
// Table directory address
SCOFF_ImageDirAddress dir;
uint32 i; // Index into OrdinalTable and NamePointerTable
uint32 Ordinal; // Index into ExportAddressTable
uint32 Address; // Virtual address of exported symbol
uint32 NameOffset; // Section offset of symbol name
uint32 SectionOffset; // Section offset of table
const char * Name; // Name of symbol
// Check if 64 bit
int Is64bit = OptionalHeader->h64.Magic == COFF_Magic_PE64;
// Exported names
if (GetImageDir(0, &dir)) {
// Beginning of export section is export directory
SCOFF_ExportDirectory * pExportDirectory = &Get<SCOFF_ExportDirectory>(dir.FileOffset);
// Find ExportAddressTable
SectionOffset = pExportDirectory->ExportAddressTableRVA - dir.VirtualAddress;
if (SectionOffset == 0 || SectionOffset >= dir.MaxOffset) {
// Points outside section
err.submit(2035); return;
}
uint32 * pExportAddressTable = &Get<uint32>(dir.FileOffset + SectionOffset);
// Find ExportNameTable
SectionOffset = pExportDirectory->NamePointerTableRVA - dir.VirtualAddress;
if (SectionOffset == 0 || SectionOffset >= dir.MaxOffset) {
// Points outside section
err.submit(2035); return;
}
uint32 * pExportNameTable = &Get<uint32>(dir.FileOffset + SectionOffset);
// Find ExportOrdinalTable
SectionOffset = pExportDirectory->OrdinalTableRVA - dir.VirtualAddress;
if (SectionOffset == 0 || SectionOffset >= dir.MaxOffset) {
// Points outside section
err.submit(2035); return;
}
uint16 * pExportOrdinalTable = &Get<uint16>(dir.FileOffset + SectionOffset);
// Get further properties
uint32 NumExports = pExportDirectory->AddressTableEntries;
uint32 NumExportNames = pExportDirectory->NamePointerEntries;
uint32 OrdinalBase = pExportDirectory->OrdinalBase;
// Print exported names
printf("\n\nExported symbols:");
// Loop through export tables
for (i = 0; i < NumExports; i++) {
Address = 0;
Name = "(None)";
// Get ordinal from table
Ordinal = pExportOrdinalTable[i];
// Address table is indexed by ordinal
if (Ordinal < NumExports) {
Address = pExportAddressTable[Ordinal];
}
// Find name if there is a name list entry
if (i < NumExportNames) {
NameOffset = pExportNameTable[i] - dir.VirtualAddress;
if (NameOffset && NameOffset < dir.MaxOffset) {
Name = &Get<char>(dir.FileOffset + NameOffset);
}
}
// Print ordinal, address and name
printf("\n Ordinal %3i, Address %6X, Name %s",
Ordinal + OrdinalBase, Address, Name);
}
}
// Imported names
if (GetImageDir(1, &dir)) {
// Print imported names
printf("\n\nImported symbols:");
// Pointer to current import directory entry
SCOFF_ImportDirectory * ImportEntry = &Get<SCOFF_ImportDirectory>(dir.FileOffset);
// Pointer to current import lookup table entry
int32 * LookupEntry = 0;
// Pointer to current hint/name table entry
SCOFF_ImportHintName * HintNameEntry;
// Loop through import directory until null entry
while (ImportEntry->DLLNameRVA) {
// Get DLL name
NameOffset = ImportEntry->DLLNameRVA - dir.VirtualAddress;
if (NameOffset < dir.MaxOffset) {
Name = &Get<char>(dir.FileOffset + NameOffset);
}
else {
Name = "Error";
}
// Print DLL name
printf("\nFrom %s", Name);
// Get lookup table
SectionOffset = ImportEntry->ImportLookupTableRVA;
if (SectionOffset == 0) SectionOffset = ImportEntry->ImportAddressTableRVA;
if (SectionOffset == 0) continue;
SectionOffset -= dir.VirtualAddress;
if (SectionOffset >= dir.MaxOffset) break; // Out of range
LookupEntry = &Get<int32>(dir.FileOffset + SectionOffset);
// Loop through lookup table
while (LookupEntry[0]) {
if (LookupEntry[Is64bit] < 0) {
// Imported by ordinal
printf("\n Ordinal %i", uint16(LookupEntry[0]));
}
else {
// Find entry in hint/name table
SectionOffset = (LookupEntry[0] & 0x7FFFFFFF) - dir.VirtualAddress;;
if (SectionOffset >= dir.MaxOffset) continue; // Out of range
HintNameEntry = &Get<SCOFF_ImportHintName>(dir.FileOffset + SectionOffset);
// Print name
printf("\n %04X %s", HintNameEntry->Hint, HintNameEntry->Name);
// Check if exported
if (HintNameEntry->Hint) {
// printf(", Export entry %i", HintNameEntry->Hint);
}
}
// Loop next
LookupEntry += Is64bit ? 2 : 1;
}
// Loop next
ImportEntry++;
}
}
}
// Functions for manipulating COFF files
uint32 COFF_PutNameInSymbolTable(SCOFF_SymTableEntry & sym, const char * name, CMemoryBuffer & StringTable) {
// Function to put a name into SCOFF_SymTableEntry.
// Put name in string table if longer than 8 characters.
// Returns index into StringTable if StringTable used
int len = (int)strlen(name); // Length of name
if (len <= 8) {
// Short name. store in section header
memcpy(sym.s.Name, name, len);
// Pad with zeroes
for (; len < 8; len++) sym.s.Name[len] = 0;
}
else {
// Long name. store in string table
sym.stringindex.zeroes = 0;
sym.stringindex.offset = StringTable.PushString(name); // Second integer = entry into string table
return sym.stringindex.offset;
}
return 0;
}
void COFF_PutNameInSectionHeader(SCOFF_SectionHeader & sec, const char * name, CMemoryBuffer & StringTable) {
// Function to put a name into SCOFF_SectionHeader.
// Put name in string table if longer than 8 characters
int len = (int)strlen(name); // Length of name
if (len <= 8) {
// Short name. store in section header
memcpy(sec.Name, name, len);
// Pad with zeroes
for (; len < 8; len++) sec.Name[len] = 0;
}
else {
// Long name. store in string table
sprintf(sec.Name, "/%i", StringTable.PushString(name));
}
}