|
|
/***********************************************************************
* 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
|