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.
1055 lines
31 KiB
1055 lines
31 KiB
/***********************************************************************
|
|
* Microsoft (R) 32-Bit Incremental Linker
|
|
*
|
|
* Copyright (C) Microsoft Corp 1992-1996. All rights reserved.
|
|
*
|
|
* File: dmppef.cpp
|
|
*
|
|
* File Comments:
|
|
*
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "link.h"
|
|
|
|
|
|
#define Switch (pimageDump->Switch)
|
|
|
|
#define MAX_INSTR_CACHED 16
|
|
#define _MAX_MAC_FNAME 64
|
|
|
|
static DWORD ichExportBegin = MAXDWORD;
|
|
|
|
STATIC
|
|
INT
|
|
PrintPefHeader(
|
|
const BYTE *pbFile
|
|
)
|
|
{
|
|
PPC_FILE_HEADER P;
|
|
|
|
memcpy(&P, pbFile, sizeof(PPC_FILE_HEADER));
|
|
|
|
SwapBytes(&P.magic1, 2);
|
|
SwapBytes(&P.magic2, 2);
|
|
SwapBytes(&P.containerID, 4);
|
|
SwapBytes(&P.architectureID, 4);
|
|
SwapBytes(&P.versionNumber, 4);
|
|
SwapBytes(&P.timestamp, 4);
|
|
SwapBytes(&P.oldDefVersion, 4);
|
|
SwapBytes(&P.oldImpVersion, 4);
|
|
SwapBytes(&P.currentVersion, 4);
|
|
SwapBytes(&P.nbrOfSections, 2);
|
|
SwapBytes(&P.loadableSections, 2);
|
|
SwapBytes(&P.memoryAddress, 4);
|
|
|
|
if (Switch.Dump.Headers) {
|
|
fprintf(InfoStream, "\n"
|
|
" Container Header\n"
|
|
"\n"
|
|
" magic1, magic2 = 0x%04X%04X\n"
|
|
" containerID = 0x%08lX\n"
|
|
" architectureID = 0x%08lX\n"
|
|
" versionNumber = 0x%08lX\n"
|
|
" timeStamp = 0x%08lX\n"
|
|
" oldDefVersion = %u\n"
|
|
" oldImpVersion = %u\n"
|
|
" currentVersion = %u\n"
|
|
" nbrOfSections = %u\n"
|
|
" loadableSections = %u\n"
|
|
" memoryAddress = 0x%08lX\n",
|
|
P.magic1,
|
|
P.magic2,
|
|
P.containerID,
|
|
P.architectureID,
|
|
P.versionNumber,
|
|
P.timestamp,
|
|
P.oldDefVersion,
|
|
P.oldImpVersion,
|
|
P.currentVersion,
|
|
P.nbrOfSections,
|
|
P.loadableSections,
|
|
P.memoryAddress);
|
|
}
|
|
|
|
return(P.nbrOfSections);
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
PrintLoaderHeader(
|
|
const LOADER_HEADER *ploaderHdr
|
|
)
|
|
{
|
|
fprintf(InfoStream, "\n"
|
|
" Loader Header\n"
|
|
"\n"
|
|
" entryPointSection = %d\n"
|
|
" entryPointOffset = %08lX\n"
|
|
" initPointSection = %d\n"
|
|
" initPointOffset = %08lX\n"
|
|
" termPointSection = %d\n"
|
|
" termPointOffset = %08lX\n"
|
|
" numImportFiles = %08lX\n"
|
|
" numImportSyms = %08lX\n"
|
|
" numSections = %d\n"
|
|
" relocationsOffset = %08lX\n"
|
|
" stringsOffset = %08lX\n"
|
|
" hashSlotTable = %08lX\n"
|
|
" hashSlotTabSize = %d (%d)\n"
|
|
" numExportedSyms = %08lX\n",
|
|
ploaderHdr->entryPointSectionNumber,
|
|
ploaderHdr->entryPointDescrOffset,
|
|
ploaderHdr->initRoutineSectionNumber,
|
|
ploaderHdr->initRoutineDescrOffset,
|
|
ploaderHdr->termRoutineSectionNumber,
|
|
ploaderHdr->termRoutineDescrOffset,
|
|
ploaderHdr->nImportIdTableEntries,
|
|
ploaderHdr->nImportSymTableEntries,
|
|
ploaderHdr->nSectionsWithRelocs,
|
|
ploaderHdr->relocTableOffset,
|
|
ploaderHdr->stringTableOffset,
|
|
ploaderHdr->hashSlotTableOffset,
|
|
ploaderHdr->hashSlotCount, 1 << ploaderHdr->hashSlotCount,
|
|
ploaderHdr->nExportedSymbols);
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
PrintImportContainers(
|
|
const LOADER_HEADER *ploaderHdr,
|
|
const CONTAINER_TABLE *containerPtr,
|
|
const char *rgchStringTable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
PrintImportContainers
|
|
|
|
Arguments:
|
|
loaderOffset includes filePtr
|
|
ploaderHdr
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD i;
|
|
|
|
if (ploaderHdr->nImportIdTableEntries == 0) {
|
|
return;
|
|
}
|
|
|
|
fprintf(InfoStream, "\n"
|
|
" Loader Import Container ID Table\n"
|
|
"\n");
|
|
|
|
for (i = 0; i < ploaderHdr->nImportIdTableEntries; i++) {
|
|
CONTAINER_TABLE container;
|
|
const char *szName;
|
|
|
|
container = *containerPtr;
|
|
|
|
DWORD ichName = DwSwap(container.nameOffset);
|
|
|
|
szName = rgchStringTable + ichName;
|
|
|
|
fprintf(InfoStream, " [%2u] containerName = 0x%08lX (%u) \"%s\"\n"
|
|
" oldImpVersion = %lu\n"
|
|
" currentVersion = %lu\n"
|
|
" nbrOfImports = %lu\n"
|
|
" firstImport = %lu\n"
|
|
" importFlags = 0x%02X\n"
|
|
" reserved = 0x%02X%02X%02X\n"
|
|
"\n",
|
|
i, ichName, ichName, szName,
|
|
DwSwap(container.oldImpVersion),
|
|
DwSwap(container.currentVersion),
|
|
DwSwap(container.nbrOfImports),
|
|
DwSwap(container.firstImport),
|
|
DwSwap(container.importFlags),
|
|
container.reserved[0],
|
|
container.reserved[1],
|
|
container.reserved[2]);
|
|
|
|
containerPtr++;
|
|
}
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
PrintImportTable(
|
|
const LOADER_HEADER *ploaderHdr,
|
|
const IMPORT_TABLE *importPtr,
|
|
const char *rgchStringTable
|
|
)
|
|
{
|
|
DWORD i;
|
|
|
|
if (ploaderHdr->nImportSymTableEntries == 0) {
|
|
return;
|
|
}
|
|
|
|
fprintf(InfoStream, " Loader Import Symbol Table\n"
|
|
"\n");
|
|
|
|
for (i = 0; i < ploaderHdr->nImportSymTableEntries; i++) {
|
|
union
|
|
{
|
|
DWORD l;
|
|
char c[4];
|
|
} x;
|
|
DWORD ichName;
|
|
BYTE symClass;
|
|
|
|
memcpy(&x, importPtr, sizeof(IMPORT_TABLE));
|
|
|
|
SwapBytes(&x, 4);
|
|
|
|
symClass = x.c[3];
|
|
|
|
const char *szClass;
|
|
|
|
switch (symClass) {
|
|
case 0 :
|
|
szClass = "Code ";
|
|
break;
|
|
|
|
case 1 :
|
|
szClass = "Data ";
|
|
break;
|
|
|
|
case 2 :
|
|
szClass = "TVector";
|
|
break;
|
|
|
|
case 3 :
|
|
szClass = "TOC ";
|
|
break;
|
|
|
|
case 4 :
|
|
szClass = "Glue ";
|
|
break;
|
|
|
|
default :
|
|
szClass = "Unknown";
|
|
break;
|
|
}
|
|
|
|
ichName = x.l & 0xFFFFFF;
|
|
|
|
const char *szName = rgchStringTable + ichName;
|
|
|
|
// UNDONE: Consider undecorating name
|
|
|
|
fprintf(InfoStream, " [%4lu] %02X %06X %s %s\n",
|
|
i,
|
|
symClass,
|
|
ichName,
|
|
szClass,
|
|
szName);
|
|
|
|
importPtr++;
|
|
}
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
PrintRelocHeaders(
|
|
const LOADER_HEADER *ploaderHdr,
|
|
const RELOCATION_HEADER *relocPtr
|
|
)
|
|
{
|
|
DWORD i;
|
|
|
|
if (ploaderHdr->nSectionsWithRelocs == 0) {
|
|
return;
|
|
}
|
|
|
|
fprintf(InfoStream, "\n"
|
|
" Loader Relocation Headers\n"
|
|
"\n");
|
|
|
|
for (i = 0; i < ploaderHdr->nSectionsWithRelocs; i++) {
|
|
fprintf(InfoStream, " sectionNumber = %u\n"
|
|
" reserved = 0x%04X\n"
|
|
" nbrOfRelocs = %u\n"
|
|
" firstRelocInstr = 0x%08lX (%u)\n",
|
|
WSwap(relocPtr->sectionNumber),
|
|
WSwap(relocPtr->reserved),
|
|
DwSwap(relocPtr->nbrOfRelocs),
|
|
DwSwap(relocPtr->firstRelocInstr), DwSwap(relocPtr->firstRelocInstr));
|
|
|
|
relocPtr++;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DumpPefRelocationInstructions(
|
|
const LOADER_HEADER *ploaderHdr,
|
|
const RELOCATION_HEADER *relocPtr
|
|
)
|
|
{
|
|
DWORD ib = 0;
|
|
DWORD i;
|
|
DWORD rgcbCache[MAX_INSTR_CACHED];
|
|
INT cacheIndex = 0;
|
|
|
|
assert(dft == dftPEF);
|
|
|
|
if (ploaderHdr->nSectionsWithRelocs == 0) {
|
|
return;
|
|
}
|
|
|
|
fprintf(InfoStream, "\n"
|
|
" Loader Relocation Instructions\n"
|
|
"\n");
|
|
|
|
const WORD *pwReloc = (WORD *) (relocPtr + ploaderHdr->nSectionsWithRelocs);
|
|
|
|
for (i = 0; i < ploaderHdr->nSectionsWithRelocs; i++, relocPtr++) {
|
|
RELOCATION_HEADER relocHdr;
|
|
DWORD j;
|
|
|
|
relocHdr = *relocPtr;
|
|
|
|
SwapBytes(&relocHdr.sectionNumber, 2);
|
|
SwapBytes(&relocHdr.nbrOfRelocs, 4);
|
|
SwapBytes(&relocHdr.firstRelocInstr, 4);
|
|
|
|
fprintf(InfoStream, " Relocations for Section %u\n\n", relocHdr.sectionNumber);
|
|
|
|
for (j = 0; j < relocHdr.nbrOfRelocs; j++) {
|
|
WORD wReloc;
|
|
INT relocType;
|
|
WORD wReloc2;
|
|
WORD subOp;
|
|
WORD subsubOp;
|
|
DWORD count;
|
|
DWORD cb;
|
|
INT words;
|
|
INT loop;
|
|
|
|
wReloc = WSwap(*pwReloc++);
|
|
|
|
if (wReloc >> 15) {
|
|
relocType = (wReloc >> (16 - 4));
|
|
} else if ((wReloc >> 14) == 0) {
|
|
relocType = (wReloc >> (16 - 2));
|
|
} else {
|
|
relocType = (wReloc >> (16 - 3));
|
|
}
|
|
|
|
switch (relocType) {
|
|
case 0 : // DDAT
|
|
words = (wReloc & ~0xC000) >> 6;
|
|
count = wReloc & 0x3F;
|
|
|
|
ib += words * 4;
|
|
rgcbCache[cacheIndex] = words * 4;
|
|
|
|
fprintf(InfoStream,
|
|
" (%08X) %04X DDAT delta=%u,n=%u\n",
|
|
ib, wReloc, words * 4, count);
|
|
|
|
ib += count * 4;
|
|
rgcbCache[cacheIndex] += count * 4;
|
|
break;
|
|
|
|
case 2 :
|
|
fprintf(InfoStream, " (%08X) %04X ", ib, wReloc);
|
|
|
|
subOp = (wReloc >> 9) & 0xF;
|
|
count = (wReloc & 0x1FF) + 1;
|
|
|
|
switch (subOp) {
|
|
case 0 :
|
|
fprintf(InfoStream, "CODE cnt=%u\n", count);
|
|
|
|
cb = count * sizeof(DWORD);
|
|
break;
|
|
|
|
case 1 :
|
|
fprintf(InfoStream, "DATA cnt=%u\n", count);
|
|
|
|
cb = count * sizeof(DWORD);
|
|
break;
|
|
|
|
case 2 :
|
|
fprintf(InfoStream, "DESC cnt=%u\n", count);
|
|
|
|
cb = count * 3 * sizeof(DWORD);
|
|
break;
|
|
|
|
case 3 :
|
|
fprintf(InfoStream, "DSC2 cnt=%u\n", count);
|
|
|
|
cb = count * 2 * sizeof(DWORD);
|
|
break;
|
|
|
|
case 4 :
|
|
fprintf(InfoStream, "VTBL cnt=%u\n", count);
|
|
|
|
cb = count * 2 * sizeof(DWORD);
|
|
break;
|
|
|
|
case 5 :
|
|
fprintf(InfoStream, "SYMR cnt=%u\n", count);
|
|
|
|
cb = count * sizeof(DWORD);
|
|
break;
|
|
|
|
default:
|
|
fprintf(InfoStream, "???? cnt=%u\n", count);
|
|
|
|
cb = 0;
|
|
break;
|
|
}
|
|
|
|
rgcbCache[cacheIndex] = cb;
|
|
ib += cb;
|
|
break;
|
|
|
|
case 3 :
|
|
fprintf(InfoStream, " (%08X) %04X ", ib, wReloc);
|
|
|
|
subOp = (wReloc >> 9) & 0xF;
|
|
count = wReloc & 0x1FF;
|
|
|
|
switch (subOp) {
|
|
case 0 :
|
|
fprintf(InfoStream, "SYMB idx=%u\n", count);
|
|
|
|
cb = 4;
|
|
break;
|
|
|
|
case 1 :
|
|
fprintf(InfoStream, "CDIS sct=%u\n", count);
|
|
|
|
cb = 0;
|
|
break;
|
|
|
|
case 2 :
|
|
fprintf(InfoStream, "DTIS sct=%u\n", count);
|
|
|
|
cb = 0;
|
|
break;
|
|
|
|
case 3 :
|
|
fprintf(InfoStream, "SECN sct=%u\n", count);
|
|
|
|
cb = 4;
|
|
break;
|
|
|
|
default:
|
|
fprintf(InfoStream, "???? %u\n", count);
|
|
|
|
cb = 0;
|
|
break;
|
|
}
|
|
|
|
rgcbCache[cacheIndex] = cb;
|
|
ib += cb;
|
|
break;
|
|
|
|
case 8 :
|
|
count = wReloc & 0xFFF;
|
|
|
|
fprintf(InfoStream,
|
|
" (%08X) %04X DELT delta=%u\n",
|
|
ib, wReloc, count + 1);
|
|
|
|
ib += count + 1;
|
|
rgcbCache[cacheIndex] = count + 1;
|
|
break;
|
|
|
|
case 9 :
|
|
subOp = (wReloc >> 8) & 0xF;
|
|
count = wReloc & 0xFF;
|
|
|
|
fprintf(InfoStream,
|
|
" (%08X) %04X RPT i=%u,rpt=%u\n",
|
|
ib, wReloc, subOp + 1, count + 1);
|
|
|
|
// Calculating new byte Offsets
|
|
|
|
cb = 0;
|
|
for (loop = subOp + 1; loop > 0; loop--) {
|
|
cb += rgcbCache[(cacheIndex + MAX_INSTR_CACHED - loop) % MAX_INSTR_CACHED];
|
|
}
|
|
|
|
ib += (count + 1) * cb;
|
|
rgcbCache[cacheIndex] = 0;
|
|
break;
|
|
|
|
case 10 :
|
|
wReloc2 = WSwap(*pwReloc++);
|
|
j++;
|
|
|
|
fprintf(InfoStream, " (%08X) %04X %04X ", ib, wReloc, wReloc2);
|
|
|
|
subOp = (wReloc >> 10) & 0x3;
|
|
count = ((DWORD) (wReloc & 0x3FF) << 16) + wReloc2;
|
|
|
|
switch (subOp) {
|
|
case 0 :
|
|
fprintf(InfoStream, "LABS offset=0x%X\n", count);
|
|
|
|
rgcbCache[cacheIndex] = 0;
|
|
ib = count;
|
|
break;
|
|
|
|
case 1 :
|
|
fprintf(InfoStream, "LSYM idx=0x%X\n", count);
|
|
|
|
rgcbCache[cacheIndex] = 4;
|
|
ib += 4;
|
|
break;
|
|
|
|
default:
|
|
fprintf(InfoStream, "???? %u\n", count);
|
|
|
|
rgcbCache[cacheIndex] = 0;
|
|
break;
|
|
}
|
|
|
|
cacheIndex = (cacheIndex+1) % MAX_INSTR_CACHED;
|
|
rgcbCache[cacheIndex] = 0;
|
|
break;
|
|
|
|
case 11 :
|
|
wReloc2 = WSwap(*pwReloc++);
|
|
j++;
|
|
|
|
fprintf(InfoStream, " (%08X) %04X %04X ", ib, wReloc, wReloc2);
|
|
|
|
subOp = (wReloc >> 10) & 0x3;
|
|
subsubOp = (wReloc >> 6) & 0xF;
|
|
count = ((DWORD) (wReloc & 0x3F) << 16) + wReloc2;
|
|
|
|
switch (subOp) {
|
|
case 0 :
|
|
fprintf(InfoStream, "LRPT i=%u,rpt=%u\n", subsubOp + 1, count);
|
|
|
|
// Calculating new byte Offsets
|
|
|
|
cb = 0;
|
|
for (loop = subsubOp + 1; loop > 0; loop--) {
|
|
cb += rgcbCache[(cacheIndex + MAX_INSTR_CACHED - loop) % MAX_INSTR_CACHED];
|
|
}
|
|
|
|
ib += count * cb;
|
|
rgcbCache[cacheIndex] = 0;
|
|
break;
|
|
|
|
case 1 :
|
|
switch (subsubOp) {
|
|
case 0 :
|
|
fprintf(InfoStream, "LSEC LSECN,sct=%u\n", count);
|
|
|
|
cb = 4;
|
|
break;
|
|
|
|
case 1 :
|
|
fprintf(InfoStream, "LSEC LCDIS,sct=%u\n", count);
|
|
|
|
cb = 0;
|
|
break;
|
|
|
|
case 2 :
|
|
fprintf(InfoStream, "LSEC LDTIS,sct=%u\n", count);
|
|
|
|
cb = 0;
|
|
break;
|
|
|
|
default:
|
|
fprintf(InfoStream, "????? %u\n", count);
|
|
|
|
cb = 0;
|
|
break;
|
|
}
|
|
|
|
ib += count * cb;
|
|
rgcbCache[cacheIndex] = 0;
|
|
break;
|
|
|
|
default:
|
|
fprintf(InfoStream, "???? %u,%u\n", subsubOp, count);
|
|
|
|
rgcbCache[cacheIndex] = 0;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
fprintf(InfoStream, " (%08X) %04X ????", ib, wReloc);
|
|
break;
|
|
}
|
|
|
|
cacheIndex = (cacheIndex+1) % MAX_INSTR_CACHED;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DumpPexRelocationInstructions(
|
|
const BYTE *pbLoaderHeader,
|
|
const LOADER_HEADER *ploaderHdr,
|
|
const RELOCATION_HEADER *relocPtr
|
|
)
|
|
{
|
|
DWORD i;
|
|
|
|
assert(dft == dftPEX);
|
|
|
|
if (ploaderHdr->nSectionsWithRelocs == 0) {
|
|
return;
|
|
}
|
|
|
|
fprintf(InfoStream, "\n"
|
|
" Loader Relocation Instructions\n"
|
|
"\n");
|
|
|
|
for (i = 0; i < ploaderHdr->nSectionsWithRelocs; i++, relocPtr++) {
|
|
DWORD isec = WSwap(relocPtr->sectionNumber);
|
|
|
|
fprintf(InfoStream, " Relocations for Section %u\n\n", isec);
|
|
|
|
DWORD ib = ploaderHdr->relocTableOffset + DwSwap(relocPtr->firstRelocInstr);
|
|
|
|
const RELOCATION_INSTR *ppexreloc = (RELOCATION_INSTR *) (pbLoaderHeader + ib);
|
|
|
|
DWORD creloc = DwSwap(relocPtr->nbrOfRelocs);
|
|
|
|
for (DWORD ireloc = 0; ireloc < creloc; ireloc++, ppexreloc++) {
|
|
fprintf(InfoStream, " [%5u] ", ireloc);
|
|
|
|
|
|
DWORD ib = OFFSET(ppexreloc->instr);
|
|
|
|
switch (ppexreloc->instr >> 29) {
|
|
case typeDDAT :
|
|
fprintf(InfoStream, "DDAT %08lX n=%u\n", ib, ppexreloc->count);
|
|
break;
|
|
|
|
case typeDESC :
|
|
fprintf(InfoStream, "DESC %08lX n=%u\n", ib, ppexreloc->count);
|
|
break;
|
|
|
|
case typeSYMB :
|
|
fprintf(InfoStream, "SYMB %08lX idx=%u\n", ib, ppexreloc->count);
|
|
break;
|
|
|
|
case typeCODE :
|
|
fprintf(InfoStream, "CODE %08lX n=%u\n", ib, ppexreloc->count);
|
|
break;
|
|
|
|
default :
|
|
fprintf(InfoStream, "???? %08lX n=%u\n", ib, ppexreloc->count);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
PrintHashSlotTable(
|
|
const LOADER_HEADER *ploaderHdr,
|
|
const LOADER_HEADER *ploaderHdrFile
|
|
)
|
|
{
|
|
INT i;
|
|
|
|
if (ploaderHdr->hashSlotCount == 0) {
|
|
return;
|
|
}
|
|
|
|
fprintf(InfoStream, "\n Hash Slot Table:\n\n");
|
|
|
|
const DWORD *slotPtr = (DWORD *) ((BYTE *) ploaderHdrFile + ploaderHdr->hashSlotTableOffset);
|
|
|
|
for (i = 0; i < (1 << ploaderHdr->hashSlotCount); i++) {
|
|
DWORD slotTable;
|
|
DWORD count;
|
|
DWORD index;
|
|
|
|
slotTable = *slotPtr;
|
|
SwapBytes(&slotTable, 4);
|
|
|
|
count = (slotTable >> 18);
|
|
index = (slotTable & 0x3FFFF);
|
|
|
|
fprintf(InfoStream,
|
|
" HashSlot %3d: chain count %3d index %3d\n",
|
|
i, count, index);
|
|
|
|
slotPtr++;
|
|
}
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
PrintExportedSymbols(
|
|
const LOADER_HEADER *ploaderHdr,
|
|
const LOADER_HEADER *ploaderHdrFile,
|
|
const char *rgchStringTable
|
|
)
|
|
{
|
|
DWORD i;
|
|
|
|
if (ploaderHdr->nExportedSymbols == 0) {
|
|
return;
|
|
}
|
|
|
|
fprintf(InfoStream, "\n Exported Symbols:\n\n");
|
|
|
|
const HASH_CHAIN_TABLE *chainTable = (HASH_CHAIN_TABLE *) ((BYTE *) ploaderHdrFile +
|
|
ploaderHdr->hashSlotTableOffset +
|
|
((1 << ploaderHdr->hashSlotCount) * sizeof(HASH_SLOT_TABLE)));
|
|
|
|
const BYTE *pbExport = (BYTE *) (chainTable + ploaderHdr->nExportedSymbols);
|
|
|
|
for (i = 0; i < ploaderHdr->nExportedSymbols; i++) {
|
|
HASH_CHAIN_TABLE hash;
|
|
union
|
|
{
|
|
DWORD l;
|
|
BYTE c[4];
|
|
} temp;
|
|
DWORD offset;
|
|
SHORT section;
|
|
DWORD ichName;
|
|
BYTE SymbolClass;
|
|
const char *szName;
|
|
|
|
hash = *chainTable++;
|
|
|
|
temp.l = *(DWORD *) pbExport;
|
|
pbExport += sizeof(DWORD);
|
|
|
|
offset = *(DWORD *) pbExport;
|
|
pbExport += sizeof(DWORD);
|
|
|
|
section = *(SHORT *) pbExport;
|
|
pbExport += sizeof(SHORT);
|
|
|
|
SwapBytes(&hash, 4);
|
|
SwapBytes(&temp, 4);
|
|
SwapBytes(&offset, 4);
|
|
SwapBytes(§ion, 2);
|
|
|
|
ichName = temp.l & 0xFFFFFF;
|
|
ichExportBegin = __min (ichExportBegin, ichName);
|
|
|
|
SymbolClass = temp.c[3];
|
|
|
|
szName = rgchStringTable + ichName;
|
|
|
|
// The upper 16 bits of the hashword is the length of the exported symbol, in bytes
|
|
|
|
fprintf(InfoStream,
|
|
" Exp %3d: sec %d offset 0x%08lX hash 0x%X class %d \"%.*s\"\n",
|
|
i, section, offset, hash, SymbolClass, hash>>16, szName);
|
|
}
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
PrintLoaderStringTable(
|
|
const LOADER_HEADER *ploaderHdr,
|
|
const LOADER_HEADER *ploaderHdrFile,
|
|
const char *rgchStringTable
|
|
)
|
|
{
|
|
DWORD cch = (ploaderHdr->hashSlotTableOffset - ploaderHdr->stringTableOffset);
|
|
|
|
if (cch == 0) {
|
|
return;
|
|
}
|
|
|
|
// We have to take care of cases of exported symbols without NULL terminators
|
|
DWORD cExports = ploaderHdr->nExportedSymbols;
|
|
const HASH_CHAIN_TABLE *chainTable;
|
|
const BYTE *pbExport;
|
|
HASH_CHAIN_TABLE hash;
|
|
DWORD ichExportName;
|
|
|
|
fprintf(InfoStream, "\n"
|
|
" Loader String Table\n"
|
|
"\n");
|
|
|
|
size_t ich = 0;
|
|
const char *szName;
|
|
|
|
|
|
while ((ich < cch) && (rgchStringTable[ich] != '\0')) {
|
|
szName = rgchStringTable + ich;
|
|
if (cExports &&
|
|
(Switch.Dump.Exports ? ich == ichExportBegin : strlen(szName) > _MAX_MAC_FNAME)) {
|
|
chainTable = (HASH_CHAIN_TABLE *) ((BYTE *) ploaderHdrFile +
|
|
ploaderHdr->hashSlotTableOffset +
|
|
((1 << ploaderHdr->hashSlotCount) * sizeof(HASH_SLOT_TABLE)));
|
|
|
|
pbExport = (BYTE *) (chainTable + ploaderHdr->nExportedSymbols);
|
|
pbExport += ((cExports-1) * (5 * sizeof(WORD)));
|
|
|
|
chainTable += cExports - 1;
|
|
|
|
while (cExports) {
|
|
ichExportName = *(DWORD *) pbExport;
|
|
SwapBytes(&ichExportName, 4);
|
|
ichExportName &= 0xFFFFFF;
|
|
hash = *chainTable--;
|
|
SwapBytes(&hash, 4);
|
|
// The upper 16 bits of the hashword is the length of the exported symbol, in bytes
|
|
hash >>= 16;
|
|
szName = rgchStringTable + ichExportName;
|
|
ich += hash;
|
|
fprintf(InfoStream, " %08lX: \"%.*s\"\n", ichExportName, hash, szName);
|
|
pbExport -= (5 * sizeof(WORD));
|
|
cExports--;
|
|
}
|
|
} else {
|
|
fprintf(InfoStream, " %08lX: \"%s\"\n", ich, szName);
|
|
ich += strlen(szName) + 1;
|
|
}
|
|
}
|
|
|
|
assert(!cExports);
|
|
}
|
|
|
|
|
|
void
|
|
DumpPefLoaderSection(
|
|
const BYTE *pbLoaderHeader
|
|
)
|
|
{
|
|
const LOADER_HEADER *ploaderHdrFile = (LOADER_HEADER *) pbLoaderHeader;
|
|
LOADER_HEADER loaderHdr = *ploaderHdrFile;
|
|
|
|
SwapBytes(&loaderHdr.entryPointSectionNumber, 4);
|
|
SwapBytes(&loaderHdr.entryPointDescrOffset, 4);
|
|
SwapBytes(&loaderHdr.initRoutineSectionNumber, 4);
|
|
SwapBytes(&loaderHdr.initRoutineDescrOffset, 4);
|
|
SwapBytes(&loaderHdr.termRoutineSectionNumber, 4);
|
|
SwapBytes(&loaderHdr.termRoutineDescrOffset, 4);
|
|
SwapBytes(&loaderHdr.nImportIdTableEntries, 4);
|
|
SwapBytes(&loaderHdr.nImportSymTableEntries, 4);
|
|
SwapBytes(&loaderHdr.nSectionsWithRelocs, 4);
|
|
SwapBytes(&loaderHdr.relocTableOffset, 4);
|
|
SwapBytes(&loaderHdr.stringTableOffset, 4);
|
|
SwapBytes(&loaderHdr.hashSlotTableOffset, 4);
|
|
SwapBytes(&loaderHdr.hashSlotCount, 4);
|
|
SwapBytes(&loaderHdr.nExportedSymbols, 4);
|
|
|
|
if (Switch.Dump.Headers) {
|
|
PrintLoaderHeader(&loaderHdr);
|
|
}
|
|
|
|
const char *rgchStringTable = (char *) ploaderHdrFile + loaderHdr.stringTableOffset;
|
|
|
|
const CONTAINER_TABLE *containerPtr = (CONTAINER_TABLE *) (ploaderHdrFile + 1);
|
|
const IMPORT_TABLE *importPtr = (IMPORT_TABLE *) (containerPtr + loaderHdr.nImportIdTableEntries);
|
|
|
|
if (Switch.Dump.Imports) {
|
|
PrintImportContainers(&loaderHdr, containerPtr, rgchStringTable);
|
|
PrintImportTable(&loaderHdr, importPtr, rgchStringTable);
|
|
}
|
|
|
|
const RELOCATION_HEADER *relocPtr = (RELOCATION_HEADER *) (importPtr + loaderHdr.nImportSymTableEntries);
|
|
|
|
if (Switch.Dump.Relocations) {
|
|
PrintRelocHeaders(&loaderHdr, relocPtr);
|
|
|
|
if (dft == dftPEF) {
|
|
DumpPefRelocationInstructions(&loaderHdr, relocPtr);
|
|
} else {
|
|
DumpPexRelocationInstructions(pbLoaderHeader, &loaderHdr, relocPtr);
|
|
}
|
|
}
|
|
|
|
PrintHashSlotTable(&loaderHdr, ploaderHdrFile);
|
|
|
|
if (Switch.Dump.Exports) {
|
|
PrintExportedSymbols(&loaderHdr, ploaderHdrFile, rgchStringTable);
|
|
}
|
|
|
|
if (Switch.Dump.Imports || Switch.Dump.Exports) {
|
|
PrintLoaderStringTable(&loaderHdr, ploaderHdrFile, rgchStringTable);
|
|
}
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
PrintPefSection(
|
|
INT sectNumber,
|
|
const BYTE *pbFile,
|
|
const char *rgchStringTable
|
|
)
|
|
{
|
|
const PPC_SECTION_HEADER *secPtr;
|
|
|
|
secPtr = (PPC_SECTION_HEADER *) (pbFile +
|
|
sizeof(PPC_FILE_HEADER) +
|
|
(sectNumber * sizeof(PPC_SECTION_HEADER)));
|
|
|
|
PPC_SECTION_HEADER secHdr = *secPtr;
|
|
|
|
SwapBytes(&secHdr.sectionName, 4);
|
|
SwapBytes(&secHdr.sectionAddress, 4);
|
|
SwapBytes(&secHdr.execSize, 4);
|
|
SwapBytes(&secHdr.initSize, 4);
|
|
SwapBytes(&secHdr.rawSize, 4);
|
|
SwapBytes(&secHdr.containerOffset, 4);
|
|
|
|
const char *szName;
|
|
|
|
if (secHdr.sectionName == 0xFFFFFFFF) {
|
|
szName = "<unnamed>";
|
|
} else {
|
|
szName = rgchStringTable + secHdr.sectionName;
|
|
|
|
if (Switch.Dump.Summary) {
|
|
PSEC psec = PsecNew(NULL, szName, 0 /* UNDONE */, &pimageDump->secs, &pimageDump->ImgOptHdr);
|
|
|
|
DWORD cbVirtual = secHdr.execSize ? secHdr.execSize : secHdr.rawSize;
|
|
|
|
psec->cbRawData += cbVirtual;
|
|
}
|
|
}
|
|
|
|
if (Switch.Dump.Headers) {
|
|
const char *szRegionKind;
|
|
|
|
switch (secHdr.regionKind) {
|
|
case 0 :
|
|
szRegionKind = "code";
|
|
break;
|
|
|
|
case 1 :
|
|
szRegionKind = "data";
|
|
break;
|
|
|
|
case 2 :
|
|
szRegionKind = "pidata";
|
|
break;
|
|
|
|
case 3 :
|
|
szRegionKind = "constant";
|
|
break;
|
|
|
|
case 4 :
|
|
szRegionKind = "loader";
|
|
break;
|
|
|
|
case 5 :
|
|
szRegionKind = "debug";
|
|
break;
|
|
|
|
default :
|
|
szRegionKind = "unknown";
|
|
break;
|
|
}
|
|
|
|
const char *szShareKind;
|
|
|
|
switch (secHdr.shareKind) {
|
|
case 1 :
|
|
szShareKind = "context share";
|
|
break;
|
|
|
|
case 4 :
|
|
szShareKind = "global share";
|
|
break;
|
|
|
|
default :
|
|
szShareKind = "unknown";
|
|
break;
|
|
}
|
|
|
|
fprintf(InfoStream, "\n"
|
|
" Section Header %u\n"
|
|
"\n"
|
|
" sectionName = 0x%08lX (%d) \"%s\"\n"
|
|
" sectionAddress = 0x%08lX\n"
|
|
" execSize = 0x%08lX (%lu)\n"
|
|
" initSize = 0x%08lX (%lu)\n"
|
|
" rawSize = 0x%08lX (%lu)\n"
|
|
" containerOffset = 0x%08lX (%lu)\n"
|
|
" regionKind = 0x%02X (%s)\n"
|
|
" shareKind = 0x%02X (%s)\n"
|
|
" alignment = 0x%02X (%lu-byte bndry)\n"
|
|
" reserved = 0x%02X\n",
|
|
sectNumber,
|
|
secHdr.sectionName, secHdr.sectionName, szName,
|
|
secHdr.sectionAddress,
|
|
secHdr.execSize, secHdr.execSize,
|
|
secHdr.initSize, secHdr.initSize,
|
|
secHdr.rawSize, secHdr.rawSize,
|
|
secHdr.containerOffset, secHdr.containerOffset,
|
|
secHdr.regionKind, szRegionKind,
|
|
secHdr.shareKind, szShareKind,
|
|
secHdr.alignment, 1UL << secHdr.alignment,
|
|
secHdr.reserved);
|
|
}
|
|
|
|
if (secHdr.regionKind == 4) {
|
|
DumpPefLoaderSection(pbFile + secHdr.containerOffset);
|
|
}
|
|
|
|
if (secHdr.rawSize != 0) {
|
|
if (Switch.Dump.Disasm && (secHdr.regionKind == 0)) {
|
|
// The disasm switch is true and the section is code (.text)
|
|
|
|
fputc('\n', InfoStream);
|
|
|
|
DisasmBuffer(IMAGE_FILE_MACHINE_MPPC_601,
|
|
FALSE,
|
|
secHdr.sectionAddress,
|
|
pbFile + secHdr.containerOffset,
|
|
secHdr.rawSize,
|
|
NULL,
|
|
0,
|
|
0,
|
|
InfoStream);
|
|
}
|
|
|
|
if (Switch.Dump.RawData && (secHdr.regionKind == 0 || secHdr.regionKind == 1)) {
|
|
fprintf(InfoStream, "\nRAW DATA #%hX\n", sectNumber);
|
|
|
|
DumpRawData(secHdr.sectionAddress,
|
|
pbFile + secHdr.containerOffset,
|
|
secHdr.rawSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DumpPefFile(
|
|
const BYTE *pbFile
|
|
)
|
|
{
|
|
int nbrOfSections = PrintPefHeader(pbFile);
|
|
|
|
const char *rgchStringTable = (char *) pbFile +
|
|
sizeof(PPC_FILE_HEADER) +
|
|
(nbrOfSections * sizeof(PPC_SECTION_HEADER));
|
|
|
|
for (int i = 0; i < nbrOfSections; i++) {
|
|
PrintPefSection(i, pbFile, rgchStringTable);
|
|
}
|
|
}
|