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.
340 lines
8.9 KiB
340 lines
8.9 KiB
/***********************************************************************
|
|
* Microsoft (R) 32-Bit Incremental Linker
|
|
*
|
|
* Copyright (C) Microsoft Corp 1992-95. All rights reserved.
|
|
*
|
|
* File: calltree.cpp
|
|
*
|
|
* File Comments:
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "link.h"
|
|
|
|
#ifdef NT_BUILD
|
|
|
|
#if DBG
|
|
|
|
DWORD ctrvaBreak = (DWORD) -1;
|
|
DWORD ctrvaLowBreak = (DWORD) -1;
|
|
DWORD ctrvaHighBreak = (DWORD) -1;
|
|
PCHAR KeyBreak = (PCHAR) -1;
|
|
|
|
#endif
|
|
|
|
typedef struct _CallStruct {
|
|
PEXTERNAL pext;
|
|
DWORD Low;
|
|
DWORD High;
|
|
DWORD iSlot;
|
|
DWORD ConStart;
|
|
}CALLSTRUCT, *PCALLSTRUCT;
|
|
|
|
int __cdecl
|
|
CallStructComp (
|
|
void const *R1,
|
|
void const *R2
|
|
)
|
|
{
|
|
PCALLSTRUCT pc1 = (PCALLSTRUCT) R1;
|
|
PCALLSTRUCT pc2 = (PCALLSTRUCT) R2;
|
|
|
|
int iRet = pc1->Low - pc2->Low;
|
|
|
|
if (iRet == 0) {
|
|
if ((pc1->pext->Flags & (EXTERN_COMDAT | EXTERN_COMMON)) != 0) {
|
|
|
|
// Sort comdat's first
|
|
iRet = -1;
|
|
}
|
|
}
|
|
|
|
return (iRet);
|
|
}
|
|
|
|
|
|
int __cdecl
|
|
CallStructSearch (
|
|
void const *R1,
|
|
void const *R2
|
|
)
|
|
{
|
|
PCALLSTRUCT pc1 = (PCALLSTRUCT) R1;
|
|
PCALLSTRUCT pc2 = (PCALLSTRUCT) R2;
|
|
|
|
return(pc1->Low - pc2->Low);
|
|
}
|
|
|
|
|
|
void
|
|
GenerateCallTree(
|
|
PIMAGE pimage
|
|
)
|
|
{
|
|
// Dump a first-level Call tree before we delete saved relocs
|
|
|
|
BOOL fSkipUnderscore;
|
|
PEXTERNAL pext;
|
|
FILE *CalltreeFile;
|
|
WORD wCodeReloc = 0xFFFF;
|
|
|
|
switch (pimage->ImgFileHdr.Machine) {
|
|
case IMAGE_FILE_MACHINE_I386 :
|
|
fSkipUnderscore = TRUE;
|
|
wCodeReloc = IMAGE_REL_I386_REL32;
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_R4000 :
|
|
case IMAGE_FILE_MACHINE_R10000 :
|
|
fSkipUnderscore = FALSE;
|
|
wCodeReloc = IMAGE_REL_MIPS_JMPADDR;
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_ALPHA :
|
|
fSkipUnderscore = FALSE;
|
|
wCodeReloc = IMAGE_REL_ALPHA_BRADDR;
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_POWERPC :
|
|
fSkipUnderscore = FALSE;
|
|
wCodeReloc = IMAGE_REL_PPC_REL24;
|
|
break;
|
|
}
|
|
|
|
if (wCodeReloc == 0xFFFF) {
|
|
return; // Unknown machine type
|
|
}
|
|
|
|
if ((CalltreeFile = fopen("calltree.out", "wt")) == NULL) {
|
|
printf("Unable to open calltree.out\n");
|
|
return;
|
|
}
|
|
|
|
// See how many we really have.
|
|
|
|
DWORD cExt;
|
|
|
|
cExt = 0;
|
|
InitEnumerateExternals(pimage->pst);
|
|
while ((pext = PexternalEnumerateNext(pimage->pst)) != NULL) {
|
|
|
|
if (pext->pcon == NULL) {
|
|
// Don't probe absolutes (no pcon)
|
|
continue;
|
|
}
|
|
|
|
if (FetchContent(pext->pcon->flags) != IMAGE_SCN_CNT_CODE) {
|
|
continue;
|
|
}
|
|
|
|
if (pimage->Switch.Link.fTCE) {
|
|
if (FDiscardPCON_TCE(pext->pcon)) {
|
|
continue;
|
|
}
|
|
}
|
|
cExt++;
|
|
}
|
|
TerminateEnumerateExternals(pimage->pst);
|
|
|
|
// Create a slot for each.
|
|
|
|
PCALLSTRUCT pC, pCall;
|
|
|
|
pC = pCall = (PCALLSTRUCT) malloc(cExt * sizeof(CALLSTRUCT));
|
|
|
|
InitEnumerateExternals(pimage->pst);
|
|
while ((pext = PexternalEnumerateNext(pimage->pst)) != NULL) {
|
|
|
|
if (pext->pcon == NULL) {
|
|
// Don't probe absolutes (no pcon)
|
|
continue;
|
|
}
|
|
|
|
if (FetchContent(pext->pcon->flags) != IMAGE_SCN_CNT_CODE) {
|
|
continue;
|
|
}
|
|
|
|
if (pimage->Switch.Link.fTCE) {
|
|
if (FDiscardPCON_TCE(pext->pcon)) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
pC->pext = pext;
|
|
pC->Low = pext->FinalValue;
|
|
pC++;
|
|
}
|
|
|
|
TerminateEnumerateExternals(pimage->pst);
|
|
|
|
// Sort and number them
|
|
|
|
qsort(pCall,
|
|
(size_t) (cExt),
|
|
sizeof(CALLSTRUCT),
|
|
CallStructComp);
|
|
|
|
DWORD i, j, iCaller, iCallee, dwSize;
|
|
PCHAR pCallMap;
|
|
|
|
for (j = 0; j < cExt; j++) {
|
|
// Set the size.
|
|
|
|
if ((pCall[j].pext->Flags & (EXTERN_COMDAT | EXTERN_COMMON)) != 0) {
|
|
|
|
// For Comdat routines, the size of code is cbRawData minus any delta caused by cbstring.
|
|
dwSize = pCall[j].pext->pcon->cbRawData - (pCall[j].pext->FinalValue - pCall[j].pext->pcon->rva);
|
|
pCall[j].ConStart = pCall[j].pext->pcon->rva;
|
|
|
|
} else {
|
|
|
|
// For non-comdat, it depends on where we are.
|
|
|
|
pCall[j].ConStart = pCall[j].Low;
|
|
|
|
if (j > 0) {
|
|
if (pCall[j].Low == pCall[j-1].Low) {
|
|
// This symbol is an alias for the one above. Use the same size.
|
|
dwSize = pCall[j-1].High - pCall[j-1].Low;
|
|
goto done;
|
|
} else if ((pCall[j].Low >= pCall[j-1].Low) &&
|
|
(pCall[j].Low <= pCall[j-1].High) ) {
|
|
// This symbol is w/i the con before. Use the same size and start.
|
|
pCall[j].ConStart = pCall[j-1].ConStart;
|
|
dwSize = pCall[j-1].High - pCall[j-1].Low;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
// Otherwise, it's the diff from one symbol to another.
|
|
// For the last one, it's what's remaining in the con.
|
|
if ((j == (cExt - 1)) ||
|
|
((pCall[j+1].pext->Flags & (EXTERN_COMDAT | EXTERN_COMMON)) != 0)) {
|
|
dwSize = pCall[j].pext->pcon->cbRawData - (pCall[j].pext->pcon->rva - pCall[j].pext->FinalValue);
|
|
} else {
|
|
dwSize = pCall[j+1].pext->FinalValue - pCall[j].pext->FinalValue;
|
|
}
|
|
}
|
|
|
|
done:
|
|
pCall[j].High = pCall[j].Low + dwSize;
|
|
|
|
pCall[j].iSlot = j;
|
|
}
|
|
|
|
pCallMap = (PCHAR) calloc(cExt * cExt, sizeof(CHAR));
|
|
|
|
// Match up the relocs with the function.
|
|
|
|
FIXPAG *pfixpag = pfixpagHead;
|
|
|
|
while (pfixpag != NULL) {
|
|
for (i=0; i < cxfixupPage; i++) {
|
|
|
|
#if DBG
|
|
if ((pfixpag->rgxfixup[i].rvaTarget == ctrvaBreak)) {
|
|
printf("TargMatch\n");
|
|
}
|
|
|
|
if ((pfixpag->rgxfixup[i].rva >= ctrvaLowBreak) &&
|
|
(pfixpag->rgxfixup[i].rva <= ctrvaHighBreak)) {
|
|
printf("SrcMatch: %x - %x - %x\n",
|
|
pfixpag->rgxfixup[i].rva,
|
|
pfixpag->rgxfixup[i].rvaTarget,
|
|
pfixpag->rgxfixup[i].wType
|
|
);
|
|
}
|
|
#endif
|
|
|
|
if (pfixpag->rgxfixup[i].wType == wCodeReloc) {
|
|
iCaller = (DWORD)-1;
|
|
iCallee = (DWORD)-1;
|
|
|
|
for (j = 0; j < cExt; j++) {
|
|
PCALLSTRUCT pC = &pCall[j];
|
|
|
|
if ((pfixpag->rgxfixup[i].rva >= pC->Low) &&
|
|
(pfixpag->rgxfixup[i].rva <= pC->High)) {
|
|
iCaller = j;
|
|
break;
|
|
}
|
|
}
|
|
|
|
CALLSTRUCT KeyStruct, *pMatch;
|
|
KeyStruct.Low = pfixpag->rgxfixup[i].rvaTarget;
|
|
|
|
pMatch = (PCALLSTRUCT) bsearch (
|
|
&KeyStruct,
|
|
pCall,
|
|
cExt,
|
|
sizeof(CALLSTRUCT),
|
|
CallStructSearch);
|
|
|
|
if (pMatch != NULL) {
|
|
iCallee = pMatch->iSlot;
|
|
}
|
|
|
|
if ((iCaller != -1) && (iCallee != -1)) {
|
|
assert(iCaller < cExt);
|
|
assert(iCallee < cExt);
|
|
|
|
PCHAR KeySet = pCallMap + ((iCaller * cExt) + iCallee);
|
|
#if DBG
|
|
if (KeySet == KeyBreak) {
|
|
printf("Setting key\n");
|
|
}
|
|
#endif
|
|
*KeySet = 1;
|
|
}
|
|
}
|
|
}
|
|
pfixpag = pfixpag->pfixpagNext;
|
|
}
|
|
|
|
// And print out the map.
|
|
|
|
for (i = 0, pC = pCall; i < cExt; i++, pC++) {
|
|
PCHAR pCMap = pCallMap + (i * cExt);
|
|
PCHAR szName = SzNamePext(pC->pext, pimage->pst);
|
|
|
|
if (fSkipUnderscore && (szName[0] == '_')) {
|
|
szName++;
|
|
}
|
|
|
|
if (((pC->pext->Flags & (EXTERN_COMDAT | EXTERN_COMMON)) == 0)) {
|
|
// non-comdat case
|
|
fprintf(CalltreeFile, "%x\tN\t%s\t%x\t%s",
|
|
pC->ConStart,
|
|
PsecPCON(pC->pext->pcon)->szName,
|
|
pC->High - pC->Low,
|
|
szName
|
|
);
|
|
} else {
|
|
// comdat case
|
|
fprintf(CalltreeFile, "%x\tC\t%s\t%x\t%s",
|
|
pC->ConStart,
|
|
PsecPCON(pC->pext->pcon)->szName,
|
|
pC->pext->pcon->cbRawData,
|
|
szName
|
|
);
|
|
}
|
|
|
|
for (j = 0; j < cExt; j++) {
|
|
if (*(pCMap + j) == 1) {
|
|
szName = SzNamePext(pCall[j].pext, pimage->pst);
|
|
if (fSkipUnderscore && (szName[0] == '_')) {
|
|
szName++;
|
|
}
|
|
fprintf(CalltreeFile, "\t%s", szName);
|
|
}
|
|
}
|
|
fprintf(CalltreeFile, "\n");
|
|
}
|
|
|
|
free(pCallMap);
|
|
free(pCall);
|
|
fclose(CalltreeFile);
|
|
return;
|
|
}
|
|
|
|
#endif // NT_BUILD
|