Windows NT 4.0 source code leak
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

4 years ago
  1. /***********************************************************************
  2. * Microsoft (R) 32-Bit Incremental Linker
  3. *
  4. * Copyright (C) Microsoft Corp 1992-95. All rights reserved.
  5. *
  6. * File: calltree.cpp
  7. *
  8. * File Comments:
  9. *
  10. ***********************************************************************/
  11. #include "link.h"
  12. #ifdef NT_BUILD
  13. #if DBG
  14. DWORD ctrvaBreak = (DWORD) -1;
  15. DWORD ctrvaLowBreak = (DWORD) -1;
  16. DWORD ctrvaHighBreak = (DWORD) -1;
  17. PCHAR KeyBreak = (PCHAR) -1;
  18. #endif
  19. typedef struct _CallStruct {
  20. PEXTERNAL pext;
  21. DWORD Low;
  22. DWORD High;
  23. DWORD iSlot;
  24. DWORD ConStart;
  25. }CALLSTRUCT, *PCALLSTRUCT;
  26. int __cdecl
  27. CallStructComp (
  28. void const *R1,
  29. void const *R2
  30. )
  31. {
  32. PCALLSTRUCT pc1 = (PCALLSTRUCT) R1;
  33. PCALLSTRUCT pc2 = (PCALLSTRUCT) R2;
  34. int iRet = pc1->Low - pc2->Low;
  35. if (iRet == 0) {
  36. if ((pc1->pext->Flags & (EXTERN_COMDAT | EXTERN_COMMON)) != 0) {
  37. // Sort comdat's first
  38. iRet = -1;
  39. }
  40. }
  41. return (iRet);
  42. }
  43. int __cdecl
  44. CallStructSearch (
  45. void const *R1,
  46. void const *R2
  47. )
  48. {
  49. PCALLSTRUCT pc1 = (PCALLSTRUCT) R1;
  50. PCALLSTRUCT pc2 = (PCALLSTRUCT) R2;
  51. return(pc1->Low - pc2->Low);
  52. }
  53. void
  54. GenerateCallTree(
  55. PIMAGE pimage
  56. )
  57. {
  58. // Dump a first-level Call tree before we delete saved relocs
  59. BOOL fSkipUnderscore;
  60. PEXTERNAL pext;
  61. FILE *CalltreeFile;
  62. WORD wCodeReloc = 0xFFFF;
  63. switch (pimage->ImgFileHdr.Machine) {
  64. case IMAGE_FILE_MACHINE_I386 :
  65. fSkipUnderscore = TRUE;
  66. wCodeReloc = IMAGE_REL_I386_REL32;
  67. break;
  68. case IMAGE_FILE_MACHINE_R4000 :
  69. case IMAGE_FILE_MACHINE_R10000 :
  70. fSkipUnderscore = FALSE;
  71. wCodeReloc = IMAGE_REL_MIPS_JMPADDR;
  72. break;
  73. case IMAGE_FILE_MACHINE_ALPHA :
  74. fSkipUnderscore = FALSE;
  75. wCodeReloc = IMAGE_REL_ALPHA_BRADDR;
  76. break;
  77. case IMAGE_FILE_MACHINE_POWERPC :
  78. fSkipUnderscore = FALSE;
  79. wCodeReloc = IMAGE_REL_PPC_REL24;
  80. break;
  81. }
  82. if (wCodeReloc == 0xFFFF) {
  83. return; // Unknown machine type
  84. }
  85. if ((CalltreeFile = fopen("calltree.out", "wt")) == NULL) {
  86. printf("Unable to open calltree.out\n");
  87. return;
  88. }
  89. // See how many we really have.
  90. DWORD cExt;
  91. cExt = 0;
  92. InitEnumerateExternals(pimage->pst);
  93. while ((pext = PexternalEnumerateNext(pimage->pst)) != NULL) {
  94. if (pext->pcon == NULL) {
  95. // Don't probe absolutes (no pcon)
  96. continue;
  97. }
  98. if (FetchContent(pext->pcon->flags) != IMAGE_SCN_CNT_CODE) {
  99. continue;
  100. }
  101. if (pimage->Switch.Link.fTCE) {
  102. if (FDiscardPCON_TCE(pext->pcon)) {
  103. continue;
  104. }
  105. }
  106. cExt++;
  107. }
  108. TerminateEnumerateExternals(pimage->pst);
  109. // Create a slot for each.
  110. PCALLSTRUCT pC, pCall;
  111. pC = pCall = (PCALLSTRUCT) malloc(cExt * sizeof(CALLSTRUCT));
  112. InitEnumerateExternals(pimage->pst);
  113. while ((pext = PexternalEnumerateNext(pimage->pst)) != NULL) {
  114. if (pext->pcon == NULL) {
  115. // Don't probe absolutes (no pcon)
  116. continue;
  117. }
  118. if (FetchContent(pext->pcon->flags) != IMAGE_SCN_CNT_CODE) {
  119. continue;
  120. }
  121. if (pimage->Switch.Link.fTCE) {
  122. if (FDiscardPCON_TCE(pext->pcon)) {
  123. continue;
  124. }
  125. }
  126. pC->pext = pext;
  127. pC->Low = pext->FinalValue;
  128. pC++;
  129. }
  130. TerminateEnumerateExternals(pimage->pst);
  131. // Sort and number them
  132. qsort(pCall,
  133. (size_t) (cExt),
  134. sizeof(CALLSTRUCT),
  135. CallStructComp);
  136. DWORD i, j, iCaller, iCallee, dwSize;
  137. PCHAR pCallMap;
  138. for (j = 0; j < cExt; j++) {
  139. // Set the size.
  140. if ((pCall[j].pext->Flags & (EXTERN_COMDAT | EXTERN_COMMON)) != 0) {
  141. // For Comdat routines, the size of code is cbRawData minus any delta caused by cbstring.
  142. dwSize = pCall[j].pext->pcon->cbRawData - (pCall[j].pext->FinalValue - pCall[j].pext->pcon->rva);
  143. pCall[j].ConStart = pCall[j].pext->pcon->rva;
  144. } else {
  145. // For non-comdat, it depends on where we are.
  146. pCall[j].ConStart = pCall[j].Low;
  147. if (j > 0) {
  148. if (pCall[j].Low == pCall[j-1].Low) {
  149. // This symbol is an alias for the one above. Use the same size.
  150. dwSize = pCall[j-1].High - pCall[j-1].Low;
  151. goto done;
  152. } else if ((pCall[j].Low >= pCall[j-1].Low) &&
  153. (pCall[j].Low <= pCall[j-1].High) ) {
  154. // This symbol is w/i the con before. Use the same size and start.
  155. pCall[j].ConStart = pCall[j-1].ConStart;
  156. dwSize = pCall[j-1].High - pCall[j-1].Low;
  157. goto done;
  158. }
  159. }
  160. // Otherwise, it's the diff from one symbol to another.
  161. // For the last one, it's what's remaining in the con.
  162. if ((j == (cExt - 1)) ||
  163. ((pCall[j+1].pext->Flags & (EXTERN_COMDAT | EXTERN_COMMON)) != 0)) {
  164. dwSize = pCall[j].pext->pcon->cbRawData - (pCall[j].pext->pcon->rva - pCall[j].pext->FinalValue);
  165. } else {
  166. dwSize = pCall[j+1].pext->FinalValue - pCall[j].pext->FinalValue;
  167. }
  168. }
  169. done:
  170. pCall[j].High = pCall[j].Low + dwSize;
  171. pCall[j].iSlot = j;
  172. }
  173. pCallMap = (PCHAR) calloc(cExt * cExt, sizeof(CHAR));
  174. // Match up the relocs with the function.
  175. FIXPAG *pfixpag = pfixpagHead;
  176. while (pfixpag != NULL) {
  177. for (i=0; i < cxfixupPage; i++) {
  178. #if DBG
  179. if ((pfixpag->rgxfixup[i].rvaTarget == ctrvaBreak)) {
  180. printf("TargMatch\n");
  181. }
  182. if ((pfixpag->rgxfixup[i].rva >= ctrvaLowBreak) &&
  183. (pfixpag->rgxfixup[i].rva <= ctrvaHighBreak)) {
  184. printf("SrcMatch: %x - %x - %x\n",
  185. pfixpag->rgxfixup[i].rva,
  186. pfixpag->rgxfixup[i].rvaTarget,
  187. pfixpag->rgxfixup[i].wType
  188. );
  189. }
  190. #endif
  191. if (pfixpag->rgxfixup[i].wType == wCodeReloc) {
  192. iCaller = (DWORD)-1;
  193. iCallee = (DWORD)-1;
  194. for (j = 0; j < cExt; j++) {
  195. PCALLSTRUCT pC = &pCall[j];
  196. if ((pfixpag->rgxfixup[i].rva >= pC->Low) &&
  197. (pfixpag->rgxfixup[i].rva <= pC->High)) {
  198. iCaller = j;
  199. break;
  200. }
  201. }
  202. CALLSTRUCT KeyStruct, *pMatch;
  203. KeyStruct.Low = pfixpag->rgxfixup[i].rvaTarget;
  204. pMatch = (PCALLSTRUCT) bsearch (
  205. &KeyStruct,
  206. pCall,
  207. cExt,
  208. sizeof(CALLSTRUCT),
  209. CallStructSearch);
  210. if (pMatch != NULL) {
  211. iCallee = pMatch->iSlot;
  212. }
  213. if ((iCaller != -1) && (iCallee != -1)) {
  214. assert(iCaller < cExt);
  215. assert(iCallee < cExt);
  216. PCHAR KeySet = pCallMap + ((iCaller * cExt) + iCallee);
  217. #if DBG
  218. if (KeySet == KeyBreak) {
  219. printf("Setting key\n");
  220. }
  221. #endif
  222. *KeySet = 1;
  223. }
  224. }
  225. }
  226. pfixpag = pfixpag->pfixpagNext;
  227. }
  228. // And print out the map.
  229. for (i = 0, pC = pCall; i < cExt; i++, pC++) {
  230. PCHAR pCMap = pCallMap + (i * cExt);
  231. PCHAR szName = SzNamePext(pC->pext, pimage->pst);
  232. if (fSkipUnderscore && (szName[0] == '_')) {
  233. szName++;
  234. }
  235. if (((pC->pext->Flags & (EXTERN_COMDAT | EXTERN_COMMON)) == 0)) {
  236. // non-comdat case
  237. fprintf(CalltreeFile, "%x\tN\t%s\t%x\t%s",
  238. pC->ConStart,
  239. PsecPCON(pC->pext->pcon)->szName,
  240. pC->High - pC->Low,
  241. szName
  242. );
  243. } else {
  244. // comdat case
  245. fprintf(CalltreeFile, "%x\tC\t%s\t%x\t%s",
  246. pC->ConStart,
  247. PsecPCON(pC->pext->pcon)->szName,
  248. pC->pext->pcon->cbRawData,
  249. szName
  250. );
  251. }
  252. for (j = 0; j < cExt; j++) {
  253. if (*(pCMap + j) == 1) {
  254. szName = SzNamePext(pCall[j].pext, pimage->pst);
  255. if (fSkipUnderscore && (szName[0] == '_')) {
  256. szName++;
  257. }
  258. fprintf(CalltreeFile, "\t%s", szName);
  259. }
  260. }
  261. fprintf(CalltreeFile, "\n");
  262. }
  263. free(pCallMap);
  264. free(pCall);
  265. fclose(CalltreeFile);
  266. return;
  267. }
  268. #endif // NT_BUILD