Source code of Windows XP (NT5)
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.

1104 lines
39 KiB

  1. #include <private.h>
  2. #include <dbgimage.h>
  3. #if defined(use_SplitSymbolsX)
  4. #include <splitsymx.h>
  5. #endif // use_SplitSymbolsX
  6. #define CLEAN_PD(addr) ((addr) & ~0x3)
  7. #define CLEAN_PD64(addr) ((addr) & ~0x3UI64)
  8. #if defined(use_SplitSymbolsX)
  9. BOOL
  10. SplitSymbolsX(
  11. LPSTR ImageName,
  12. LPSTR SymbolsPath,
  13. LPSTR SymbolFilePath,
  14. ULONG Flags,
  15. PCHAR RSDSDllToLoad,
  16. LPSTR DestinationSymbol,
  17. DWORD LenDestSymbolBuffer
  18. )
  19. #else
  20. BOOL
  21. IMAGEAPI
  22. SplitSymbols(
  23. LPSTR ImageName,
  24. LPSTR SymbolsPath,
  25. LPSTR SymbolFilePath,
  26. ULONG Flags
  27. )
  28. #endif // use_SplitSymbolsX
  29. {
  30. // UnSafe...
  31. HANDLE FileHandle, SymbolFileHandle;
  32. HANDLE hMappedFile;
  33. LPVOID ImageBase;
  34. PIMAGE_NT_HEADERS32 NtHeaders;
  35. LPSTR ImageFileName;
  36. DWORD SizeOfSymbols;
  37. ULONG_PTR ImageNameOffset;
  38. ULONG_PTR DebugSectionStart;
  39. PIMAGE_SECTION_HEADER DebugSection = NULL;
  40. DWORD SectionNumber, BytesWritten, NewFileSize, HeaderSum, CheckSum;
  41. PIMAGE_DEBUG_DIRECTORY DebugDirectory, DebugDirectories, DbgDebugDirectories = NULL;
  42. IMAGE_DEBUG_DIRECTORY MiscDebugDirectory = {0};
  43. IMAGE_DEBUG_DIRECTORY FpoDebugDirectory = {0};
  44. IMAGE_DEBUG_DIRECTORY FunctionTableDir;
  45. PIMAGE_DEBUG_DIRECTORY pFpoDebugDirectory = NULL;
  46. DWORD DebugDirectorySize, DbgFileHeaderSize, NumberOfDebugDirectories;
  47. IMAGE_SEPARATE_DEBUG_HEADER DbgFileHeader;
  48. PIMAGE_EXPORT_DIRECTORY ExportDirectory;
  49. DWORD ExportedNamesSize;
  50. LPDWORD pp;
  51. LPSTR ExportedNames = NULL, Src, Dst;
  52. DWORD i, j, RvaOffset, ExportDirectorySize;
  53. PFPO_DATA FpoTable = NULL;
  54. DWORD FpoTableSize;
  55. PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY RuntimeFunctionTable, pSrc;
  56. DWORD RuntimeFunctionTableSize;
  57. PIMAGE_FUNCTION_ENTRY FunctionTable = NULL, pDst;
  58. DWORD FunctionTableSize;
  59. ULONG NumberOfFunctionTableEntries, DbgOffset;
  60. DWORD SavedErrorCode;
  61. BOOL InsertExtensionSubDir;
  62. LPSTR ImageFilePathToSaveInImage;
  63. BOOL MiscInRdata = FALSE;
  64. BOOL DiscardFPO = Flags & SPLITSYM_EXTRACT_ALL;
  65. BOOL MiscDebugFound, OtherDebugFound, PdbDebugFound;
  66. BOOL fNewCvData = FALSE;
  67. PCHAR NewDebugData = NULL;
  68. CHAR AltPdbPath[_MAX_PATH];
  69. PIMAGE_FILE_HEADER FileHeader;
  70. PIMAGE_OPTIONAL_HEADER32 OptionalHeader;
  71. PIMAGE_SECTION_HEADER Sections;
  72. PCVDD pDebugCV;
  73. if (Flags & SPLITSYM_SYMBOLPATH_IS_SRC) {
  74. strncpy(AltPdbPath, SymbolFilePath, sizeof(AltPdbPath));
  75. }
  76. ImageFileName = ImageName + strlen( ImageName );
  77. while (ImageFileName > ImageName) {
  78. if (*ImageFileName == '\\' ||
  79. *ImageFileName == '/' ||
  80. *ImageFileName == ':' )
  81. {
  82. ImageFileName = CharNext(ImageFileName);
  83. break;
  84. } else {
  85. ImageFileName = CharPrev(ImageName, ImageFileName);
  86. }
  87. }
  88. if (SymbolsPath == NULL ||
  89. SymbolsPath[ 0 ] == '\0' ||
  90. SymbolsPath[ 0 ] == '.' )
  91. {
  92. strncpy( SymbolFilePath, ImageName, (int)(ImageFileName - ImageName) );
  93. SymbolFilePath[ ImageFileName - ImageName ] = '\0';
  94. InsertExtensionSubDir = FALSE;
  95. } else {
  96. strcpy( SymbolFilePath, SymbolsPath );
  97. InsertExtensionSubDir = TRUE;
  98. }
  99. Dst = SymbolFilePath + strlen( SymbolFilePath );
  100. if (Dst > SymbolFilePath &&
  101. *CharPrev(SymbolFilePath, Dst) != '\\' &&
  102. *CharPrev(SymbolFilePath, Dst) != '/' &&
  103. *CharPrev(SymbolFilePath, Dst) != ':')
  104. {
  105. *Dst++ = '\\';
  106. }
  107. ImageFilePathToSaveInImage = Dst;
  108. Src = strrchr( ImageFileName, '.' );
  109. if (Src != NULL && InsertExtensionSubDir) {
  110. while (*Dst = *++Src) {
  111. Dst += 1;
  112. }
  113. *Dst++ = '\\';
  114. }
  115. strcpy( Dst, ImageFileName );
  116. Dst = strrchr( Dst, '.' );
  117. if (Dst == NULL) {
  118. Dst = SymbolFilePath + strlen( SymbolFilePath );
  119. }
  120. strcpy( Dst, ".dbg" );
  121. #ifdef _WIN64
  122. return TRUE;
  123. #else
  124. // Now, open and map the input file.
  125. FileHandle = CreateFile( ImageName,
  126. GENERIC_READ | GENERIC_WRITE,
  127. FILE_SHARE_READ,
  128. NULL,
  129. OPEN_EXISTING,
  130. 0,
  131. NULL
  132. );
  133. if (FileHandle == INVALID_HANDLE_VALUE) {
  134. return FALSE;
  135. }
  136. hMappedFile = CreateFileMapping( FileHandle,
  137. NULL,
  138. PAGE_READWRITE,
  139. 0,
  140. 0,
  141. NULL
  142. );
  143. if (!hMappedFile) {
  144. CloseHandle( FileHandle );
  145. return FALSE;
  146. }
  147. ImageBase = MapViewOfFile( hMappedFile,
  148. FILE_MAP_WRITE,
  149. 0,
  150. 0,
  151. 0
  152. );
  153. CloseHandle( hMappedFile );
  154. if (!ImageBase) {
  155. CloseHandle( FileHandle );
  156. return FALSE;
  157. }
  158. //
  159. // Everything is mapped. Now check the image and find nt image headers
  160. //
  161. NtHeaders = ImageNtHeader( ImageBase );
  162. if (NtHeaders == NULL) {
  163. FileHeader = (PIMAGE_FILE_HEADER)ImageBase;
  164. OptionalHeader = ((PIMAGE_OPTIONAL_HEADER32)((ULONG_PTR)FileHeader+IMAGE_SIZEOF_FILE_HEADER));
  165. // One last check
  166. if (OptionalHeader->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
  167. goto HeaderOk;
  168. HeaderBad:
  169. UnmapViewOfFile( ImageBase );
  170. CloseHandle( FileHandle );
  171. SetLastError( ERROR_BAD_EXE_FORMAT );
  172. return FALSE;
  173. } else {
  174. FileHeader = &NtHeaders->FileHeader;
  175. OptionalHeader = &NtHeaders->OptionalHeader;
  176. if (OptionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
  177. goto HeaderBad;
  178. }
  179. HeaderOk:
  180. if ((OptionalHeader->MajorLinkerVersion < 3) &&
  181. (OptionalHeader->MinorLinkerVersion < 5) )
  182. {
  183. UnmapViewOfFile( ImageBase );
  184. CloseHandle( FileHandle );
  185. SetLastError( ERROR_BAD_EXE_FORMAT );
  186. return FALSE;
  187. }
  188. {
  189. DWORD dwCertificateSize;
  190. PVOID pCertificates;
  191. pCertificates = ImageDirectoryEntryToData(ImageBase, FALSE, IMAGE_DIRECTORY_ENTRY_SECURITY, &dwCertificateSize);
  192. if (pCertificates || dwCertificateSize) {
  193. // This image has been signed. Can't strip the symbols w/o invalidating the certificate.
  194. UnmapViewOfFile( ImageBase );
  195. CloseHandle( FileHandle );
  196. SetLastError( ERROR_BAD_EXE_FORMAT );
  197. return FALSE;
  198. }
  199. }
  200. if (FileHeader->Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
  201. {
  202. // The symbols have already been stripped. No need to continue.
  203. UnmapViewOfFile( ImageBase );
  204. CloseHandle( FileHandle );
  205. SetLastError( ERROR_ALREADY_ASSIGNED );
  206. return FALSE;
  207. }
  208. DebugDirectories = (PIMAGE_DEBUG_DIRECTORY) ImageDirectoryEntryToData( ImageBase,
  209. FALSE,
  210. IMAGE_DIRECTORY_ENTRY_DEBUG,
  211. &DebugDirectorySize
  212. );
  213. if (!DebugDirectoryIsUseful(DebugDirectories, DebugDirectorySize)) {
  214. UnmapViewOfFile( ImageBase );
  215. CloseHandle( FileHandle );
  216. SetLastError( ERROR_BAD_EXE_FORMAT );
  217. return FALSE;
  218. }
  219. NumberOfDebugDirectories = DebugDirectorySize / sizeof( IMAGE_DEBUG_DIRECTORY );
  220. // See if there's a MISC debug dir and if not, there s/b ONLY a CV data or it's an error.
  221. MiscDebugFound = FALSE;
  222. OtherDebugFound = FALSE;
  223. for (i=0,DebugDirectory=DebugDirectories; i<NumberOfDebugDirectories; i++,DebugDirectory++) {
  224. switch (DebugDirectory->Type) {
  225. case IMAGE_DEBUG_TYPE_MISC:
  226. MiscDebugFound = TRUE;
  227. break;
  228. case IMAGE_DEBUG_TYPE_CODEVIEW:
  229. pDebugCV = ( PCVDD ) (DebugDirectory->PointerToRawData + (PCHAR)ImageBase);
  230. if (pDebugCV->dwSig == '01BN') {
  231. PdbDebugFound = TRUE;
  232. }
  233. #if defined(use_SplitSymbolsX)
  234. if (pDebugCV->dwSig == 'SDSR') {
  235. PdbDebugFound = TRUE;
  236. }
  237. #endif
  238. break;
  239. default:
  240. OtherDebugFound = TRUE;
  241. break;
  242. }
  243. }
  244. if (OtherDebugFound && !MiscDebugFound) {
  245. UnmapViewOfFile( ImageBase );
  246. CloseHandle( FileHandle );
  247. SetLastError( ERROR_BAD_EXE_FORMAT );
  248. return FALSE;
  249. }
  250. if (PdbDebugFound && !OtherDebugFound && (OptionalHeader->MajorLinkerVersion >= 6)) {
  251. // This is a VC6 generated image. Don't create a .dbg file.
  252. MiscDebugFound = FALSE;
  253. }
  254. // Make sure we can open the .dbg file before we continue...
  255. if (!MakeSureDirectoryPathExists( SymbolFilePath )) {
  256. return FALSE;
  257. }
  258. if (MiscDebugFound) {
  259. // Try to open the symbol file
  260. SymbolFileHandle = CreateFile( SymbolFilePath,
  261. GENERIC_WRITE,
  262. 0,
  263. NULL,
  264. CREATE_ALWAYS,
  265. 0,
  266. NULL
  267. );
  268. if (SymbolFileHandle == INVALID_HANDLE_VALUE) {
  269. goto nosyms;
  270. }
  271. }
  272. // The entire file is mapped so we don't have to care if the rva's
  273. // are correct. It is interesting to note if there's a debug section
  274. // we need to whack before terminating, though.
  275. {
  276. if (NtHeaders) {
  277. Sections = IMAGE_FIRST_SECTION( NtHeaders );
  278. } else {
  279. Sections = (PIMAGE_SECTION_HEADER)
  280. ((ULONG_PTR)ImageBase +
  281. ((PIMAGE_FILE_HEADER)ImageBase)->SizeOfOptionalHeader +
  282. IMAGE_SIZEOF_FILE_HEADER );
  283. }
  284. for (SectionNumber = 0;
  285. SectionNumber < FileHeader->NumberOfSections;
  286. SectionNumber++ ) {
  287. if (Sections[ SectionNumber ].PointerToRawData != 0 &&
  288. !_stricmp( (char *) Sections[ SectionNumber ].Name, ".debug" )) {
  289. DebugSection = &Sections[ SectionNumber ];
  290. }
  291. }
  292. }
  293. FpoTable = NULL;
  294. ExportedNames = NULL;
  295. DebugSectionStart = 0xffffffff;
  296. //
  297. // Find the size of the debug section.
  298. //
  299. SizeOfSymbols = 0;
  300. for (i=0,DebugDirectory=DebugDirectories; i<NumberOfDebugDirectories; i++,DebugDirectory++) {
  301. switch (DebugDirectory->Type) {
  302. case IMAGE_DEBUG_TYPE_MISC :
  303. // Save it away.
  304. MiscDebugDirectory = *DebugDirectory;
  305. // check to see if the misc debug data is in some other section.
  306. // If Address Of Raw Data is cleared, it must be in .debug (there's no such thing as not-mapped rdata)
  307. // If it's set and there's no debug section, it must be somewhere else.
  308. // If it's set and there's a debug section, check the range.
  309. if ((DebugDirectory->AddressOfRawData != 0) &&
  310. ((DebugSection == NULL) ||
  311. (((DebugDirectory->PointerToRawData < DebugSection->PointerToRawData) ||
  312. (DebugDirectory->PointerToRawData >= DebugSection->PointerToRawData + DebugSection->SizeOfRawData)
  313. )
  314. )
  315. )
  316. )
  317. {
  318. MiscInRdata = TRUE;
  319. } else {
  320. if (DebugDirectory->PointerToRawData < DebugSectionStart) {
  321. DebugSectionStart = DebugDirectory->PointerToRawData;
  322. }
  323. }
  324. break;
  325. case IMAGE_DEBUG_TYPE_FPO:
  326. if (DebugDirectory->PointerToRawData < DebugSectionStart) {
  327. DebugSectionStart = DebugDirectory->PointerToRawData;
  328. }
  329. // Save it away.
  330. FpoDebugDirectory = *DebugDirectory;
  331. pFpoDebugDirectory = DebugDirectory;
  332. break;
  333. case IMAGE_DEBUG_TYPE_CODEVIEW:
  334. {
  335. ULONG NewDebugSize;
  336. if (DebugDirectory->PointerToRawData < DebugSectionStart) {
  337. DebugSectionStart = DebugDirectory->PointerToRawData;
  338. }
  339. // If private's are removed do so to the static CV data and save the new size...
  340. pDebugCV = ( PCVDD ) (DebugDirectory->PointerToRawData + (PCHAR)ImageBase);
  341. if (pDebugCV->dwSig == '01BN') {
  342. // Got a PDB. The name immediately follows the signature.
  343. CHAR PdbName[_MAX_PATH];
  344. CHAR NewPdbName[_MAX_PATH];
  345. CHAR Drive[_MAX_DRIVE];
  346. CHAR Dir[_MAX_DIR];
  347. CHAR Filename[_MAX_FNAME];
  348. CHAR FileExt[_MAX_EXT];
  349. BOOL rc;
  350. memset(PdbName, 0, sizeof(PdbName));
  351. memcpy(PdbName, ((PCHAR)pDebugCV)+ sizeof(NB10IH), DebugDirectory->SizeOfData - sizeof(NB10IH));
  352. _splitpath(PdbName, NULL, NULL, Filename, FileExt);
  353. _splitpath(SymbolFilePath, Drive, Dir, NULL, NULL);
  354. _makepath(NewPdbName, Drive, Dir, Filename, FileExt);
  355. #if defined(use_SplitSymbolsX)
  356. if (DestinationSymbol)
  357. {
  358. strncpy(DestinationSymbol, NewPdbName, LenDestSymbolBuffer);
  359. DestinationSymbol[LenDestSymbolBuffer-1] = '\0'; // ensure termination
  360. }
  361. rc = CopyPdbX(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE, NULL);
  362. #else
  363. rc = CopyPdb(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE);
  364. #endif
  365. if (!rc) {
  366. if (Flags & SPLITSYM_SYMBOLPATH_IS_SRC) {
  367. // Try the AltPdbPath.
  368. strcpy(PdbName, AltPdbPath);
  369. strcat(PdbName, Filename);
  370. strcat(PdbName, FileExt);
  371. #if defined(use_SplitSymbolsX)
  372. rc = CopyPdbX(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE, NULL);
  373. #else
  374. rc = CopyPdb(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE);
  375. #endif
  376. }
  377. if ( !rc) {
  378. // It's possible the name in the pdb isn't in the same location as it was when built. See if we can
  379. // find it in the same dir as the image...
  380. _splitpath(ImageName, Drive, Dir, NULL, NULL);
  381. _makepath(PdbName, Drive, Dir, Filename, FileExt);
  382. #if defined(use_SplitSymbolsX)
  383. rc = CopyPdbX(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE, NULL);
  384. #else
  385. rc = CopyPdb(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE);
  386. #endif
  387. }
  388. }
  389. if (rc) {
  390. SetFileAttributes(NewPdbName, FILE_ATTRIBUTE_NORMAL);
  391. // Change the data so only the pdb name is in the .dbg file (no path).
  392. if (MiscDebugFound) {
  393. NewDebugSize = sizeof(NB10IH) + strlen(Filename) + strlen(FileExt) + 1;
  394. #if defined(use_SplitSymbolsX)
  395. NewDebugData = (PCHAR) malloc( NewDebugSize );
  396. #else
  397. NewDebugData = (PCHAR) MemAlloc( NewDebugSize );
  398. #endif
  399. ((PCVDD)NewDebugData)->nb10ih = pDebugCV->nb10ih;
  400. strcpy(NewDebugData + sizeof(NB10IH), Filename);
  401. strcat(NewDebugData + sizeof(NB10IH), FileExt);
  402. DebugDirectory->PointerToRawData = (ULONG) (NewDebugData - (PCHAR)ImageBase);
  403. DebugDirectory->SizeOfData = NewDebugSize;
  404. } else {
  405. strcpy(((PCHAR)pDebugCV) + sizeof(NB10IH), Filename);
  406. strcat(((PCHAR)pDebugCV) + sizeof(NB10IH), FileExt);
  407. }
  408. } else {
  409. // Replace <Path>\<filename>.<ext> with just <filename>.<ext> in the debug data
  410. strcpy(((PCHAR)pDebugCV) + sizeof(NB10IH), Filename);
  411. strcat(((PCHAR)pDebugCV) + sizeof(NB10IH), FileExt);
  412. DebugDirectory->SizeOfData = sizeof(NB10IH) + strlen(Filename) + strlen(FileExt) + 1;
  413. }
  414. #if defined(use_SplitSymbolsX)
  415. } else if ( pDebugCV->dwSig == 'SDSR') {
  416. // Got a PDB. The name immediately follows the signature.
  417. CHAR PdbName[sizeof(((PRSDSI)(0))->szPdb)];
  418. CHAR NewPdbName[_MAX_PATH];
  419. CHAR Drive[_MAX_DRIVE];
  420. CHAR Dir[_MAX_DIR];
  421. CHAR Filename[_MAX_FNAME];
  422. CHAR FileExt[_MAX_EXT];
  423. BOOL rc;
  424. ZeroMemory(PdbName, sizeof(PdbName));
  425. memcpy(PdbName, ((PCHAR)pDebugCV)+ sizeof(RSDSIH), __min(DebugDirectory->SizeOfData - sizeof(RSDSIH), sizeof(PdbName)));
  426. _splitpath(PdbName, NULL, NULL, Filename, FileExt);
  427. _splitpath(SymbolFilePath, Drive, Dir, NULL, NULL);
  428. _makepath(NewPdbName, Drive, Dir, Filename, FileExt);
  429. if (DestinationSymbol)
  430. {
  431. strncpy(DestinationSymbol, NewPdbName, LenDestSymbolBuffer);
  432. DestinationSymbol[LenDestSymbolBuffer-1] = '\0'; // ensure termination
  433. }
  434. rc = CopyPdbX(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE, RSDSDllToLoad);
  435. if (!rc) {
  436. if (Flags & SPLITSYM_SYMBOLPATH_IS_SRC) {
  437. // Try the AltPdbPath.
  438. strcpy(PdbName, AltPdbPath);
  439. strcat(PdbName, Filename);
  440. strcat(PdbName, FileExt);
  441. rc = CopyPdbX(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE, RSDSDllToLoad);
  442. }
  443. if ( !rc) {
  444. // It's possible the name in the pdb isn't in the same location as it was when built. See if we can
  445. // find it in the same dir as the image...
  446. _splitpath(ImageName, Drive, Dir, NULL, NULL);
  447. _makepath(PdbName, Drive, Dir, Filename, FileExt);
  448. rc = CopyPdbX(PdbName, NewPdbName, Flags & SPLITSYM_REMOVE_PRIVATE, RSDSDllToLoad);
  449. }
  450. }
  451. if (rc) {
  452. SetFileAttributes(NewPdbName, FILE_ATTRIBUTE_NORMAL);
  453. // Change the data so only the pdb name is in the .dbg file (no path).
  454. if (MiscDebugFound) {
  455. NewDebugSize = sizeof(RSDSIH) + strlen(Filename) + strlen(FileExt) + 1;
  456. NewDebugData = (PCHAR) malloc( NewDebugSize );
  457. ((PCVDD)NewDebugData)->rsdsih = pDebugCV->rsdsih;
  458. strcpy(NewDebugData + sizeof(RSDSIH), Filename);
  459. strcat(NewDebugData + sizeof(RSDSIH), FileExt);
  460. DebugDirectory->PointerToRawData = (ULONG) (NewDebugData - (PCHAR)ImageBase);
  461. DebugDirectory->SizeOfData = NewDebugSize;
  462. } else {
  463. strcpy(((PCHAR)pDebugCV) + sizeof(RSDSIH), Filename);
  464. strcat(((PCHAR)pDebugCV) + sizeof(RSDSIH), FileExt);
  465. }
  466. } else {
  467. // Replace <Path>\<filename>.<ext> with just <filename>.<ext> in the debug data
  468. strcpy(((PCHAR)pDebugCV) + sizeof(NB10IH), Filename);
  469. strcat(((PCHAR)pDebugCV) + sizeof(NB10IH), FileExt);
  470. DebugDirectory->SizeOfData = sizeof(RSDSIH) + strlen(Filename) + strlen(FileExt) + 1;
  471. }
  472. #endif
  473. } else {
  474. if (Flags & SPLITSYM_REMOVE_PRIVATE) {
  475. if (RemovePrivateCvSymbolicEx(DebugDirectory->PointerToRawData + (PCHAR)ImageBase,
  476. DebugDirectory->SizeOfData,
  477. &NewDebugData,
  478. &NewDebugSize)) {
  479. if (DebugDirectory->PointerToRawData != (ULONG) (NewDebugData - (PCHAR)ImageBase))
  480. {
  481. DebugDirectory->PointerToRawData = (ULONG) (NewDebugData - (PCHAR)ImageBase);
  482. DebugDirectory->SizeOfData = NewDebugSize;
  483. } else {
  484. NewDebugData = NULL;
  485. }
  486. }
  487. }
  488. }
  489. }
  490. break;
  491. case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
  492. case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
  493. if (DebugDirectory->PointerToRawData < DebugSectionStart) {
  494. DebugSectionStart = DebugDirectory->PointerToRawData;
  495. }
  496. // W/o the OMAP, FPO is useless.
  497. DiscardFPO = TRUE;
  498. break;
  499. case IMAGE_DEBUG_TYPE_FIXUP:
  500. if (DebugDirectory->PointerToRawData < DebugSectionStart) {
  501. DebugSectionStart = DebugDirectory->PointerToRawData;
  502. }
  503. // If all PRIVATE debug is removed, don't send FIXUP along.
  504. if (Flags & SPLITSYM_REMOVE_PRIVATE) {
  505. DebugDirectory->SizeOfData = 0;
  506. }
  507. break;
  508. default:
  509. if (DebugDirectory->SizeOfData &&
  510. (DebugDirectory->PointerToRawData < DebugSectionStart))
  511. {
  512. DebugSectionStart = DebugDirectory->PointerToRawData;
  513. }
  514. // Nothing else to special case...
  515. break;
  516. }
  517. SizeOfSymbols += (DebugDirectory->SizeOfData + 3) & ~3; // Minimally align it all.
  518. }
  519. if (!MiscDebugFound) {
  520. NewFileSize = GetFileSize(FileHandle, NULL);
  521. CheckSumMappedFile( ImageBase,
  522. NewFileSize,
  523. &HeaderSum,
  524. &CheckSum
  525. );
  526. OptionalHeader->CheckSum = CheckSum;
  527. goto nomisc;
  528. }
  529. if (DiscardFPO) {
  530. pFpoDebugDirectory = NULL;
  531. }
  532. if (pFpoDebugDirectory) {
  533. // If FPO stays here, make a copy so we don't need to worry about stomping on it.
  534. FpoTableSize = pFpoDebugDirectory->SizeOfData;
  535. #if defined(use_SplitSymbolsX)
  536. FpoTable = (PFPO_DATA) malloc( FpoTableSize );
  537. #else
  538. FpoTable = (PFPO_DATA) MemAlloc( FpoTableSize );
  539. #endif
  540. if ( FpoTable == NULL ) {
  541. goto nosyms;
  542. }
  543. RtlMoveMemory( FpoTable,
  544. (PCHAR) ImageBase + pFpoDebugDirectory->PointerToRawData,
  545. FpoTableSize );
  546. }
  547. ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)
  548. ImageDirectoryEntryToData( ImageBase,
  549. FALSE,
  550. IMAGE_DIRECTORY_ENTRY_EXPORT,
  551. &ExportDirectorySize
  552. );
  553. if (ExportDirectory) {
  554. //
  555. // This particular piece of magic gets us the RVA of the
  556. // EXPORT section. Dont ask.
  557. //
  558. RvaOffset = (ULONG_PTR)
  559. ImageDirectoryEntryToData( ImageBase,
  560. TRUE,
  561. IMAGE_DIRECTORY_ENTRY_EXPORT,
  562. &ExportDirectorySize
  563. ) - (ULONG_PTR)ImageBase;
  564. pp = (LPDWORD)((ULONG_PTR)ExportDirectory +
  565. (ULONG_PTR)ExportDirectory->AddressOfNames - RvaOffset
  566. );
  567. ExportedNamesSize = 1;
  568. for (i=0; i<ExportDirectory->NumberOfNames; i++) {
  569. Src = (LPSTR)((ULONG_PTR)ExportDirectory + *pp++ - RvaOffset);
  570. ExportedNamesSize += strlen( Src ) + 1;
  571. }
  572. ExportedNamesSize = (ExportedNamesSize + 16) & ~15;
  573. #if defined(use_SplitSymbolsX)
  574. Dst = (LPSTR) malloc( ExportedNamesSize );
  575. #else
  576. Dst = (LPSTR) MemAlloc( ExportedNamesSize );
  577. #endif
  578. if (Dst != NULL) {
  579. ExportedNames = Dst;
  580. pp = (LPDWORD)((ULONG_PTR)ExportDirectory +
  581. (ULONG_PTR)ExportDirectory->AddressOfNames - RvaOffset
  582. );
  583. for (i=0; i<ExportDirectory->NumberOfNames; i++) {
  584. Src = (LPSTR)((ULONG_PTR)ExportDirectory + *pp++ - RvaOffset);
  585. while (*Dst++ = *Src++) {
  586. ;
  587. }
  588. }
  589. }
  590. } else {
  591. ExportedNamesSize = 0;
  592. }
  593. RuntimeFunctionTable = (PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY)
  594. ImageDirectoryEntryToData( ImageBase,
  595. FALSE,
  596. IMAGE_DIRECTORY_ENTRY_EXCEPTION,
  597. &RuntimeFunctionTableSize
  598. );
  599. if (RuntimeFunctionTable == NULL) {
  600. RuntimeFunctionTableSize = 0;
  601. FunctionTableSize = 0;
  602. FunctionTable = NULL;
  603. }
  604. else {
  605. NumberOfFunctionTableEntries = RuntimeFunctionTableSize / sizeof( IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY );
  606. FunctionTableSize = NumberOfFunctionTableEntries * sizeof( IMAGE_FUNCTION_ENTRY );
  607. #if defined(use_SplitSymbolsX)
  608. FunctionTable = (PIMAGE_FUNCTION_ENTRY) malloc( FunctionTableSize );
  609. #else
  610. FunctionTable = (PIMAGE_FUNCTION_ENTRY) MemAlloc( FunctionTableSize );
  611. #endif
  612. if (FunctionTable == NULL) {
  613. goto nosyms;
  614. }
  615. pSrc = RuntimeFunctionTable;
  616. pDst = FunctionTable;
  617. for (i=0; i<NumberOfFunctionTableEntries; i++) {
  618. //
  619. // Make .pdata entries in .DBG file relative.
  620. //
  621. pDst->StartingAddress = CLEAN_PD(pSrc->BeginAddress) - OptionalHeader->ImageBase;
  622. pDst->EndingAddress = CLEAN_PD(pSrc->EndAddress) - OptionalHeader->ImageBase;
  623. pDst->EndOfPrologue = CLEAN_PD(pSrc->PrologEndAddress) - OptionalHeader->ImageBase;
  624. pSrc += 1;
  625. pDst += 1;
  626. }
  627. }
  628. DbgFileHeaderSize = sizeof( DbgFileHeader ) +
  629. ((FileHeader->NumberOfSections - (DebugSection ? 1 : 0)) *
  630. sizeof( IMAGE_SECTION_HEADER )) +
  631. ExportedNamesSize +
  632. FunctionTableSize +
  633. DebugDirectorySize;
  634. if (FunctionTable != NULL) {
  635. DbgFileHeaderSize += sizeof( IMAGE_DEBUG_DIRECTORY );
  636. memset( &FunctionTableDir, 0, sizeof( IMAGE_DEBUG_DIRECTORY ) );
  637. FunctionTableDir.Type = IMAGE_DEBUG_TYPE_EXCEPTION;
  638. FunctionTableDir.SizeOfData = FunctionTableSize;
  639. FunctionTableDir.PointerToRawData = DbgFileHeaderSize - FunctionTableSize;
  640. }
  641. DbgFileHeaderSize = ((DbgFileHeaderSize + 15) & ~15);
  642. BytesWritten = 0;
  643. if (SetFilePointer( SymbolFileHandle,
  644. DbgFileHeaderSize,
  645. NULL,
  646. FILE_BEGIN
  647. ) == DbgFileHeaderSize ) {
  648. for (i=0, DebugDirectory=DebugDirectories;
  649. i < NumberOfDebugDirectories;
  650. i++, DebugDirectory++) {
  651. DWORD WriteCount;
  652. if (DebugDirectory->SizeOfData) {
  653. WriteFile( SymbolFileHandle,
  654. (PCHAR) ImageBase + DebugDirectory->PointerToRawData,
  655. (DebugDirectory->SizeOfData +3) & ~3,
  656. &WriteCount,
  657. NULL );
  658. BytesWritten += WriteCount;
  659. }
  660. }
  661. }
  662. if (BytesWritten == SizeOfSymbols) {
  663. FileHeader->PointerToSymbolTable = 0;
  664. FileHeader->NumberOfSymbols = 0;
  665. FileHeader->Characteristics |= IMAGE_FILE_DEBUG_STRIPPED;
  666. if (DebugSection != NULL) {
  667. OptionalHeader->SizeOfImage = DebugSection->VirtualAddress;
  668. OptionalHeader->SizeOfInitializedData -= DebugSection->SizeOfRawData;
  669. FileHeader->NumberOfSections--;
  670. // NULL out that section
  671. memset(DebugSection, 0, IMAGE_SIZEOF_SECTION_HEADER);
  672. }
  673. NewFileSize = DebugSectionStart; // Start with no symbolic
  674. //
  675. // Now that the data has moved to the .dbg file, rebuild the original
  676. // with MISC debug first and FPO second.
  677. //
  678. if (MiscDebugDirectory.SizeOfData) {
  679. if (MiscInRdata) {
  680. // Just store the new name in the existing misc field...
  681. ImageNameOffset = (ULONG_PTR) ((PCHAR)ImageBase +
  682. MiscDebugDirectory.PointerToRawData +
  683. FIELD_OFFSET( IMAGE_DEBUG_MISC, Data ));
  684. RtlCopyMemory( (LPVOID) ImageNameOffset,
  685. ImageFilePathToSaveInImage,
  686. strlen(ImageFilePathToSaveInImage) + 1 );
  687. } else {
  688. if (DebugSectionStart != MiscDebugDirectory.PointerToRawData) {
  689. RtlMoveMemory((PCHAR) ImageBase + DebugSectionStart,
  690. (PCHAR) ImageBase + MiscDebugDirectory.PointerToRawData,
  691. MiscDebugDirectory.SizeOfData);
  692. }
  693. ImageNameOffset = (ULONG_PTR) ((PCHAR)ImageBase + DebugSectionStart +
  694. FIELD_OFFSET( IMAGE_DEBUG_MISC, Data ));
  695. RtlCopyMemory( (LPVOID)ImageNameOffset,
  696. ImageFilePathToSaveInImage,
  697. strlen(ImageFilePathToSaveInImage) + 1 );
  698. NewFileSize += MiscDebugDirectory.SizeOfData;
  699. NewFileSize = (NewFileSize + 3) & ~3;
  700. }
  701. }
  702. if (FpoTable) {
  703. RtlCopyMemory( (PCHAR) ImageBase + NewFileSize,
  704. FpoTable,
  705. FpoTableSize );
  706. NewFileSize += FpoTableSize;
  707. NewFileSize = (NewFileSize + 3) & ~3;
  708. }
  709. // Make a copy of the Debug directory that we can write into the .dbg file
  710. #if defined(use_SplitSymbolsX)
  711. DbgDebugDirectories = (PIMAGE_DEBUG_DIRECTORY) malloc( NumberOfDebugDirectories * sizeof(IMAGE_DEBUG_DIRECTORY) );
  712. #else
  713. DbgDebugDirectories = (PIMAGE_DEBUG_DIRECTORY) MemAlloc( NumberOfDebugDirectories * sizeof(IMAGE_DEBUG_DIRECTORY) );
  714. #endif
  715. RtlMoveMemory(DbgDebugDirectories,
  716. DebugDirectories,
  717. sizeof(IMAGE_DEBUG_DIRECTORY) * NumberOfDebugDirectories);
  718. // Then write the MISC and (perhaps) FPO data to the image.
  719. FpoDebugDirectory.PointerToRawData = DebugSectionStart;
  720. DebugDirectorySize = 0;
  721. if (MiscDebugDirectory.SizeOfData != 0) {
  722. if (!MiscInRdata) {
  723. MiscDebugDirectory.PointerToRawData = DebugSectionStart;
  724. FpoDebugDirectory.PointerToRawData += MiscDebugDirectory.SizeOfData;
  725. MiscDebugDirectory.AddressOfRawData = 0;
  726. }
  727. DebugDirectories[0] = MiscDebugDirectory;
  728. DebugDirectorySize += sizeof(IMAGE_DEBUG_DIRECTORY);
  729. }
  730. if (pFpoDebugDirectory) {
  731. FpoDebugDirectory.AddressOfRawData = 0;
  732. DebugDirectories[DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY)] = FpoDebugDirectory;
  733. DebugDirectorySize += sizeof(IMAGE_DEBUG_DIRECTORY);
  734. }
  735. // Zero out remaining slots in image.
  736. if (NumberOfDebugDirectories < (DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY))) {
  737. ZeroMemory(&DebugDirectories[DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY)],
  738. NumberOfDebugDirectories * sizeof(IMAGE_DEBUG_DIRECTORY) -
  739. DebugDirectorySize);
  740. }
  741. OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size = DebugDirectorySize;
  742. DbgOffset = DbgFileHeaderSize;
  743. for (i = 0, j=0, DebugDirectory=DbgDebugDirectories;
  744. i < NumberOfDebugDirectories; i++) {
  745. if (DebugDirectory[i].SizeOfData) {
  746. DebugDirectory[j] = DebugDirectory[i];
  747. DebugDirectory[j].AddressOfRawData = 0;
  748. DebugDirectory[j].PointerToRawData = DbgOffset;
  749. DbgOffset += (DebugDirectory[j].SizeOfData + 3 )& ~3;
  750. j++;
  751. }
  752. }
  753. if (FunctionTable) {
  754. FunctionTableDir.PointerToRawData -= sizeof(IMAGE_DEBUG_DIRECTORY) * (NumberOfDebugDirectories - j);
  755. }
  756. NumberOfDebugDirectories = j;
  757. CheckSumMappedFile( ImageBase,
  758. NewFileSize,
  759. &HeaderSum,
  760. &CheckSum
  761. );
  762. OptionalHeader->CheckSum = CheckSum;
  763. DbgFileHeader.Signature = IMAGE_SEPARATE_DEBUG_SIGNATURE;
  764. DbgFileHeader.Flags = 0;
  765. DbgFileHeader.Machine = FileHeader->Machine;
  766. DbgFileHeader.Characteristics = FileHeader->Characteristics;
  767. DbgFileHeader.TimeDateStamp = FileHeader->TimeDateStamp;
  768. DbgFileHeader.CheckSum = CheckSum;
  769. DbgFileHeader.ImageBase = OptionalHeader->ImageBase;
  770. DbgFileHeader.SizeOfImage = OptionalHeader->SizeOfImage;
  771. DbgFileHeader.ExportedNamesSize = ExportedNamesSize;
  772. DbgFileHeader.DebugDirectorySize = NumberOfDebugDirectories * sizeof(IMAGE_DEBUG_DIRECTORY);
  773. if (FunctionTable) {
  774. DbgFileHeader.DebugDirectorySize += sizeof (IMAGE_DEBUG_DIRECTORY);
  775. }
  776. DbgFileHeader.NumberOfSections = FileHeader->NumberOfSections;
  777. memset( DbgFileHeader.Reserved, 0, sizeof( DbgFileHeader.Reserved ) );
  778. DbgFileHeader.SectionAlignment = OptionalHeader->SectionAlignment;
  779. SetFilePointer( SymbolFileHandle, 0, NULL, FILE_BEGIN );
  780. WriteFile( SymbolFileHandle,
  781. &DbgFileHeader,
  782. sizeof( DbgFileHeader ),
  783. &BytesWritten,
  784. NULL
  785. );
  786. if (NtHeaders) {
  787. Sections = IMAGE_FIRST_SECTION( NtHeaders );
  788. } else {
  789. Sections = (PIMAGE_SECTION_HEADER)
  790. ((ULONG_PTR)ImageBase +
  791. ((PIMAGE_FILE_HEADER)ImageBase)->SizeOfOptionalHeader +
  792. IMAGE_SIZEOF_FILE_HEADER );
  793. }
  794. WriteFile( SymbolFileHandle,
  795. (PVOID)Sections,
  796. sizeof( IMAGE_SECTION_HEADER ) * FileHeader->NumberOfSections,
  797. &BytesWritten,
  798. NULL
  799. );
  800. if (ExportedNamesSize) {
  801. WriteFile( SymbolFileHandle,
  802. ExportedNames,
  803. ExportedNamesSize,
  804. &BytesWritten,
  805. NULL
  806. );
  807. }
  808. WriteFile( SymbolFileHandle,
  809. DbgDebugDirectories,
  810. sizeof (IMAGE_DEBUG_DIRECTORY) * NumberOfDebugDirectories,
  811. &BytesWritten,
  812. NULL );
  813. if (FunctionTable) {
  814. WriteFile( SymbolFileHandle,
  815. &FunctionTableDir,
  816. sizeof (IMAGE_DEBUG_DIRECTORY),
  817. &BytesWritten,
  818. NULL );
  819. WriteFile( SymbolFileHandle,
  820. FunctionTable,
  821. FunctionTableSize,
  822. &BytesWritten,
  823. NULL
  824. );
  825. }
  826. SetFilePointer( SymbolFileHandle, 0, NULL, FILE_END );
  827. CloseHandle( SymbolFileHandle );
  828. nomisc:
  829. FlushViewOfFile( ImageBase, NewFileSize );
  830. UnmapViewOfFile( ImageBase );
  831. SetFilePointer( FileHandle, NewFileSize, NULL, FILE_BEGIN );
  832. SetEndOfFile( FileHandle );
  833. TouchFileTimes( FileHandle, NULL );
  834. CloseHandle( FileHandle );
  835. if (ExportedNames) {
  836. #if defined(use_SplitSymbolsX)
  837. free( ExportedNames );
  838. #else
  839. MemFree( ExportedNames );
  840. #endif
  841. }
  842. if (FpoTable) {
  843. #if defined(use_SplitSymbolsX)
  844. free( FpoTable );
  845. #else
  846. MemFree( FpoTable );
  847. #endif
  848. }
  849. if (FunctionTable) {
  850. #if defined(use_SplitSymbolsX)
  851. free( FunctionTable );
  852. #else
  853. MemFree( FunctionTable );
  854. #endif
  855. }
  856. if (NewDebugData) {
  857. #if defined(use_SplitSymbolsX)
  858. free(NewDebugData);
  859. #else
  860. MemFree(NewDebugData);
  861. #endif
  862. }
  863. if (DbgDebugDirectories) {
  864. #if defined(use_SplitSymbolsX)
  865. free(DbgDebugDirectories);
  866. #else
  867. MemFree(DbgDebugDirectories);
  868. #endif
  869. }
  870. return TRUE;
  871. } else {
  872. CloseHandle( SymbolFileHandle );
  873. DeleteFile( SymbolFilePath );
  874. }
  875. nosyms:
  876. SavedErrorCode = GetLastError();
  877. if (ExportedNames != NULL) {
  878. #if defined(use_SplitSymbolsX)
  879. free( ExportedNames );
  880. #else
  881. MemFree( ExportedNames );
  882. #endif
  883. }
  884. if (FpoTable != NULL) {
  885. #if defined(use_SplitSymbolsX)
  886. free( FpoTable );
  887. #else
  888. MemFree( FpoTable );
  889. #endif
  890. }
  891. if (FunctionTable != NULL) {
  892. #if defined(use_SplitSymbolsX)
  893. free( FunctionTable );
  894. #else
  895. MemFree( FunctionTable );
  896. #endif
  897. }
  898. UnmapViewOfFile( ImageBase );
  899. CloseHandle( FileHandle );
  900. SetLastError( SavedErrorCode );
  901. return FALSE;
  902. #endif
  903. }
  904. #if defined(use_SplitSymbolsX)
  905. LPSTR CharNext(
  906. LPCSTR lpCurrentChar)
  907. {
  908. if (IsDBCSLeadByte(*lpCurrentChar)) {
  909. lpCurrentChar++;
  910. }
  911. /*
  912. * if we have only DBCS LeadingByte, we will point string-terminaler.
  913. */
  914. if (*lpCurrentChar) {
  915. lpCurrentChar++;
  916. }
  917. return (LPSTR)lpCurrentChar;
  918. }
  919. LPSTR CharPrev(
  920. LPCSTR lpStart,
  921. LPCSTR lpCurrentChar)
  922. {
  923. if (lpCurrentChar > lpStart) {
  924. LPCSTR lpChar;
  925. BOOL bDBC = FALSE;
  926. for (lpChar = --lpCurrentChar - 1 ; lpChar >= lpStart ; lpChar--) {
  927. if (!IsDBCSLeadByte(*lpChar))
  928. break;
  929. bDBC = !bDBC;
  930. }
  931. if (bDBC)
  932. lpCurrentChar--;
  933. }
  934. return (LPSTR)lpCurrentChar;
  935. }
  936. #endif