mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4444 lines
122 KiB
4444 lines
122 KiB
/***********************************************************************
|
|
* Microsoft (R) 32-Bit Incremental Linker
|
|
*
|
|
* Copyright (C) Microsoft Corp 1992-1996. All rights reserved.
|
|
*
|
|
* File: dump.cpp
|
|
*
|
|
* File Comments:
|
|
*
|
|
* Prints the contents of object/archive files in readable form.
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "link.h"
|
|
|
|
#include "exe_vxd.h"
|
|
|
|
|
|
DFT dft;
|
|
PIMAGE pimageDump;
|
|
|
|
static DWORD FileLen;
|
|
static PIMAGE_SYMBOL rgsym;
|
|
static BOOL fUserSpecInvalidSize;
|
|
static LPBYTE DumpStringTable;
|
|
static BOOL fDumpStringsLoaded;
|
|
static BLK blkStringTable;
|
|
|
|
// Definitions & macros for the new image structure. File scope to make it easier.
|
|
|
|
#define Switch (pimageDump->Switch)
|
|
#define ImageOptionalHdr (pimageDump->ImgOptHdr)
|
|
#define ImageFileHdr (pimageDump->ImgFileHdr)
|
|
|
|
|
|
const static char * const MachineName[] = {
|
|
"Unknown",
|
|
"i386",
|
|
"R3000",
|
|
"R4000",
|
|
"Alpha AXP",
|
|
"PPC",
|
|
"PARISC",
|
|
"M68K",
|
|
"MPPC",
|
|
"R10000",
|
|
};
|
|
|
|
const static char * const SubsystemName[] = {
|
|
"Unknown",
|
|
"Native",
|
|
"Windows GUI",
|
|
"Windows CUI",
|
|
"Posix CUI",
|
|
"MMOSA",
|
|
};
|
|
|
|
const static char * const DirectoryEntryName[] = {
|
|
"Export",
|
|
"Import",
|
|
"Resource",
|
|
"Exception",
|
|
"Security",
|
|
"Base Relocation",
|
|
"Debug",
|
|
"Description",
|
|
"Special",
|
|
"Thread Storage",
|
|
"Load Configuration",
|
|
"Bound Import",
|
|
"Import Address Table",
|
|
"Reserved",
|
|
"Reserved",
|
|
"Reserved",
|
|
0
|
|
};
|
|
|
|
static PIMAGE_SECTION_HEADER rgsh = 0;
|
|
|
|
|
|
void
|
|
DumperUsage(VOID)
|
|
{
|
|
if (fNeedBanner) {
|
|
PrintBanner();
|
|
}
|
|
|
|
puts("usage: DUMPBIN [options] [files]\n\n"
|
|
|
|
" options:\n\n"
|
|
|
|
" /ALL\n"
|
|
" /ARCHIVEMEMBERS\n"
|
|
" /DIRECTIVES\n"
|
|
" /DISASM\n"
|
|
" /EXPORTS\n"
|
|
" /FPO\n"
|
|
" /HEADERS\n"
|
|
" /IMPORTS\n"
|
|
" /LINENUMBERS\n"
|
|
" /LINKERMEMBER[:{1|2}]\n"
|
|
" /OUT:filename\n"
|
|
" /PDATA\n"
|
|
" /RAWDATA[:{NONE|BYTES|SHORTS|LONGS}[,#]]\n"
|
|
" /RELOCATIONS\n"
|
|
" /SECTION:name\n"
|
|
" /SUMMARY\n"
|
|
" /SYMBOLS\n");
|
|
|
|
fflush(stdout);
|
|
exit(USAGE);
|
|
}
|
|
|
|
|
|
void
|
|
ProcessDumperSwitches (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process all Dumper switches.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL fIncludeRawData = TRUE;
|
|
WORD i;
|
|
PARGUMENT_LIST argument;
|
|
|
|
for (i = 0, argument = SwitchArguments.First;
|
|
i < SwitchArguments.Count;
|
|
i++, argument = argument->Next) {
|
|
|
|
if (!strcmp(argument->OriginalName, "?")) {
|
|
DumperUsage();
|
|
assert(FALSE); // doesn't return
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "out:", 4)) {
|
|
if (argument->OriginalName[4]) {
|
|
szInfoFilename = argument->OriginalName+4;
|
|
if (!(InfoStream = fopen(szInfoFilename, "wt"))) {
|
|
Fatal(NULL, CANTOPENFILE, szInfoFilename);
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "rawdata", 7)) {
|
|
Switch.Dump.RawData = TRUE;
|
|
|
|
if (argument->OriginalName[7] == ':') {
|
|
WORD j;
|
|
|
|
j = 8;
|
|
if (!_strnicmp(argument->OriginalName+8, "bytes", 5)) {
|
|
Switch.Dump.RawDisplayType = Bytes;
|
|
j += 5;
|
|
} else if (!_strnicmp(argument->OriginalName+8, "shorts", 6)) {
|
|
Switch.Dump.RawDisplayType = Shorts;
|
|
j += 6;
|
|
} else if (!_strnicmp(argument->OriginalName+8, "longs", 5)) {
|
|
Switch.Dump.RawDisplayType = Longs;
|
|
j += 5;
|
|
} else if (!_strnicmp(argument->OriginalName+8, "none", 4)) {
|
|
j += 4;
|
|
|
|
Switch.Dump.RawData = FALSE;
|
|
fIncludeRawData = FALSE;
|
|
}
|
|
|
|
if (argument->OriginalName[j] == ',') {
|
|
Switch.Dump.RawDisplaySize = 0;
|
|
|
|
sscanf(argument->OriginalName+j+1, "%li", &Switch.Dump.RawDisplaySize);
|
|
|
|
if (Switch.Dump.RawDisplaySize == 0) {
|
|
fUserSpecInvalidSize = TRUE;
|
|
}
|
|
} else if (argument->OriginalName[j] != '\0') {
|
|
Fatal(NULL, SWITCHSYNTAX, argument->OriginalName);
|
|
}
|
|
} else if (argument->OriginalName[7] != '\0') {
|
|
Fatal(NULL, SWITCHSYNTAX, argument->OriginalName);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "section:", 8)) {
|
|
if (*(argument->OriginalName+8)) {
|
|
AddArgument(&SectionNames, argument->OriginalName+8);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "all")) {
|
|
Switch.Dump.RawData = fIncludeRawData;
|
|
Switch.Dump.Headers = TRUE;
|
|
Switch.Dump.Relocations = TRUE;
|
|
Switch.Dump.BaseRelocations = TRUE;
|
|
Switch.Dump.Linenumbers = TRUE;
|
|
Switch.Dump.Symbols = TRUE;
|
|
Switch.Dump.Imports = TRUE;
|
|
Switch.Dump.Exports = TRUE;
|
|
Switch.Dump.Summary = TRUE;
|
|
Switch.Dump.ArchiveMembers = TRUE;
|
|
Switch.Dump.FpoData = TRUE;
|
|
Switch.Dump.PData = TRUE;
|
|
Switch.Dump.OmapTo = TRUE;
|
|
Switch.Dump.OmapFrom = TRUE;
|
|
Switch.Dump.Fixup = TRUE;
|
|
Switch.Dump.Directives = TRUE;
|
|
Switch.Dump.LinkerMember = 3;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "headers")) {
|
|
Switch.Dump.Headers = TRUE;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "relocations")) {
|
|
Switch.Dump.Relocations = TRUE;
|
|
Switch.Dump.BaseRelocations = TRUE;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "linenumbers")) {
|
|
Switch.Dump.Linenumbers = TRUE;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "map")) {
|
|
Switch.Dump.SymbolMap = TRUE;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "fpo")) {
|
|
Switch.Dump.FpoData = TRUE;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "pdata")) {
|
|
Switch.Dump.PData = TRUE;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "omapt")) {
|
|
Switch.Dump.OmapTo = TRUE;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "omapf")) {
|
|
Switch.Dump.OmapFrom = TRUE;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "fixup")) {
|
|
Switch.Dump.Fixup = TRUE;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "imports")) {
|
|
Switch.Dump.Imports = TRUE;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "exports")) {
|
|
Switch.Dump.Exports = TRUE;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "summary")) {
|
|
Switch.Dump.Summary = TRUE;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "directives")) {
|
|
Switch.Dump.Directives = TRUE;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "archivemembers")) {
|
|
Switch.Dump.ArchiveMembers = TRUE;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "linkermember", 12)) {
|
|
|
|
if (argument->OriginalName[12] == '\0') {
|
|
Switch.Dump.LinkerMember |= 3;
|
|
continue;
|
|
}
|
|
|
|
char chMember;
|
|
if (argument->OriginalName[12] != ':' ||
|
|
((chMember = argument->OriginalName[13]) < '1') ||
|
|
chMember > '2' ||
|
|
argument->OriginalName[14] != '\0') {
|
|
Fatal(NULL, SWITCHSYNTAX, argument->OriginalName);
|
|
}
|
|
|
|
Switch.Dump.LinkerMember |= (WORD)(chMember - '0');
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "undecorate")) {
|
|
//Switch.Dump.Undecorate = Switch.Dump.Symbols = TRUE;
|
|
|
|
Warning(NULL, OBSOLETESWITCH, argument->OriginalName);
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "disasm")) {
|
|
Switch.Dump.Disasm = TRUE;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "symbols", 7)) {
|
|
Switch.Dump.Symbols = TRUE;
|
|
|
|
if (argument->OriginalName[7] == ':') {
|
|
if (!_stricmp(argument->OriginalName+8, "coff")) {
|
|
Switch.Dump.SymbolType = IMAGE_DEBUG_TYPE_COFF;
|
|
} else if (!_stricmp(argument->OriginalName+8, "cv")) {
|
|
Switch.Dump.SymbolType = IMAGE_DEBUG_TYPE_CODEVIEW;
|
|
} else if (!_stricmp(argument->OriginalName+8, "both")) {
|
|
Switch.Dump.SymbolType = IMAGE_DEBUG_TYPE_COFF |
|
|
IMAGE_DEBUG_TYPE_CODEVIEW;
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
Warning(NULL, WARN_UNKNOWN_SWITCH, argument->OriginalName);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DumpHeaders (
|
|
BOOL fArchive
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints the file header and optional header.
|
|
|
|
Arguments:
|
|
|
|
fArchive - TRUE if file is an archive.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD i, j;
|
|
const char *time;
|
|
const char *name;
|
|
|
|
InternalError.Phase = "DumpHeaders";
|
|
|
|
if (ImageFileHdr.SizeOfOptionalHeader != 0) {
|
|
ReadOptionalHeader(FileReadHandle, &ImageOptionalHdr, ImageFileHdr.SizeOfOptionalHeader);
|
|
}
|
|
|
|
if (ImageFileHdr.SizeOfOptionalHeader == sizeof(IMAGE_ROM_OPTIONAL_HEADER)) {
|
|
dft = dftROM;
|
|
} else if (ImageFileHdr.Characteristics & IMAGE_FILE_DLL) {
|
|
dft = dftPE;
|
|
} else if (ImageFileHdr.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) {
|
|
dft = dftPE;
|
|
} else if (ImageFileHdr.SizeOfOptionalHeader == 0) {
|
|
dft = dftObject;
|
|
} else {
|
|
dft = dftUnknown;
|
|
}
|
|
|
|
if ((dft == dftPE) && (ImageFileHdr.Machine == IMAGE_FILE_MACHINE_MPPC_601)) {
|
|
dft = dftPEX;
|
|
}
|
|
|
|
// Print out file type
|
|
|
|
if (!fArchive) {
|
|
switch (dft) {
|
|
case dftObject :
|
|
fputs("\nFile Type: COFF OBJECT\n", InfoStream);
|
|
break;
|
|
|
|
case dftPE :
|
|
case dftPEX :
|
|
if (ImageFileHdr.Characteristics & IMAGE_FILE_DLL) {
|
|
fputs("\nFile Type: DLL\n", InfoStream);
|
|
} else {
|
|
fputs("\nFile Type: EXECUTABLE IMAGE\n", InfoStream);
|
|
}
|
|
break;
|
|
|
|
case dftROM :
|
|
fputs("\nFile Type: ROM IMAGE\n", InfoStream);
|
|
break;
|
|
|
|
default :
|
|
fputs("\nFile Type: UNKNOWN\n", InfoStream);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
if (Switch.Dump.Headers) {
|
|
DWORD dw;
|
|
|
|
switch (ImageFileHdr.Machine) {
|
|
case IMAGE_FILE_MACHINE_I386 : i = 1; break;
|
|
case IMAGE_FILE_MACHINE_R3000 : i = 2; break;
|
|
case IMAGE_FILE_MACHINE_R4000 : i = 3; break;
|
|
case IMAGE_FILE_MACHINE_ALPHA : i = 4; break;
|
|
case IMAGE_FILE_MACHINE_POWERPC : i = 5; break;
|
|
case 0x0290 : i = 6; break; // UNDONE: IMAGE_FILE_MACHINE_PARISC
|
|
case IMAGE_FILE_MACHINE_M68K : i = 7; break;
|
|
case IMAGE_FILE_MACHINE_MPPC_601 : i = 8; break;
|
|
case IMAGE_FILE_MACHINE_R10000 : i = 9; break;
|
|
default : i = 0;
|
|
}
|
|
|
|
fprintf(InfoStream,
|
|
"\n"
|
|
"FILE HEADER VALUES\n"
|
|
"%8hX machine (%s)\n"
|
|
"%8hX number of sections\n"
|
|
"%8lX time date stamp",
|
|
ImageFileHdr.Machine,
|
|
MachineName[i],
|
|
ImageFileHdr.NumberOfSections,
|
|
ImageFileHdr.TimeDateStamp);
|
|
|
|
if ((time = ctime((time_t *) &ImageFileHdr.TimeDateStamp)) != NULL) {
|
|
fprintf(InfoStream, " %s", time);
|
|
} else {
|
|
fputc('\n', InfoStream);
|
|
}
|
|
|
|
fprintf(InfoStream,
|
|
"%8lX file pointer to symbol table\n"
|
|
"%8lX number of symbols\n"
|
|
"%8hX size of optional header\n"
|
|
"%8hX characteristics\n",
|
|
ImageFileHdr.PointerToSymbolTable,
|
|
ImageFileHdr.NumberOfSymbols,
|
|
ImageFileHdr.SizeOfOptionalHeader,
|
|
ImageFileHdr.Characteristics);
|
|
|
|
for (dw = ImageFileHdr.Characteristics, j = 0; dw; dw >>= 1, j++) {
|
|
if (dw & 1) {
|
|
switch (1 << j) {
|
|
case IMAGE_FILE_RELOCS_STRIPPED : name = "Relocations stripped"; break;
|
|
case IMAGE_FILE_EXECUTABLE_IMAGE : name = "Executable"; break;
|
|
case IMAGE_FILE_LINE_NUMS_STRIPPED : name = "Line numbers stripped"; break;
|
|
case IMAGE_FILE_LOCAL_SYMS_STRIPPED : name = "Symbols stripped"; break;
|
|
case IMAGE_FILE_BYTES_REVERSED_LO : name = "Bytes reversed"; break;
|
|
case IMAGE_FILE_32BIT_MACHINE : name = "32 bit word machine"; break;
|
|
case IMAGE_FILE_DEBUG_STRIPPED : name = "Debug information stripped"; break;
|
|
case IMAGE_FILE_SYSTEM : name = "System"; break;
|
|
case IMAGE_FILE_UP_SYSTEM_ONLY : name = "Uniprocessor Only"; break;
|
|
case IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP : name = "CD - run from swapfile"; break;
|
|
case IMAGE_FILE_NET_RUN_FROM_SWAP : name = "Net - run from swapfile"; break;
|
|
case IMAGE_FILE_DLL : name = "DLL"; break;
|
|
case IMAGE_FILE_AGGRESIVE_WS_TRIM : name = "Aggressively trim working set"; break;
|
|
case IMAGE_FILE_BYTES_REVERSED_HI : name = ""; break;
|
|
default : name = "RESERVED - UNKNOWN";
|
|
}
|
|
|
|
if (*name) {
|
|
fprintf(InfoStream, " %s\n", name);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ImageFileHdr.SizeOfOptionalHeader != 0) {
|
|
char szLinkerVersion[30];
|
|
|
|
sprintf(szLinkerVersion,
|
|
"%u.%02u",
|
|
ImageOptionalHdr.MajorLinkerVersion,
|
|
ImageOptionalHdr.MinorLinkerVersion);
|
|
|
|
fprintf(InfoStream,
|
|
"\n"
|
|
"OPTIONAL HEADER VALUES\n"
|
|
"%8hX magic #\n"
|
|
"%8s linker version\n"
|
|
"%8lX size of code\n"
|
|
"%8lX size of initialized data\n"
|
|
"%8lX size of uninitialized data\n"
|
|
"%8lX address of entry point\n"
|
|
"%8lX base of code\n"
|
|
"%8lX base of data\n",
|
|
ImageOptionalHdr.Magic,
|
|
szLinkerVersion,
|
|
ImageOptionalHdr.SizeOfCode,
|
|
ImageOptionalHdr.SizeOfInitializedData,
|
|
ImageOptionalHdr.SizeOfUninitializedData,
|
|
ImageOptionalHdr.AddressOfEntryPoint,
|
|
ImageOptionalHdr.BaseOfCode,
|
|
ImageOptionalHdr.BaseOfData);
|
|
}
|
|
|
|
if (dft == dftROM) {
|
|
PIMAGE_ROM_OPTIONAL_HEADER romOptionalHdr;
|
|
|
|
romOptionalHdr = (PIMAGE_ROM_OPTIONAL_HEADER) &ImageOptionalHdr;
|
|
fprintf(InfoStream,
|
|
" ----- rom -----\n"
|
|
"%8lX base of bss\n"
|
|
"%8lX gpr mask\n"
|
|
" cpr mask\n"
|
|
" %08lX %08lX %08lX %08lX\n"
|
|
"%8hX gp value\n",
|
|
romOptionalHdr->BaseOfBss,
|
|
romOptionalHdr->GprMask,
|
|
romOptionalHdr->CprMask[0],
|
|
romOptionalHdr->CprMask[1],
|
|
romOptionalHdr->CprMask[2],
|
|
romOptionalHdr->CprMask[3],
|
|
romOptionalHdr->GpValue);
|
|
}
|
|
|
|
if (ImageFileHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER)) {
|
|
char szOSVersion[30];
|
|
char szImageVersion[30];
|
|
char szSubsystemVersion[30];
|
|
|
|
switch (ImageOptionalHdr.Subsystem) {
|
|
case IMAGE_SUBSYSTEM_MMOSA : i = 5; break;
|
|
case IMAGE_SUBSYSTEM_POSIX_CUI : i = 4; break;
|
|
case IMAGE_SUBSYSTEM_WINDOWS_CUI : i = 3; break;
|
|
case IMAGE_SUBSYSTEM_WINDOWS_GUI : i = 2; break;
|
|
case IMAGE_SUBSYSTEM_NATIVE : i = 1; break;
|
|
default : i = 0;
|
|
}
|
|
|
|
sprintf(szOSVersion,
|
|
"%hu.%02hu",
|
|
ImageOptionalHdr.MajorOperatingSystemVersion,
|
|
ImageOptionalHdr.MinorOperatingSystemVersion);
|
|
|
|
sprintf(szImageVersion,
|
|
"%hu.%02hu",
|
|
ImageOptionalHdr.MajorImageVersion,
|
|
ImageOptionalHdr.MinorImageVersion);
|
|
|
|
sprintf(szSubsystemVersion,
|
|
"%hu.%02hu",
|
|
ImageOptionalHdr.MajorSubsystemVersion,
|
|
ImageOptionalHdr.MinorSubsystemVersion);
|
|
|
|
fprintf(InfoStream,
|
|
" ----- new -----\n"
|
|
"%8lX image base\n"
|
|
"%8lX section alignment\n"
|
|
"%8lX file alignment\n"
|
|
"%8hX subsystem (%s)\n"
|
|
"%8s operating system version\n"
|
|
"%8s image version\n"
|
|
"%8s subsystem version\n"
|
|
"%8lX size of image\n"
|
|
"%8lX size of headers\n"
|
|
"%8lX checksum\n"
|
|
"%8lX size of stack reserve\n"
|
|
"%8lX size of stack commit\n"
|
|
"%8lX size of heap reserve\n"
|
|
"%8lX size of heap commit\n%",
|
|
ImageOptionalHdr.ImageBase,
|
|
ImageOptionalHdr.SectionAlignment,
|
|
ImageOptionalHdr.FileAlignment,
|
|
ImageOptionalHdr.Subsystem,
|
|
SubsystemName[i],
|
|
szOSVersion,
|
|
szImageVersion,
|
|
szSubsystemVersion,
|
|
ImageOptionalHdr.SizeOfImage,
|
|
ImageOptionalHdr.SizeOfHeaders,
|
|
ImageOptionalHdr.CheckSum,
|
|
ImageOptionalHdr.SizeOfStackReserve,
|
|
ImageOptionalHdr.SizeOfStackCommit,
|
|
ImageOptionalHdr.SizeOfHeapReserve,
|
|
ImageOptionalHdr.SizeOfHeapCommit);
|
|
|
|
if (ImageOptionalHdr.DllCharacteristics) {
|
|
fprintf(InfoStream, "%8lX dll characteristics\n", ImageOptionalHdr.DllCharacteristics);
|
|
}
|
|
|
|
for (i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) {
|
|
if (!DirectoryEntryName[i]) {
|
|
break;
|
|
}
|
|
|
|
fprintf(InfoStream, "%8lX [%8lX] address [size] of %s Directory\n%",
|
|
ImageOptionalHdr.DataDirectory[i].VirtualAddress,
|
|
ImageOptionalHdr.DataDirectory[i].Size,
|
|
DirectoryEntryName[i]
|
|
);
|
|
}
|
|
|
|
fputc('\n', InfoStream);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
LoadStrings (
|
|
const char *Filename
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Seeks to LONG (greater than 8 bytes) string table, allocates and
|
|
reads strings from disk to memory, and then prints the strings.
|
|
|
|
Arguments:
|
|
|
|
Filename - File name we're reading.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Size;
|
|
|
|
if (!fDumpStringsLoaded) {
|
|
DumpStringTable = (LPBYTE) ReadStringTable(Filename,
|
|
ImageFileHdr.PointerToSymbolTable+
|
|
(sizeof(IMAGE_SYMBOL)* ImageFileHdr.NumberOfSymbols)+
|
|
MemberSeekBase,
|
|
&Size);
|
|
fDumpStringsLoaded = TRUE;
|
|
blkStringTable.pb = DumpStringTable;
|
|
blkStringTable.cb = Size;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DumpSectionHeader (
|
|
WORD i,
|
|
PIMAGE_SECTION_HEADER Sh
|
|
)
|
|
{
|
|
const char *name;
|
|
char *szOutput;
|
|
DWORD li, lj;
|
|
WORD memFlags;
|
|
|
|
fprintf(InfoStream,
|
|
"\n"
|
|
"SECTION HEADER #%hX\n"
|
|
"%8.8s name",
|
|
i,
|
|
Sh->Name);
|
|
|
|
if (Sh->Name[0] == '/') {
|
|
name = SzObjSectionName((char *) Sh->Name, (char *) DumpStringTable);
|
|
|
|
fprintf(InfoStream, " (%s)", name);
|
|
}
|
|
|
|
fprintf(InfoStream,
|
|
"\n"
|
|
"%8lX %s\n"
|
|
"%8lX virtual address\n"
|
|
"%8lX size of raw data\n"
|
|
"%8lX file pointer to raw data\n"
|
|
"%8lX file pointer to relocation table\n"
|
|
"%8lX file pointer to line numbers\n"
|
|
"%8hX number of relocations\n"
|
|
"%8hX number of line numbers\n"
|
|
"%8lX flags\n",
|
|
Sh->Misc.PhysicalAddress,
|
|
(dft == dftObject) ? "physical address" : "virtual size",
|
|
Sh->VirtualAddress,
|
|
Sh->SizeOfRawData,
|
|
Sh->PointerToRawData,
|
|
Sh->PointerToRelocations,
|
|
Sh->PointerToLinenumbers,
|
|
Sh->NumberOfRelocations,
|
|
Sh->NumberOfLinenumbers,
|
|
Sh->Characteristics);
|
|
|
|
memFlags = 0;
|
|
|
|
li = Sh->Characteristics;
|
|
|
|
if (dft == dftROM) {
|
|
for (lj = 0L; li; li = li >> 1, lj++) {
|
|
if (li & 1) {
|
|
switch ((li & 1) << lj) {
|
|
case STYP_REG : name = "Regular"; break;
|
|
case STYP_TEXT : name = "Text"; memFlags = 1; break;
|
|
case STYP_INIT : name = "Init Code"; memFlags = 1; break;
|
|
case STYP_RDATA : name = "Data"; memFlags = 2; break;
|
|
case STYP_DATA : name = "Data"; memFlags = 6; break;
|
|
case STYP_LIT8 : name = "Literal 8"; break;
|
|
case STYP_LIT4 : name = "Literal 4"; break;
|
|
case STYP_SDATA : name = "GP Init Data"; memFlags = 6; break;
|
|
case STYP_SBSS : name = "GP Uninit Data"; memFlags = 6; break;
|
|
case STYP_BSS : name = "Uninit Data"; memFlags = 6; break;
|
|
case STYP_LIB : name = "Library"; break;
|
|
case STYP_UCODE : name = "UCode"; break;
|
|
case S_NRELOC_OVFL : name = "Non-Relocatable overlay"; memFlags = 1; break;
|
|
default : name = "RESERVED - UNKNOWN";
|
|
}
|
|
|
|
fprintf(InfoStream, " %s\n", name);
|
|
}
|
|
}
|
|
} else {
|
|
// Clear the padding bits
|
|
|
|
li &= ~0x00700000;
|
|
|
|
for (lj = 0L; li; li = li >> 1, lj++) {
|
|
if (li & 1) {
|
|
switch ((li & 1) << lj) {
|
|
case IMAGE_SCN_TYPE_NO_PAD : name = "No Pad"; break;
|
|
|
|
case IMAGE_SCN_CNT_CODE : name = "Code"; break;
|
|
case IMAGE_SCN_CNT_INITIALIZED_DATA : name = "Initialized Data"; break;
|
|
case IMAGE_SCN_CNT_UNINITIALIZED_DATA : name = "Uninitialized Data"; break;
|
|
|
|
case IMAGE_SCN_LNK_OTHER : name = "Other"; break;
|
|
case IMAGE_SCN_LNK_INFO : name = "Info"; break;
|
|
case IMAGE_SCN_LNK_REMOVE : name = "Remove"; break;
|
|
case IMAGE_SCN_LNK_COMDAT : name = "Communal"; break;
|
|
case IMAGE_SCN_LNK_NRELOC_OVFL : name = "Extended relocations"; break;
|
|
|
|
case IMAGE_SCN_MEM_DISCARDABLE: name = "Discardable"; break;
|
|
case IMAGE_SCN_MEM_NOT_CACHED: name = "Not Cached"; break;
|
|
case IMAGE_SCN_MEM_NOT_PAGED: name = "Not Paged"; break;
|
|
case IMAGE_SCN_MEM_SHARED : name = "Shared"; break;
|
|
case IMAGE_SCN_MEM_EXECUTE : name = ""; memFlags |= 1; break;
|
|
case IMAGE_SCN_MEM_READ : name = ""; memFlags |= 2; break;
|
|
case IMAGE_SCN_MEM_WRITE : name = ""; memFlags |= 4; break;
|
|
|
|
case IMAGE_SCN_MEM_FARDATA : name = "Far Data"; break;
|
|
case IMAGE_SCN_MEM_SYSHEAP : name = "Sys Heap"; break;
|
|
case IMAGE_SCN_MEM_PURGEABLE: name = "Purgeable or 16-Bit"; break;
|
|
case IMAGE_SCN_MEM_LOCKED : name = "Locked"; break;
|
|
case IMAGE_SCN_MEM_PRELOAD : name = "Preload"; break;
|
|
case IMAGE_SCN_MEM_PROTECTED: name = "Protected"; break;
|
|
|
|
default : name = "RESERVED - UNKNOWN";
|
|
}
|
|
|
|
if (*name) {
|
|
fprintf(InfoStream, " %s", name);
|
|
|
|
if ((li & 1) << lj == IMAGE_SCN_LNK_COMDAT && rgsym != NULL) {
|
|
// Look for comdat name in symbol table.
|
|
DWORD isym;
|
|
|
|
for (isym = 0;
|
|
isym < ImageFileHdr.NumberOfSymbols;
|
|
isym += rgsym[isym].NumberOfAuxSymbols + 1) {
|
|
if (rgsym[isym].SectionNumber != i) {
|
|
continue;
|
|
}
|
|
|
|
switch (rgsym[isym].StorageClass) {
|
|
case IMAGE_SYM_CLASS_STATIC :
|
|
if (rgsym[isym].NumberOfAuxSymbols == 1) {
|
|
// Check for a section header.
|
|
|
|
if (!ISFCN(rgsym[isym].Type)) {
|
|
break; // scn hdr; give up
|
|
}
|
|
}
|
|
|
|
// it's a real symbol
|
|
// fall through
|
|
|
|
case IMAGE_SYM_CLASS_EXTERNAL:
|
|
szOutput = SzOutputSymbolName(
|
|
SzNameSym(rgsym[isym], blkStringTable), TRUE);
|
|
|
|
fprintf(InfoStream, "; sym= %s", szOutput);
|
|
|
|
if (szOutput != SzNameSym(rgsym[isym], blkStringTable)) {
|
|
FreePv(szOutput);
|
|
}
|
|
goto BreakFor;
|
|
}
|
|
}
|
|
|
|
fputs(" (no symbol)", InfoStream);
|
|
BreakFor:;
|
|
}
|
|
|
|
fputc('\n', InfoStream);
|
|
}
|
|
}
|
|
}
|
|
|
|
// print alignment
|
|
|
|
switch (Sh->Characteristics & 0x00700000) {
|
|
default: name = "(no align specified)"; break;
|
|
case IMAGE_SCN_ALIGN_1BYTES: name = "1 byte align"; break;
|
|
case IMAGE_SCN_ALIGN_2BYTES: name = "2 byte align"; break;
|
|
case IMAGE_SCN_ALIGN_4BYTES: name = "4 byte align"; break;
|
|
case IMAGE_SCN_ALIGN_8BYTES: name = "8 byte align"; break;
|
|
case IMAGE_SCN_ALIGN_16BYTES: name = "16 byte align"; break;
|
|
case IMAGE_SCN_ALIGN_32BYTES: name = "32 byte align"; break;
|
|
case IMAGE_SCN_ALIGN_64BYTES: name = "64 byte align"; break;
|
|
}
|
|
|
|
fprintf(InfoStream, " %s\n", name);
|
|
}
|
|
|
|
if (memFlags) {
|
|
switch (memFlags) {
|
|
case 1 : name = "Execute Only"; break;
|
|
case 2 : name = "Read Only"; break;
|
|
case 3 : name = "Execute Read"; break;
|
|
case 4 : name = "Write Only"; break;
|
|
case 5 : name = "Execute Write"; break;
|
|
case 6 : name = "Read Write"; break;
|
|
case 7 : name = "Execute Read Write"; break;
|
|
}
|
|
fprintf(InfoStream, " %s\n", name);
|
|
}
|
|
}
|
|
|
|
|
|
int __cdecl
|
|
ComparePsym(void const *ppsym1, void const *ppsym2)
|
|
{
|
|
DWORD val1 = (*(PIMAGE_SYMBOL *) ppsym1)->Value;
|
|
DWORD val2 = (*(PIMAGE_SYMBOL *) ppsym2)->Value;
|
|
|
|
if (val1 < val2) {
|
|
return(-1);
|
|
}
|
|
|
|
if (val1 > val2) {
|
|
return(1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
void DisasmSection(
|
|
WORD wMachine,
|
|
PIMAGE_SECTION_HEADER pish,
|
|
WORD isec,
|
|
DWORD ImageBase,
|
|
const BYTE *rgb,
|
|
DWORD cbVirtual)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Disassemble a COFF section.
|
|
|
|
Arguments:
|
|
|
|
pish - COFF section header
|
|
|
|
fd - file descriptor of COFF file to disassemble section from
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL f16Bit = FALSE;
|
|
DWORD addr = (dft == dftObject) ? 0 : (ImageBase + pish->VirtualAddress);
|
|
|
|
if (wMachine == IMAGE_FILE_MACHINE_I386) {
|
|
if ((pish->Characteristics & IMAGE_SCN_MEM_16BIT) != 0) {
|
|
f16Bit = TRUE;
|
|
addr = ((DWORD) isec) << 16;
|
|
}
|
|
}
|
|
|
|
// Get sorted array of symbol pointers
|
|
|
|
DWORD csym = (rgsym == NULL) ? 0 : ImageFileHdr.NumberOfSymbols;
|
|
PIMAGE_SYMBOL *rgpsym = (PIMAGE_SYMBOL *) PvAlloc(csym * sizeof(PIMAGE_SYMBOL));
|
|
DWORD cpsym = 0;
|
|
|
|
for (DWORD isym = 0; isym < csym; isym++) {
|
|
if (rgsym[isym].SectionNumber == isec) {
|
|
switch (rgsym[isym].StorageClass) {
|
|
case IMAGE_SYM_CLASS_STATIC :
|
|
if (rgsym[isym].NumberOfAuxSymbols != 0) {
|
|
// Section symbol or static function
|
|
|
|
if (!ISFCN(rgsym[isym].Type)) {
|
|
// Section symbol
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Fall through
|
|
|
|
case IMAGE_SYM_CLASS_EXTERNAL :
|
|
case IMAGE_SYM_CLASS_LABEL :
|
|
rgpsym[cpsym++] = (PIMAGE_SYMBOL) &rgsym[isym];
|
|
break;
|
|
}
|
|
}
|
|
|
|
isym += rgsym[isym].NumberOfAuxSymbols;
|
|
}
|
|
|
|
qsort(rgpsym, cpsym, sizeof(PIMAGE_SYMBOL), ComparePsym);
|
|
|
|
rgpsym = (PIMAGE_SYMBOL *) realloc(rgpsym, cpsym * sizeof(PIMAGE_SYMBOL));
|
|
|
|
if (wMachine == IMAGE_FILE_MACHINE_M68K) {
|
|
DisasmBuffer68K(rgb,
|
|
cbVirtual,
|
|
rgpsym,
|
|
cpsym);
|
|
} else {
|
|
DisasmBuffer(wMachine,
|
|
f16Bit,
|
|
addr,
|
|
rgb,
|
|
cbVirtual,
|
|
rgpsym,
|
|
cpsym,
|
|
(dft == dftObject) ? 0 : pish->VirtualAddress,
|
|
InfoStream);
|
|
}
|
|
|
|
FreePv(rgpsym);
|
|
}
|
|
|
|
|
|
void
|
|
DumpNamePsym(
|
|
FILE *pfile,
|
|
const char *szFormat,
|
|
PIMAGE_SYMBOL psym
|
|
)
|
|
{
|
|
char *szFormatted;
|
|
char szsName[IMAGE_SIZEOF_SHORT_NAME + 1];
|
|
const char *szSymName;
|
|
|
|
if (IsLongName(*psym)) {
|
|
szSymName = (char *) &DumpStringTable[psym->n_offset];
|
|
} else {
|
|
WORD i;
|
|
|
|
for (i = 0; i < IMAGE_SIZEOF_SHORT_NAME; i++) {
|
|
if ((psym->n_name[i]>0x1f) && (psym->n_name[i]<0x7f)) {
|
|
szsName[i] = psym->n_name[i];
|
|
} else {
|
|
szsName[i] = '\0';
|
|
}
|
|
}
|
|
szsName[IMAGE_SIZEOF_SHORT_NAME] = '\0';
|
|
szSymName = szsName;
|
|
}
|
|
|
|
szFormatted = SzOutputSymbolName(szSymName, FALSE);
|
|
|
|
fprintf(pfile, szFormat, szFormatted);
|
|
|
|
if (szFormatted != szSymName) {
|
|
free(szFormatted);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
PrintSymbolName(
|
|
DWORD SymbolValue
|
|
)
|
|
{
|
|
DWORD i;
|
|
PIMAGE_SYMBOL Symbol;
|
|
|
|
if ((rgsym != NULL) && (dft != dftObject)) {
|
|
for (i = 0; i < ImageFileHdr.NumberOfSymbols; i++) {
|
|
Symbol = &rgsym[i];
|
|
if (Symbol->Value == SymbolValue &&
|
|
((Symbol->StorageClass == IMAGE_SYM_CLASS_EXTERNAL ||
|
|
Symbol->StorageClass == IMAGE_SYM_CLASS_STATIC) &&
|
|
ISFCN(Symbol->Type)))
|
|
{
|
|
DumpNamePsym(InfoStream, " %s", Symbol);
|
|
break;
|
|
}
|
|
|
|
i += Symbol->NumberOfAuxSymbols;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void DumpRawData(DWORD addr, const BYTE *rgb, DWORD cbBuffer)
|
|
{
|
|
const char *p;
|
|
WORD j;
|
|
|
|
DUMP_RAW_DISPLAY_TYPE display = Switch.Dump.RawDisplayType;
|
|
WORD numberUnits = Switch.Dump.RawDisplaySize;
|
|
|
|
BOOL fUserDisplay = (numberUnits != 0);
|
|
|
|
if (!fUserDisplay) {
|
|
numberUnits = 4;
|
|
|
|
switch (display) {
|
|
case Bytes : numberUnits <<= 1; // 16
|
|
case Shorts : numberUnits <<= 1; // 8
|
|
case Longs : break; // 4
|
|
}
|
|
}
|
|
|
|
DWORD ibCur = 0;
|
|
|
|
const BYTE *pbCur = rgb;
|
|
|
|
while (pbCur < (rgb + cbBuffer)) {
|
|
int cchOut;
|
|
|
|
cchOut = fprintf(InfoStream, "%08lX ", addr + ibCur);
|
|
|
|
p = (const char *) pbCur;
|
|
|
|
for (j = numberUnits; j; j--) {
|
|
if (pbCur >= (rgb + cbBuffer)) {
|
|
break;
|
|
}
|
|
|
|
if (!fUserDisplay && (j == numberUnits / 2)) {
|
|
cchOut += fputs("| ", InfoStream);
|
|
}
|
|
|
|
switch (display) {
|
|
case Bytes :
|
|
cchOut += fprintf(InfoStream, "%02X ", *pbCur);
|
|
|
|
pbCur += sizeof(BYTE);
|
|
ibCur += sizeof(BYTE);
|
|
break;
|
|
|
|
case Shorts :
|
|
cchOut += fprintf(InfoStream, "%04hX ", *(WORD UNALIGNED *) pbCur);
|
|
|
|
pbCur += sizeof(WORD);
|
|
ibCur += sizeof(WORD);
|
|
|
|
if ((pbCur + sizeof(WORD)) > (rgb + cbBuffer)) {
|
|
display = Bytes;
|
|
}
|
|
break;
|
|
|
|
case Longs :
|
|
cchOut += fprintf(InfoStream, "%08lX ", *(DWORD UNALIGNED *) pbCur);
|
|
|
|
pbCur += sizeof(DWORD);
|
|
ibCur += sizeof(DWORD);
|
|
|
|
if ((pbCur + sizeof(DWORD)) > (rgb + cbBuffer)) {
|
|
display = Bytes;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!fUserDisplay) {
|
|
for (int i = 61-cchOut; i; i--) {
|
|
fputc(' ', InfoStream);
|
|
}
|
|
|
|
for (cchOut = 0; cchOut < 16; cchOut++) {
|
|
if ((BYTE *) p == (rgb + cbBuffer)) {
|
|
break;
|
|
}
|
|
|
|
if (cchOut == 8) {
|
|
fputc('|', InfoStream);
|
|
}
|
|
|
|
char ch = *p++;
|
|
|
|
if (!isprint(ch)) {
|
|
ch = '.';
|
|
}
|
|
|
|
fputc(ch, InfoStream);
|
|
|
|
}
|
|
}
|
|
|
|
fputc('\n', InfoStream);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DumpFpoData (
|
|
DWORD FpoOffset,
|
|
DWORD FpoSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads and prints each Fpo table entry.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PFPO_DATA pFpoData;
|
|
PFPO_DATA pfpoT;
|
|
DWORD fpoEntries;
|
|
static const char * const szFrameTypes[] = {"fpo", "trap", "tss", "std"};
|
|
|
|
FileSeek(FileReadHandle, FpoOffset, SEEK_SET);
|
|
|
|
fpoEntries = FpoSize / sizeof(FPO_DATA);
|
|
fprintf(InfoStream, "\nFPO Data (%ld)\n", fpoEntries);
|
|
|
|
pFpoData = (PFPO_DATA) PvAlloc(FpoSize + sizeof(FPO_DATA));
|
|
FileRead(FileReadHandle, pFpoData, FpoSize);
|
|
|
|
fputs(" Use Has Frame\n"
|
|
" Address Proc Size Locals Prolog BP SEH Type Params\n", InfoStream);
|
|
|
|
pfpoT = pFpoData;
|
|
for (; fpoEntries; fpoEntries--, pfpoT++) {
|
|
fprintf(InfoStream, "%08X %8X %8X %8X %c %c %4s %4X ",
|
|
pfpoT->ulOffStart,
|
|
pfpoT->cbProcSize,
|
|
pfpoT->cdwLocals,
|
|
pfpoT->cbProlog,
|
|
pfpoT->fUseBP ? 'Y' : 'N',
|
|
pfpoT->fHasSEH ? 'Y' : 'N',
|
|
szFrameTypes[pfpoT->cbFrame],
|
|
pfpoT->cdwParams * 4);
|
|
PrintSymbolName(pfpoT->ulOffStart);
|
|
fputs("\n", InfoStream);
|
|
}
|
|
|
|
FreePv(pFpoData);
|
|
}
|
|
|
|
|
|
void
|
|
DumpOmap (
|
|
DWORD OmapOffset,
|
|
DWORD cb,
|
|
BOOL MapTo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads and prints each OMAP table entry.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
POMAP pOmap, pOmapData;
|
|
DWORD symval;
|
|
|
|
pOmapData = pOmap = (POMAP) PvAlloc(cb);
|
|
FileSeek(FileReadHandle, OmapOffset, SEEK_SET);
|
|
FileRead(FileReadHandle, pOmapData, cb);
|
|
|
|
fprintf(InfoStream, "\nOMAP Data (%s_SRC) - (%ld):\n\n", MapTo ? "TO" : "FROM", cb / sizeof(OMAP));
|
|
|
|
fputs(" Rva RvaTo Symbol\n"
|
|
" -------- -------- --------\n", InfoStream);
|
|
|
|
for (cb; cb > 0; pOmap++, cb -= sizeof(OMAP)) {
|
|
fprintf(InfoStream, " %08X %08X", pOmap->rva, pOmap->rvaTo);
|
|
symval = MapTo ? pOmap->rvaTo : pOmap->rva;
|
|
if (symval) {
|
|
PrintSymbolName(symval);
|
|
}
|
|
fputs("\n", InfoStream);
|
|
}
|
|
|
|
FreePv(pOmapData);
|
|
}
|
|
|
|
|
|
void
|
|
DumpFixup (
|
|
DWORD FixupOffset,
|
|
DWORD cb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads and prints each Fixup Debug entry.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PXFIXUP pFixup, pFixupData;
|
|
|
|
pFixupData = pFixup = (XFIXUP *) PvAlloc(cb);
|
|
FileSeek(FileReadHandle, FixupOffset, SEEK_SET);
|
|
FileRead(FileReadHandle, pFixupData, cb);
|
|
|
|
fprintf(InfoStream, "\nFixup Data (%ld):\n\n", cb / sizeof(XFIXUP));
|
|
|
|
fputs(" Type Rva RvaTarget Symbol\n"
|
|
" ---- ---- -------- -------- --------\n", InfoStream);
|
|
|
|
for (cb; cb > 0; pFixup++, cb -= sizeof(XFIXUP)) {
|
|
fprintf(InfoStream, " %04X %04X %08X %08X", pFixup->wType, pFixup->wExtra, pFixup->rva, pFixup->rvaTarget);
|
|
if (pFixup->rvaTarget) {
|
|
PrintSymbolName(pFixup->rvaTarget);
|
|
}
|
|
fputs("\n", InfoStream);
|
|
}
|
|
|
|
FreePv(pFixupData);
|
|
}
|
|
|
|
|
|
void
|
|
DumpDebugData (
|
|
PIMAGE_SECTION_HEADER sh
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Walk the debug directory, dumping whatever the user asked for.
|
|
|
|
Arguments:
|
|
|
|
sh - Section header for section that contains the debug directory.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
DWORD foDebugDir;
|
|
DWORD NumDebugDirs;
|
|
|
|
if (dft == dftROM) {
|
|
foDebugDir = sh->PointerToRawData + MemberSeekBase;
|
|
|
|
NumDebugDirs = ULONG_MAX;
|
|
} else {
|
|
foDebugDir = sh->PointerToRawData + MemberSeekBase +
|
|
(ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress -
|
|
sh->VirtualAddress);
|
|
|
|
NumDebugDirs = ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size /
|
|
sizeof(IMAGE_DEBUG_DIRECTORY);
|
|
}
|
|
|
|
while (NumDebugDirs--) {
|
|
IMAGE_DEBUG_DIRECTORY debugDir;
|
|
|
|
FileSeek(FileReadHandle, foDebugDir, SEEK_SET);
|
|
FileRead(FileReadHandle, &debugDir, sizeof(IMAGE_DEBUG_DIRECTORY));
|
|
|
|
if (debugDir.Type == 0) {
|
|
break;
|
|
}
|
|
|
|
switch (debugDir.Type) {
|
|
case IMAGE_DEBUG_TYPE_FPO:
|
|
if (Switch.Dump.FpoData) {
|
|
DumpFpoData(debugDir.PointerToRawData, debugDir.SizeOfData);
|
|
}
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_FIXUP:
|
|
if (Switch.Dump.Fixup) {
|
|
DumpFixup(debugDir.PointerToRawData, debugDir.SizeOfData);
|
|
}
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
|
|
if (Switch.Dump.OmapTo) {
|
|
DumpOmap(debugDir.PointerToRawData, debugDir.SizeOfData, TRUE);
|
|
}
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
|
|
if (Switch.Dump.OmapFrom) {
|
|
DumpOmap(debugDir.PointerToRawData, debugDir.SizeOfData, FALSE);
|
|
}
|
|
break;
|
|
}
|
|
|
|
foDebugDir += sizeof(IMAGE_DEBUG_DIRECTORY);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DumpDebugDirectory (
|
|
PIMAGE_DEBUG_DIRECTORY DebugDir
|
|
)
|
|
{
|
|
InternalError.Phase = "DumpDebugDirectory";
|
|
|
|
fputs(" ", InfoStream);
|
|
|
|
switch (DebugDir->Type) {
|
|
case IMAGE_DEBUG_TYPE_COFF:
|
|
fputs("coff ", InfoStream);
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_CODEVIEW:
|
|
fputs("cv ", InfoStream);
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_FPO:
|
|
fputs("fpo ", InfoStream);
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_MISC:
|
|
fputs("misc ", InfoStream);
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_FIXUP:
|
|
fputs("fixup ", InfoStream);
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
|
|
fputs("-> src ", InfoStream);
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
|
|
fputs("src -> ", InfoStream);
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_EXCEPTION:
|
|
fputs("pdata ", InfoStream);
|
|
break;
|
|
|
|
default:
|
|
fprintf(InfoStream, "(%6lu)", DebugDir->Type);
|
|
break;
|
|
}
|
|
|
|
fprintf(InfoStream, "%8X %08X %8X",
|
|
DebugDir->SizeOfData,
|
|
DebugDir->AddressOfRawData,
|
|
DebugDir->PointerToRawData);
|
|
|
|
if (DebugDir->PointerToRawData &&
|
|
DebugDir->Type == IMAGE_DEBUG_TYPE_MISC)
|
|
{
|
|
PIMAGE_DEBUG_MISC miscData;
|
|
PIMAGE_DEBUG_MISC miscDataCur;
|
|
DWORD saveAddr, len;
|
|
|
|
saveAddr = FileTell(FileReadHandle);
|
|
FileSeek(FileReadHandle, DebugDir->PointerToRawData, SEEK_SET);
|
|
len = DebugDir->SizeOfData;
|
|
miscData = (PIMAGE_DEBUG_MISC) PvAlloc(len);
|
|
FileRead(FileReadHandle, miscData, len);
|
|
|
|
miscDataCur = miscData;
|
|
do {
|
|
if (miscDataCur->DataType == IMAGE_DEBUG_MISC_EXENAME) {
|
|
if (ImageOptionalHdr.MajorLinkerVersion == 2 &&
|
|
ImageOptionalHdr.MinorLinkerVersion < 37) {
|
|
fprintf(InfoStream, " Image Name: %s", miscDataCur->Reserved);
|
|
} else {
|
|
fprintf(InfoStream, " Image Name: %s", miscDataCur->Data);
|
|
}
|
|
break;
|
|
}
|
|
len -= miscDataCur->Length;
|
|
miscDataCur = (PIMAGE_DEBUG_MISC) ((DWORD) miscDataCur + miscData->Length);
|
|
} while (len > 0);
|
|
|
|
FreePv(miscData);
|
|
FileSeek(FileReadHandle, saveAddr, SEEK_SET);
|
|
}
|
|
|
|
if (DebugDir->PointerToRawData &&
|
|
DebugDir->Type == IMAGE_DEBUG_TYPE_CODEVIEW)
|
|
{
|
|
DWORD saveAddr, len;
|
|
|
|
saveAddr = FileTell(FileReadHandle);
|
|
FileSeek(FileReadHandle, DebugDir->PointerToRawData, SEEK_SET);
|
|
len = DebugDir->SizeOfData;
|
|
FileRead(FileReadHandle, &nb10i, sizeof(nb10i));
|
|
|
|
fprintf(InfoStream, " Format: %4.4s", &nb10i.nb10);
|
|
|
|
if (nb10i.nb10 == '01BN') {
|
|
CHAR PdbName[_MAX_PATH];
|
|
assert(len - sizeof(nb10i) <= _MAX_PATH);
|
|
FileRead(FileReadHandle, PdbName, len - sizeof(nb10i));
|
|
fprintf(InfoStream, ", %x, %x, %s", nb10i.sig, nb10i.age, PdbName);
|
|
}
|
|
|
|
FileSeek(FileReadHandle, saveAddr, SEEK_SET);
|
|
}
|
|
|
|
fputs("\n", InfoStream);
|
|
}
|
|
|
|
|
|
void
|
|
DumpDebugDirectories (
|
|
PIMAGE_SECTION_HEADER sh
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Print out the contents of all debug directories
|
|
|
|
Arguments:
|
|
|
|
sh - Section header for section that contains debug dirs
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
int numDebugDirs;
|
|
IMAGE_DEBUG_DIRECTORY debugDir;
|
|
DWORD dwDebugDirAddr;
|
|
|
|
InternalError.Phase = "DumpDebugDirectories";
|
|
|
|
if (dft == dftROM) {
|
|
dwDebugDirAddr = MemberSeekBase + sh->PointerToRawData;
|
|
FileSeek(FileReadHandle, dwDebugDirAddr, SEEK_SET);
|
|
FileRead(FileReadHandle, &debugDir, sizeof(IMAGE_DEBUG_DIRECTORY));
|
|
numDebugDirs = 0;
|
|
while (debugDir.Type != 0) {
|
|
numDebugDirs++;
|
|
FileRead(FileReadHandle, &debugDir, sizeof(IMAGE_DEBUG_DIRECTORY));
|
|
}
|
|
} else {
|
|
dwDebugDirAddr = MemberSeekBase + sh->PointerToRawData +
|
|
(ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress -
|
|
sh->VirtualAddress);
|
|
numDebugDirs = ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size /
|
|
sizeof(IMAGE_DEBUG_DIRECTORY);
|
|
}
|
|
|
|
FileSeek(FileReadHandle, dwDebugDirAddr, SEEK_SET);
|
|
|
|
fprintf(InfoStream, "\n"
|
|
"\n"
|
|
"Debug Directories(%d)\n"
|
|
" Type Size Address Pointer\n"
|
|
"\n",
|
|
numDebugDirs);
|
|
|
|
while (numDebugDirs) {
|
|
FileRead(FileReadHandle, &debugDir, sizeof(IMAGE_DEBUG_DIRECTORY));
|
|
DumpDebugDirectory(&debugDir);
|
|
numDebugDirs--;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DumpDirectives (
|
|
DWORD DirectiveOffset,
|
|
DWORD DirectiveSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads and prints each Directive entry.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PCHAR pDirectiveData;
|
|
PCHAR pNextDirective;
|
|
|
|
FileSeek(FileReadHandle, DirectiveOffset, SEEK_SET);
|
|
|
|
pDirectiveData = (PCHAR) PvAlloc(DirectiveSize);
|
|
FileRead(FileReadHandle, pDirectiveData, DirectiveSize);
|
|
|
|
fputs("\nLinker Directives\n"
|
|
"-----------------\n", InfoStream);
|
|
|
|
pNextDirective = strtok(pDirectiveData, " ");
|
|
while (pNextDirective) {
|
|
fprintf(InfoStream, "%s\n", pNextDirective);
|
|
pNextDirective = strtok(NULL, " ");
|
|
}
|
|
|
|
FreePv(pDirectiveData);
|
|
}
|
|
|
|
BOOL
|
|
ValidFileOffsetInfo (
|
|
DWORD fo,
|
|
DWORD cbOffset
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ensures that the file ptr and offset are valid.
|
|
|
|
Arguments:
|
|
|
|
fo - file offset to validate.
|
|
|
|
cbOffset - cbOffset from fo that has to be valid as well.
|
|
|
|
Return Value:
|
|
|
|
TRUE if info is valid.
|
|
|
|
--*/
|
|
|
|
{
|
|
assert(fo);
|
|
|
|
if ((fo + cbOffset) <= FileLen) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void
|
|
DumpImports (
|
|
PIMAGE_SECTION_HEADER SectionHdr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints Import information.
|
|
|
|
Arguments:
|
|
|
|
SectionHdr - Section header for section that contains Import data.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD foDesc;
|
|
PIMAGE_BOUND_IMPORT_DESCRIPTOR NewImports, NewImport;
|
|
PIMAGE_BOUND_FORWARDER_REF NewForwarder;
|
|
BOOL NewBindImage;
|
|
const char *time;
|
|
|
|
InternalError.Phase = "DumpImports";
|
|
|
|
if (ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress) {
|
|
NewBindImage = TRUE;
|
|
} else {
|
|
NewBindImage = FALSE;
|
|
}
|
|
|
|
fputs("\n Section contains the following Imports\n", InfoStream);
|
|
foDesc = (ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
|
|
- SectionHdr->VirtualAddress)
|
|
+ SectionHdr->PointerToRawData;
|
|
|
|
if (!ValidFileOffsetInfo(foDesc, 0)) {
|
|
Warning(NULL, INVALIDFILEOFFSET, foDesc, "IMPORTS");
|
|
return;
|
|
}
|
|
|
|
for (;;) {
|
|
IMAGE_IMPORT_DESCRIPTOR desc;
|
|
WORD stringSection = 0;
|
|
WORD IATSection;
|
|
WORD j;
|
|
DWORD foName;
|
|
DWORD foINT;
|
|
DWORD foIAT;
|
|
|
|
FileSeek(FileReadHandle, foDesc, SEEK_SET);
|
|
FileRead(FileReadHandle, &desc, sizeof(IMAGE_IMPORT_DESCRIPTOR));
|
|
|
|
foDesc += sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
|
|
|
if ((desc.Characteristics == 0) && (desc.Name == 0) && (desc.FirstThunk == 0)) {
|
|
// End of import descriptors
|
|
|
|
break;
|
|
}
|
|
|
|
// UNDONE: Create SzFromRva to return string allocated from heap
|
|
|
|
for (j = 0; j < ImageFileHdr.NumberOfSections; j++) {
|
|
if ((DWORD) desc.Name >= rgsh[j].VirtualAddress &&
|
|
(DWORD) desc.Name < rgsh[j].VirtualAddress+rgsh[j].SizeOfRawData) {
|
|
stringSection = j;
|
|
}
|
|
|
|
if ((DWORD) desc.FirstThunk >= rgsh[j].VirtualAddress &&
|
|
(DWORD) desc.FirstThunk < rgsh[j].VirtualAddress+rgsh[j].SizeOfRawData) {
|
|
IATSection = j;
|
|
}
|
|
}
|
|
|
|
foName = (DWORD) desc.Name - rgsh[stringSection].VirtualAddress + rgsh[stringSection].PointerToRawData;
|
|
FileSeek(FileReadHandle, foName, SEEK_SET);
|
|
|
|
fputs("\n ", InfoStream);
|
|
|
|
for (;;) {
|
|
char ch;
|
|
|
|
FileRead(FileReadHandle, &ch, sizeof(char));
|
|
|
|
if (ch == '\0') {
|
|
break;
|
|
}
|
|
|
|
fputc(ch, InfoStream);
|
|
}
|
|
|
|
fputc('\n', InfoStream);
|
|
|
|
if ((desc.TimeDateStamp != 0) &&
|
|
(!NewBindImage || desc.TimeDateStamp != 0xFFFFFFFF))
|
|
{
|
|
fprintf(InfoStream, " %8lX time date stamp", desc.TimeDateStamp);
|
|
|
|
if ((time = ctime((time_t *) &desc.TimeDateStamp)) != NULL) {
|
|
fprintf(InfoStream, " %s", time);
|
|
} else {
|
|
fputc('\n', InfoStream);
|
|
}
|
|
|
|
if (desc.ForwarderChain != -1) {
|
|
fprintf(InfoStream, " %8lX index of first forwarder reference\n", desc.ForwarderChain);
|
|
}
|
|
}
|
|
|
|
foIAT = (DWORD) desc.FirstThunk -
|
|
rgsh[IATSection].VirtualAddress +
|
|
rgsh[IATSection].PointerToRawData;
|
|
|
|
if (desc.Characteristics == 0) {
|
|
// Borland's linker doesn't set Characteristics.
|
|
foINT = foIAT;
|
|
foIAT = 0;
|
|
} else {
|
|
foINT = (DWORD) desc.Characteristics -
|
|
SectionHdr->VirtualAddress +
|
|
SectionHdr->PointerToRawData;
|
|
if (!(desc.Characteristics && desc.TimeDateStamp)) {
|
|
foIAT = 0;
|
|
}
|
|
}
|
|
|
|
for (;;) {
|
|
IMAGE_THUNK_DATA thunk;
|
|
IMAGE_THUNK_DATA thunkIAT;
|
|
|
|
FileSeek(FileReadHandle, foINT, SEEK_SET);
|
|
FileRead(FileReadHandle, &thunk, sizeof(IMAGE_THUNK_DATA));
|
|
|
|
foINT += sizeof(IMAGE_THUNK_DATA);
|
|
|
|
if (thunk.u1.AddressOfData == 0) {
|
|
// End of imports
|
|
|
|
break;
|
|
}
|
|
|
|
if (foIAT != 0) {
|
|
FileSeek(FileReadHandle, foIAT, SEEK_SET);
|
|
FileRead(FileReadHandle, &thunkIAT, sizeof(IMAGE_THUNK_DATA));
|
|
|
|
foIAT += sizeof(IMAGE_THUNK_DATA);
|
|
}
|
|
|
|
fputs(" ", InfoStream);
|
|
|
|
if (foIAT != 0) {
|
|
fprintf(InfoStream, "%8X ", thunkIAT.u1.Function);
|
|
}
|
|
|
|
if (IMAGE_SNAP_BY_ORDINAL(thunk.u1.Ordinal)) {
|
|
fprintf(InfoStream, "Ordinal %5lu\n", IMAGE_ORDINAL(thunk.u1.Ordinal));
|
|
} else {
|
|
WORD wHint;
|
|
|
|
// UNDONE: Create WFromRva to return hint word
|
|
|
|
foName = (DWORD) thunk.u1.AddressOfData - rgsh[stringSection].VirtualAddress + rgsh[stringSection].PointerToRawData;
|
|
|
|
FileSeek(FileReadHandle, foName, SEEK_SET);
|
|
FileRead(FileReadHandle, &wHint, sizeof(WORD));
|
|
|
|
fprintf(InfoStream, "% 4hX ", wHint);
|
|
|
|
for (;;) {
|
|
char ch;
|
|
|
|
FileRead(FileReadHandle, &ch, sizeof(char));
|
|
|
|
if (ch == '\0') {
|
|
break;
|
|
}
|
|
|
|
fputc(ch, InfoStream);
|
|
}
|
|
|
|
fputc('\n', InfoStream);
|
|
}
|
|
}
|
|
}
|
|
|
|
// With the BIND changes for the PPC release, a bound image now has a
|
|
// parallel mini import descriptor array stored in the header. The
|
|
// BOUND_IMPORT slot in the data directory points to it.
|
|
|
|
foDesc = ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress;
|
|
if (foDesc == 0) {
|
|
return;
|
|
}
|
|
|
|
// Make sure the header size was adjusted properly and we're pointing into it.
|
|
|
|
fputs("\n Header contains the following Bound Imports Information\n", InfoStream);
|
|
if (foDesc >= ImageOptionalHdr.SizeOfHeaders) {
|
|
fprintf(InfoStream, " **** Invalid offset %x\n", foDesc);
|
|
return;
|
|
}
|
|
|
|
// Read in the table
|
|
|
|
{
|
|
DWORD cb;
|
|
cb = ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size;
|
|
NewImports = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)PvAlloc(cb);
|
|
FileSeek(FileReadHandle, foDesc, SEEK_SET);
|
|
FileRead(FileReadHandle, NewImports, cb);
|
|
}
|
|
|
|
// Walk the list. The table consists of BOUND_IMPORT_DESCRIPTOR followed
|
|
// by NumberOfModuleForwarderRef BOUND_FORWARDER_REF structs. It's
|
|
// terminated by a NULL BOUND_IMPORT_DESCRIPTOR. Immediately following
|
|
// the last descriptor is the string table.
|
|
|
|
NewImport = NewImports;
|
|
while (NewImport->OffsetModuleName) {
|
|
DWORD i;
|
|
fprintf(InfoStream, " Bound to %s [%8lX]",
|
|
(LPSTR)NewImports + NewImport->OffsetModuleName,
|
|
NewImport->TimeDateStamp);
|
|
if (time = ctime((time_t *) &NewImport->TimeDateStamp)) {
|
|
fprintf(InfoStream, " %s", time);
|
|
} else {
|
|
fputc('\n', InfoStream);
|
|
}
|
|
NewForwarder = (PIMAGE_BOUND_FORWARDER_REF)(NewImport+1);
|
|
for (i=0; i<NewImport->NumberOfModuleForwarderRefs; i++) {
|
|
fprintf( InfoStream, " Contained forwarders bound to %s [%8lX]",
|
|
(LPSTR)NewImports + NewForwarder->OffsetModuleName,
|
|
NewForwarder->TimeDateStamp
|
|
);
|
|
if (time = ctime((time_t *) &NewForwarder->TimeDateStamp)) {
|
|
fprintf(InfoStream, " %s", time);
|
|
} else {
|
|
fputc('\n', InfoStream);
|
|
}
|
|
NewForwarder += 1;
|
|
}
|
|
|
|
NewImport = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)NewForwarder;
|
|
}
|
|
|
|
FreePv(NewImports);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
DumpExports (
|
|
PIMAGE_SECTION_HEADER SectionHdr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints Export information.
|
|
|
|
Arguments:
|
|
|
|
SectionHdr - Section header for section that contains Export data.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD lfa;
|
|
const char *time;
|
|
char c;
|
|
char szVersion[30];
|
|
DWORD li;
|
|
DWORD *funcTable;
|
|
DWORD *nameTable;
|
|
WORD *rgwOrdinal;
|
|
IMAGE_EXPORT_DIRECTORY dir;
|
|
|
|
InternalError.Phase = "DumpExports";
|
|
|
|
// Read the Export Directory
|
|
|
|
lfa = (ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress - SectionHdr->VirtualAddress) + SectionHdr->PointerToRawData;
|
|
|
|
if (!ValidFileOffsetInfo(lfa, 0UL)) {
|
|
Warning(NULL, INVALIDFILEOFFSET, lfa, "EXPORTS");
|
|
return;
|
|
}
|
|
|
|
FileSeek(FileReadHandle, lfa, SEEK_SET);
|
|
FileRead(FileReadHandle, &dir, sizeof(IMAGE_EXPORT_DIRECTORY));
|
|
|
|
// Read the Export Name
|
|
|
|
lfa = (DWORD) dir.Name - SectionHdr->VirtualAddress + SectionHdr->PointerToRawData;
|
|
FileSeek(FileReadHandle, lfa, SEEK_SET);
|
|
fputs("\n Section contains the following Exports for ", InfoStream);
|
|
for (;;) {
|
|
FileRead(FileReadHandle, &c, sizeof(char));
|
|
|
|
if (c == '\0') {
|
|
break;
|
|
}
|
|
|
|
fputc(c, InfoStream);
|
|
}
|
|
|
|
fprintf(InfoStream,
|
|
"\n"
|
|
"\n"
|
|
" %8lX characteristics\n"
|
|
" %8lX time date stamp",
|
|
dir.Characteristics,
|
|
dir.TimeDateStamp);
|
|
|
|
if ((time = ctime((time_t *) &dir.TimeDateStamp)) != NULL) {
|
|
fprintf(InfoStream, " %s", time);
|
|
} else {
|
|
fputc('\n', InfoStream);
|
|
}
|
|
|
|
sprintf(szVersion, "%hu.%02hu", dir.MajorVersion, dir.MinorVersion);
|
|
|
|
fprintf(InfoStream,
|
|
" %8s version\n"
|
|
" %8lu ordinal base\n"
|
|
" %8lu number of functions\n"
|
|
" %8lu number of names\n"
|
|
"\n"
|
|
" ordinal hint name\n"
|
|
"\n",
|
|
szVersion,
|
|
dir.Base,
|
|
dir.NumberOfFunctions,
|
|
dir.NumberOfNames);
|
|
|
|
funcTable = (DWORD *) PvAlloc(dir.NumberOfFunctions * sizeof(DWORD));
|
|
nameTable = (DWORD *) PvAlloc(dir.NumberOfNames * sizeof(DWORD));
|
|
rgwOrdinal = (WORD *) PvAlloc(dir.NumberOfNames * sizeof(WORD));
|
|
|
|
// Read the Function Ptr Table
|
|
|
|
lfa = (DWORD) dir.AddressOfFunctions - SectionHdr->VirtualAddress + SectionHdr->PointerToRawData;
|
|
FileSeek(FileReadHandle, lfa, SEEK_SET);
|
|
FileRead(FileReadHandle, funcTable, dir.NumberOfFunctions * sizeof(DWORD));
|
|
|
|
// Read the Name Ptr Table
|
|
|
|
lfa = (DWORD) dir.AddressOfNames - SectionHdr->VirtualAddress + SectionHdr->PointerToRawData;
|
|
FileSeek(FileReadHandle, lfa, SEEK_SET);
|
|
FileRead(FileReadHandle, nameTable, dir.NumberOfNames * sizeof(DWORD));
|
|
|
|
// Read the Ordinal Table
|
|
|
|
lfa = (DWORD) dir.AddressOfNameOrdinals - SectionHdr->VirtualAddress + SectionHdr->PointerToRawData;
|
|
FileSeek(FileReadHandle, lfa, SEEK_SET);
|
|
FileRead(FileReadHandle, rgwOrdinal, dir.NumberOfNames * sizeof(WORD));
|
|
|
|
for (li = 0; li < dir.NumberOfNames; li++) {
|
|
WORD wOrdinal;
|
|
|
|
wOrdinal = rgwOrdinal[li];
|
|
|
|
fprintf(InfoStream, " %5u %4X ", dir.Base + wOrdinal, li);
|
|
|
|
lfa = nameTable[li] - SectionHdr->VirtualAddress + SectionHdr->PointerToRawData;
|
|
FileSeek(FileReadHandle, lfa, SEEK_SET);
|
|
for (;;) {
|
|
FileRead(FileReadHandle, &c, sizeof(char));
|
|
|
|
if (c == '\0') {
|
|
break;
|
|
}
|
|
|
|
fputc(c, InfoStream);
|
|
};
|
|
|
|
if (funcTable[wOrdinal] > (DWORD)ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress &&
|
|
funcTable[wOrdinal] < ((DWORD)ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress +
|
|
(DWORD)ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
|
|
) {
|
|
fputs(" (forwarded to ", InfoStream);
|
|
|
|
lfa = funcTable[wOrdinal] - SectionHdr->VirtualAddress + SectionHdr->PointerToRawData;
|
|
FileSeek(FileReadHandle, lfa, SEEK_SET);
|
|
for (;;) {
|
|
FileRead(FileReadHandle, &c, sizeof(char));
|
|
|
|
if (c == '\0') {
|
|
break;
|
|
}
|
|
|
|
fputc(c, InfoStream);
|
|
};
|
|
|
|
fputs(")\n", InfoStream);
|
|
} else {
|
|
fprintf(InfoStream, " (%08X)\n", funcTable[wOrdinal]);
|
|
}
|
|
funcTable[wOrdinal] = 0;
|
|
}
|
|
|
|
for (li = 0; li < dir.NumberOfFunctions; li++) {
|
|
if (funcTable[li]) {
|
|
fprintf(InfoStream, " %5u ", dir.Base + li);
|
|
|
|
if (funcTable[li] > (DWORD)ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress &&
|
|
funcTable[li] < ((DWORD)ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress +
|
|
(DWORD)ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
|
|
) {
|
|
fputs(" (forwarded to ", InfoStream);
|
|
|
|
lfa = funcTable[li] - SectionHdr->VirtualAddress + SectionHdr->PointerToRawData;
|
|
FileSeek(FileReadHandle, lfa, SEEK_SET);
|
|
for (;;) {
|
|
FileRead(FileReadHandle, &c, sizeof(char));
|
|
|
|
if (c == '\0') {
|
|
break;
|
|
}
|
|
|
|
fputc(c, InfoStream);
|
|
};
|
|
|
|
fputs(")\n", InfoStream);
|
|
} else {
|
|
fprintf(InfoStream, " (%08X)\n", funcTable[li]);
|
|
}
|
|
}
|
|
}
|
|
|
|
FreePv(funcTable);
|
|
FreePv(nameTable);
|
|
FreePv(rgwOrdinal);
|
|
}
|
|
|
|
|
|
void
|
|
DumpBaseRelocations (
|
|
PIMAGE_BASE_RELOCATION Reloc,
|
|
WORD *pwFixup
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints a block of relocation records.
|
|
|
|
Arguments:
|
|
|
|
Reloc - Pointer to a base relocation record.
|
|
|
|
pwFixup - Pointer to type/offsets.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD *pwMax;
|
|
|
|
InternalError.Phase = "DumpBaseRelocations";
|
|
|
|
fprintf(InfoStream, "%8lX virtual address, %8lX SizeOfBlock\n", Reloc->VirtualAddress, Reloc->SizeOfBlock);
|
|
|
|
pwMax = pwFixup + (Reloc->SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION) / sizeof(WORD);
|
|
|
|
while (pwFixup < pwMax) {
|
|
WORD wType;
|
|
const char *szName;
|
|
|
|
wType = (WORD) (*pwFixup >> 12);
|
|
switch (wType) {
|
|
case IMAGE_REL_BASED_ABSOLUTE :
|
|
szName = "ABS";
|
|
break;
|
|
|
|
case IMAGE_REL_BASED_HIGH :
|
|
szName = "HIGH";
|
|
break;
|
|
|
|
case IMAGE_REL_BASED_LOW :
|
|
szName = "LOW";
|
|
break;
|
|
|
|
case IMAGE_REL_BASED_HIGHLOW :
|
|
szName = "HIGHLOW";
|
|
break;
|
|
|
|
case IMAGE_REL_BASED_HIGHADJ :
|
|
szName = "HIGHADJ";
|
|
break;
|
|
|
|
case IMAGE_REL_BASED_MIPS_JMPADDR :
|
|
szName = "JMPADDR";
|
|
break;
|
|
|
|
#if 1
|
|
case IMAGE_REL_BASED_SECTION :
|
|
szName = "SECTION";
|
|
break;
|
|
|
|
case IMAGE_REL_BASED_REL32 :
|
|
szName = "REL32";
|
|
break;
|
|
#endif
|
|
|
|
default :
|
|
fprintf(InfoStream, "0x%hx ", wType);
|
|
szName = "UNKNOWN BASED RELOCATION";
|
|
break;
|
|
}
|
|
|
|
fprintf(InfoStream, "%8hX %s", *pwFixup++ & 0xfff, szName);
|
|
|
|
if (wType == IMAGE_REL_BASED_HIGHADJ) {
|
|
fprintf(InfoStream, " (%04hx)\n", *pwFixup++);
|
|
} else {
|
|
fputs("\n", InfoStream);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DumpRomRelocations (
|
|
PIMAGE_SECTION_HEADER pish,
|
|
DWORD crel,
|
|
const BYTE * /* rgb */,
|
|
DWORD cbVirtual)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints the relocation records.
|
|
|
|
Arguments:
|
|
|
|
crel - Number of relocations to dump.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
InternalError.Phase = "DumpRomRelocations";
|
|
|
|
const char *(*pfnSzRelocationType)(WORD, WORD *, BOOL *);
|
|
|
|
switch (ImageFileHdr.Machine) {
|
|
case IMAGE_FILE_MACHINE_I386 :
|
|
pfnSzRelocationType = SzI386RelocationType;
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_R3000 :
|
|
case IMAGE_FILE_MACHINE_R4000 :
|
|
case IMAGE_FILE_MACHINE_R10000 :
|
|
pfnSzRelocationType = &SzMipsRelocationType;
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_ALPHA :
|
|
pfnSzRelocationType = &SzAlphaRelocationType;
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_POWERPC :
|
|
pfnSzRelocationType = &SzPpcRelocationType;
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_M68K :
|
|
pfnSzRelocationType = &SzM68KRelocationType;
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_MPPC_601 :
|
|
pfnSzRelocationType = &SzMPPCRelocationType;
|
|
break;
|
|
|
|
default :
|
|
pfnSzRelocationType = 0;
|
|
break;
|
|
}
|
|
|
|
DWORD cbRelocs = crel * sizeof(IMAGE_BASE_RELOCATION);
|
|
|
|
PIMAGE_BASE_RELOCATION rgrel = (PIMAGE_BASE_RELOCATION) PvAlloc(cbRelocs);
|
|
|
|
FileRead(FileReadHandle, (void *) rgrel, cbRelocs);
|
|
|
|
DWORD irel;
|
|
PIMAGE_BASE_RELOCATION prel;
|
|
|
|
for (irel = 0, prel = rgrel; irel < crel; irel++, prel++) {
|
|
WORD wType;
|
|
char rgchType[17];
|
|
const char *szType;
|
|
WORD cbType;
|
|
BOOL fSymValid;
|
|
|
|
wType = (WORD) (prel->SizeOfBlock >> 27);
|
|
|
|
if (pfnSzRelocationType == 0) {
|
|
sprintf(rgchType, "0x%04X", wType);
|
|
|
|
szType = rgchType;
|
|
cbType = 0;
|
|
} else {
|
|
szType = (*pfnSzRelocationType)(wType, &cbType, &fSymValid);
|
|
|
|
if (szType == NULL) {
|
|
sprintf(rgchType, "Unknown (0x%04X)", wType);
|
|
|
|
szType = rgchType;
|
|
cbType = 0;
|
|
}
|
|
}
|
|
|
|
fprintf(InfoStream, "%8lX virtual address, % 6lX target, %s\n",
|
|
prel->VirtualAddress,
|
|
prel->SizeOfBlock & 0x7FFFFFF,
|
|
szType);
|
|
|
|
if (((prel->VirtualAddress + sizeof(DWORD)) >
|
|
(pish->VirtualAddress + cbVirtual))) {
|
|
fputs("LINK : warning : Relocations beyond end of section\n", InfoStream);
|
|
}
|
|
}
|
|
|
|
FreePv((void *) rgrel);
|
|
}
|
|
|
|
|
|
void
|
|
DumpRelocations (
|
|
PIMAGE_SECTION_HEADER pish,
|
|
DWORD crel,
|
|
const BYTE *rgb,
|
|
DWORD cbVirtual)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints the relocation records.
|
|
|
|
Arguments:
|
|
|
|
crel - Number of relocations to dump.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
InternalError.Phase = "DumpRelocations";
|
|
|
|
if (pish->Characteristics & IMAGE_SCN_LNK_NRELOC_OVFL) {
|
|
if ((crel == 0xFFFF) && (dft == dftObject)) {
|
|
// Read real count from VirtualAddress of first relocation
|
|
|
|
FileRead(FileReadHandle, (void *) &crel, sizeof(DWORD));
|
|
|
|
if (crel < 0xFFFF) {
|
|
Fatal(NULL, BADCOFF_RELOCCOUNT, crel);
|
|
}
|
|
|
|
FileSeek(FileReadHandle, -(long) sizeof(DWORD), SEEK_CUR);
|
|
}
|
|
}
|
|
|
|
fputs(" Symbol Symbol\n"
|
|
" Offset Type Applied To Index Name\n"
|
|
" -------- ---------------- ----------------- -------- ------\n", InfoStream);
|
|
|
|
const char *(*pfnSzRelocationType)(WORD, WORD *, BOOL *);
|
|
|
|
switch (ImageFileHdr.Machine) {
|
|
case IMAGE_FILE_MACHINE_I386 :
|
|
pfnSzRelocationType = SzI386RelocationType;
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_R3000 :
|
|
case IMAGE_FILE_MACHINE_R4000 :
|
|
case IMAGE_FILE_MACHINE_R10000 :
|
|
pfnSzRelocationType = &SzMipsRelocationType;
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_ALPHA :
|
|
pfnSzRelocationType = &SzAlphaRelocationType;
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_POWERPC :
|
|
pfnSzRelocationType = &SzPpcRelocationType;
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_M68K :
|
|
pfnSzRelocationType = &SzM68KRelocationType;
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_MPPC_601 :
|
|
pfnSzRelocationType = &SzMPPCRelocationType;
|
|
break;
|
|
|
|
default :
|
|
pfnSzRelocationType = 0;
|
|
break;
|
|
}
|
|
|
|
const BYTE *pbMax = rgb + cbVirtual;
|
|
|
|
DWORD cbRelocs = crel * sizeof(IMAGE_RELOCATION);
|
|
|
|
PIMAGE_RELOCATION rgrel = (PIMAGE_RELOCATION) PvAlloc(cbRelocs);
|
|
|
|
FileRead(FileReadHandle, (void *) rgrel, cbRelocs);
|
|
|
|
DWORD irel;
|
|
PIMAGE_RELOCATION prel;
|
|
|
|
for (irel = 0, prel = rgrel; irel < crel; irel++, prel++) {
|
|
char rgchType[17];
|
|
const char *szType;
|
|
WORD cbType;
|
|
BOOL fSymValid;
|
|
char rgchValue[18];
|
|
char *szValue;
|
|
|
|
if (pfnSzRelocationType == 0) {
|
|
sprintf(rgchType, "0x%04X", prel->Type);
|
|
|
|
szType = rgchType;
|
|
cbType = 0;
|
|
fSymValid = FALSE;
|
|
} else {
|
|
szType = (*pfnSzRelocationType)(prel->Type, &cbType, &fSymValid);
|
|
|
|
if (szType == NULL) {
|
|
sprintf(rgchType, "Unknown (0x%04X)", prel->Type);
|
|
|
|
szType = rgchType;
|
|
cbType = 0;
|
|
fSymValid = FALSE;
|
|
}
|
|
}
|
|
|
|
szValue = rgchValue + sizeof(rgchValue) - 1;
|
|
*szValue = '\0';
|
|
|
|
const BYTE *pb = rgb + (prel->VirtualAddress - pish->VirtualAddress);
|
|
|
|
for (WORD ib = 0; ib < cbType; ib++, pb++) {
|
|
if (ib == 4) {
|
|
*--szValue = ' ';
|
|
}
|
|
|
|
if (pb >= pbMax) {
|
|
*--szValue = '*';
|
|
*--szValue = '*';
|
|
continue;
|
|
}
|
|
|
|
*--szValue = "0123456789ABCDEF"[*pb % 16];
|
|
*--szValue = "0123456789ABCDEF"[*pb / 16];
|
|
}
|
|
|
|
fprintf(InfoStream, " %08lX %-16s %17s %8lX",
|
|
prel->VirtualAddress,
|
|
szType,
|
|
szValue,
|
|
prel->SymbolTableIndex);
|
|
|
|
if (fSymValid) {
|
|
DumpNamePsym(InfoStream, " %s", rgsym + prel->SymbolTableIndex);
|
|
}
|
|
|
|
fputc('\n', InfoStream);
|
|
}
|
|
|
|
FreePv((void *) rgrel);
|
|
}
|
|
|
|
|
|
void
|
|
DumpLinenumbers (
|
|
DWORD cLinenum
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints the linenumbers.
|
|
|
|
Arguments:
|
|
|
|
cLinenum - Number of linenumbers to dump.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD cbLinenum;
|
|
PIMAGE_LINENUMBER rgLinenum;
|
|
PIMAGE_LINENUMBER pLinenum;
|
|
DWORD lj;
|
|
WORD numberUnits;
|
|
|
|
InternalError.Phase = "DumpLinenumbers";
|
|
|
|
//
|
|
// Use sizeof struct because it may be larger than struct on disk.
|
|
//
|
|
|
|
cbLinenum = cLinenum * sizeof(IMAGE_LINENUMBER);
|
|
rgLinenum = (PIMAGE_LINENUMBER) PvAlloc(cbLinenum);
|
|
|
|
FileRead(FileReadHandle, (void *) rgLinenum, cbLinenum);
|
|
|
|
pLinenum = rgLinenum;
|
|
for (lj = cLinenum, numberUnits = 5; lj; --lj, --numberUnits) {
|
|
if (!numberUnits) {
|
|
numberUnits = 5;
|
|
fputc('\n', InfoStream);
|
|
}
|
|
|
|
if (pLinenum->Linenumber == 0) {
|
|
if (numberUnits != 5) {
|
|
// Guarantee a line break
|
|
fputc('\n', InfoStream);
|
|
}
|
|
}
|
|
|
|
fprintf(InfoStream, "%8lX %4hX ",
|
|
pLinenum->Type.VirtualAddress, pLinenum->Linenumber);
|
|
|
|
if (pLinenum->Linenumber == 0) {
|
|
PIMAGE_SYMBOL psym;
|
|
|
|
if (rgsym == NULL) {
|
|
fputs("\n", InfoStream);
|
|
} else if ((pLinenum->Type.VirtualAddress < ImageFileHdr.NumberOfSymbols) &&
|
|
(((psym = &rgsym[pLinenum->Type.VirtualAddress])->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) ||
|
|
((psym->StorageClass == IMAGE_SYM_CLASS_STATIC) &&
|
|
ISFCN(psym->Type))) &&
|
|
psym->NumberOfAuxSymbols == 1)
|
|
{
|
|
DumpNamePsym(InfoStream, "sym= %s\n", psym);
|
|
} else {
|
|
fputs("(error: invalid symbol index)\n", InfoStream);
|
|
}
|
|
numberUnits = 5; // indicate that we generated a line break
|
|
}
|
|
|
|
pLinenum++;
|
|
}
|
|
|
|
fputc('\n', InfoStream);
|
|
|
|
FreePv((void *) rgLinenum);
|
|
}
|
|
|
|
|
|
void
|
|
DumpSections (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints section header, raw data, relocations, linenumber.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD j;
|
|
WORD i;
|
|
const char *szName;
|
|
PARGUMENT_LIST argument;
|
|
|
|
InternalError.Phase = "DumpSections";
|
|
|
|
DWORD fo = MemberSeekBase + CoffHeaderSeek + sizeof(IMAGE_FILE_HEADER) + ImageFileHdr.SizeOfOptionalHeader;
|
|
DWORD cb = ImageFileHdr.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
|
|
|
|
rgsh = (PIMAGE_SECTION_HEADER) PvAlloc(cb);
|
|
|
|
FileSeek(FileReadHandle, fo, SEEK_SET);
|
|
FileRead(FileReadHandle, rgsh, cb);
|
|
|
|
// Warning for sections requested that don't exist
|
|
|
|
for (j = 0, argument = SectionNames.First;
|
|
j < SectionNames.Count;
|
|
j++, argument = argument->Next) {
|
|
BOOL fFound = FALSE;
|
|
|
|
for (i = 1; i <= ImageFileHdr.NumberOfSections; i++) {
|
|
szName = SzObjSectionName((char *) rgsh[i-1].Name, (char *) DumpStringTable);
|
|
|
|
if (!strcmp(szName, argument->OriginalName)) {
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!fFound) {
|
|
Warning(NULL, SECTIONNOTFOUND, argument->OriginalName);
|
|
}
|
|
}
|
|
|
|
for (i = 1; i <= ImageFileHdr.NumberOfSections; i++) {
|
|
IMAGE_SECTION_HEADER sh = rgsh[i-1];
|
|
|
|
szName = SzObjSectionName((char *) sh.Name, (char *) DumpStringTable);
|
|
|
|
if (SectionNames.Count != 0) {
|
|
for (j = 0, argument = SectionNames.First;
|
|
j < SectionNames.Count;
|
|
j++, argument = argument->Next) {
|
|
if (!strcmp(szName, argument->OriginalName)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (j == SectionNames.Count) {
|
|
// This section isn't in the list. Don't dump it.
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
DWORD cbVirtual;
|
|
|
|
if (dft == dftObject) {
|
|
cbVirtual = sh.SizeOfRawData;
|
|
} else {
|
|
cbVirtual = sh.Misc.VirtualSize;
|
|
|
|
if (cbVirtual == 0) {
|
|
cbVirtual = sh.SizeOfRawData;
|
|
}
|
|
}
|
|
|
|
if (Switch.Dump.Summary) {
|
|
PSEC psec = PsecNew(NULL, szName, sh.Characteristics, &pimageDump->secs, &pimageDump->ImgOptHdr);
|
|
|
|
if (dft == dftPE) {
|
|
psec->cbRawData += SectionAlign(ImageOptionalHdr.SectionAlignment, cbVirtual);
|
|
} else {
|
|
psec->cbRawData += cbVirtual;
|
|
}
|
|
}
|
|
|
|
if (cbVirtual > sh.SizeOfRawData) {
|
|
// Don't dump more than there is on disk
|
|
|
|
cbVirtual = sh.SizeOfRawData;
|
|
}
|
|
|
|
if (Switch.Dump.Headers || SectionNames.Count) {
|
|
DumpSectionHeader(i, &sh);
|
|
}
|
|
|
|
BYTE *pbRawData = NULL;
|
|
BOOL fMapped = FALSE;
|
|
|
|
if ((sh.PointerToRawData != 0) && (sh.SizeOfRawData != 0)) {
|
|
pbRawData = PbMappedRegion(FileReadHandle, MemberSeekBase + sh.PointerToRawData, cbVirtual);
|
|
|
|
fMapped = (pbRawData != NULL);
|
|
|
|
if (!fMapped) {
|
|
// Allocate memory for raw data
|
|
|
|
pbRawData = (BYTE *) PvAlloc(cbVirtual);
|
|
|
|
// Read raw data into memory
|
|
|
|
if (FileSeek(FileReadHandle, MemberSeekBase + sh.PointerToRawData, SEEK_SET) == -1) {
|
|
Error(NULL, CANTSEEKFILE, MemberSeekBase + sh.PointerToRawData);
|
|
}
|
|
|
|
FileRead(FileReadHandle, pbRawData, cbVirtual);
|
|
}
|
|
}
|
|
|
|
if (pbRawData != NULL) {
|
|
if (Switch.Dump.Disasm && (sh.Characteristics & IMAGE_SCN_CNT_CODE)) {
|
|
fputc('\n', InfoStream);
|
|
|
|
switch (ImageFileHdr.Machine) {
|
|
case IMAGE_FILE_MACHINE_I386 :
|
|
case IMAGE_FILE_MACHINE_R3000 :
|
|
case IMAGE_FILE_MACHINE_R4000 :
|
|
case IMAGE_FILE_MACHINE_R10000 :
|
|
case IMAGE_FILE_MACHINE_ALPHA :
|
|
case IMAGE_FILE_MACHINE_POWERPC :
|
|
case IMAGE_FILE_MACHINE_M68K :
|
|
case IMAGE_FILE_MACHINE_MPPC_601 :
|
|
DisasmSection(ImageFileHdr.Machine,
|
|
&sh,
|
|
i,
|
|
ImageOptionalHdr.ImageBase,
|
|
pbRawData,
|
|
cbVirtual);
|
|
break;
|
|
|
|
default:
|
|
fputs("LINK : warning : Disassembly not supported for this target machine\n", InfoStream);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Switch.Dump.RawData) {
|
|
fprintf(InfoStream, "\nRAW DATA #%hX\n", i);
|
|
|
|
DumpRawData(/* UNDONE */ 0, pbRawData, cbVirtual);
|
|
}
|
|
}
|
|
|
|
if (dft == dftObject) {
|
|
// The debug section name is used here because obj files do not have an
|
|
// optional header pointing to the debug section
|
|
|
|
if (Switch.Dump.FpoData && (!strcmp(szName, ".debug$F"))) {
|
|
DumpFpoData(sh.PointerToRawData + MemberSeekBase, sh.SizeOfRawData);
|
|
}
|
|
|
|
if (Switch.Dump.PData && !strcmp(szName, ReservedSection.Exception.Name)) {
|
|
FileSeek(FileReadHandle, MemberSeekBase + sh.PointerToRawData, SEEK_SET);
|
|
DumpObjFunctionTable(&sh, i);
|
|
}
|
|
|
|
if (Switch.Dump.Directives && (!strcmp(szName, ".drectve"))) {
|
|
DumpDirectives(sh.PointerToRawData + MemberSeekBase, sh.SizeOfRawData);
|
|
}
|
|
|
|
} else if (dft == dftROM) {
|
|
if (!(ImageFileHdr.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)) {
|
|
|
|
// If we're looking at the .rdata section and the symbols
|
|
// aren't stripped, the debug directory must be here.
|
|
|
|
if (!strcmp(szName, ReservedSection.ReadOnlyData.Name)) {
|
|
if (Switch.Dump.Headers) {
|
|
DumpDebugDirectories(&sh);
|
|
}
|
|
|
|
DumpDebugData(&sh);
|
|
}
|
|
}
|
|
} else if (dft == dftPE) {
|
|
DWORD li;
|
|
|
|
if ((li = ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) != 0) {
|
|
if (li >= sh.VirtualAddress && li < sh.VirtualAddress+sh.SizeOfRawData) {
|
|
if (Switch.Dump.Headers) {
|
|
DumpDebugDirectories(&sh);
|
|
}
|
|
|
|
DumpDebugData(&sh);
|
|
}
|
|
}
|
|
|
|
if (Switch.Dump.PData) {
|
|
li = ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
|
|
|
|
if ((li != 0) && (li >= sh.VirtualAddress) && (li < sh.VirtualAddress+sh.SizeOfRawData)) {
|
|
DumpFunctionTable(pimageDump, rgsym, (char *) DumpStringTable);
|
|
}
|
|
}
|
|
|
|
if (Switch.Dump.Imports) {
|
|
li = ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
|
|
|
|
if ((li != 0) && (li >= sh.VirtualAddress) && (li < sh.VirtualAddress+sh.SizeOfRawData)) {
|
|
DumpImports(&sh);
|
|
}
|
|
}
|
|
|
|
if (Switch.Dump.Exports) {
|
|
li = ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
|
|
|
if ((li != 0) && (li >= sh.VirtualAddress) && (li < sh.VirtualAddress+sh.SizeOfRawData)) {
|
|
// UNDONE: Is this check really necessary?
|
|
|
|
if (ImageFileHdr.Machine != IMAGE_FILE_MACHINE_MPPC_601) {
|
|
DumpExports(&sh);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Switch.Dump.BaseRelocations) {
|
|
li = ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
|
|
|
|
if ((li != 0) && (li >= sh.VirtualAddress) && (li < sh.VirtualAddress+sh.SizeOfRawData)) {
|
|
fprintf(InfoStream, "\nBASE RELOCATIONS #%hX\n", i);
|
|
|
|
if (ValidFileOffsetInfo((li - sh.VirtualAddress) + sh.PointerToRawData, 0UL)) {
|
|
FileSeek(FileReadHandle, (li - sh.VirtualAddress) + sh.PointerToRawData, SEEK_SET);
|
|
|
|
li = ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
|
|
|
|
while (li) {
|
|
IMAGE_BASE_RELOCATION bre;
|
|
|
|
FileRead(FileReadHandle, &bre, IMAGE_SIZEOF_BASE_RELOCATION);
|
|
|
|
if (bre.SizeOfBlock == 0) {
|
|
break;
|
|
}
|
|
|
|
WORD *fixups = (WORD *) PvAlloc(bre.SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION);
|
|
|
|
FileRead(FileReadHandle, fixups, bre.SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION);
|
|
DumpBaseRelocations(&bre, fixups);
|
|
li -= bre.SizeOfBlock;
|
|
|
|
FreePv(fixups);
|
|
}
|
|
} else {
|
|
Warning(NULL, INVALIDFILEOFFSET, li - sh.VirtualAddress + sh.PointerToRawData, "BASERELOCATIONS");
|
|
}
|
|
}
|
|
}
|
|
} else if (dft == dftPEX) {
|
|
DWORD li;
|
|
|
|
if ((li = ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress) != 0) {
|
|
if (li >= sh.VirtualAddress && li < sh.VirtualAddress+sh.SizeOfRawData) {
|
|
if (Switch.Dump.Headers) {
|
|
DumpDebugDirectories(&sh);
|
|
}
|
|
|
|
DumpDebugData(&sh);
|
|
}
|
|
}
|
|
|
|
if (Switch.Dump.PData) {
|
|
li = ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
|
|
|
|
if ((li != 0) && (li >= sh.VirtualAddress) && (li < sh.VirtualAddress+sh.SizeOfRawData)) {
|
|
DumpPexFunctionTable((PIMAGE_RUNTIME_FUNCTION_ENTRY) (pbRawData + li - sh.VirtualAddress),
|
|
ImageOptionalHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY));
|
|
}
|
|
}
|
|
|
|
if (strcmp(szName, ".ppcldr") == 0) {
|
|
if (pbRawData != NULL) {
|
|
DumpPefLoaderSection(pbRawData);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Switch.Dump.Relocations && sh.NumberOfRelocations) {
|
|
DWORD cb;
|
|
|
|
fprintf(InfoStream, "\nRELOCATIONS #%hX\n", i);
|
|
|
|
if (dft == dftROM) {
|
|
cb = (DWORD) sh.NumberOfRelocations * sizeof(IMAGE_BASE_RELOCATION);
|
|
} else {
|
|
cb = (DWORD) sh.NumberOfRelocations * sizeof(IMAGE_RELOCATION);
|
|
}
|
|
|
|
if (ValidFileOffsetInfo(MemberSeekBase + sh.PointerToRelocations, cb)) {
|
|
FileSeek(FileReadHandle, MemberSeekBase + sh.PointerToRelocations, SEEK_SET);
|
|
|
|
if (dft == dftROM) {
|
|
DumpRomRelocations(&sh, (DWORD) sh.NumberOfRelocations, pbRawData, cbVirtual);
|
|
} else {
|
|
DumpRelocations(&sh, (DWORD) sh.NumberOfRelocations, pbRawData, cbVirtual);
|
|
}
|
|
} else {
|
|
Warning(NULL, INVALIDFILEOFFSET, MemberSeekBase + sh.PointerToRelocations, "RELOCATIONS");
|
|
}
|
|
}
|
|
|
|
if (Switch.Dump.Linenumbers && sh.NumberOfLinenumbers) {
|
|
fprintf(InfoStream, "\nLINENUMBERS #%hX\n", i);
|
|
|
|
if (ValidFileOffsetInfo(MemberSeekBase + sh.PointerToLinenumbers,(DWORD)sh.NumberOfLinenumbers*sizeof(IMAGE_LINENUMBER))) {
|
|
FileSeek(FileReadHandle,MemberSeekBase + sh.PointerToLinenumbers, SEEK_SET);
|
|
DumpLinenumbers((DWORD) sh.NumberOfLinenumbers);
|
|
} else {
|
|
Warning(NULL, INVALIDFILEOFFSET, MemberSeekBase + sh.PointerToLinenumbers, "LINENUMBERS");
|
|
}
|
|
}
|
|
|
|
if (!fMapped) {
|
|
FreePv(pbRawData);
|
|
}
|
|
}
|
|
|
|
// UNDONE: Is is safe to call FreePv(rgsh);
|
|
}
|
|
|
|
|
|
void
|
|
DumpSymbolMap (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads and prints symbol map, which includes the size of each symbol.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIMAGE_SYMBOL NextSymbol, Symbol;
|
|
PIMAGE_AUX_SYMBOL AuxSymbol;
|
|
DWORD i = 0L, endAddr;
|
|
SHORT j, numaux;
|
|
CHAR SymbolNameBuffer[9];
|
|
PCHAR SymbolName;
|
|
|
|
InternalError.Phase = "DumpSymbolMap";
|
|
|
|
fputs("\nSYMBOL MAP\n", InfoStream);
|
|
|
|
for (j=0; j<9; j++) {
|
|
SymbolNameBuffer[j] = '\0';
|
|
}
|
|
|
|
NextSymbol = rgsym;
|
|
while (i < ImageFileHdr.NumberOfSymbols) {
|
|
i++;
|
|
Symbol = FetchNextSymbol(&NextSymbol);
|
|
numaux = Symbol->NumberOfAuxSymbols;
|
|
|
|
if (numaux != 0) {
|
|
for (j = numaux; j; j--) {
|
|
AuxSymbol = (PIMAGE_AUX_SYMBOL) FetchNextSymbol(&NextSymbol);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (Symbol->SectionNumber > 0 && Symbol->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) {
|
|
if (IsLongName(*Symbol)) {
|
|
SymbolName = (PCHAR) &DumpStringTable[Symbol->n_offset];
|
|
} else {
|
|
SymbolName = strncpy(SymbolNameBuffer, (char*)Symbol->n_name, 8);
|
|
}
|
|
|
|
if (*SymbolName == '_') {
|
|
SymbolName++;
|
|
}
|
|
|
|
fprintf(InfoStream, "%08lX", Symbol->Value);
|
|
if ((i+1) < ImageFileHdr.NumberOfSymbols &&
|
|
NextSymbol->SectionNumber == Symbol->SectionNumber) {
|
|
fprintf(InfoStream, " , %8lu", NextSymbol->Value - Symbol->Value);
|
|
} else {
|
|
endAddr = rgsh[Symbol->SectionNumber-1].VirtualAddress
|
|
+ rgsh[Symbol->SectionNumber-1].SizeOfRawData;
|
|
fprintf(InfoStream, " , %8lu", endAddr - Symbol->Value);
|
|
}
|
|
fprintf(InfoStream, ", %s\n", SymbolName);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DumpSymbolInfo (
|
|
PIMAGE_SYMBOL Symbol,
|
|
char *szOut
|
|
)
|
|
|
|
{
|
|
WORD type;
|
|
size_t i;
|
|
size_t cch;
|
|
const char *szT;
|
|
|
|
switch (Symbol->SectionNumber) {
|
|
case IMAGE_SYM_UNDEFINED :
|
|
strcpy(szOut, "UNDEF ");
|
|
break;
|
|
|
|
case IMAGE_SYM_ABSOLUTE :
|
|
strcpy(szOut, "ABS ");
|
|
break;
|
|
|
|
case IMAGE_SYM_DEBUG :
|
|
strcpy(szOut, "DEBUG ");
|
|
break;
|
|
|
|
default :
|
|
sprintf(szOut, "SECT%hX ", Symbol->SectionNumber);
|
|
|
|
if (Symbol->SectionNumber < 0x10) {
|
|
strcat(szOut, " " );
|
|
}
|
|
}
|
|
|
|
szOut += strlen(szOut);
|
|
|
|
switch (Symbol->Type & 0xf) {
|
|
case IMAGE_SYM_TYPE_NULL :
|
|
szT = "notype";
|
|
break;
|
|
|
|
case IMAGE_SYM_TYPE_VOID :
|
|
szT = "void";
|
|
break;
|
|
|
|
case IMAGE_SYM_TYPE_CHAR :
|
|
szT = "char";
|
|
break;
|
|
|
|
case IMAGE_SYM_TYPE_SHORT :
|
|
szT = "short";
|
|
break;
|
|
|
|
case IMAGE_SYM_TYPE_INT :
|
|
szT = "int";
|
|
break;
|
|
|
|
case IMAGE_SYM_TYPE_LONG :
|
|
szT = "long";
|
|
break;
|
|
|
|
case IMAGE_SYM_TYPE_FLOAT :
|
|
szT = "float";
|
|
break;
|
|
|
|
case IMAGE_SYM_TYPE_DOUBLE :
|
|
szT = "double";
|
|
break;
|
|
|
|
case IMAGE_SYM_TYPE_STRUCT :
|
|
szT = "struct";
|
|
break;
|
|
|
|
case IMAGE_SYM_TYPE_UNION :
|
|
szT = "union";
|
|
break;
|
|
|
|
case IMAGE_SYM_TYPE_ENUM :
|
|
szT = "enum";
|
|
break;
|
|
|
|
case IMAGE_SYM_TYPE_MOE :
|
|
szT = "moe";
|
|
break;
|
|
|
|
case IMAGE_SYM_TYPE_BYTE :
|
|
szT = "byte";
|
|
break;
|
|
|
|
case IMAGE_SYM_TYPE_WORD :
|
|
szT = "word";
|
|
break;
|
|
|
|
case IMAGE_SYM_TYPE_UINT :
|
|
szT = "uint";
|
|
break;
|
|
|
|
case IMAGE_SYM_TYPE_DWORD :
|
|
szT = "dword";
|
|
break;
|
|
|
|
default :
|
|
szT = "????";
|
|
break;
|
|
}
|
|
|
|
strcpy(szOut, szT);
|
|
strcat(szOut, " ");
|
|
|
|
cch = strlen(szOut);
|
|
szOut += cch;
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
type = (WORD) ((Symbol->Type >> (10-(i*2)+4)) & 3);
|
|
|
|
if (type == IMAGE_SYM_DTYPE_POINTER) {
|
|
cch += sprintf(szOut, "*");
|
|
szOut += 1;
|
|
}
|
|
|
|
if (type == IMAGE_SYM_DTYPE_ARRAY) {
|
|
cch += sprintf(szOut, "[]");
|
|
szOut += 2;
|
|
}
|
|
|
|
if (type == IMAGE_SYM_DTYPE_FUNCTION) {
|
|
cch += sprintf(szOut, "()");
|
|
szOut += 2;
|
|
}
|
|
}
|
|
|
|
for (i = cch; i < 12; i++) {
|
|
*szOut++ = ' ';
|
|
}
|
|
*szOut++ = ' ';
|
|
|
|
switch (Symbol->StorageClass) {
|
|
case IMAGE_SYM_CLASS_END_OF_FUNCTION :
|
|
szT = "EndOfFunction";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_NULL :
|
|
szT = "NoClass";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_AUTOMATIC :
|
|
szT = "AutoVar";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_EXTERNAL :
|
|
szT = "External";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_STATIC :
|
|
szT = "Static";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_REGISTER :
|
|
szT = "RegisterVar";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_EXTERNAL_DEF :
|
|
szT = "ExternalDef";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_LABEL :
|
|
szT = "Label";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_UNDEFINED_LABEL :
|
|
szT = "UndefinedLabel";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT :
|
|
szT = "MemberOfStruct";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_ARGUMENT :
|
|
szT = "FunctionArg";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_STRUCT_TAG :
|
|
szT = "StructTag";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_MEMBER_OF_UNION :
|
|
szT = "MemberOfUnion";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_UNION_TAG :
|
|
szT = "UnionTag";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_TYPE_DEFINITION :
|
|
szT = "TypeDefinition";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_UNDEFINED_STATIC :
|
|
szT = "UndefinedStatic";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_ENUM_TAG :
|
|
szT = "EnumTag";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_MEMBER_OF_ENUM :
|
|
szT = "MemberOfEnum";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_REGISTER_PARAM :
|
|
szT = "RegisterParam";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_BIT_FIELD :
|
|
szT = "BitField";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_BLOCK :
|
|
switch (Symbol->n_name[1]) {
|
|
case 'b' :
|
|
szT = "BeginBlock";
|
|
break;
|
|
|
|
case 'e' :
|
|
szT = "EndBlock";
|
|
break;
|
|
|
|
default :
|
|
szT = ".bb or.eb";
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_FUNCTION :
|
|
switch (Symbol->n_name[1]) {
|
|
case 'b' :
|
|
szT = "BeginFunction";
|
|
break;
|
|
|
|
case 'e' :
|
|
szT = "EndFunction";
|
|
break;
|
|
|
|
default :
|
|
szT = ".bf or.ef";
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_END_OF_STRUCT :
|
|
szT = "EndOfStruct";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_FILE :
|
|
szT = "Filename";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_SECTION :
|
|
szT = "Section";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_WEAK_EXTERNAL :
|
|
szT = "WeakExternal";
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_FAR_EXTERNAL :
|
|
szT = "Far External";
|
|
break;
|
|
|
|
default :
|
|
sprintf(szOut, "0x%hx ", Symbol->StorageClass);
|
|
szOut += strlen(szOut);
|
|
szT = "UNKNOWN SYMBOL CLASS";
|
|
break;
|
|
}
|
|
|
|
strcpy(szOut, szT);
|
|
}
|
|
|
|
|
|
void
|
|
DumpSymbolTableEntry (
|
|
PIMAGE_SYMBOL Symbol
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints a symbol table entry.
|
|
|
|
Arguments:
|
|
|
|
Symbol - Symbol table entry.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
char Buffer[256];
|
|
|
|
|
|
fprintf(InfoStream, "%08lX ", Symbol->Value);
|
|
|
|
Buffer[0] = '\0';
|
|
DumpSymbolInfo(Symbol, Buffer);
|
|
|
|
fprintf(InfoStream, "%-32s | ", Buffer );
|
|
|
|
DumpNamePsym(InfoStream, "%s\n", Symbol);
|
|
}
|
|
|
|
|
|
void
|
|
DumpAuxSymbolTableEntry (
|
|
PIMAGE_SYMBOL Symbol,
|
|
PIMAGE_AUX_SYMBOL AuxSymbol
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints a auxiliary symbol entry.
|
|
|
|
Arguments:
|
|
|
|
Symbol - Symbol entry.
|
|
|
|
AuxSymbol - Auxiliary symbol entry.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
SHORT i;
|
|
const BYTE *ae;
|
|
|
|
fputs(" ", InfoStream);
|
|
|
|
switch (Symbol->StorageClass) {
|
|
case IMAGE_SYM_CLASS_EXTERNAL :
|
|
DoFunction:
|
|
fprintf(InfoStream, "tag index %08lX size %08lX lines %08lX next function %08lX\n",
|
|
AuxSymbol->Sym.TagIndex,
|
|
AuxSymbol->Sym.Misc.TotalSize,
|
|
AuxSymbol->Sym.FcnAry.Function.PointerToLinenumber,
|
|
AuxSymbol->Sym.FcnAry.Function.PointerToNextFunction);
|
|
return;
|
|
|
|
case IMAGE_SYM_CLASS_WEAK_EXTERNAL :
|
|
fprintf(InfoStream, "Default index %8lX", AuxSymbol->Sym.TagIndex);
|
|
|
|
switch (AuxSymbol->Sym.Misc.TotalSize) {
|
|
case 1 :
|
|
fputs(" No library search\n", InfoStream);
|
|
break;
|
|
|
|
case 2 :
|
|
fputs(" library search\n", InfoStream);
|
|
break;
|
|
|
|
case 3 :
|
|
fputs(" Alias record\n", InfoStream);
|
|
break;
|
|
|
|
default :
|
|
fputs(" Unknown\n", InfoStream);
|
|
break;
|
|
}
|
|
return;
|
|
|
|
case IMAGE_SYM_CLASS_STATIC :
|
|
if (((Symbol->Value == 0) || (dft != dftObject)) &&
|
|
(Symbol->SectionNumber > 0) &&
|
|
(Symbol->Type == IMAGE_SYM_TYPE_NULL) &&
|
|
((*Symbol->n_name == '.') || (AuxSymbol->Section.Length != 0))) {
|
|
fprintf(InfoStream,
|
|
"Section length % 4lX, #relocs % 4hX, #linenums % 4hX",
|
|
AuxSymbol->Section.Length,
|
|
AuxSymbol->Section.NumberOfRelocations,
|
|
AuxSymbol->Section.NumberOfLinenumbers);
|
|
|
|
if (rgsh[Symbol->SectionNumber-1].Characteristics & IMAGE_SCN_LNK_COMDAT) {
|
|
const char *szSelection;
|
|
|
|
fprintf(InfoStream,
|
|
", checksum %8lX, selection % 4hX",
|
|
AuxSymbol->Section.CheckSum,
|
|
AuxSymbol->Section.Selection);
|
|
|
|
switch (AuxSymbol->Section.Selection) {
|
|
case IMAGE_COMDAT_SELECT_NODUPLICATES :
|
|
szSelection = "no duplicates";
|
|
break;
|
|
|
|
case IMAGE_COMDAT_SELECT_ANY :
|
|
szSelection = "any";
|
|
break;
|
|
|
|
case IMAGE_COMDAT_SELECT_SAME_SIZE :
|
|
szSelection = "same size";
|
|
break;
|
|
|
|
case IMAGE_COMDAT_SELECT_EXACT_MATCH :
|
|
szSelection = "exact match";
|
|
break;
|
|
|
|
case IMAGE_COMDAT_SELECT_ASSOCIATIVE :
|
|
szSelection = "associative";
|
|
break;
|
|
|
|
case IMAGE_COMDAT_SELECT_LARGEST :
|
|
szSelection = "largest";
|
|
break;
|
|
|
|
case IMAGE_COMDAT_SELECT_NEWEST :
|
|
szSelection = "newest";
|
|
break;
|
|
|
|
default :
|
|
szSelection = "unknown";
|
|
break;
|
|
}
|
|
|
|
if (AuxSymbol->Section.Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
|
|
fprintf(InfoStream, " (pick %s Section %hx)", szSelection, AuxSymbol->Section.Number);
|
|
} else {
|
|
fprintf(InfoStream, " (pick %s)", szSelection);
|
|
}
|
|
}
|
|
|
|
fputc('\n', InfoStream);
|
|
return;
|
|
}
|
|
|
|
goto DoFunction;
|
|
|
|
case IMAGE_SYM_CLASS_FILE :
|
|
if (Symbol->StorageClass == IMAGE_SYM_CLASS_FILE) {
|
|
fprintf(InfoStream, "%-18.18s\n", AuxSymbol->File.Name);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case IMAGE_SYM_CLASS_STRUCT_TAG :
|
|
case IMAGE_SYM_CLASS_UNION_TAG :
|
|
case IMAGE_SYM_CLASS_ENUM_TAG :
|
|
fprintf(InfoStream, "tag index %08lX size %08lX\n",
|
|
AuxSymbol->Sym.TagIndex, AuxSymbol->Sym.Misc.TotalSize);
|
|
return;
|
|
|
|
case IMAGE_SYM_CLASS_END_OF_STRUCT :
|
|
fprintf(InfoStream, "tag index %08lX size %08lX\n",
|
|
AuxSymbol->Sym.TagIndex, AuxSymbol->Sym.Misc.TotalSize);
|
|
return;
|
|
|
|
case IMAGE_SYM_CLASS_BLOCK :
|
|
case IMAGE_SYM_CLASS_FUNCTION :
|
|
fprintf(InfoStream, "line# %04hx", AuxSymbol->Sym.Misc.LnSz.Linenumber);
|
|
if (!strncmp((char*)Symbol->n_name, ".b", 2)) {
|
|
fprintf(InfoStream, " end %08lX", AuxSymbol->Sym.FcnAry.Function.PointerToNextFunction);
|
|
}
|
|
fputc('\n', InfoStream);
|
|
return;
|
|
}
|
|
|
|
if (ISARY(Symbol->Type)) {
|
|
fputs("Array Bounds ", InfoStream);
|
|
for (i = 0; i < 4; i++) {
|
|
if (AuxSymbol->Sym.FcnAry.Array.Dimension[i]) {
|
|
fprintf(InfoStream, "[%04X]", AuxSymbol->Sym.FcnAry.Array.Dimension[i]);
|
|
|
|
}
|
|
}
|
|
fputc('\n', InfoStream);
|
|
return;
|
|
}
|
|
|
|
ae = (BYTE *) AuxSymbol;
|
|
for (i = 1; i <= sizeof(IMAGE_AUX_SYMBOL); i++) {
|
|
fprintf(InfoStream, "%1X", (*ae >> 4) & 0xf);
|
|
fprintf(InfoStream, "%1X ", *ae & 0xf);
|
|
ae++;
|
|
}
|
|
fputc('\n', InfoStream);
|
|
}
|
|
|
|
|
|
void
|
|
DumpCoffSymbols(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads and prints each symbol table entry.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIMAGE_SYMBOL NextSymbol;
|
|
DWORD i;
|
|
|
|
InternalError.Phase = "DumpCoffSymbols";
|
|
|
|
if ((Switch.Dump.SymbolType & IMAGE_DEBUG_TYPE_COFF) == 0) {
|
|
return;
|
|
}
|
|
|
|
if ((ImageFileHdr.PointerToSymbolTable == 0) ||
|
|
(ImageFileHdr.NumberOfSymbols == 0)) {
|
|
|
|
return;
|
|
}
|
|
|
|
assert(rgsym != NULL);
|
|
|
|
fputs("\nCOFF SYMBOL TABLE\n", InfoStream);
|
|
|
|
NextSymbol = rgsym;
|
|
i = 0;
|
|
while (i < ImageFileHdr.NumberOfSymbols) {
|
|
PIMAGE_SYMBOL Symbol;
|
|
BYTE NumberOfAuxSymbols;
|
|
|
|
Symbol = NextSymbol++;
|
|
|
|
fprintf(InfoStream, "%03lX ", i++);
|
|
|
|
DumpSymbolTableEntry(Symbol);
|
|
|
|
NumberOfAuxSymbols = Symbol->NumberOfAuxSymbols;
|
|
|
|
if (NumberOfAuxSymbols != 0) {
|
|
if (!strncmp((char *) Symbol->N.ShortName, ".file", 5)) {
|
|
fprintf(InfoStream, " %s\n", (char *) NextSymbol);
|
|
|
|
NextSymbol += NumberOfAuxSymbols;
|
|
} else {
|
|
WORD j;
|
|
|
|
for (j = 0; j < NumberOfAuxSymbols; j++) {
|
|
DumpAuxSymbolTableEntry(Symbol, (PIMAGE_AUX_SYMBOL) NextSymbol++);
|
|
}
|
|
}
|
|
|
|
i += NumberOfAuxSymbols;
|
|
}
|
|
}
|
|
|
|
fprintf(InfoStream, "\nString Table Size = 0x%lX bytes\n", blkStringTable.cb);
|
|
}
|
|
|
|
|
|
void
|
|
DumpObject (
|
|
const char *OriginalFilename,
|
|
BOOL fArchive
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens, prints, closes file.
|
|
|
|
Arguments:
|
|
|
|
OriginalFilename - Name of object or archive to dump.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DumpHeaders(fArchive);
|
|
|
|
if ((ImageFileHdr.PointerToSymbolTable != 0) &&
|
|
(ImageFileHdr.NumberOfSymbols != 0))
|
|
{
|
|
InternalError.Phase = "ReadStringTable";
|
|
LoadStrings(OriginalFilename);
|
|
|
|
InternalError.Phase = "ReadSymbolTable";
|
|
rgsym = ReadSymbolTable(MemberSeekBase +
|
|
ImageFileHdr.PointerToSymbolTable,
|
|
ImageFileHdr.NumberOfSymbols, FALSE);
|
|
assert(rgsym != NULL);
|
|
} else {
|
|
rgsym = NULL;
|
|
}
|
|
|
|
DumpSections();
|
|
|
|
if (Switch.Dump.SymbolMap || Switch.Dump.Symbols || Switch.Dump.FpoData) {
|
|
if (Switch.Dump.SymbolMap) {
|
|
DumpSymbolMap();
|
|
}
|
|
|
|
if (Switch.Dump.Symbols) {
|
|
DumpCoffSymbols();
|
|
}
|
|
}
|
|
|
|
|
|
// Cleanup.
|
|
|
|
if (rgsym != NULL) {
|
|
FreeSymbolTable(rgsym);
|
|
rgsym = NULL;
|
|
}
|
|
|
|
if (rgsh) {
|
|
FreePv(rgsh);
|
|
|
|
rgsh = NULL;
|
|
}
|
|
|
|
if (fDumpStringsLoaded) {
|
|
FreeStringTable((char *) DumpStringTable);
|
|
fDumpStringsLoaded = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DumpMemberHeader (
|
|
PLIB plib,
|
|
IMAGE_ARCHIVE_MEMBER_HEADER ArchiveMemberHdr,
|
|
DWORD FilePtr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints a member header.
|
|
|
|
Arguments:
|
|
|
|
plib - library node in driver map
|
|
|
|
ArchiveMemberHdr - The member header to print.
|
|
|
|
FilePtr - File pointer where member header was read from.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
SHORT uid, gid, mode;
|
|
DWORD membersize;
|
|
time_t timdat;
|
|
const char *time;
|
|
const char *name;
|
|
|
|
InternalError.Phase = "DumpMemberHeader";
|
|
|
|
// Convert all fields from machine independent integers.
|
|
|
|
// UNDONE: Validate all fields. uid and gid may be all spaces
|
|
|
|
sscanf((char *) ArchiveMemberHdr.Date, "%ld", &timdat);
|
|
sscanf((char *) ArchiveMemberHdr.Mode, "%ho", &mode);
|
|
sscanf((char *) ArchiveMemberHdr.Size, "%ld", &membersize);
|
|
|
|
fprintf(InfoStream, "\nArchive member name at %lX: %.16s", FilePtr, ArchiveMemberHdr.Name);
|
|
|
|
if (plib && ArchiveMemberHdr.Name[0] == '/') {
|
|
name = ExpandMemberName(plib, (char *) ArchiveMemberHdr.Name);
|
|
if (!name) {
|
|
name = "member corrupt";
|
|
}
|
|
fputs(name, InfoStream);
|
|
}
|
|
|
|
fputc('\n', InfoStream);
|
|
|
|
fprintf(InfoStream, "%8lX time/date", timdat);
|
|
if ((time = ctime(&timdat)) != NULL) {
|
|
fprintf(InfoStream, " %s", time);
|
|
} else {
|
|
fputc('\n', InfoStream);
|
|
}
|
|
|
|
if (memcmp(ArchiveMemberHdr.UserID, " ", 6) == 0) {
|
|
fputs(" ", InfoStream);
|
|
} else {
|
|
sscanf((char *) ArchiveMemberHdr.UserID, "%hd", &uid);
|
|
fprintf(InfoStream, "%8hX", uid);
|
|
}
|
|
fputs(" uid\n", InfoStream);
|
|
|
|
if (memcmp(ArchiveMemberHdr.GroupID, " ", 6) == 0) {
|
|
fputs(" ", InfoStream);
|
|
} else {
|
|
sscanf((char *) ArchiveMemberHdr.GroupID, "%hd", &gid);
|
|
fprintf(InfoStream, "%8hX", gid);
|
|
}
|
|
fputs(" gid\n", InfoStream);
|
|
|
|
fprintf(InfoStream, "%8ho mode\n%8lX size\n", mode, membersize);
|
|
|
|
if (memcmp(ArchiveMemberHdr.EndHeader, IMAGE_ARCHIVE_END, 2)) {
|
|
fputs("in", InfoStream);
|
|
}
|
|
|
|
fputs("correct header end\n", InfoStream);
|
|
}
|
|
|
|
void
|
|
DumpSpecialLinkerInterfaceMembers(
|
|
PLIB plib
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads the linker interface member out of an archive file, and adds
|
|
its extern symbols to the archive list. A linker member must exist in an
|
|
archive file, or the archive file will not be searched for undefined
|
|
externals. A warning is given if no linker member exits. The optional
|
|
header from the first member is read to determine what machine and
|
|
subsystem the library is targeted for.
|
|
|
|
An achive file may contain 2 linker members. The first would be that
|
|
of standard coff. The offsets are sorted, the strings aren't. The
|
|
second linker member is a slightly different format, and is sorted
|
|
by symbol names. If the second linker member is present, it will be
|
|
used for symbol lookup since it is faster.
|
|
|
|
The members long file name table is also read if it exits.
|
|
|
|
Arguments:
|
|
|
|
plib - library node for the driver map to be updated
|
|
|
|
usDumpMode - 1 - dump the first linker member header and public symbols
|
|
- 2 - dump the second linker member header and public symbol
|
|
- 3 - dump both linker member headers and public symbols
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIMAGE_ARCHIVE_MEMBER_HEADER pImArcMemHdr;
|
|
IMAGE_ARCHIVE_MEMBER_HEADER ImArcMemHdrPos;
|
|
BYTE *pbST;
|
|
BYTE *pb;
|
|
DWORD csymIntMem;
|
|
DWORD cMemberOffsets;
|
|
DWORD foNewMem;
|
|
DWORD cbST;
|
|
DWORD isym;
|
|
|
|
InternalError.Phase = "DumpSpecialLinkerInterfaceMembers";
|
|
|
|
MemberSeekBase = IMAGE_ARCHIVE_START_SIZE;
|
|
MemberSize = 0;
|
|
|
|
// Read member and verify it is a linker member.
|
|
pImArcMemHdr = ReadArchiveMemberHeader();
|
|
|
|
if (memcmp(pImArcMemHdr->Name, IMAGE_ARCHIVE_LINKER_MEMBER, 16)) {
|
|
if (Tool != Librarian) {
|
|
Warning(plib->szName, NOLINKERMEMBER);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (Switch.Dump.LinkerMember & 1) {
|
|
DumpMemberHeader(NULL, *pImArcMemHdr, IMAGE_ARCHIVE_START_SIZE);
|
|
}
|
|
|
|
// Read the number of public symbols defined in linker member.
|
|
|
|
FileRead(FileReadHandle, &csymIntMem, sizeof(DWORD));
|
|
|
|
// All fields in member headers are stored machine independent
|
|
// integers (4 bytes). Convert numbers to current machine long word.
|
|
|
|
csymIntMem = plib->csymIntMem = sgetl(&csymIntMem);
|
|
|
|
// Create space to store linker member offsets and read it in.
|
|
|
|
plib->rgulSymMemOff = (DWORD *) PvAlloc((size_t) (csymIntMem + 1) * sizeof(DWORD));
|
|
|
|
FileRead(FileReadHandle, plib->rgulSymMemOff, csymIntMem * sizeof(DWORD));
|
|
|
|
// Calculate size of linker member string table. The string table is
|
|
// the last part of a linker member and follows the offsets (which
|
|
// were just read in), thus the total size of the strings is the
|
|
// total size of the member minus the current position of the file
|
|
// pointer.
|
|
|
|
cbST = IMAGE_ARCHIVE_START_SIZE + sizeof(IMAGE_ARCHIVE_MEMBER_HEADER) +
|
|
(MemberSize - FileTell(FileReadHandle));
|
|
|
|
// Now that we know the size of the linker member string table, lets
|
|
// make space for it and read it in.
|
|
|
|
plib->rgbST = (BYTE *) PvAlloc((size_t) cbST);
|
|
|
|
FileRead(FileReadHandle, plib->rgbST, cbST);
|
|
|
|
if (Switch.Dump.LinkerMember & 1) {
|
|
printf("\n %lu public symbols\n\n", plib->csymIntMem);
|
|
pb = plib->rgbST;
|
|
|
|
for (isym = 0; isym < plib->csymIntMem; isym++) {
|
|
printf(" %8lX ", sgetl((DWORD *) &plib->rgulSymMemOff[isym]));
|
|
pb += printf("%s\n", pb);
|
|
}
|
|
}
|
|
|
|
// Peek ahead and see if there is a second linker member.
|
|
// Remember member headers always start on an even byte.
|
|
|
|
foNewMem = EvenByteAlign(MemberSeekBase + MemberSize);
|
|
FileSeek(FileReadHandle, foNewMem, SEEK_SET);
|
|
FileRead(FileReadHandle, &ImArcMemHdrPos, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
|
|
|
|
if (!memcmp(ImArcMemHdrPos.Name, IMAGE_ARCHIVE_LINKER_MEMBER, 16)) {
|
|
// Second linker member was found so read it.
|
|
|
|
pImArcMemHdr = ReadArchiveMemberHeader();
|
|
|
|
if (Switch.Dump.LinkerMember & 2) {
|
|
DumpMemberHeader(NULL, *pImArcMemHdr, foNewMem);
|
|
}
|
|
|
|
plib->flags |= LIB_NewIntMem;
|
|
|
|
// Free offsets for first linker member and malloc new offsets
|
|
// for the second linker member. Can't store new offsets over
|
|
// the old offsets because even though the second linker
|
|
// member offsets are unique and are not repeated like they are
|
|
// for the first linker member, you can't assume there will
|
|
// never be more offsets in the second linker member that there
|
|
// are in the first. This wouldn't be true if there were four
|
|
// members, the first and last members each had a public symbol,
|
|
// but the second and third had no public symbols. Of course there
|
|
// is no way the linker would extract the second and third members,
|
|
// but it would still be a valid library.
|
|
|
|
FreePv(plib->rgulSymMemOff);
|
|
|
|
FileRead(FileReadHandle, &cMemberOffsets, sizeof(DWORD));
|
|
|
|
plib->rgulSymMemOff = (DWORD *) PvAlloc((size_t) (cMemberOffsets + 1) * sizeof(DWORD));
|
|
|
|
FileRead(FileReadHandle, &plib->rgulSymMemOff[1], cMemberOffsets * sizeof(DWORD));
|
|
|
|
// Unlike the first linker member, the second linker member has an
|
|
// additional table. This table is used to index into the offset table.
|
|
// So make space for the offset index table and read it in.
|
|
|
|
FileRead(FileReadHandle, &csymIntMem, sizeof(DWORD));
|
|
|
|
plib->rgusOffIndex = (WORD *) PvAlloc((size_t) csymIntMem * sizeof(WORD));
|
|
|
|
FileRead(FileReadHandle, plib->rgusOffIndex, csymIntMem * sizeof(WORD));
|
|
|
|
// Read the sorted string table over the top of the string table stored
|
|
// for the first linker member. Unlike the first linker member, strings
|
|
// aren't repeated, thus the table will never be larger than that of
|
|
// the first linker member.
|
|
|
|
cbST = MemberSize - (FileTell(FileReadHandle) - (foNewMem + sizeof(IMAGE_ARCHIVE_MEMBER_HEADER)));
|
|
|
|
FileRead(FileReadHandle, plib->rgbST, cbST);
|
|
|
|
if (Switch.Dump.LinkerMember & 2) {
|
|
printf("\n %lu offsets\n\n", cMemberOffsets);
|
|
for (isym = 1; isym <= cMemberOffsets; isym++) {
|
|
printf(" %8lX %8lX\n", isym, plib->rgulSymMemOff[isym]);
|
|
}
|
|
|
|
printf("\n %lu public symbols\n\n", plib->csymIntMem);
|
|
pb = plib->rgbST;
|
|
|
|
for (isym = 0; isym < plib->csymIntMem; isym++) {
|
|
printf(" %8hX ", plib->rgusOffIndex[isym]);
|
|
pb += printf("%s\n", pb);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Since we are going to use an index to reference into the
|
|
// offset table, we will make a string table, in which the
|
|
// same index can be used to find the symbol name or visa versa.
|
|
|
|
plib->rgszSym = (char **) PvAlloc((size_t) plib->csymIntMem * sizeof(char *));
|
|
|
|
for (isym = 0, pbST = plib->rgbST; isym < plib->csymIntMem; isym++) {
|
|
plib->rgszSym[isym] = (char *) pbST;
|
|
while (*pbST++) {
|
|
}
|
|
}
|
|
|
|
// Read the member long file name table if it exits.
|
|
// Peek ahead and see if there is a long filename table.
|
|
// Remember member headers always start on an even byte.
|
|
|
|
foNewMem = EvenByteAlign(MemberSeekBase + MemberSize);
|
|
FileSeek(FileReadHandle, foNewMem, SEEK_SET);
|
|
FileRead(FileReadHandle, &ImArcMemHdrPos, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
|
|
|
|
if (!memcmp(ImArcMemHdrPos.Name, IMAGE_ARCHIVE_LONGNAMES_MEMBER, 16)) {
|
|
// Long filename table was found so read it.
|
|
|
|
pImArcMemHdr = ReadArchiveMemberHeader();
|
|
|
|
if (Switch.Dump.LinkerMember & 2) {
|
|
DumpMemberHeader(NULL, *pImArcMemHdr, foNewMem);
|
|
}
|
|
|
|
// Read the strings.
|
|
|
|
pbST = (BYTE *) PvAlloc((size_t) MemberSize);
|
|
|
|
FileRead(FileReadHandle, pbST, MemberSize);
|
|
|
|
plib->rgbLongFileNames = pbST;
|
|
} else {
|
|
plib->rgbLongFileNames = NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
DumpArchive (
|
|
const char *OriginalFilename
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens, prints, closes file.
|
|
|
|
Arguments:
|
|
|
|
OriginalFilename - Name of object or archive to dump.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIB plib;
|
|
|
|
InternalError.Phase = "DumpArchive";
|
|
|
|
fputs("\nFile Type: LIBRARY\n", InfoStream);
|
|
|
|
ImageFileHdr.Machine = 0; // don't want to verify target
|
|
|
|
plib = PlibNew(OriginalFilename, 0, &pimageDump->libs);
|
|
|
|
DumpSpecialLinkerInterfaceMembers(plib);
|
|
|
|
do {
|
|
PIMAGE_ARCHIVE_MEMBER_HEADER archive_member;
|
|
|
|
archive_member = ReadArchiveMemberHeader();
|
|
|
|
if (Switch.Dump.ArchiveMembers) {
|
|
DumpMemberHeader(plib, *archive_member, FileTell(FileReadHandle)-sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
|
|
}
|
|
|
|
ReadFileHeader(FileReadHandle, &ImageFileHdr);
|
|
if (FValidFileHdr(OriginalFilename, &ImageFileHdr)) {
|
|
DumpObject(OriginalFilename, TRUE);
|
|
}
|
|
} while (MemberSeekBase+MemberSize+1 < FileLen);
|
|
}
|
|
|
|
|
|
void
|
|
LoadCoffSymbolTable (
|
|
DWORD coffSymbolTableOffset,
|
|
const char * Filename
|
|
)
|
|
{
|
|
IMAGE_COFF_SYMBOLS_HEADER debugInfo;
|
|
|
|
if (coffSymbolTableOffset) {
|
|
FileSeek(FileReadHandle, coffSymbolTableOffset, SEEK_SET);
|
|
FileRead(FileReadHandle, &debugInfo, sizeof(debugInfo));
|
|
|
|
ImageFileHdr.NumberOfSymbols = debugInfo.NumberOfSymbols;
|
|
ImageFileHdr.PointerToSymbolTable = coffSymbolTableOffset + debugInfo.LvaToFirstSymbol;
|
|
|
|
LoadStrings(Filename);
|
|
|
|
InternalError.Phase = "ReadSymbolTable";
|
|
|
|
rgsym = ReadSymbolTable(MemberSeekBase +
|
|
ImageFileHdr.PointerToSymbolTable,
|
|
ImageFileHdr.NumberOfSymbols, FALSE);
|
|
}
|
|
}
|
|
|
|
void
|
|
DumpDebugFile (
|
|
const char *Filename
|
|
)
|
|
{
|
|
IMAGE_SEPARATE_DEBUG_HEADER dbgHeader;
|
|
int numDebugDirs;
|
|
const char *s;
|
|
WORD i;
|
|
DWORD cbCoffHeader;
|
|
DWORD foCoffHeader = 0;
|
|
DWORD cbFunctionTable = 0;
|
|
DWORD foFunctionTable;
|
|
DWORD cbFpoData = 0;
|
|
DWORD foFpoData;
|
|
DWORD cbFixups = 0;
|
|
DWORD foFixups;
|
|
DWORD cbOmapTo = 0;
|
|
DWORD foOmapTo;
|
|
DWORD cbOmapFrom = 0;
|
|
DWORD foOmapFrom;
|
|
|
|
InternalError.Phase = "DumpDebugFile";
|
|
|
|
FileRead(FileReadHandle, &dbgHeader, sizeof(dbgHeader));
|
|
|
|
rgsh = (PIMAGE_SECTION_HEADER) PvAlloc(dbgHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
|
|
|
|
FileRead(FileReadHandle, rgsh, dbgHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER));
|
|
|
|
if (Switch.Dump.Headers) {
|
|
switch (dbgHeader.Machine) {
|
|
case IMAGE_FILE_MACHINE_I386 : i = 1; break;
|
|
case IMAGE_FILE_MACHINE_R3000 : i = 2; break;
|
|
case IMAGE_FILE_MACHINE_R4000 : i = 3; break;
|
|
case IMAGE_FILE_MACHINE_ALPHA : i = 4; break;
|
|
case IMAGE_FILE_MACHINE_POWERPC : i = 5; break;
|
|
case 0x0290 : i = 6; break; // UNDONE: IMAGE_FILE_MACHINE_PARISC
|
|
case IMAGE_FILE_MACHINE_M68K : i = 7; break;
|
|
case IMAGE_FILE_MACHINE_MPPC_601 : i = 8; break;
|
|
case IMAGE_FILE_MACHINE_R10000 : i = 9; break;
|
|
default : i = 0;
|
|
}
|
|
|
|
fprintf(InfoStream, "%8hX signature\n", dbgHeader.Signature);
|
|
fprintf(InfoStream, "%8hX flags\n", dbgHeader.Flags);
|
|
fprintf(InfoStream, "%8hX machine (%s)\n", dbgHeader.Machine, MachineName[i]);
|
|
fprintf(InfoStream, "%8hX characteristics\n", dbgHeader.Characteristics);
|
|
fprintf(InfoStream, "%8lX time date stamp", dbgHeader.TimeDateStamp);
|
|
if (dbgHeader.TimeDateStamp &&
|
|
((s = ctime((time_t *) &dbgHeader.TimeDateStamp)) != NULL)) {
|
|
fprintf(InfoStream, " %s", s);
|
|
} else {
|
|
fputc('\n', InfoStream);
|
|
}
|
|
fprintf(InfoStream, "%8X checksum of image\n", dbgHeader.CheckSum);
|
|
fprintf(InfoStream, "%8X base of image\n", dbgHeader.ImageBase);
|
|
fprintf(InfoStream, "%8X size of image\n", dbgHeader.SizeOfImage);
|
|
fprintf(InfoStream, "%8X number of sections\n", dbgHeader.NumberOfSections);
|
|
if (dbgHeader.ExportedNamesSize) {
|
|
fprintf(InfoStream, "%8X size of exported names table\n", dbgHeader.ExportedNamesSize);
|
|
}
|
|
fprintf(InfoStream, "%8X size of debug directories\n", dbgHeader.DebugDirectorySize);
|
|
|
|
for (i = 1; i <= dbgHeader.NumberOfSections; i++) {
|
|
DumpSectionHeader(i, &rgsh[i-1]);
|
|
}
|
|
}
|
|
|
|
if (dbgHeader.ExportedNamesSize) {
|
|
char *exportedNames;
|
|
|
|
exportedNames = (char *) PvAlloc(dbgHeader.ExportedNamesSize);
|
|
|
|
FileRead(FileReadHandle, exportedNames, dbgHeader.ExportedNamesSize);
|
|
|
|
if (Switch.Dump.Exports) {
|
|
fprintf(InfoStream, "\nExported Names: %8lX bytes\n", dbgHeader.ExportedNamesSize);
|
|
|
|
s = exportedNames;
|
|
|
|
while (*s) {
|
|
fprintf(InfoStream, "\t%s\n", s);
|
|
|
|
while (*s++) {
|
|
}
|
|
}
|
|
}
|
|
|
|
FreePv(exportedNames);
|
|
}
|
|
|
|
numDebugDirs = dbgHeader.DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY);
|
|
if (Switch.Dump.Headers) {
|
|
fprintf(InfoStream, "\n"
|
|
"\n"
|
|
"Debug Directories(%d)\n"
|
|
" Type Size Address Pointer\n"
|
|
"\n",
|
|
numDebugDirs);
|
|
}
|
|
|
|
while (numDebugDirs--) {
|
|
IMAGE_DEBUG_DIRECTORY debugDir;
|
|
|
|
FileRead(FileReadHandle, &debugDir, sizeof(debugDir));
|
|
|
|
if (Switch.Dump.Headers) {
|
|
DumpDebugDirectory(&debugDir);
|
|
}
|
|
|
|
switch (debugDir.Type) {
|
|
case IMAGE_DEBUG_TYPE_COFF :
|
|
cbCoffHeader = debugDir.SizeOfData;
|
|
foCoffHeader = debugDir.PointerToRawData;
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_FPO :
|
|
cbFpoData = debugDir.SizeOfData;
|
|
foFpoData = debugDir.PointerToRawData;
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_EXCEPTION :
|
|
cbFunctionTable = debugDir.SizeOfData;
|
|
foFunctionTable = debugDir.PointerToRawData;
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_FIXUP :
|
|
cbFixups = debugDir.SizeOfData;
|
|
foFixups = debugDir.PointerToRawData;
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_OMAP_TO_SRC :
|
|
cbOmapTo = debugDir.SizeOfData;
|
|
foOmapTo = debugDir.PointerToRawData;
|
|
break;
|
|
|
|
case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC :
|
|
cbOmapFrom = debugDir.SizeOfData;
|
|
foOmapFrom = debugDir.PointerToRawData;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Switch.Dump.Symbols || Switch.Dump.SymbolMap) {
|
|
if (Switch.Dump.SymbolType & IMAGE_DEBUG_TYPE_COFF) {
|
|
LoadCoffSymbolTable(foCoffHeader, Filename);
|
|
|
|
if (Switch.Dump.SymbolMap) {
|
|
DumpSymbolMap();
|
|
} else {
|
|
DumpCoffSymbols();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Switch.Dump.PData && cbFunctionTable) {
|
|
LoadCoffSymbolTable(foCoffHeader, Filename);
|
|
DumpDbgFunctionTable(foFunctionTable, cbFunctionTable);
|
|
}
|
|
|
|
if (Switch.Dump.OmapTo && cbOmapTo) {
|
|
LoadCoffSymbolTable(foCoffHeader, Filename);
|
|
DumpOmap(foOmapTo, cbOmapTo, TRUE);
|
|
}
|
|
|
|
if (Switch.Dump.OmapFrom && cbOmapFrom) {
|
|
LoadCoffSymbolTable(foCoffHeader, Filename);
|
|
DumpOmap(foOmapFrom, cbOmapFrom, FALSE);
|
|
}
|
|
|
|
if (Switch.Dump.Fixup && cbFixups) {
|
|
LoadCoffSymbolTable(foCoffHeader, Filename);
|
|
DumpFixup(foFixups, cbFixups);
|
|
}
|
|
|
|
if (Switch.Dump.FpoData && cbFpoData) {
|
|
LoadCoffSymbolTable(foCoffHeader, Filename);
|
|
DumpFpoData(foFpoData, cbFpoData);
|
|
}
|
|
|
|
if (rgsym) {
|
|
FreeSymbolTable(rgsym);
|
|
rgsym = NULL;
|
|
}
|
|
|
|
if (fDumpStringsLoaded) {
|
|
FreeStringTable((char *) DumpStringTable);
|
|
fDumpStringsLoaded = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DumpPeFile(
|
|
const char *szFilename
|
|
)
|
|
{
|
|
if (Switch.Dump.Headers) {
|
|
fputs("\nPE signature found\n", InfoStream);
|
|
}
|
|
|
|
CoffHeaderSeek = FileTell(FileReadHandle);
|
|
|
|
ReadFileHeader(FileReadHandle, &ImageFileHdr);
|
|
if (!FValidFileHdr(szFilename, &ImageFileHdr)) {
|
|
return;
|
|
}
|
|
|
|
DumpHeaders(FALSE);
|
|
|
|
if ((ImageFileHdr.PointerToSymbolTable != 0) &&
|
|
(ImageFileHdr.NumberOfSymbols != 0)) {
|
|
InternalError.Phase = "ReadStringTable";
|
|
LoadStrings(szFilename);
|
|
|
|
InternalError.Phase = "ReadSymbolTable";
|
|
rgsym = ReadSymbolTable(MemberSeekBase +
|
|
ImageFileHdr.PointerToSymbolTable,
|
|
ImageFileHdr.NumberOfSymbols, FALSE);
|
|
assert(rgsym != NULL);
|
|
} else {
|
|
rgsym = NULL;
|
|
}
|
|
|
|
DumpSections();
|
|
|
|
if (Switch.Dump.SymbolMap || Switch.Dump.Symbols || Switch.Dump.FpoData) {
|
|
if (Switch.Dump.SymbolMap) {
|
|
DumpSymbolMap();
|
|
}
|
|
if (Switch.Dump.Symbols) {
|
|
DumpCoffSymbols();
|
|
}
|
|
}
|
|
|
|
if (rgsym) {
|
|
FreeSymbolTable(rgsym);
|
|
rgsym = NULL;
|
|
}
|
|
|
|
if (fDumpStringsLoaded) {
|
|
FreeStringTable((char *) DumpStringTable);
|
|
fDumpStringsLoaded = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DumpDosFile(
|
|
const char *szFilename
|
|
)
|
|
{
|
|
Warning(NULL, NODOSDUMP, szFilename);
|
|
}
|
|
|
|
|
|
void
|
|
DumpFile(
|
|
const char *szFilename
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens, prints, closes file.
|
|
|
|
Arguments:
|
|
|
|
szFilename - Name of object or archive to dump.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
fprintf((Switch.Dump.SymbolMap ? stderr : InfoStream),
|
|
"\nDump of file %s\n", szFilename);
|
|
|
|
MemberSeekBase = MemberSize = 0; // Stays zero unless dumping archive file
|
|
|
|
FileReadHandle = FileOpen(szFilename, O_RDONLY | O_BINARY, 0);
|
|
FileLen = FileLength(FileReadHandle);
|
|
|
|
if (IsArchiveFile(szFilename, FileReadHandle)) {
|
|
DumpArchive(szFilename);
|
|
} else {
|
|
WORD wMagic;
|
|
|
|
FileSeek(FileReadHandle, 0L, SEEK_SET);
|
|
FileRead(FileReadHandle, &wMagic, sizeof(WORD));
|
|
|
|
FileSeek(FileReadHandle, 0L, SEEK_SET);
|
|
|
|
if (wMagic == IMAGE_SEPARATE_DEBUG_SIGNATURE) {
|
|
DumpDebugFile(szFilename);
|
|
} else if (wMagic == IMAGE_DOS_SIGNATURE) {
|
|
IMAGE_DOS_HEADER DosHeader;
|
|
DWORD dwMagic;
|
|
|
|
if (FileLen < sizeof(IMAGE_DOS_HEADER)) {
|
|
// The file isn't large enough to contain a full DOS EXE header
|
|
|
|
goto DoObject;
|
|
}
|
|
|
|
FileRead(FileReadHandle, &DosHeader, sizeof(IMAGE_DOS_HEADER));
|
|
|
|
if (DosHeader.e_lfanew == 0) {
|
|
// There is no pointer to an new style header
|
|
|
|
goto DoDosFile;
|
|
}
|
|
|
|
if (DosHeader.e_lfanew + sizeof(DWORD) > FileLen) {
|
|
// The file isn't large enough to contain a new style header
|
|
|
|
goto DoDosFile;
|
|
}
|
|
|
|
FileSeek(FileReadHandle, DosHeader.e_lfanew, SEEK_SET);
|
|
FileRead(FileReadHandle, &dwMagic, sizeof(DWORD));
|
|
|
|
if (dwMagic == IMAGE_NT_SIGNATURE) {
|
|
DumpPeFile(szFilename);
|
|
} else if ((WORD) dwMagic == IMAGE_OS2_SIGNATURE) {
|
|
dft = dftNE;
|
|
|
|
DumpNeFile(szFilename);
|
|
} else if ((WORD) dwMagic == IMAGE_OS2_SIGNATURE_LE) {
|
|
dft = dftLE;
|
|
|
|
DumpLeFile(szFilename);
|
|
#ifdef DUMPLX
|
|
} else if ((WORD) dwMagic == 'XL') {
|
|
dft = dftLX;
|
|
|
|
DumpLeFile(szFilename);
|
|
#endif // DUMPLX
|
|
} else {
|
|
DoDosFile:
|
|
DumpDosFile(szFilename);
|
|
}
|
|
} else if (wMagic == 'oJ') {
|
|
PPC_FILE_HEADER pefhdr;
|
|
|
|
if (FileLen < sizeof(PPC_FILE_HEADER)) {
|
|
// The file isn't large enough to contain a full PEF header
|
|
|
|
goto DoObject;
|
|
}
|
|
|
|
FileRead(FileReadHandle, &pefhdr, sizeof(PPC_FILE_HEADER));
|
|
|
|
if ((pefhdr.magic2 != '!y') || (pefhdr.containerID != 'ffep')) {
|
|
// This file isn't a PEF format file
|
|
|
|
goto DoObject;
|
|
}
|
|
|
|
BYTE *pbFile = PbMappedRegion(FileReadHandle, 0, FileLen);
|
|
|
|
if (pbFile == NULL) {
|
|
// The PEF dump code requires mapped files
|
|
|
|
Fatal(NULL, CANTOPENFILE, szFilename);
|
|
}
|
|
|
|
dft = dftPEF;
|
|
|
|
DumpPefFile(pbFile);
|
|
} else {
|
|
DoObject:
|
|
CoffHeaderSeek = 0;
|
|
|
|
ReadFileHeader(FileReadHandle, &ImageFileHdr);
|
|
|
|
if (FValidFileHdr(szFilename, &ImageFileHdr)) {
|
|
DumpObject(szFilename, FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
FileClose(FileReadHandle, TRUE);
|
|
|
|
// If we read the linker member only to dump it, then free
|
|
// the space allocated to store the linker member information.
|
|
|
|
FreePLIB(&pimageDump->libs);
|
|
}
|
|
|
|
|
|
MainFunc
|
|
DumperMain(int Argc, char *Argv[])
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps an object or image in human readable form.
|
|
|
|
Arguments:
|
|
|
|
Argc - Standard C argument count.
|
|
|
|
Argv - Standard C argument strings.
|
|
|
|
Return Value:
|
|
|
|
0 Dump was successful.
|
|
!0 Dumper error index.
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD i;
|
|
PARGUMENT_LIST argument;
|
|
|
|
if (Argc < 2) {
|
|
DumperUsage();
|
|
}
|
|
|
|
InitImage(&pimageDump, imagetPE);
|
|
|
|
ParseCommandLine(Argc, Argv, NULL);
|
|
ProcessDumperSwitches();
|
|
|
|
if (fNeedBanner) {
|
|
PrintBanner();
|
|
}
|
|
|
|
if (fUserSpecInvalidSize) {
|
|
WORD numUnits;
|
|
|
|
numUnits = 4;
|
|
switch (Switch.Dump.RawDisplayType) {
|
|
case Bytes: numUnits <<= 1;
|
|
case Shorts: numUnits <<= 1;
|
|
case Longs: break;
|
|
}
|
|
|
|
Warning(NULL, DEFAULTUNITSPERLINE, numUnits);
|
|
}
|
|
|
|
for (i = 0, argument = FilenameArguments.First;
|
|
i < FilenameArguments.Count;
|
|
i++, argument = argument->Next) {
|
|
if (i != 0) {
|
|
fputc('\f', InfoStream);
|
|
}
|
|
|
|
DumpFile(argument->OriginalName);
|
|
}
|
|
|
|
if (Switch.Dump.Summary) {
|
|
ENM_SEC enm_sec;
|
|
|
|
fputs("\n Summary\n\n", InfoStream);
|
|
|
|
SortSectionListByName(&pimageDump->secs);
|
|
|
|
InitEnmSec(&enm_sec, &pimageDump->secs);
|
|
while (FNextEnmSec(&enm_sec)) {
|
|
PSEC psec;
|
|
|
|
psec = enm_sec.psec;
|
|
|
|
fprintf(InfoStream, " %8lX %s\n", psec->cbRawData, psec->szName);
|
|
}
|
|
EndEnmSec(&enm_sec);
|
|
}
|
|
|
|
fclose(InfoStream);
|
|
|
|
FileCloseAll();
|
|
RemoveConvertTempFiles();
|
|
|
|
return(0);
|
|
}
|