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.

2337 lines
81 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. checksum.c
  5. Abstract:
  6. This module implements functions for splitting debugging information
  7. out of an image file and into a separate .DBG file.
  8. Author:
  9. Steven R. Wood (stevewo) 4-May-1993
  10. Revision History:
  11. --*/
  12. #include <private.h>
  13. API_VERSION ApiVersion = { (VER_PRODUCTVERSION_W >> 8), (VER_PRODUCTVERSION_W & 0xff), API_VERSION_NUMBER, 0 };
  14. //
  15. // If the app does not call ImagehlpApiVersionEx, always assume
  16. // that it is version 3.
  17. //
  18. API_VERSION AppVersion = { 3, 5, 3, 0 };
  19. LPSTR
  20. GetEnvVariable(
  21. IN LPSTR VariableName
  22. );
  23. #define ROUNDUP(x, y) ((x + (y-1)) & ~(y-1))
  24. BOOL
  25. SplitSymbols(
  26. LPSTR ImageName,
  27. LPSTR SymbolsPath,
  28. LPSTR SymbolFilePath,
  29. ULONG Flags
  30. )
  31. {
  32. HANDLE FileHandle, SymbolFileHandle;
  33. HANDLE hMappedFile;
  34. LPVOID ImageBase;
  35. PIMAGE_NT_HEADERS NtHeaders;
  36. LPSTR ImageFileName;
  37. DWORD SizeOfSymbols, ImageNameOffset, DebugSectionStart;
  38. PIMAGE_SECTION_HEADER DebugSection = NULL;
  39. DWORD SectionNumber, BytesWritten, NewFileSize, HeaderSum, CheckSum;
  40. PIMAGE_DEBUG_DIRECTORY DebugDirectory, DebugDirectories, DbgDebugDirectories = NULL;
  41. IMAGE_DEBUG_DIRECTORY MiscDebugDirectory = {0};
  42. IMAGE_DEBUG_DIRECTORY FpoDebugDirectory = {0};
  43. IMAGE_DEBUG_DIRECTORY FunctionTableDir;
  44. PIMAGE_DEBUG_DIRECTORY pFpoDebugDirectory = NULL;
  45. DWORD DebugDirectorySize, DbgFileHeaderSize, NumberOfDebugDirectories;
  46. IMAGE_SEPARATE_DEBUG_HEADER DbgFileHeader;
  47. PIMAGE_EXPORT_DIRECTORY ExportDirectory;
  48. DWORD ExportedNamesSize;
  49. LPDWORD pp;
  50. LPSTR ExportedNames, Src, Dst;
  51. DWORD i, j, RvaOffset, ExportDirectorySize;
  52. PFPO_DATA FpoTable;
  53. DWORD FpoTableSize;
  54. PIMAGE_RUNTIME_FUNCTION_ENTRY RuntimeFunctionTable, pSrc;
  55. DWORD RuntimeFunctionTableSize;
  56. PIMAGE_FUNCTION_ENTRY FunctionTable, pDst;
  57. DWORD FunctionTableSize;
  58. ULONG NumberOfFunctionTableEntries, DbgOffset;
  59. DWORD SavedErrorCode;
  60. BOOL InsertExtensionSubDir;
  61. LPSTR ImageFilePathToSaveInImage;
  62. BOOL MiscInRdata = FALSE;
  63. BOOL DiscardFPO = Flags & SPLITSYM_EXTRACT_ALL;
  64. BOOL fNewCvData = FALSE;
  65. PCHAR NewDebugData = NULL;
  66. ImageFileName = ImageName + strlen( ImageName );
  67. while (ImageFileName > ImageName) {
  68. if (ImageFileName[ -1 ] == '\\' ||
  69. ImageFileName[ -1 ] == '/' ||
  70. ImageFileName[ -1 ] == ':' )
  71. {
  72. break;
  73. } else {
  74. ImageFileName -= 1;
  75. }
  76. }
  77. if (SymbolsPath == NULL ||
  78. SymbolsPath[ 0 ] == '\0' ||
  79. SymbolsPath[ 0 ] == '.' )
  80. {
  81. strncpy( SymbolFilePath, ImageName, ImageFileName - ImageName );
  82. SymbolFilePath[ ImageFileName - ImageName ] = '\0';
  83. InsertExtensionSubDir = FALSE;
  84. } else {
  85. strcpy( SymbolFilePath, SymbolsPath );
  86. InsertExtensionSubDir = TRUE;
  87. }
  88. Dst = SymbolFilePath + strlen( SymbolFilePath );
  89. if ((Dst > SymbolFilePath) &&
  90. (Dst[-1] != '\\') &&
  91. (Dst[-1] != '/') &&
  92. (Dst[-1] != ':') )
  93. {
  94. *Dst++ = '\\';
  95. }
  96. ImageFilePathToSaveInImage = Dst;
  97. Src = strrchr( ImageFileName, '.' );
  98. if (Src != NULL && InsertExtensionSubDir) {
  99. while (*Dst = *++Src) {
  100. Dst += 1;
  101. }
  102. *Dst++ = '\\';
  103. }
  104. strcpy( Dst, ImageFileName );
  105. Dst = strrchr( Dst, '.' );
  106. if (Dst == NULL) {
  107. Dst = SymbolFilePath + strlen( SymbolFilePath );
  108. }
  109. strcpy( Dst, ".dbg" );
  110. // Make sure we can open the .dbg file before we continue...
  111. if (!MakeSureDirectoryPathExists( SymbolFilePath ))
  112. return FALSE;
  113. // Now, open and map the input file.
  114. FileHandle = CreateFile( ImageName,
  115. GENERIC_READ | GENERIC_WRITE,
  116. FILE_SHARE_READ,
  117. NULL,
  118. OPEN_EXISTING,
  119. 0,
  120. NULL
  121. );
  122. if (FileHandle == INVALID_HANDLE_VALUE) {
  123. return FALSE;
  124. }
  125. hMappedFile = CreateFileMapping( FileHandle,
  126. NULL,
  127. PAGE_READWRITE,
  128. 0,
  129. 0,
  130. NULL
  131. );
  132. if (!hMappedFile) {
  133. CloseHandle( FileHandle );
  134. return FALSE;
  135. }
  136. ImageBase = MapViewOfFile( hMappedFile,
  137. FILE_MAP_WRITE,
  138. 0,
  139. 0,
  140. 0
  141. );
  142. if (!ImageBase) {
  143. CloseHandle( hMappedFile );
  144. CloseHandle( FileHandle );
  145. return FALSE;
  146. }
  147. //
  148. // Everything is mapped. Now check the image and find nt image headers
  149. //
  150. NtHeaders = ImageNtHeader( ImageBase );
  151. if (NtHeaders == NULL) {
  152. UnmapViewOfFile( ImageBase );
  153. CloseHandle( hMappedFile );
  154. CloseHandle( FileHandle );
  155. SetLastError( ERROR_BAD_EXE_FORMAT );
  156. return FALSE;
  157. }
  158. if ((NtHeaders->OptionalHeader.MajorLinkerVersion < 3) &&
  159. (NtHeaders->OptionalHeader.MinorLinkerVersion < 5) )
  160. {
  161. UnmapViewOfFile( ImageBase );
  162. CloseHandle( hMappedFile );
  163. CloseHandle( FileHandle );
  164. SetLastError( ERROR_BAD_EXE_FORMAT );
  165. return FALSE;
  166. }
  167. if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
  168. {
  169. // The symbols have already been stripped. No need to continue.
  170. UnmapViewOfFile( ImageBase );
  171. CloseHandle( hMappedFile );
  172. CloseHandle( FileHandle );
  173. SetLastError( ERROR_ALREADY_ASSIGNED );
  174. return FALSE;
  175. }
  176. DebugDirectories = (PIMAGE_DEBUG_DIRECTORY) ImageDirectoryEntryToData( ImageBase,
  177. FALSE,
  178. IMAGE_DIRECTORY_ENTRY_DEBUG,
  179. &DebugDirectorySize
  180. );
  181. if (!DebugDirectoryIsUseful(DebugDirectories, DebugDirectorySize)) {
  182. UnmapViewOfFile( ImageBase );
  183. CloseHandle( hMappedFile );
  184. CloseHandle( FileHandle );
  185. SetLastError( ERROR_BAD_EXE_FORMAT );
  186. return FALSE;
  187. }
  188. // Try to open the symbol file
  189. SymbolFileHandle = CreateFile( SymbolFilePath,
  190. GENERIC_WRITE,
  191. 0,
  192. NULL,
  193. CREATE_ALWAYS,
  194. 0,
  195. NULL
  196. );
  197. if (SymbolFileHandle == INVALID_HANDLE_VALUE)
  198. goto nosyms;
  199. NumberOfDebugDirectories = DebugDirectorySize / sizeof( IMAGE_DEBUG_DIRECTORY );
  200. // The entire file is mapped so we don't have to care if the rva's
  201. // are correct. It is interesting to note if there's a debug section
  202. // we need to whack before terminating, though.
  203. {
  204. PIMAGE_SECTION_HEADER Sections;
  205. Sections = IMAGE_FIRST_SECTION( NtHeaders );
  206. for (SectionNumber = 0;
  207. SectionNumber < NtHeaders->FileHeader.NumberOfSections;
  208. SectionNumber++ ) {
  209. if (Sections[ SectionNumber ].PointerToRawData != 0 &&
  210. !_stricmp( (char *) Sections[ SectionNumber ].Name, ".debug" )) {
  211. DebugSection = &Sections[ SectionNumber ];
  212. }
  213. }
  214. }
  215. FpoTable = NULL;
  216. ExportedNames = NULL;
  217. DebugSectionStart = 0xffffffff;
  218. //
  219. // Find the size of the debug section.
  220. //
  221. SizeOfSymbols = 0;
  222. for (i=0,DebugDirectory=DebugDirectories; i<NumberOfDebugDirectories; i++,DebugDirectory++) {
  223. switch (DebugDirectory->Type) {
  224. case IMAGE_DEBUG_TYPE_MISC :
  225. // Save it away.
  226. MiscDebugDirectory = *DebugDirectory;
  227. // check to see if the misc debug data is in some other section.
  228. // If Address Of Raw Data is cleared, it must be in .debug (there's no such thing as not-mapped rdata)
  229. // If it's set and there's no debug section, it must be somewhere else.
  230. // If it's set and there's a debug section, check the range.
  231. if ((DebugDirectory->AddressOfRawData != 0) &&
  232. ((DebugSection == NULL) ||
  233. (((DebugDirectory->PointerToRawData < DebugSection->PointerToRawData) ||
  234. (DebugDirectory->PointerToRawData >= DebugSection->PointerToRawData + DebugSection->SizeOfRawData)
  235. )
  236. )
  237. )
  238. )
  239. {
  240. MiscInRdata = TRUE;
  241. } else {
  242. if (DebugDirectory->PointerToRawData < DebugSectionStart) {
  243. DebugSectionStart = DebugDirectory->PointerToRawData;
  244. }
  245. }
  246. break;
  247. case IMAGE_DEBUG_TYPE_FPO:
  248. if (DebugDirectory->PointerToRawData < DebugSectionStart) {
  249. DebugSectionStart = DebugDirectory->PointerToRawData;
  250. }
  251. // Save it away.
  252. FpoDebugDirectory = *DebugDirectory;
  253. pFpoDebugDirectory = DebugDirectory;
  254. break;
  255. case IMAGE_DEBUG_TYPE_CODEVIEW:
  256. {
  257. ULONG NewDebugSize;
  258. if (DebugDirectory->PointerToRawData < DebugSectionStart) {
  259. DebugSectionStart = DebugDirectory->PointerToRawData;
  260. }
  261. // If private's are removed, do so and save the new size...
  262. if (Flags & SPLITSYM_REMOVE_PRIVATE) {
  263. if (RemovePrivateCvSymbolic(DebugDirectory->PointerToRawData + (PCHAR)ImageBase,
  264. &NewDebugData,
  265. &NewDebugSize)) {
  266. DebugDirectory->PointerToRawData = (ULONG) (NewDebugData - (PCHAR)ImageBase);
  267. DebugDirectory->SizeOfData = NewDebugSize;
  268. }
  269. }
  270. if (DebugDirectory->SizeOfData && DebugDirectory->PointerToRawData) {
  271. // If there's a .pdb, copy it to the same location as the .dbg file.
  272. typedef struct NB10I // NB10 debug info
  273. {
  274. DWORD nb10; // NB10
  275. DWORD off; // offset, always 0
  276. DWORD sig;
  277. DWORD age;
  278. } NB10I;
  279. NB10I *pNB10Info;
  280. pNB10Info = (NB10I *) (DebugDirectory->PointerToRawData + (PCHAR)ImageBase);
  281. if (pNB10Info->nb10 == '01BN') {
  282. // Got a PDB. The name immediately follows the signature.
  283. CHAR PdbName[_MAX_PATH];
  284. CHAR NewPdbName[_MAX_PATH];
  285. CHAR Drive[_MAX_DRIVE];
  286. CHAR Dir[_MAX_DIR];
  287. CHAR Filename[_MAX_FNAME];
  288. CHAR FileExt[_MAX_EXT];
  289. memset(PdbName, 0, sizeof(PdbName));
  290. memcpy(PdbName, ((PCHAR)pNB10Info) + sizeof(NB10I), DebugDirectory->SizeOfData - sizeof(NB10I));
  291. _splitpath(PdbName, NULL, NULL, Filename, FileExt);
  292. _splitpath(SymbolFilePath, Drive, Dir, NULL, NULL);
  293. _makepath(NewPdbName, Drive, Dir, Filename, FileExt);
  294. if ( !CopyFile(PdbName, NewPdbName, FALSE)) {
  295. // It's possible the name in the pdb isn't in the same location as it was when built. See if we can
  296. // find it in the same dir as the image...
  297. _splitpath(ImageName, Drive, Dir, NULL, NULL);
  298. _makepath(PdbName, Drive, Dir, Filename, FileExt);
  299. CopyFile(PdbName, NewPdbName, FALSE);
  300. }
  301. SetFileAttributes(NewPdbName, FILE_ATTRIBUTE_NORMAL);
  302. // Change the data so only the pdb name is in the .dbg file (no path).
  303. NewDebugSize = sizeof(NB10I) + strlen(Filename) + strlen(FileExt) + 1;
  304. NewDebugData = (PCHAR) MemAlloc( NewDebugSize );
  305. *(NB10I *)NewDebugData = *pNB10Info;
  306. strcpy(NewDebugData + sizeof(NB10I), Filename);
  307. strcat(NewDebugData + sizeof(NB10I), FileExt);
  308. DebugDirectory->PointerToRawData = (ULONG) (NewDebugData - (PCHAR)ImageBase);
  309. DebugDirectory->SizeOfData = NewDebugSize;
  310. }
  311. }
  312. }
  313. break;
  314. case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
  315. case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
  316. if (DebugDirectory->PointerToRawData < DebugSectionStart) {
  317. DebugSectionStart = DebugDirectory->PointerToRawData;
  318. }
  319. // W/o the OMAP, FPO is useless.
  320. DiscardFPO = TRUE;
  321. break;
  322. case IMAGE_DEBUG_TYPE_FIXUP:
  323. if (DebugDirectory->PointerToRawData < DebugSectionStart) {
  324. DebugSectionStart = DebugDirectory->PointerToRawData;
  325. }
  326. // If all PRIVATE debug is removed, don't send FIXUP along.
  327. if (Flags & SPLITSYM_REMOVE_PRIVATE) {
  328. DebugDirectory->SizeOfData = 0;
  329. }
  330. break;
  331. default:
  332. if (DebugDirectory->PointerToRawData < DebugSectionStart) {
  333. DebugSectionStart = DebugDirectory->PointerToRawData;
  334. }
  335. // Nothing else to special case...
  336. break;
  337. }
  338. SizeOfSymbols += (DebugDirectory->SizeOfData + 3) & ~3; // Minimally align it all.
  339. }
  340. if (DiscardFPO) {
  341. pFpoDebugDirectory = NULL;
  342. }
  343. if (pFpoDebugDirectory) {
  344. // If FPO stays here, make a copy so we don't need to worry about stomping on it.
  345. FpoTableSize = pFpoDebugDirectory->SizeOfData;
  346. FpoTable = (PFPO_DATA) MemAlloc( FpoTableSize );
  347. if ( FpoTable == NULL ) {
  348. goto nosyms;
  349. }
  350. RtlMoveMemory( FpoTable,
  351. (PCHAR) ImageBase + pFpoDebugDirectory->PointerToRawData,
  352. FpoTableSize );
  353. }
  354. ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)
  355. ImageDirectoryEntryToData( ImageBase,
  356. FALSE,
  357. IMAGE_DIRECTORY_ENTRY_EXPORT,
  358. &ExportDirectorySize
  359. );
  360. if (ExportDirectory) {
  361. //
  362. // This particular piece of magic gets us the RVA of the
  363. // EXPORT section. Dont ask.
  364. //
  365. RvaOffset = (DWORD)
  366. ImageDirectoryEntryToData( ImageBase,
  367. TRUE,
  368. IMAGE_DIRECTORY_ENTRY_EXPORT,
  369. &ExportDirectorySize
  370. ) - (DWORD)ImageBase;
  371. pp = (LPDWORD)((DWORD)ExportDirectory +
  372. (DWORD)ExportDirectory->AddressOfNames - RvaOffset
  373. );
  374. ExportedNamesSize = 1;
  375. for (i=0; i<ExportDirectory->NumberOfNames; i++) {
  376. Src = (LPSTR)((DWORD)ExportDirectory + *pp++ - RvaOffset);
  377. ExportedNamesSize += strlen( Src ) + 1;
  378. }
  379. ExportedNamesSize = (ExportedNamesSize + 16) & ~15;
  380. Dst = (LPSTR) MemAlloc( ExportedNamesSize );
  381. if (Dst != NULL) {
  382. ExportedNames = Dst;
  383. pp = (LPDWORD)((DWORD)ExportDirectory +
  384. (DWORD)ExportDirectory->AddressOfNames - RvaOffset
  385. );
  386. for (i=0; i<ExportDirectory->NumberOfNames; i++) {
  387. Src = (LPSTR)((DWORD)ExportDirectory + *pp++ - RvaOffset);
  388. while (*Dst++ = *Src++) {
  389. }
  390. }
  391. }
  392. } else {
  393. ExportedNamesSize = 0;
  394. }
  395. RuntimeFunctionTable = (PIMAGE_RUNTIME_FUNCTION_ENTRY)
  396. ImageDirectoryEntryToData( ImageBase,
  397. FALSE,
  398. IMAGE_DIRECTORY_ENTRY_EXCEPTION,
  399. &RuntimeFunctionTableSize
  400. );
  401. if (RuntimeFunctionTable == NULL) {
  402. RuntimeFunctionTableSize = 0;
  403. FunctionTableSize = 0;
  404. FunctionTable = NULL;
  405. }
  406. else {
  407. NumberOfFunctionTableEntries = RuntimeFunctionTableSize / sizeof( IMAGE_RUNTIME_FUNCTION_ENTRY );
  408. FunctionTableSize = NumberOfFunctionTableEntries * sizeof( IMAGE_FUNCTION_ENTRY );
  409. FunctionTable = (PIMAGE_FUNCTION_ENTRY) MemAlloc( FunctionTableSize );
  410. if (FunctionTable == NULL) {
  411. goto nosyms;
  412. }
  413. pSrc = RuntimeFunctionTable;
  414. pDst = FunctionTable;
  415. for (i=0; i<NumberOfFunctionTableEntries; i++) {
  416. //
  417. // Make .pdata entries in .DBG file relative.
  418. //
  419. pDst->StartingAddress = pSrc->BeginAddress - NtHeaders->OptionalHeader.ImageBase;
  420. pDst->EndingAddress = pSrc->EndAddress - NtHeaders->OptionalHeader.ImageBase;
  421. pDst->EndOfPrologue = pSrc->PrologEndAddress - NtHeaders->OptionalHeader.ImageBase;
  422. pSrc += 1;
  423. pDst += 1;
  424. }
  425. }
  426. DbgFileHeaderSize = sizeof( DbgFileHeader ) +
  427. ((NtHeaders->FileHeader.NumberOfSections - (DebugSection ? 1 : 0)) *
  428. sizeof( IMAGE_SECTION_HEADER )) +
  429. ExportedNamesSize +
  430. FunctionTableSize +
  431. DebugDirectorySize;
  432. if (FunctionTable != NULL) {
  433. DbgFileHeaderSize += sizeof( IMAGE_DEBUG_DIRECTORY );
  434. memset( &FunctionTableDir, 0, sizeof( IMAGE_DEBUG_DIRECTORY ) );
  435. FunctionTableDir.Type = IMAGE_DEBUG_TYPE_EXCEPTION;
  436. FunctionTableDir.SizeOfData = FunctionTableSize;
  437. FunctionTableDir.PointerToRawData = DbgFileHeaderSize - FunctionTableSize;
  438. }
  439. DbgFileHeaderSize = ((DbgFileHeaderSize + 15) & ~15);
  440. BytesWritten = 0;
  441. if (SetFilePointer( SymbolFileHandle,
  442. DbgFileHeaderSize,
  443. NULL,
  444. FILE_BEGIN
  445. ) == DbgFileHeaderSize ) {
  446. for (i=0, DebugDirectory=DebugDirectories;
  447. i < NumberOfDebugDirectories;
  448. i++, DebugDirectory++) {
  449. DWORD WriteCount;
  450. if (DebugDirectory->SizeOfData) {
  451. WriteFile( SymbolFileHandle,
  452. (PCHAR) ImageBase + DebugDirectory->PointerToRawData,
  453. (DebugDirectory->SizeOfData +3) & ~3,
  454. &WriteCount,
  455. NULL );
  456. BytesWritten += WriteCount;
  457. }
  458. }
  459. }
  460. if (BytesWritten == SizeOfSymbols) {
  461. NtHeaders->FileHeader.PointerToSymbolTable = 0;
  462. NtHeaders->FileHeader.Characteristics |= IMAGE_FILE_DEBUG_STRIPPED;
  463. if (DebugSection != NULL) {
  464. NtHeaders->OptionalHeader.SizeOfImage = DebugSection->VirtualAddress;
  465. NtHeaders->OptionalHeader.SizeOfInitializedData -= DebugSection->SizeOfRawData;
  466. NtHeaders->FileHeader.NumberOfSections--;
  467. // NULL out that section
  468. memset(DebugSection, 0, IMAGE_SIZEOF_SECTION_HEADER);
  469. }
  470. NewFileSize = DebugSectionStart; // Start with no symbolic
  471. //
  472. // Now that the data has moved to the .dbg file, rebuild the original
  473. // with MISC debug first and FPO second.
  474. //
  475. if (MiscDebugDirectory.SizeOfData) {
  476. if (MiscInRdata) {
  477. // Just store the new name in the existing misc field...
  478. ImageNameOffset = (DWORD) ((PCHAR)ImageBase +
  479. MiscDebugDirectory.PointerToRawData +
  480. FIELD_OFFSET( IMAGE_DEBUG_MISC, Data ));
  481. RtlCopyMemory( (LPVOID) ImageNameOffset,
  482. ImageFilePathToSaveInImage,
  483. strlen(ImageFilePathToSaveInImage) + 1 );
  484. } else {
  485. if (DebugSectionStart != MiscDebugDirectory.PointerToRawData) {
  486. RtlMoveMemory((PCHAR) ImageBase + DebugSectionStart,
  487. (PCHAR) ImageBase + MiscDebugDirectory.PointerToRawData,
  488. MiscDebugDirectory.SizeOfData);
  489. }
  490. ImageNameOffset = (DWORD) ((PCHAR)ImageBase + DebugSectionStart +
  491. FIELD_OFFSET( IMAGE_DEBUG_MISC, Data ));
  492. RtlCopyMemory( (LPVOID)ImageNameOffset,
  493. ImageFilePathToSaveInImage,
  494. strlen(ImageFilePathToSaveInImage) + 1 );
  495. NewFileSize += MiscDebugDirectory.SizeOfData;
  496. NewFileSize = (NewFileSize + 3) & ~3;
  497. }
  498. }
  499. if (FpoTable) {
  500. RtlCopyMemory( (PCHAR) ImageBase + NewFileSize,
  501. FpoTable,
  502. FpoTableSize );
  503. NewFileSize += FpoTableSize;
  504. NewFileSize = (NewFileSize + 3) & ~3;
  505. }
  506. // Make a copy of the Debug directory that we can write into the .dbg file
  507. DbgDebugDirectories = (PIMAGE_DEBUG_DIRECTORY) MemAlloc( NumberOfDebugDirectories * sizeof(IMAGE_DEBUG_DIRECTORY) );
  508. RtlMoveMemory(DbgDebugDirectories,
  509. DebugDirectories,
  510. sizeof(IMAGE_DEBUG_DIRECTORY) * NumberOfDebugDirectories);
  511. // Then write the MISC and (perhaps) FPO data to the image.
  512. FpoDebugDirectory.PointerToRawData = DebugSectionStart;
  513. DebugDirectorySize = 0;
  514. if (MiscDebugDirectory.SizeOfData != 0) {
  515. if (!MiscInRdata) {
  516. MiscDebugDirectory.PointerToRawData = DebugSectionStart;
  517. FpoDebugDirectory.PointerToRawData += MiscDebugDirectory.SizeOfData;
  518. MiscDebugDirectory.AddressOfRawData = 0;
  519. }
  520. DebugDirectories[0] = MiscDebugDirectory;
  521. DebugDirectorySize += sizeof(IMAGE_DEBUG_DIRECTORY);
  522. }
  523. if (pFpoDebugDirectory) {
  524. FpoDebugDirectory.AddressOfRawData = 0;
  525. DebugDirectories[1] = FpoDebugDirectory;
  526. DebugDirectorySize += sizeof(IMAGE_DEBUG_DIRECTORY);
  527. }
  528. NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size = DebugDirectorySize;
  529. DbgOffset = DbgFileHeaderSize;
  530. for (i = 0, j=0, DebugDirectory=DbgDebugDirectories;
  531. i < NumberOfDebugDirectories; i++) {
  532. if (DebugDirectory[i].SizeOfData) {
  533. DebugDirectory[j] = DebugDirectory[i];
  534. DebugDirectory[j].AddressOfRawData = 0;
  535. DebugDirectory[j].PointerToRawData = DbgOffset;
  536. DbgOffset += (DebugDirectory[j].SizeOfData + 3 )& ~3;
  537. j++;
  538. }
  539. }
  540. if (FunctionTable) {
  541. FunctionTableDir.PointerToRawData -= sizeof(IMAGE_DEBUG_DIRECTORY) * (NumberOfDebugDirectories - j);
  542. }
  543. NumberOfDebugDirectories = j;
  544. CheckSumMappedFile( ImageBase,
  545. NewFileSize,
  546. &HeaderSum,
  547. &CheckSum
  548. );
  549. NtHeaders->OptionalHeader.CheckSum = CheckSum;
  550. DbgFileHeader.Signature = IMAGE_SEPARATE_DEBUG_SIGNATURE;
  551. DbgFileHeader.Flags = 0;
  552. DbgFileHeader.Machine = NtHeaders->FileHeader.Machine;
  553. DbgFileHeader.Characteristics = NtHeaders->FileHeader.Characteristics;
  554. DbgFileHeader.TimeDateStamp = NtHeaders->FileHeader.TimeDateStamp;
  555. DbgFileHeader.CheckSum = CheckSum;
  556. DbgFileHeader.ImageBase = NtHeaders->OptionalHeader.ImageBase;
  557. DbgFileHeader.SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;
  558. DbgFileHeader.ExportedNamesSize = ExportedNamesSize;
  559. DbgFileHeader.DebugDirectorySize = NumberOfDebugDirectories * sizeof(IMAGE_DEBUG_DIRECTORY);
  560. if (FunctionTable) {
  561. DbgFileHeader.DebugDirectorySize += sizeof (IMAGE_DEBUG_DIRECTORY);
  562. }
  563. DbgFileHeader.NumberOfSections = NtHeaders->FileHeader.NumberOfSections;
  564. memset( DbgFileHeader.Reserved, 0, sizeof( DbgFileHeader.Reserved ) );
  565. DbgFileHeader.SectionAlignment = NtHeaders->OptionalHeader.SectionAlignment;
  566. SetFilePointer( SymbolFileHandle, 0, NULL, FILE_BEGIN );
  567. WriteFile( SymbolFileHandle,
  568. &DbgFileHeader,
  569. sizeof( DbgFileHeader ),
  570. &BytesWritten,
  571. NULL
  572. );
  573. WriteFile( SymbolFileHandle,
  574. IMAGE_FIRST_SECTION( NtHeaders ),
  575. sizeof( IMAGE_SECTION_HEADER ) * NtHeaders->FileHeader.NumberOfSections,
  576. &BytesWritten,
  577. NULL
  578. );
  579. if (ExportedNamesSize) {
  580. WriteFile( SymbolFileHandle,
  581. ExportedNames,
  582. ExportedNamesSize,
  583. &BytesWritten,
  584. NULL
  585. );
  586. }
  587. WriteFile( SymbolFileHandle,
  588. DbgDebugDirectories,
  589. sizeof (IMAGE_DEBUG_DIRECTORY) * NumberOfDebugDirectories,
  590. &BytesWritten,
  591. NULL );
  592. if (FunctionTable) {
  593. WriteFile( SymbolFileHandle,
  594. &FunctionTableDir,
  595. sizeof (IMAGE_DEBUG_DIRECTORY),
  596. &BytesWritten,
  597. NULL );
  598. WriteFile( SymbolFileHandle,
  599. FunctionTable,
  600. FunctionTableSize,
  601. &BytesWritten,
  602. NULL
  603. );
  604. }
  605. SetFilePointer( SymbolFileHandle, 0, NULL, FILE_END );
  606. CloseHandle( SymbolFileHandle );
  607. FlushViewOfFile( ImageBase, NewFileSize );
  608. UnmapViewOfFile( ImageBase );
  609. CloseHandle( hMappedFile );
  610. SetFilePointer( FileHandle, NewFileSize, NULL, FILE_BEGIN );
  611. SetEndOfFile( FileHandle );
  612. TouchFileTimes( FileHandle, NULL );
  613. CloseHandle( FileHandle );
  614. if (ExportedNames != NULL) {
  615. MemFree( ExportedNames );
  616. }
  617. if (FpoTable != NULL) {
  618. MemFree( FpoTable );
  619. }
  620. if (FunctionTable != NULL) {
  621. MemFree( FunctionTable );
  622. }
  623. if (NewDebugData) {
  624. MemFree(NewDebugData);
  625. }
  626. if (DbgDebugDirectories) {
  627. MemFree(DbgDebugDirectories);
  628. }
  629. return TRUE;
  630. } else {
  631. CloseHandle( SymbolFileHandle );
  632. DeleteFile( SymbolFilePath );
  633. }
  634. nosyms:
  635. SavedErrorCode = GetLastError();
  636. if (ExportedNames != NULL) {
  637. MemFree( ExportedNames );
  638. }
  639. if (FpoTable != NULL) {
  640. MemFree( FpoTable );
  641. }
  642. if (FunctionTable != NULL) {
  643. MemFree( FunctionTable );
  644. }
  645. UnmapViewOfFile( ImageBase );
  646. CloseHandle( hMappedFile );
  647. CloseHandle( FileHandle );
  648. SetLastError( SavedErrorCode );
  649. return FALSE;
  650. }
  651. BOOL
  652. SearchTreeForFile(
  653. LPSTR RootPath,
  654. PCHAR InputPathName,
  655. PCHAR OutputPathBuffer
  656. );
  657. HANDLE
  658. FindExecutableImage(
  659. LPSTR FileName,
  660. LPSTR SymbolPath,
  661. LPSTR ImageFilePath
  662. );
  663. BOOL
  664. GetImageNameFromMiscDebugData(
  665. HANDLE FileHandle,
  666. PVOID MappedBase,
  667. PIMAGE_NT_HEADERS NtHeaders,
  668. PIMAGE_DEBUG_DIRECTORY DebugDirectories,
  669. ULONG NumberOfDebugDirectories,
  670. LPSTR ImageFilePath
  671. );
  672. #define AddToDebugInfoSize(x) (DebugInfoSize += (((x + 7) & ~7)+4)) // Make sure all the con's start at a qword boundary
  673. #define AdvanceNext(x) (Next = (PVOID)((((ULONG)Next + x) + 7) & ~7))
  674. void
  675. ProcessDbgFile(
  676. PIMAGE_DEBUG_INFORMATION DebugInfo,
  677. PIMAGE_SEPARATE_DEBUG_HEADER DebugFileHeader,
  678. ULONG ImageBase,
  679. ULONG FunctionTableSize,
  680. ULONG DebugInfoHeaderSize
  681. )
  682. {
  683. PVOID MappedBase, Next;
  684. PIMAGE_DEBUG_DIRECTORY DebugDirectory;
  685. ULONG i, j;
  686. ULONG NumberOfDebugDirectories;
  687. LONG BaseOffset;
  688. PIMAGE_FUNCTION_ENTRY FunctionTable;
  689. //
  690. // .DBG file processing
  691. //
  692. DebugInfo->Machine = DebugFileHeader->Machine;
  693. DebugInfo->Characteristics = DebugFileHeader->Characteristics;
  694. DebugInfo->TimeDateStamp = DebugFileHeader->TimeDateStamp;
  695. DebugInfo->CheckSum = DebugFileHeader->CheckSum;
  696. DebugInfo->ImageBase = DebugFileHeader->ImageBase;
  697. DebugInfo->SizeOfImage = DebugFileHeader->SizeOfImage;
  698. DebugInfo->NumberOfSections = DebugFileHeader->NumberOfSections;
  699. DebugInfo->Sections = (PIMAGE_SECTION_HEADER)(DebugFileHeader + 1);
  700. Next = (PVOID)(DebugInfo->Sections + DebugInfo->NumberOfSections);
  701. DebugInfo->ExportedNamesSize = DebugFileHeader->ExportedNamesSize;
  702. if (DebugInfo->ExportedNamesSize) {
  703. DebugInfo->ExportedNames = (LPSTR)Next;
  704. Next = (PVOID)((PCHAR)Next + DebugInfo->ExportedNamesSize);
  705. }
  706. DebugDirectory = DebugInfo->DebugDirectory;
  707. MappedBase = DebugInfo->MappedBase;
  708. NumberOfDebugDirectories = DebugFileHeader->DebugDirectorySize / sizeof( IMAGE_DEBUG_DIRECTORY );
  709. Next = (PVOID)((PCHAR)Next + DebugFileHeader->DebugDirectorySize);
  710. for (i=0; i<NumberOfDebugDirectories; i++) {
  711. switch (DebugDirectory->Type) {
  712. case IMAGE_DEBUG_TYPE_EXCEPTION:
  713. DebugInfo->FunctionTableEntries = (PIMAGE_FUNCTION_ENTRY)
  714. ((PCHAR)MappedBase + DebugDirectory->PointerToRawData);
  715. BaseOffset = ImageBase ? ImageBase : DebugInfo->ImageBase;
  716. FunctionTable = (PIMAGE_FUNCTION_ENTRY)((ULONG)DebugInfo + DebugInfoHeaderSize);
  717. memmove( FunctionTable, DebugInfo->FunctionTableEntries, FunctionTableSize );
  718. DebugInfo->FunctionTableEntries = FunctionTable;
  719. DebugInfo->LowestFunctionStartingAddress = (ULONG)0xFFFFFFFF;
  720. DebugInfo->HighestFunctionEndingAddress = 0;
  721. for (j=0; j<DebugInfo->NumberOfFunctionTableEntries; j++) {
  722. FunctionTable->StartingAddress += BaseOffset;
  723. if (FunctionTable->StartingAddress < DebugInfo->LowestFunctionStartingAddress) {
  724. DebugInfo->LowestFunctionStartingAddress = FunctionTable->StartingAddress;
  725. }
  726. FunctionTable->EndingAddress += BaseOffset;
  727. if (FunctionTable->EndingAddress > DebugInfo->HighestFunctionEndingAddress) {
  728. DebugInfo->HighestFunctionEndingAddress = FunctionTable->EndingAddress;
  729. }
  730. FunctionTable->EndOfPrologue += BaseOffset;
  731. FunctionTable += 1;
  732. }
  733. break;
  734. case IMAGE_DEBUG_TYPE_FPO:
  735. DebugInfo->NumberOfFpoTableEntries = DebugDirectory->SizeOfData / sizeof( FPO_DATA );
  736. DebugInfo->FpoTableEntries = (PFPO_DATA) ((PCHAR)MappedBase + DebugDirectory->PointerToRawData);
  737. break;
  738. case IMAGE_DEBUG_TYPE_COFF:
  739. DebugInfo->SizeOfCoffSymbols = DebugDirectory->SizeOfData;
  740. DebugInfo->CoffSymbols = (PIMAGE_COFF_SYMBOLS_HEADER) ((PCHAR)MappedBase + DebugDirectory->PointerToRawData);
  741. break;
  742. case IMAGE_DEBUG_TYPE_CODEVIEW:
  743. DebugInfo->SizeOfCodeViewSymbols = DebugDirectory->SizeOfData;
  744. DebugInfo->CodeViewSymbols = (PVOID) ((PCHAR)MappedBase + DebugDirectory->PointerToRawData);
  745. break;
  746. }
  747. DebugDirectory++;
  748. }
  749. }
  750. PIMAGE_DEBUG_INFORMATION
  751. MapDebugInformation(
  752. HANDLE FileHandle,
  753. LPSTR FileName,
  754. LPSTR SymbolPath,
  755. ULONG ImageBase
  756. )
  757. {
  758. ULONG NumberOfHandlesToClose;
  759. HANDLE HandlesToClose[ 4 ];
  760. HANDLE MappingHandle;
  761. PVOID MappedBase, Next;
  762. BOOL SeparateSymbols;
  763. UCHAR ImageFilePath[ MAX_PATH ];
  764. UCHAR DebugFilePath[ MAX_PATH ];
  765. PIMAGE_DEBUG_INFORMATION DebugInfo;
  766. PIMAGE_NT_HEADERS NtHeaders;
  767. PIMAGE_DEBUG_DIRECTORY DebugDirectories;
  768. PIMAGE_DEBUG_DIRECTORY DebugDirectory;
  769. PIMAGE_SEPARATE_DEBUG_HEADER DebugFileHeader;
  770. PIMAGE_EXPORT_DIRECTORY ExportDirectory;
  771. PIMAGE_RUNTIME_FUNCTION_ENTRY RuntimeFunctionTable;
  772. PIMAGE_FUNCTION_ENTRY FunctionTable;
  773. ULONG NumberOfFunctionTableEntries, FunctionTableSize;
  774. PVOID DebugData;
  775. LPSTR Src, Dst;
  776. PULONG pp;
  777. ULONG RvaOffset;
  778. ULONG i, j;
  779. ULONG ExportedNamesSize;
  780. ULONG DebugInfoHeaderSize;
  781. ULONG DebugInfoSize = 0;
  782. ULONG Size;
  783. ULONG NumberOfDebugDirectories;
  784. LONG BaseOffset;
  785. HANDLE SavedImageFileHandle;
  786. BOOL RomImage = FALSE;
  787. PIMAGE_ROM_HEADERS RomHeader;
  788. ULONG FallbackChecksum;
  789. ULONG FallbackNumberOfSections;
  790. ULONG FallbackSectionSize;
  791. PIMAGE_SECTION_HEADER FallbackSections = NULL;
  792. if (FileHandle == NULL && (FileName == NULL || FileName[ 0 ] == '\0')) {
  793. return NULL;
  794. }
  795. DebugInfo = NULL;
  796. NumberOfHandlesToClose = 0;
  797. MappedBase = NULL;
  798. SeparateSymbols = FALSE;
  799. SavedImageFileHandle = NULL;
  800. if (FileName) {
  801. strcpy(ImageFilePath, FileName);
  802. } else {
  803. ImageFilePath[0] = '\0';
  804. }
  805. NumberOfFunctionTableEntries = 0;
  806. FunctionTableSize = 0;
  807. FunctionTable = NULL;
  808. __try {
  809. __try {
  810. if (FileHandle == NULL) {
  811. FileHandle = FindExecutableImage( FileName, SymbolPath, (PCHAR) ImageFilePath );
  812. if (FileHandle == NULL) {
  813. strcpy( (PCHAR) ImageFilePath, FileName );
  814. getDebugFile:
  815. FileHandle = FindDebugInfoFile( FileName, SymbolPath, (PCHAR) DebugFilePath );
  816. if (FileHandle == NULL) {
  817. if (SavedImageFileHandle != NULL) {
  818. FileHandle = SavedImageFileHandle;
  819. goto noDebugFile;
  820. }
  821. else {
  822. __leave;
  823. }
  824. }
  825. else {
  826. SeparateSymbols = TRUE;
  827. }
  828. }
  829. else {
  830. SavedImageFileHandle = FileHandle;
  831. }
  832. HandlesToClose[ NumberOfHandlesToClose++ ] = FileHandle;
  833. }
  834. else {
  835. SavedImageFileHandle = FileHandle;
  836. }
  837. //
  838. // map image file and process enough to get the image name and capture
  839. // stuff from header.
  840. //
  841. MappingHandle = CreateFileMapping( FileHandle,
  842. NULL,
  843. PAGE_READONLY,
  844. 0,
  845. 0,
  846. NULL
  847. );
  848. if (MappingHandle == NULL) {
  849. __leave;
  850. }
  851. HandlesToClose[ NumberOfHandlesToClose++ ] = MappingHandle;
  852. MappedBase = MapViewOfFile( MappingHandle,
  853. FILE_MAP_READ,
  854. 0,
  855. 0,
  856. 0
  857. );
  858. if (MappedBase == NULL) {
  859. __leave;
  860. }
  861. AddToDebugInfoSize((sizeof( *DebugInfo ) + strlen( (PCHAR) ImageFilePath ) + 1));
  862. if (SeparateSymbols) {
  863. AddToDebugInfoSize((strlen( (PCHAR) DebugFilePath ) + 1));
  864. }
  865. if (!SeparateSymbols) {
  866. NtHeaders = ImageNtHeader( MappedBase );
  867. if (NtHeaders == NULL) {
  868. if (((PIMAGE_FILE_HEADER)MappedBase)->SizeOfOptionalHeader == IMAGE_SIZEOF_ROM_OPTIONAL_HEADER) {
  869. //
  870. // rom image
  871. //
  872. RomImage = TRUE;
  873. RomHeader = (PIMAGE_ROM_HEADERS) MappedBase;
  874. } else {
  875. __leave;
  876. }
  877. }
  878. DebugDirectories = (PIMAGE_DEBUG_DIRECTORY)
  879. ImageDirectoryEntryToData( MappedBase,
  880. FALSE,
  881. IMAGE_DIRECTORY_ENTRY_DEBUG,
  882. &Size
  883. );
  884. if (DebugDirectoryIsUseful(DebugDirectories, Size)) {
  885. NumberOfDebugDirectories = Size / sizeof( IMAGE_DEBUG_DIRECTORY );
  886. } else {
  887. NumberOfDebugDirectories = 0;
  888. DebugDirectories = NULL;
  889. }
  890. if (FileName == NULL && NtHeaders &&
  891. GetImageNameFromMiscDebugData( FileHandle,
  892. MappedBase,
  893. NtHeaders,
  894. DebugDirectories,
  895. NumberOfDebugDirectories,
  896. (PCHAR) ImageFilePath
  897. )
  898. ) {
  899. FileName = (PCHAR) ImageFilePath;
  900. AddToDebugInfoSize( strlen((PCHAR) ImageFilePath ));
  901. }
  902. DebugInfoHeaderSize = DebugInfoSize;
  903. FallbackChecksum = NtHeaders->OptionalHeader.CheckSum;
  904. if (RomImage) {
  905. FallbackNumberOfSections = RomHeader->FileHeader.NumberOfSections;
  906. FallbackSectionSize = FallbackNumberOfSections * sizeof(IMAGE_SECTION_HEADER);
  907. FallbackSections = (PIMAGE_SECTION_HEADER)MemAlloc( FallbackSectionSize );
  908. if (!FallbackSections) {
  909. leave;
  910. }
  911. RtlCopyMemory(FallbackSections,
  912. (PVOID)((ULONG)MappedBase +
  913. IMAGE_SIZEOF_ROM_OPTIONAL_HEADER +
  914. IMAGE_SIZEOF_FILE_HEADER ),
  915. FallbackSectionSize);
  916. } else {
  917. FallbackNumberOfSections = NtHeaders->FileHeader.NumberOfSections;
  918. FallbackSectionSize = FallbackNumberOfSections * sizeof(IMAGE_SECTION_HEADER);
  919. FallbackSections = (PIMAGE_SECTION_HEADER)MemAlloc( FallbackSectionSize );
  920. if (!FallbackSections) {
  921. leave;
  922. }
  923. RtlCopyMemory(FallbackSections,
  924. (PVOID)IMAGE_FIRST_SECTION( NtHeaders ),
  925. FallbackSectionSize);
  926. }
  927. if (!RomImage &&
  928. NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) {
  929. goto getDebugFile;
  930. }
  931. if (NumberOfDebugDirectories == 0) {
  932. goto getDebugFile;
  933. }
  934. noDebugFile:
  935. ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)
  936. ImageDirectoryEntryToData( MappedBase,
  937. FALSE,
  938. IMAGE_DIRECTORY_ENTRY_EXPORT,
  939. &Size
  940. );
  941. if (ExportDirectory) {
  942. //
  943. // This particular piece of magic gets us the RVA of the
  944. // EXPORT section. Dont ask.
  945. //
  946. RvaOffset = (ULONG)
  947. ImageDirectoryEntryToData( MappedBase,
  948. TRUE,
  949. IMAGE_DIRECTORY_ENTRY_EXPORT,
  950. &Size
  951. ) - (DWORD)MappedBase;
  952. pp = (PULONG)((ULONG)ExportDirectory +
  953. (ULONG)ExportDirectory->AddressOfNames - RvaOffset
  954. );
  955. ExportedNamesSize = 1;
  956. for (i=0; i<ExportDirectory->NumberOfNames; i++) {
  957. Src = (LPSTR)((ULONG)ExportDirectory + *pp++ - RvaOffset);
  958. ExportedNamesSize += strlen( Src ) + 1;
  959. }
  960. ExportedNamesSize = (ExportedNamesSize + 16) & ~15;
  961. AddToDebugInfoSize(ExportedNamesSize);
  962. }
  963. else {
  964. ExportedNamesSize = 0;
  965. }
  966. RuntimeFunctionTable = (PIMAGE_RUNTIME_FUNCTION_ENTRY)
  967. ImageDirectoryEntryToData( MappedBase,
  968. FALSE,
  969. IMAGE_DIRECTORY_ENTRY_EXCEPTION,
  970. &Size
  971. );
  972. if (RuntimeFunctionTable != NULL) {
  973. NumberOfFunctionTableEntries = Size / sizeof( IMAGE_RUNTIME_FUNCTION_ENTRY );
  974. FunctionTableSize = NumberOfFunctionTableEntries *
  975. sizeof( IMAGE_FUNCTION_ENTRY );
  976. AddToDebugInfoSize(FunctionTableSize);
  977. }
  978. if (NumberOfDebugDirectories != 0) {
  979. DebugDirectory = DebugDirectories;
  980. for (i=0; i<NumberOfDebugDirectories; i++) {
  981. if (DebugDirectory->Type == IMAGE_DEBUG_TYPE_FPO ||
  982. DebugDirectory->Type == IMAGE_DEBUG_TYPE_COFF ||
  983. DebugDirectory->Type == IMAGE_DEBUG_TYPE_CODEVIEW
  984. ) {
  985. AddToDebugInfoSize(DebugDirectory->SizeOfData);
  986. }
  987. DebugDirectory += 1;
  988. }
  989. }
  990. } else {
  991. DebugFileHeader = (PIMAGE_SEPARATE_DEBUG_HEADER)MappedBase;
  992. if (DebugFileHeader->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE) {
  993. //
  994. // Yes, .DBG file information
  995. //
  996. Next = (PVOID)((PIMAGE_SECTION_HEADER)(DebugFileHeader + 1) + DebugFileHeader->NumberOfSections);
  997. if (DebugFileHeader->ExportedNamesSize != 0) {
  998. Next = (PVOID)((PCHAR)Next + DebugFileHeader->ExportedNamesSize);
  999. }
  1000. DebugDirectories = (PIMAGE_DEBUG_DIRECTORY)Next;
  1001. DebugDirectory = DebugDirectories;
  1002. NumberOfDebugDirectories = DebugFileHeader->DebugDirectorySize / sizeof( IMAGE_DEBUG_DIRECTORY );
  1003. for (i=0; i<NumberOfDebugDirectories; i++) {
  1004. if (DebugDirectory->Type == IMAGE_DEBUG_TYPE_EXCEPTION) {
  1005. FunctionTableSize = DebugDirectory->SizeOfData;
  1006. NumberOfFunctionTableEntries = FunctionTableSize / sizeof( IMAGE_FUNCTION_ENTRY );
  1007. break;
  1008. }
  1009. DebugDirectory += 1;
  1010. }
  1011. DebugInfoHeaderSize = DebugInfoSize;
  1012. AddToDebugInfoSize(FunctionTableSize);
  1013. } else {
  1014. //
  1015. // No, some other sort of debug information
  1016. //
  1017. DebugFileHeader = NULL;
  1018. DebugDirectories = NULL;
  1019. DebugDirectory = NULL;
  1020. NumberOfDebugDirectories = 0;
  1021. //
  1022. // We need the fallback section info (add to size and remeber where
  1023. // to store our stuff relative to the rest of the info).
  1024. //
  1025. DebugInfoHeaderSize = DebugInfoSize;
  1026. AddToDebugInfoSize( FallbackSectionSize );
  1027. }
  1028. }
  1029. DebugInfo = (PIMAGE_DEBUG_INFORMATION) MemAlloc( DebugInfoSize );
  1030. if (DebugInfo == NULL) {
  1031. __leave;
  1032. }
  1033. InitializeListHead( &DebugInfo->List );
  1034. DebugInfo->Size = DebugInfoSize;
  1035. DebugInfo->ImageFilePath = (LPSTR)(DebugInfo + 1);
  1036. strcpy( DebugInfo->ImageFilePath, (PCHAR) ImageFilePath );
  1037. Src = strchr( DebugInfo->ImageFilePath, '\0' );
  1038. while (Src > DebugInfo->ImageFilePath) {
  1039. if (Src[ -1 ] == '\\' || Src[ -1 ] == '/' || Src[ -1 ] == ':') {
  1040. break;
  1041. } else {
  1042. Src -= 1;
  1043. }
  1044. }
  1045. DebugInfo->ImageFileName = Src;
  1046. DebugInfo->DebugFilePath = DebugInfo->ImageFilePath;
  1047. if (SeparateSymbols) {
  1048. DebugInfo->DebugFilePath += strlen( DebugInfo->ImageFilePath ) + 1;
  1049. strcpy( DebugInfo->DebugFilePath, (PCHAR) DebugFilePath );
  1050. }
  1051. DebugInfo->MappedBase = MappedBase;
  1052. DebugInfo->DebugDirectory = DebugDirectories;
  1053. DebugInfo->NumberOfDebugDirectories = NumberOfDebugDirectories;
  1054. DebugInfo->NumberOfFunctionTableEntries = NumberOfFunctionTableEntries;
  1055. if (SeparateSymbols) {
  1056. if (DebugFileHeader) {
  1057. ProcessDbgFile(DebugInfo, DebugFileHeader, ImageBase, FunctionTableSize, DebugInfoHeaderSize);
  1058. } else {
  1059. //
  1060. // Some other kind of file processing
  1061. //
  1062. DebugInfo->Machine = 0;
  1063. DebugInfo->Characteristics = 0;
  1064. DebugInfo->TimeDateStamp = 0;
  1065. DebugInfo->CheckSum = FallbackChecksum;
  1066. DebugInfo->ImageBase = 0;
  1067. DebugInfo->SizeOfImage = 0;
  1068. DebugInfo->NumberOfSections = FallbackNumberOfSections;
  1069. DebugInfo->Sections = (PIMAGE_SECTION_HEADER)((ULONG)DebugInfo + DebugInfoHeaderSize);
  1070. memmove( DebugInfo->Sections, FallbackSections, FallbackSectionSize );
  1071. DebugInfo->ExportedNamesSize = 0;
  1072. DebugInfo->ExportedNames = NULL;
  1073. DebugInfo->NumberOfFunctionTableEntries = 0;
  1074. DebugInfo->FunctionTableEntries = NULL;
  1075. DebugInfo->LowestFunctionStartingAddress = (ULONG)0xFFFFFFFF;
  1076. DebugInfo->HighestFunctionEndingAddress = 0;
  1077. DebugInfo->NumberOfFpoTableEntries = 0;
  1078. DebugInfo->FpoTableEntries = NULL;
  1079. DebugInfo->SizeOfCoffSymbols = 0;
  1080. DebugInfo->CoffSymbols = NULL;
  1081. DebugInfo->SizeOfCodeViewSymbols = 0;
  1082. DebugInfo->CodeViewSymbols = NULL;
  1083. }
  1084. } else {
  1085. if (RomImage) {
  1086. DebugInfo->Machine = RomHeader->FileHeader.Machine;
  1087. DebugInfo->Characteristics = RomHeader->FileHeader.Characteristics;
  1088. DebugInfo->TimeDateStamp = RomHeader->FileHeader.TimeDateStamp;
  1089. DebugInfo->NumberOfSections = RomHeader->FileHeader.NumberOfSections;
  1090. DebugInfo->CheckSum = 0;
  1091. DebugInfo->ImageBase = RomHeader->OptionalHeader.BaseOfCode;
  1092. DebugInfo->SizeOfImage = RomHeader->OptionalHeader.SizeOfCode;
  1093. DebugInfo->Sections = (PIMAGE_SECTION_HEADER) ((ULONG)MappedBase +
  1094. IMAGE_SIZEOF_ROM_OPTIONAL_HEADER +
  1095. IMAGE_SIZEOF_FILE_HEADER );
  1096. } else {
  1097. DebugInfo->Machine = NtHeaders->FileHeader.Machine;
  1098. DebugInfo->Characteristics = NtHeaders->FileHeader.Characteristics;
  1099. DebugInfo->TimeDateStamp = NtHeaders->FileHeader.TimeDateStamp;
  1100. DebugInfo->CheckSum = NtHeaders->OptionalHeader.CheckSum;
  1101. DebugInfo->ImageBase = NtHeaders->OptionalHeader.ImageBase;
  1102. DebugInfo->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;
  1103. DebugInfo->NumberOfSections = NtHeaders->FileHeader.NumberOfSections;
  1104. DebugInfo->Sections = IMAGE_FIRST_SECTION( NtHeaders );
  1105. }
  1106. Next = (PVOID)((ULONG)DebugInfo + DebugInfoHeaderSize);
  1107. DebugInfo->ExportedNamesSize = ExportedNamesSize;
  1108. if (DebugInfo->ExportedNamesSize) {
  1109. DebugInfo->ExportedNames = (LPSTR)Next;
  1110. AdvanceNext(ExportedNamesSize);
  1111. pp = (PULONG)((ULONG)ExportDirectory +
  1112. (ULONG)ExportDirectory->AddressOfNames - RvaOffset
  1113. );
  1114. Dst = DebugInfo->ExportedNames;
  1115. for (i=0; i<ExportDirectory->NumberOfNames; i++) {
  1116. Src = (LPSTR)((ULONG)ExportDirectory + *pp++ - RvaOffset);
  1117. while (*Dst++ = *Src++)
  1118. ;
  1119. }
  1120. }
  1121. if (RuntimeFunctionTable != NULL) {
  1122. BaseOffset = ImageBase ? ImageBase - DebugInfo->ImageBase : 0;
  1123. DebugInfo->FunctionTableEntries = (PIMAGE_FUNCTION_ENTRY)Next;
  1124. DebugInfo->NumberOfFunctionTableEntries = NumberOfFunctionTableEntries;
  1125. AdvanceNext(FunctionTableSize);
  1126. DebugInfo->LowestFunctionStartingAddress = (ULONG)0xFFFFFFFF;
  1127. DebugInfo->HighestFunctionEndingAddress = 0;
  1128. FunctionTable = DebugInfo->FunctionTableEntries;
  1129. for (i=0; i<NumberOfFunctionTableEntries; i++) {
  1130. FunctionTable->StartingAddress = RuntimeFunctionTable->BeginAddress + BaseOffset;
  1131. if (FunctionTable->StartingAddress < DebugInfo->LowestFunctionStartingAddress) {
  1132. DebugInfo->LowestFunctionStartingAddress = FunctionTable->StartingAddress;
  1133. }
  1134. FunctionTable->EndingAddress = RuntimeFunctionTable->EndAddress + BaseOffset;
  1135. if (FunctionTable->EndingAddress > DebugInfo->HighestFunctionEndingAddress) {
  1136. DebugInfo->HighestFunctionEndingAddress = FunctionTable->EndingAddress;
  1137. }
  1138. FunctionTable->EndOfPrologue = RuntimeFunctionTable->PrologEndAddress + BaseOffset;
  1139. RuntimeFunctionTable += 1;
  1140. FunctionTable += 1;
  1141. }
  1142. }
  1143. DebugDirectory = DebugDirectories;
  1144. if (RomImage) {
  1145. if (RomHeader->FileHeader.NumberOfSymbols) {
  1146. DebugInfo->CoffSymbols = (PIMAGE_COFF_SYMBOLS_HEADER)
  1147. ((ULONG)MappedBase +
  1148. RomHeader->FileHeader.PointerToSymbolTable -
  1149. sizeof(IMAGE_COFF_SYMBOLS_HEADER));
  1150. DebugInfo->SizeOfCoffSymbols =
  1151. RomHeader->FileHeader.NumberOfSymbols *
  1152. IMAGE_SIZEOF_SYMBOL;
  1153. DebugInfo->SizeOfCoffSymbols +=
  1154. *(ULONG UNALIGNED *)((ULONG)DebugInfo->CoffSymbols +
  1155. DebugInfo->SizeOfCoffSymbols);
  1156. }
  1157. } else {
  1158. for (i=0; i<NumberOfDebugDirectories; i++) {
  1159. if (DebugDirectory->Type == IMAGE_DEBUG_TYPE_FPO ||
  1160. (((DebugDirectory->Type == IMAGE_DEBUG_TYPE_CODEVIEW) ||
  1161. (DebugDirectory->Type == IMAGE_DEBUG_TYPE_COFF)) &&
  1162. !(NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
  1163. )
  1164. ) {
  1165. DebugData = NULL;
  1166. if (DebugDirectory->AddressOfRawData == 0) {
  1167. if (SetFilePointer( FileHandle,
  1168. DebugDirectory->PointerToRawData,
  1169. NULL,
  1170. FILE_BEGIN
  1171. ) == DebugDirectory->PointerToRawData
  1172. ) {
  1173. if (ReadFile( FileHandle,
  1174. Next,
  1175. DebugDirectory->SizeOfData,
  1176. &Size,
  1177. NULL
  1178. ) &&
  1179. DebugDirectory->SizeOfData == Size
  1180. ) {
  1181. DebugData = Next;
  1182. AdvanceNext(Size);
  1183. }
  1184. }
  1185. } else {
  1186. DebugData = (LPSTR)MappedBase + DebugDirectory->PointerToRawData;
  1187. Size = DebugDirectory->SizeOfData;
  1188. }
  1189. if (DebugData != NULL) {
  1190. if (DebugDirectory->Type == IMAGE_DEBUG_TYPE_FPO) {
  1191. DebugInfo->FpoTableEntries = (PFPO_DATA) DebugData;
  1192. DebugInfo->NumberOfFpoTableEntries = Size / sizeof( FPO_DATA );
  1193. } else if (DebugDirectory->Type == IMAGE_DEBUG_TYPE_COFF) {
  1194. DebugInfo->CoffSymbols = (PIMAGE_COFF_SYMBOLS_HEADER) DebugData;
  1195. DebugInfo->SizeOfCoffSymbols = Size;
  1196. } else if (DebugDirectory->Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
  1197. DebugInfo->CodeViewSymbols = (PVOID) DebugData;
  1198. DebugInfo->SizeOfCodeViewSymbols = Size;
  1199. }
  1200. }
  1201. }
  1202. DebugDirectory += 1;
  1203. }
  1204. }
  1205. }
  1206. } __except( EXCEPTION_EXECUTE_HANDLER ) {
  1207. if (DebugInfo != NULL) {
  1208. MemFree( DebugInfo );
  1209. DebugInfo = NULL;
  1210. }
  1211. }
  1212. } __finally {
  1213. if (FallbackSections) {
  1214. MemFree(FallbackSections);
  1215. }
  1216. if (DebugInfo == NULL) {
  1217. if (MappedBase != NULL) {
  1218. UnmapViewOfFile( MappedBase );
  1219. }
  1220. }
  1221. while (NumberOfHandlesToClose--) {
  1222. CloseHandle( HandlesToClose[ NumberOfHandlesToClose ] );
  1223. }
  1224. }
  1225. if (DebugInfo) {
  1226. DebugInfo->RomImage = RomImage;
  1227. }
  1228. return DebugInfo;
  1229. }
  1230. BOOL
  1231. UnmapDebugInformation(
  1232. PIMAGE_DEBUG_INFORMATION DebugInfo
  1233. )
  1234. {
  1235. if (DebugInfo != NULL) {
  1236. __try {
  1237. UnmapViewOfFile( DebugInfo->MappedBase );
  1238. memset( DebugInfo, 0, sizeof( *DebugInfo ) );
  1239. MemFree( DebugInfo );
  1240. } __except( EXCEPTION_EXECUTE_HANDLER ) {
  1241. return FALSE;
  1242. }
  1243. }
  1244. return TRUE;
  1245. }
  1246. LPSTR
  1247. ExpandPath(
  1248. LPSTR lpPath
  1249. )
  1250. {
  1251. LPSTR p = lpPath;
  1252. LPSTR newpath = (LPSTR) MemAlloc( (lpPath? strlen(lpPath): 0) + MAX_PATH );
  1253. LPSTR p1;
  1254. LPSTR p2 = newpath;
  1255. CHAR envvar[MAX_PATH];
  1256. CHAR envstr[MAX_PATH];
  1257. ULONG i;
  1258. while( p && *p) {
  1259. if (*p == '%') {
  1260. i = 0;
  1261. p++;
  1262. while (p && *p && *p != '%') {
  1263. envvar[i++] = *p++;
  1264. }
  1265. p++;
  1266. envvar[i] = '\0';
  1267. p1 = envstr;
  1268. *p1 = 0;
  1269. GetEnvironmentVariable( envvar, p1, MAX_PATH );
  1270. while (p1 && *p1) {
  1271. *p2++ = *p1++;
  1272. }
  1273. }
  1274. *p2++ = *p++;
  1275. }
  1276. *p2 = '\0';
  1277. return newpath;
  1278. }
  1279. HANDLE
  1280. FindExecutableImage(
  1281. LPSTR FileName,
  1282. LPSTR SymbolPath,
  1283. LPSTR ImageFilePath
  1284. )
  1285. {
  1286. LPSTR Start, End;
  1287. HANDLE FileHandle;
  1288. UCHAR DirectoryPath[ MAX_PATH ];
  1289. LPSTR NewSymbolPath = ExpandPath(SymbolPath);
  1290. if (GetFullPathName( FileName, MAX_PATH, ImageFilePath, &Start )) {
  1291. FileHandle = CreateFile( ImageFilePath,
  1292. GENERIC_READ,
  1293. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1294. NULL,
  1295. OPEN_EXISTING,
  1296. 0,
  1297. NULL
  1298. );
  1299. if (FileHandle != INVALID_HANDLE_VALUE) {
  1300. MemFree( NewSymbolPath );
  1301. return FileHandle;
  1302. }
  1303. }
  1304. Start = NewSymbolPath;
  1305. while (Start && *Start != '\0') {
  1306. if (End = strchr( Start, ';' )) {
  1307. strncpy( (PCHAR) DirectoryPath, Start, End - Start );
  1308. DirectoryPath[ End - Start ] = '\0';
  1309. End += 1;
  1310. }
  1311. else {
  1312. strcpy( (PCHAR) DirectoryPath, Start );
  1313. }
  1314. if (SearchTreeForFile( (PCHAR) DirectoryPath, FileName, ImageFilePath )) {
  1315. FileHandle = CreateFile( ImageFilePath,
  1316. GENERIC_READ,
  1317. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1318. NULL,
  1319. OPEN_EXISTING,
  1320. 0,
  1321. NULL
  1322. );
  1323. if (FileHandle != INVALID_HANDLE_VALUE) {
  1324. MemFree( NewSymbolPath );
  1325. return FileHandle;
  1326. }
  1327. }
  1328. Start = End;
  1329. }
  1330. MemFree( NewSymbolPath );
  1331. return NULL;
  1332. }
  1333. HANDLE
  1334. FindDebugInfoFile(
  1335. LPSTR FileName,
  1336. LPSTR SymbolPath,
  1337. LPSTR DebugFilePath
  1338. )
  1339. {
  1340. HANDLE FileHandle;
  1341. LPSTR s;
  1342. LPSTR Start, End;
  1343. UCHAR BaseName[ MAX_PATH ];
  1344. DWORD n;
  1345. LPSTR NewSymbolPath = ExpandPath(SymbolPath);
  1346. BOOL UseSymbolsDir = TRUE;
  1347. LPSTR pExt = NULL;
  1348. if (!(s = strrchr( FileName, '.' )) || _stricmp( s, ".dbg" )) {
  1349. if (s != NULL) {
  1350. strcpy( (PCHAR) BaseName, s+1 );
  1351. strcat( (PCHAR) BaseName, "\\" );
  1352. } else {
  1353. BaseName[ 0 ] = '\0';
  1354. }
  1355. s = FileName + strlen( FileName );
  1356. while (s > FileName) {
  1357. if (*--s == '\\' || *s == '/' || *s == ':') {
  1358. s += 1;
  1359. break;
  1360. }
  1361. }
  1362. strcat( (PCHAR) BaseName, s );
  1363. if (!(s = strrchr( (PCHAR) BaseName, '.' ))) {
  1364. s = strchr( (PCHAR) BaseName, '\0' );
  1365. }
  1366. strcpy( s, ".dbg" );
  1367. pExt = s;
  1368. } else {
  1369. strcpy( (PCHAR) BaseName, FileName );
  1370. }
  1371. try_again:
  1372. Start = NewSymbolPath;
  1373. while (Start && *Start != '\0') {
  1374. if (End = strchr( Start, ';' )) {
  1375. *End = '\0';
  1376. }
  1377. n = GetFullPathName( Start, MAX_PATH, DebugFilePath, &s );
  1378. if (End) {
  1379. *End++ = ';';
  1380. }
  1381. Start = End;
  1382. if (n == 0) {
  1383. continue;
  1384. }
  1385. if (UseSymbolsDir) {
  1386. if (s != NULL && !_stricmp( s, "Symbols" )) {
  1387. strcat( DebugFilePath, "\\" );
  1388. } else {
  1389. strcat( DebugFilePath, "\\Symbols\\" );
  1390. }
  1391. } else {
  1392. strcat( DebugFilePath, "\\" );
  1393. }
  1394. strcat( DebugFilePath, (PCHAR) BaseName );
  1395. FileHandle = CreateFile( DebugFilePath,
  1396. GENERIC_READ,
  1397. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1398. NULL,
  1399. OPEN_EXISTING,
  1400. 0,
  1401. NULL
  1402. );
  1403. if (FileHandle != INVALID_HANDLE_VALUE) {
  1404. MemFree( NewSymbolPath );
  1405. return FileHandle;
  1406. }
  1407. }
  1408. if (pExt) {
  1409. if (_stricmp(pExt,".dbg") == 0) {
  1410. //
  1411. // Now Try again with .SYM
  1412. //
  1413. strcpy(pExt, ".sym");
  1414. goto try_again;
  1415. }
  1416. if (_stricmp(pExt,".sym") == 0) {
  1417. strcpy(pExt, ".dbg"); // Restore to pre-sym searching state
  1418. }
  1419. }
  1420. if (UseSymbolsDir) {
  1421. //
  1422. // this code allows the symbol file to be
  1423. // located when the symbols are placed into
  1424. // a flat directory.
  1425. //
  1426. UseSymbolsDir = FALSE;
  1427. s = strrchr( (char *) BaseName, '\\' );
  1428. if (s) {
  1429. strcpy( (char *) BaseName, s+1 );
  1430. }
  1431. if (!(s = strrchr( (PCHAR) BaseName, '.' ))) {
  1432. s = strchr( (PCHAR) BaseName, '\0' );
  1433. }
  1434. pExt = s;
  1435. goto try_again;
  1436. }
  1437. MemFree( NewSymbolPath );
  1438. return NULL;
  1439. }
  1440. BOOL
  1441. GetImageNameFromMiscDebugData(
  1442. IN HANDLE FileHandle,
  1443. IN PVOID MappedBase,
  1444. IN PIMAGE_NT_HEADERS NtHeaders,
  1445. IN PIMAGE_DEBUG_DIRECTORY DebugDirectories,
  1446. IN ULONG NumberOfDebugDirectories,
  1447. OUT LPSTR ImageFilePath
  1448. )
  1449. {
  1450. IMAGE_DEBUG_MISC TempMiscData;
  1451. PIMAGE_DEBUG_MISC DebugMiscData;
  1452. ULONG BytesToRead, BytesRead;
  1453. BOOLEAN FoundImageName;
  1454. LPSTR ImageName;
  1455. while (NumberOfDebugDirectories) {
  1456. if (DebugDirectories->Type == IMAGE_DEBUG_TYPE_MISC) {
  1457. break;
  1458. }
  1459. else {
  1460. DebugDirectories += 1;
  1461. NumberOfDebugDirectories -= 1;
  1462. }
  1463. }
  1464. if (NumberOfDebugDirectories == 0) {
  1465. return FALSE;
  1466. }
  1467. if ((NtHeaders->OptionalHeader.MajorLinkerVersion < 3) &&
  1468. (NtHeaders->OptionalHeader.MinorLinkerVersion < 36) ) {
  1469. BytesToRead = FIELD_OFFSET( IMAGE_DEBUG_MISC, Reserved );
  1470. }
  1471. else {
  1472. BytesToRead = FIELD_OFFSET( IMAGE_DEBUG_MISC, Data );
  1473. }
  1474. DebugMiscData = NULL;
  1475. FoundImageName = FALSE;
  1476. if (MappedBase == 0) {
  1477. if (SetFilePointer( FileHandle,
  1478. DebugDirectories->PointerToRawData,
  1479. NULL,
  1480. FILE_BEGIN
  1481. ) == DebugDirectories->PointerToRawData
  1482. ) {
  1483. if (ReadFile( FileHandle,
  1484. &TempMiscData,
  1485. BytesToRead,
  1486. &BytesRead,
  1487. NULL
  1488. ) &&
  1489. BytesRead == BytesToRead
  1490. ) {
  1491. DebugMiscData = &TempMiscData;
  1492. if (DebugMiscData->DataType == IMAGE_DEBUG_MISC_EXENAME) {
  1493. BytesToRead = DebugMiscData->Length - BytesToRead;
  1494. BytesToRead = BytesToRead > MAX_PATH ? MAX_PATH : BytesToRead;
  1495. if (ReadFile( FileHandle,
  1496. ImageFilePath,
  1497. BytesToRead,
  1498. &BytesRead,
  1499. NULL
  1500. ) &&
  1501. BytesRead == BytesToRead
  1502. ) {
  1503. FoundImageName = TRUE;
  1504. }
  1505. }
  1506. }
  1507. }
  1508. }
  1509. else {
  1510. DebugMiscData = (PIMAGE_DEBUG_MISC)((PCHAR)MappedBase +
  1511. DebugDirectories->PointerToRawData );
  1512. if (DebugMiscData->DataType == IMAGE_DEBUG_MISC_EXENAME) {
  1513. ImageName = (PCHAR)DebugMiscData + BytesToRead;
  1514. BytesToRead = DebugMiscData->Length - BytesToRead;
  1515. BytesToRead = BytesToRead > MAX_PATH ? MAX_PATH : BytesToRead;
  1516. if (*ImageName != '\0' ) {
  1517. memcpy( ImageFilePath, ImageName, BytesToRead );
  1518. FoundImageName = TRUE;
  1519. }
  1520. }
  1521. }
  1522. return FoundImageName;
  1523. }
  1524. #define MAX_DEPTH 32
  1525. BOOL
  1526. SearchTreeForFile(
  1527. LPSTR RootPath,
  1528. LPSTR InputPathName,
  1529. LPSTR OutputPathBuffer
  1530. )
  1531. {
  1532. PCHAR FileName;
  1533. PUCHAR Prefix = (PUCHAR) "";
  1534. CHAR PathBuffer[ MAX_PATH ];
  1535. ULONG Depth;
  1536. PCHAR PathTail[ MAX_DEPTH ];
  1537. PCHAR FindHandle[ MAX_DEPTH ];
  1538. LPWIN32_FIND_DATA FindFileData;
  1539. UCHAR FindFileBuffer[ MAX_PATH + sizeof( WIN32_FIND_DATA ) ];
  1540. BOOL Result;
  1541. strcpy( PathBuffer, RootPath );
  1542. FileName = InputPathName;
  1543. while (*InputPathName) {
  1544. if (*InputPathName == ':' || *InputPathName == '\\' || *InputPathName == '/') {
  1545. FileName = ++InputPathName;
  1546. }
  1547. else {
  1548. InputPathName++;
  1549. }
  1550. }
  1551. FindFileData = (LPWIN32_FIND_DATA)FindFileBuffer;
  1552. Depth = 0;
  1553. Result = FALSE;
  1554. while (TRUE) {
  1555. startDirectorySearch:
  1556. PathTail[ Depth ] = strchr( PathBuffer, '\0' );
  1557. if (PathTail[ Depth ] > PathBuffer && PathTail[ Depth ][ -1 ] != '\\') {
  1558. *(PathTail[ Depth ])++ = '\\';
  1559. }
  1560. strcpy( PathTail[ Depth ], "*.*" );
  1561. FindHandle[ Depth ] = (PCHAR) FindFirstFile( PathBuffer, FindFileData );
  1562. if (FindHandle[ Depth ] == INVALID_HANDLE_VALUE) {
  1563. return FALSE;
  1564. }
  1565. do {
  1566. if (FindFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  1567. if (strcmp( FindFileData->cFileName, "." ) &&
  1568. strcmp( FindFileData->cFileName, ".." ) &&
  1569. Depth < MAX_DEPTH
  1570. ) {
  1571. strcpy(PathTail[ Depth ], FindFileData->cFileName);
  1572. strcat(PathTail[ Depth ], "\\");
  1573. Depth++;
  1574. goto startDirectorySearch;
  1575. }
  1576. }
  1577. else
  1578. if (!_stricmp( FindFileData->cFileName, FileName )) {
  1579. strcpy( PathTail[ Depth ], FindFileData->cFileName );
  1580. strcpy( OutputPathBuffer, PathBuffer );
  1581. Result = TRUE;
  1582. }
  1583. restartDirectorySearch:
  1584. if (Result) {
  1585. break;
  1586. }
  1587. }
  1588. while (FindNextFile( FindHandle[ Depth ], FindFileData ));
  1589. FindClose( FindHandle[ Depth ] );
  1590. if (Depth == 0) {
  1591. break;
  1592. }
  1593. Depth--;
  1594. goto restartDirectorySearch;
  1595. }
  1596. return Result;
  1597. }
  1598. BOOL
  1599. MakeSureDirectoryPathExists(
  1600. LPCSTR DirPath
  1601. )
  1602. {
  1603. LPSTR p, DirCopy;
  1604. DWORD dw;
  1605. // Make a copy of the string for editing.
  1606. __try {
  1607. DirCopy = (LPSTR) MemAlloc(strlen(DirPath) + 1);
  1608. if (!DirCopy) {
  1609. return FALSE;
  1610. }
  1611. strcpy(DirCopy, DirPath);
  1612. p = DirCopy;
  1613. // If the second character in the path is "\", then this is a UNC
  1614. // path, and we should skip forward until we reach the 2nd \ in the path.
  1615. if ((*p == '\\') && (*(p+1) == '\\')) {
  1616. p++; // Skip over the first \ in the name.
  1617. p++; // Skip over the second \ in the name.
  1618. // Skip until we hit the first "\" (\\Server\).
  1619. while (*p && *p != '\\') {
  1620. p++;
  1621. }
  1622. // Advance over it.
  1623. if (*p) {
  1624. p++;
  1625. }
  1626. // Skip until we hit the second "\" (\\Server\Share\).
  1627. while (*p && *p != '\\') {
  1628. p++;
  1629. }
  1630. // Advance over it also.
  1631. if (*p) {
  1632. p++;
  1633. }
  1634. } else
  1635. // Not a UNC. See if it's <drive>:
  1636. if (*(p+1) == ':' ) {
  1637. p++;
  1638. p++;
  1639. // If it exists, skip over the root specifier
  1640. if (*p && (*p == '\\')) {
  1641. p++;
  1642. }
  1643. }
  1644. while( *p ) {
  1645. if ( *p == '\\' ) {
  1646. *p = '\0';
  1647. dw = GetFileAttributes(DirCopy);
  1648. // Nothing exists with this name. Try to make the directory name and error if unable to.
  1649. if ( dw == 0xffffffff ) {
  1650. if ( !CreateDirectory(DirCopy,NULL) ) {
  1651. MemFree(DirCopy);
  1652. return FALSE;
  1653. }
  1654. } else
  1655. if ( (dw & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ) {
  1656. // Something exists with this name, but it's not a directory... Error
  1657. MemFree(DirCopy);
  1658. return FALSE;
  1659. }
  1660. *p = '\\';
  1661. }
  1662. p++;
  1663. }
  1664. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1665. SetLastError( GetExceptionCode() );
  1666. MemFree(DirCopy);
  1667. return(FALSE);
  1668. }
  1669. MemFree(DirCopy);
  1670. return TRUE;
  1671. }
  1672. BOOL
  1673. UpdateDebugInfoFile(
  1674. LPSTR ImageFileName,
  1675. LPSTR SymbolPath,
  1676. LPSTR DebugFilePath,
  1677. PIMAGE_NT_HEADERS NtHeaders
  1678. )
  1679. {
  1680. return UpdateDebugInfoFileEx(
  1681. ImageFileName,
  1682. SymbolPath,
  1683. DebugFilePath,
  1684. NtHeaders,
  1685. NtHeaders->OptionalHeader.CheckSum);
  1686. }
  1687. BOOL
  1688. UpdateDebugInfoFileEx(
  1689. LPSTR ImageFileName,
  1690. LPSTR SymbolPath,
  1691. LPSTR DebugFilePath,
  1692. PIMAGE_NT_HEADERS NtHeaders,
  1693. DWORD OldCheckSum
  1694. )
  1695. {
  1696. HANDLE hDebugFile, hMappedFile;
  1697. PVOID MappedAddress;
  1698. PIMAGE_SEPARATE_DEBUG_HEADER DbgFileHeader;
  1699. hDebugFile = FindDebugInfoFile(
  1700. ImageFileName,
  1701. SymbolPath,
  1702. DebugFilePath
  1703. );
  1704. if ( hDebugFile == NULL ) {
  1705. return FALSE;
  1706. }
  1707. CloseHandle(hDebugFile);
  1708. hDebugFile = CreateFile( DebugFilePath,
  1709. GENERIC_READ | GENERIC_WRITE,
  1710. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1711. NULL,
  1712. OPEN_EXISTING,
  1713. 0,
  1714. NULL
  1715. );
  1716. if ( hDebugFile == INVALID_HANDLE_VALUE ) {
  1717. return FALSE;
  1718. }
  1719. hMappedFile = CreateFileMapping(
  1720. hDebugFile,
  1721. NULL,
  1722. PAGE_READWRITE,
  1723. 0,
  1724. 0,
  1725. NULL
  1726. );
  1727. if ( !hMappedFile ) {
  1728. CloseHandle(hDebugFile);
  1729. return FALSE;
  1730. }
  1731. MappedAddress = MapViewOfFile(hMappedFile,
  1732. FILE_MAP_WRITE,
  1733. 0,
  1734. 0,
  1735. 0
  1736. );
  1737. CloseHandle(hMappedFile);
  1738. if ( !MappedAddress ) {
  1739. CloseHandle(hDebugFile);
  1740. return FALSE;
  1741. }
  1742. DbgFileHeader = (PIMAGE_SEPARATE_DEBUG_HEADER)MappedAddress;
  1743. if (DbgFileHeader->ImageBase != NtHeaders->OptionalHeader.ImageBase ||
  1744. DbgFileHeader->CheckSum != NtHeaders->OptionalHeader.CheckSum
  1745. ) {
  1746. DbgFileHeader->ImageBase = NtHeaders->OptionalHeader.ImageBase;
  1747. DbgFileHeader->CheckSum = NtHeaders->OptionalHeader.CheckSum;
  1748. DbgFileHeader->TimeDateStamp = NtHeaders->FileHeader.TimeDateStamp;
  1749. if (OldCheckSum != NtHeaders->OptionalHeader.CheckSum) {
  1750. DbgFileHeader->Flags |= IMAGE_SEPARATE_DEBUG_MISMATCH;
  1751. SetLastError(ERROR_INVALID_DATA);
  1752. } else {
  1753. SetLastError(ERROR_SUCCESS);
  1754. }
  1755. UnmapViewOfFile(MappedAddress);
  1756. FlushViewOfFile(MappedAddress,0);
  1757. TouchFileTimes(hDebugFile,NULL);
  1758. CloseHandle(hDebugFile);
  1759. return TRUE;
  1760. } else {
  1761. UnmapViewOfFile(MappedAddress);
  1762. FlushViewOfFile(MappedAddress,0);
  1763. CloseHandle(hDebugFile);
  1764. return FALSE;
  1765. }
  1766. }
  1767. LPAPI_VERSION
  1768. ImagehlpApiVersion(
  1769. VOID
  1770. )
  1771. {
  1772. return &ApiVersion;
  1773. }
  1774. LPAPI_VERSION
  1775. ImagehlpApiVersionEx(
  1776. LPAPI_VERSION av
  1777. )
  1778. {
  1779. AppVersion = *av;
  1780. return &ApiVersion;
  1781. }
  1782. DWORD
  1783. GetTimestampForLoadedLibrary(
  1784. HMODULE Module
  1785. )
  1786. {
  1787. PIMAGE_DOS_HEADER DosHdr;
  1788. PIMAGE_NT_HEADERS NtHdr;
  1789. DosHdr = (PIMAGE_DOS_HEADER) Module;
  1790. if (DosHdr->e_magic == IMAGE_DOS_SIGNATURE) {
  1791. NtHdr = (PIMAGE_NT_HEADERS) ((LPBYTE)Module + DosHdr->e_lfanew);
  1792. } else if (DosHdr->e_magic == IMAGE_NT_SIGNATURE) {
  1793. NtHdr = (PIMAGE_NT_HEADERS) DosHdr;
  1794. } else {
  1795. return 0;
  1796. }
  1797. return NtHdr->FileHeader.TimeDateStamp;
  1798. }
  1799. BOOL
  1800. RemovePrivateCvSymbolic(
  1801. PCHAR DebugData,
  1802. PCHAR * NewDebugData,
  1803. ULONG * NewDebugSize
  1804. )
  1805. {
  1806. OMFSignature *CvDebugData, *NewStartCvSig, *NewEndCvSig;
  1807. OMFDirEntry *CvDebugDirEntry;
  1808. OMFDirHeader *CvDebugDirHead;
  1809. unsigned int i, j;
  1810. PCHAR NewCvData;
  1811. ULONG NewCvSize = 0, NewCvOffset;
  1812. BOOL RC = FALSE;
  1813. __try {
  1814. CvDebugDirHead = NULL;
  1815. CvDebugDirEntry = NULL;
  1816. CvDebugData = (OMFSignature *)DebugData;
  1817. if ((((*(PULONG)(CvDebugData->Signature)) == '90BN') ||
  1818. ((*(PULONG)(CvDebugData->Signature)) == '80BN')) &&
  1819. ((CvDebugDirHead = (OMFDirHeader *)((PUCHAR) CvDebugData + CvDebugData->filepos)) != NULL) &&
  1820. ((CvDebugDirEntry = (OMFDirEntry *)((PUCHAR) CvDebugDirHead + CvDebugDirHead->cbDirHeader)) != NULL)) {
  1821. // Walk the directory. Keep what we want, zero out the rest.
  1822. for (i=0, j=0; i < CvDebugDirHead->cDir; i++) {
  1823. switch (CvDebugDirEntry[i].SubSection) {
  1824. case sstSegMap:
  1825. case sstSegName:
  1826. case sstOffsetMap16:
  1827. case sstOffsetMap32:
  1828. case sstModule:
  1829. case SSTMODULE:
  1830. case SSTPUBLIC:
  1831. case sstPublic:
  1832. case sstPublicSym:
  1833. case sstGlobalPub:
  1834. CvDebugDirEntry[j] = CvDebugDirEntry[i];
  1835. NewCvSize += CvDebugDirEntry[j].cb;
  1836. NewCvSize = (NewCvSize + 3) & ~3;
  1837. if (i != j++) {
  1838. // Clear the old entry.
  1839. RtlZeroMemory(&CvDebugDirEntry[i], CvDebugDirHead->cbDirEntry);
  1840. }
  1841. break;
  1842. default:
  1843. RC = TRUE;
  1844. RtlZeroMemory(CvDebugDirEntry[i].lfo + (PUCHAR) CvDebugData, CvDebugDirEntry[i].cb);
  1845. RtlZeroMemory(&CvDebugDirEntry[i], CvDebugDirHead->cbDirEntry);
  1846. break;
  1847. }
  1848. }
  1849. // Now, allocate the new cv data.
  1850. CvDebugDirHead->cDir = j;
  1851. NewCvSize += (j * CvDebugDirHead->cbDirEntry) + // The directory itself
  1852. CvDebugDirHead->cbDirHeader + // The directory header
  1853. (sizeof(OMFSignature) * 2); // The signature/offset pairs at each end.
  1854. NewCvData = (PCHAR) MemAlloc( NewCvSize );
  1855. // And move the stuff we kept into the new section.
  1856. NewCvOffset = sizeof(OMFSignature);
  1857. RtlCopyMemory(NewCvData + NewCvOffset, CvDebugDirHead, CvDebugDirHead->cbDirHeader);
  1858. CvDebugDirHead = (OMFDirHeader *) (NewCvData + NewCvOffset);
  1859. NewCvOffset += CvDebugDirHead->cbDirHeader;
  1860. RtlCopyMemory(NewCvData + NewCvOffset,
  1861. CvDebugDirEntry,
  1862. CvDebugDirHead->cDir * CvDebugDirHead->cbDirEntry);
  1863. CvDebugDirEntry = (OMFDirEntry *)(NewCvData + NewCvOffset);
  1864. NewCvOffset += (CvDebugDirHead->cbDirEntry * CvDebugDirHead->cDir);
  1865. for (i=0; i < CvDebugDirHead->cDir; i++) {
  1866. RtlCopyMemory(NewCvData + NewCvOffset,
  1867. CvDebugDirEntry[i].lfo + (PCHAR) CvDebugData,
  1868. CvDebugDirEntry[i].cb);
  1869. CvDebugDirEntry[i].lfo = NewCvOffset;
  1870. NewCvOffset += (CvDebugDirEntry[i].cb + 3) & ~3;
  1871. }
  1872. // Re-do the start/end signatures
  1873. NewStartCvSig = (OMFSignature *) NewCvData;
  1874. NewEndCvSig = (OMFSignature *) ((PCHAR)NewCvData + NewCvOffset);
  1875. *(PULONG)(NewStartCvSig->Signature) = *(PULONG)(CvDebugData->Signature);
  1876. NewStartCvSig->filepos = (PCHAR)CvDebugDirHead - (PCHAR)NewStartCvSig;
  1877. *(PULONG)(NewEndCvSig->Signature) = *(PULONG)(CvDebugData->Signature);
  1878. NewCvOffset += sizeof(OMFSignature);
  1879. NewEndCvSig->filepos = (LONG)NewCvOffset;
  1880. // Set the return values appropriately
  1881. *NewDebugData = NewCvData;
  1882. *NewDebugSize = NewCvSize;
  1883. } else {
  1884. // Not NB09 or NB08. Forget we ever heard of it.
  1885. // UNDONE: What we really need to do here is write a new pdb file with just the
  1886. // public info...
  1887. *NewDebugData = NULL;
  1888. *NewDebugSize = 0;
  1889. RC = TRUE;
  1890. }
  1891. } __except(EXCEPTION_EXECUTE_HANDLER) {
  1892. RC = FALSE;
  1893. }
  1894. return(RC);
  1895. }
  1896. VOID
  1897. RemoveRelocations(
  1898. PCHAR ImageName
  1899. )
  1900. {
  1901. LOADED_IMAGE li;
  1902. IMAGE_SECTION_HEADER RelocSectionHdr, *Section, *pRelocSecHdr;
  1903. PIMAGE_DEBUG_DIRECTORY DebugDirectory;
  1904. ULONG DebugDirectorySize, i, RelocSecNum;
  1905. if (!MapAndLoad(ImageName, NULL, &li, FALSE, FALSE)) {
  1906. return;
  1907. }
  1908. // See if the image has already been stripped or there are no relocs.
  1909. if ((li.FileHeader->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) ||
  1910. (!li.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size)) {
  1911. UnMapAndLoad(&li);
  1912. return;
  1913. }
  1914. for (Section = li.Sections, i = 0; i < li.NumberOfSections; Section++, i++) {
  1915. if (Section->PointerToRawData != 0) {
  1916. if (!_stricmp( (char *) Section->Name, ".reloc" )) {
  1917. RelocSectionHdr = *Section;
  1918. pRelocSecHdr = Section;
  1919. RelocSecNum = i + 1;
  1920. }
  1921. }
  1922. }
  1923. RelocSectionHdr.Misc.VirtualSize = ROUNDUP(RelocSectionHdr.Misc.VirtualSize, li.FileHeader->OptionalHeader.SectionAlignment);
  1924. RelocSectionHdr.SizeOfRawData = ROUNDUP(RelocSectionHdr.SizeOfRawData, li.FileHeader->OptionalHeader.FileAlignment);
  1925. if (RelocSecNum != li.NumberOfSections) {
  1926. // Move everything else up and fixup old addresses.
  1927. for (i = RelocSecNum - 1, Section = pRelocSecHdr;i < li.NumberOfSections - 1; Section++, i++) {
  1928. *Section = *(Section + 1);
  1929. Section->VirtualAddress -= RelocSectionHdr.Misc.VirtualSize;
  1930. Section->PointerToRawData -= RelocSectionHdr.SizeOfRawData;
  1931. }
  1932. }
  1933. // Zero out the last one.
  1934. RtlZeroMemory(Section, sizeof(IMAGE_SECTION_HEADER));
  1935. // Reduce the section count.
  1936. li.FileHeader->FileHeader.NumberOfSections--;
  1937. // Set the strip bit in the header
  1938. li.FileHeader->FileHeader.Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
  1939. // If there's a pointer to the coff symbol table, move it back.
  1940. if (li.FileHeader->FileHeader.PointerToSymbolTable) {
  1941. li.FileHeader->FileHeader.PointerToSymbolTable -= RelocSectionHdr.SizeOfRawData;
  1942. }
  1943. // Clear out the base reloc entry in the data dir.
  1944. li.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0;
  1945. li.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0;
  1946. // Reduce the Init Data size.
  1947. li.FileHeader->OptionalHeader.SizeOfInitializedData -= RelocSectionHdr.Misc.VirtualSize;
  1948. // Reduce the image size.
  1949. li.FileHeader->OptionalHeader.SizeOfImage -=
  1950. ((RelocSectionHdr.SizeOfRawData +
  1951. (li.FileHeader->OptionalHeader.SectionAlignment - 1)
  1952. ) & ~(li.FileHeader->OptionalHeader.SectionAlignment - 1));
  1953. // Move the debug info up (if there is any).
  1954. DebugDirectory = (PIMAGE_DEBUG_DIRECTORY)
  1955. ImageDirectoryEntryToData( li.MappedAddress,
  1956. FALSE,
  1957. IMAGE_DIRECTORY_ENTRY_DEBUG,
  1958. &DebugDirectorySize
  1959. );
  1960. if (DebugDirectoryIsUseful(DebugDirectory, DebugDirectorySize)) {
  1961. for (i = 0; i < (DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY)); i++) {
  1962. RtlMoveMemory(li.MappedAddress + DebugDirectory->PointerToRawData - RelocSectionHdr.SizeOfRawData,
  1963. li.MappedAddress + DebugDirectory->PointerToRawData,
  1964. DebugDirectory->SizeOfData);
  1965. DebugDirectory->PointerToRawData -= RelocSectionHdr.SizeOfRawData;
  1966. if (DebugDirectory->AddressOfRawData) {
  1967. DebugDirectory->AddressOfRawData -= RelocSectionHdr.Misc.VirtualSize;
  1968. }
  1969. DebugDirectory++;
  1970. }
  1971. }
  1972. // Truncate the image size
  1973. li.SizeOfImage -= RelocSectionHdr.SizeOfRawData;
  1974. // And we're done.
  1975. UnMapAndLoad(&li);
  1976. }