Leaked source code of windows server 2003
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.

1208 lines
31 KiB

  1. /*++
  2. Copyright 1996 - 1997 Microsoft Corporation
  3. Module Name:
  4. symedit.c
  5. Abstract:
  6. Author:
  7. Wesley A. Witt (wesw) 19-April-1993
  8. Environment:
  9. Win32, User Mode
  10. --*/
  11. #include <windows.h>
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <symcvt.h>
  16. #include <cv.h>
  17. #include "strings.h"
  18. #include <imagehlp.h>
  19. #undef UNICODE
  20. #define MAX_PATH 260
  21. // prototypes for this module
  22. BOOL CalculateOutputFilePointers( PIMAGEPOINTERS pi, PIMAGEPOINTERS po );
  23. void ProcessCommandLineArgs( int argc, WCHAR *argv[] );
  24. void PrintCopyright( void );
  25. void PrintUsage( void );
  26. void FatalError( int, ... );
  27. BOOL MapOutputFile ( PPOINTERS p, char *fname, int );
  28. void ComputeChecksum( char *szExeFile );
  29. void ReadDebugInfo( PPOINTERS p );
  30. void WriteDebugInfo( PPOINTERS p, BOOL);
  31. void MungeDebugHeadersCoffToCv( PPOINTERS p, BOOL fAddCV );
  32. void MungeExeName( PPOINTERS p, char * szExeName );
  33. void DoCoffToCv(char *, char *, BOOL);
  34. void DoSymToCv(char *, char *, char *, char *);
  35. void DoNameChange(char *, char *, char *);
  36. void DoExtract(char *, char *, char *);
  37. void DoStrip(char *, char *);
  38. IMAGE_DEBUG_DIRECTORY DbgDirSpare;
  39. #define AdjustPtr(ptr) (((ptr) != NULL) ? \
  40. ((DWORD)ptr - (DWORD)pi->fptr + (DWORD)po->fptr) : \
  41. ((DWORD)(ptr)))
  42. int _cdecl
  43. wmain(
  44. int argc,
  45. WCHAR * argv[]
  46. )
  47. /*++
  48. Routine Description:
  49. Shell for this utility.
  50. Arguments:
  51. argc - argument count
  52. argv - argument pointers
  53. Return Value:
  54. 0 - image was converted
  55. >0 - image could not be converted
  56. --*/
  57. {
  58. // Scan the command line and check what operations we are doing
  59. ProcessCommandLineArgs( argc, argv );
  60. return 0;
  61. }
  62. __inline void PrintCopyright( void )
  63. {
  64. puts( "\nMicrosoft(R) Windows NT SymEdit Version 1.0\n"
  65. "(C) 1989-1995 Microsoft Corp. All rights reserved.\n");
  66. }
  67. __inline void PrintUsage( void )
  68. {
  69. PrintCopyright();
  70. puts ("\nUsage: SYMEDIT <OPERATION> -q -o<file out> <file in>\n\n"
  71. "\t<OPERATION> is:\n"
  72. "\tC\tModify CodeView symbol information\n"
  73. "\tN\tEdit name field\n"
  74. "\tX\tExtract debug information\n"
  75. "\tS\tStrip all debug information\n\n"
  76. "Options:\n"
  77. "\t-a\t\tAdd CodeView debug info to file\n"
  78. "\t-n<name>\tName to change to\n"
  79. "\t-o<file>\tspecify output file\n"
  80. "\t-q\t\tquiet mode\n"
  81. "\t-r\t\tReplace COFF debug info with CV info\n"
  82. "\t-s<file>\tSym file source");
  83. }
  84. void
  85. ProcessCommandLineArgs(
  86. int argc,
  87. WCHAR *argv[]
  88. )
  89. /*++
  90. Routine Description:
  91. Processes the command line arguments and sets global flags to
  92. indicate the user's desired behavior.
  93. Arguments:
  94. argc - argument count
  95. argv - argument pointers
  96. Return Value:
  97. void
  98. --*/
  99. {
  100. int i;
  101. BOOL fQuiet = FALSE;
  102. BOOL fSilent = FALSE;
  103. char szOutputFile[MAX_PATH];
  104. char szInputFile[MAX_PATH];
  105. char szExeName[MAX_PATH];
  106. char szDbgFile[MAX_PATH];
  107. char szSymFile[MAX_PATH];
  108. int iOperation;
  109. BOOLEAN fAddCV = FALSE;
  110. // Minimun number of of arguments is 2 -- program and operation
  111. if (argc < 2 ||
  112. (wcscmp(argv[1], L"-?") == 0) ||
  113. (wcscmp(argv[1], L"?") == 0) )
  114. {
  115. PrintUsage();
  116. exit(1);
  117. }
  118. // All operations on 1 character wide
  119. if (argv[1][1] != 0) {
  120. FatalError(ERR_OP_UNKNOWN, argv[1]);
  121. }
  122. // Validate the operation
  123. switch( argv[1][0] ) {
  124. case L'C':
  125. case L'N':
  126. case L'X':
  127. case L'S':
  128. iOperation = argv[1][0];
  129. break;
  130. default:
  131. FatalError(ERR_OP_UNKNOWN, argv[1]);
  132. }
  133. // Parse out any other switches on the command line
  134. for (i=2; i<argc; i++) {
  135. if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
  136. switch (towupper(argv[i][1])) {
  137. // Add the CV debug information section rather than
  138. // replace the COFF section with the CV info.
  139. case L'A':
  140. fAddCV = TRUE;
  141. break;
  142. // Specify the output name for the DBG file
  143. case L'D':
  144. if (argv[i][2] == 0) {
  145. i += 1;
  146. wcstombs(szDbgFile, argv[i], MAX_PATH);
  147. } else {
  148. wcstombs(szDbgFile, &argv[i][2], MAX_PATH);
  149. }
  150. break;
  151. // Specify a new name to shove into the name of the
  152. // debuggee field in the Misc. Debug info field
  153. case L'N':
  154. if (argv[i][2] == 0) {
  155. i += 1;
  156. wcstombs(szExeName, argv[i], MAX_PATH);
  157. } else {
  158. wcstombs(szExeName, &argv[i][2], MAX_PATH);
  159. }
  160. break;
  161. // Specify the name of the output file
  162. case L'O':
  163. if (argv[i][2] == 0) {
  164. i += 1;
  165. wcstombs(szOutputFile,argv[i], MAX_PATH);
  166. } else {
  167. wcstombs(szOutputFile, &argv[i][2], MAX_PATH);
  168. }
  169. break;
  170. // Be quite and don't put out the banner
  171. case L'Q':
  172. fQuiet = TRUE;
  173. fSilent = TRUE;
  174. break;
  175. // Replace COFF debug information with CODEVIEW debug information
  176. case L'R':
  177. break;
  178. // Convert a Symbol File to CV info
  179. case L'S':
  180. if (argv[i][2] == 0) {
  181. i += 1;
  182. wcstombs(szSymFile, argv[i], MAX_PATH);
  183. } else {
  184. wcstombs(szSymFile, &argv[i][2], MAX_PATH);
  185. }
  186. break;
  187. // Print the command line options
  188. case L'?':
  189. PrintUsage();
  190. exit(1);
  191. break;
  192. // Unrecognized option
  193. default:
  194. FatalError( ERR_OP_UNKNOWN, argv[i] );
  195. break;
  196. }
  197. } else {
  198. // No leading switch character -- must be a file name
  199. wcstombs(szInputFile, &argv[i][0], MAX_PATH);
  200. // Process the file(s)
  201. if (!fQuiet) {
  202. PrintCopyright();
  203. fQuiet = TRUE;
  204. }
  205. if (!fSilent) {
  206. printf("processing file: %s\n", szInputFile );
  207. }
  208. // Do switch validation cheching and setup any missing global variables
  209. switch ( iOperation ) {
  210. // For conversions -- there are three types
  211. //
  212. // 1. Coff to CV -- add
  213. // 2. Coff to CV -- replace
  214. // 3. SYM to CV --- add
  215. // 4. SYM to CV -- seperate file
  216. //
  217. // Optional input file (not needed for case 4)
  218. // Optional output file
  219. // Optional sym file (implys sym->CV)
  220. // Optional DBG file
  221. case 'C':
  222. if (szSymFile == NULL) {
  223. DoCoffToCv(szInputFile, szOutputFile, fAddCV);
  224. } else {
  225. DoSymToCv(szInputFile, szOutputFile, szDbgFile, szSymFile);
  226. }
  227. break;
  228. // For changing the name of the debuggee --
  229. // Must specify input file
  230. // Must specify new name
  231. // Optional output file
  232. case 'N':
  233. DoNameChange(szInputFile, szOutputFile, szExeName);
  234. break;
  235. // For extraction of debug information
  236. // Must specify input file
  237. // Optional output file name
  238. // Optional debug file name
  239. case 'X':
  240. DoExtract(szInputFile, szOutputFile, szDbgFile);
  241. break;
  242. // For full strip of debug information
  243. // Must specify input file
  244. // Optional output file
  245. case 'S':
  246. DoStrip(szInputFile, szOutputFile);
  247. break;
  248. }
  249. }
  250. }
  251. return;
  252. }
  253. void
  254. ReadDebugInfo(
  255. PPOINTERS p
  256. )
  257. /*++
  258. Routine Description:
  259. This function will go out and read in all of the debug information
  260. into memory -- this is required because the input and output
  261. files might be the same, if so then writing out informaiton may
  262. destory data we need at a later time.
  263. Arguments:
  264. p - Supplies a pointer to the structure describing the debug info file
  265. Return Value:
  266. None.
  267. --*/
  268. {
  269. int i;
  270. // int cb;
  271. // char * pb;
  272. // PIMAGE_COFF_SYMBOLS_HEADER pCoffDbgInfo;
  273. // Allocate space to save pointers to debug info
  274. p->iptrs.rgpbDebugSave = (PCHAR *) malloc(p->iptrs.cDebugDir * sizeof(PCHAR));
  275. memset(p->iptrs.rgpbDebugSave, 0, p->iptrs.cDebugDir * sizeof(PCHAR));
  276. // Check each possible debug type record
  277. for (i=0; i<p->iptrs.cDebugDir; i++) {
  278. // If there was debug information then copy over the
  279. // description block and cache in the actual debug data.
  280. if (p->iptrs.rgDebugDir[i] != NULL) {
  281. p->iptrs.rgpbDebugSave[i] =
  282. malloc( p->iptrs.rgDebugDir[i]->SizeOfData );
  283. if (p->iptrs.rgpbDebugSave[i] == NULL) {
  284. FatalError(ERR_NO_MEMORY);
  285. }
  286. __try {
  287. memcpy(p->iptrs.rgpbDebugSave[i],
  288. p->iptrs.fptr +
  289. p->iptrs.rgDebugDir[i]->PointerToRawData,
  290. p->iptrs.rgDebugDir[i]->SizeOfData );
  291. } __except(EXCEPTION_EXECUTE_HANDLER ) {
  292. free(p->iptrs.rgpbDebugSave[i]);
  293. p->iptrs.rgpbDebugSave[i] = NULL;
  294. }
  295. }
  296. }
  297. return;
  298. }
  299. void
  300. WriteDebugInfo(
  301. PPOINTERS p,
  302. BOOL fAddCV
  303. )
  304. /*++
  305. Routine Description:
  306. This function will go out and read in all of the debug information
  307. into memory -- this is required because the input and output
  308. files might be the same, if so then writing out informaiton may
  309. destory data we need at a later time.
  310. Arguments:
  311. p - Supplies a pointer to the structure describing the debug info file
  312. Return Value:
  313. None.
  314. --*/
  315. {
  316. ULONG PointerToDebugData = 0; // Offset from the start of the file
  317. // to the current location to write
  318. // debug information out.
  319. ULONG BaseOfDebugData = 0;
  320. int i, flen;
  321. PIMAGE_DEBUG_DIRECTORY pDir, pDbgDir = NULL;
  322. if (p->optrs.debugSection) {
  323. BaseOfDebugData = PointerToDebugData =
  324. p->optrs.debugSection->PointerToRawData;
  325. } else if (p->optrs.sepHdr) {
  326. BaseOfDebugData = PointerToDebugData =
  327. sizeof(IMAGE_SEPARATE_DEBUG_HEADER) +
  328. p->optrs.sepHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
  329. p->optrs.sepHdr->ExportedNamesSize;
  330. }
  331. // Step 2. If the debug information is mapped, we know this
  332. // from the section headers, then we may need to write
  333. // out a new debug director to point to the debug information
  334. if (fAddCV) {
  335. if (p->optrs.optHdr) {
  336. p->optrs.optHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].
  337. VirtualAddress = p->optrs.debugSection->VirtualAddress;
  338. p->optrs.optHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size +=
  339. sizeof(IMAGE_DEBUG_DIRECTORY);
  340. } else if (p->optrs.sepHdr) {
  341. p->optrs.sepHdr->DebugDirectorySize += sizeof(IMAGE_DEBUG_DIRECTORY);
  342. } else {
  343. exit(1);
  344. }
  345. if (p->optrs.sepHdr) {
  346. pDbgDir = (PIMAGE_DEBUG_DIRECTORY) malloc(p->optrs.cDebugDir * sizeof(IMAGE_DEBUG_DIRECTORY));
  347. for (i=0; i<p->optrs.cDebugDir; i++) {
  348. if (p->optrs.rgDebugDir[i] != NULL) {
  349. pDbgDir[i] = *(p->optrs.rgDebugDir[i]);
  350. p->optrs.rgDebugDir[i] = &pDbgDir[i];
  351. }
  352. }
  353. }
  354. for (i=0; i<p->optrs.cDebugDir; i++) {
  355. if (p->optrs.rgDebugDir[i]) {
  356. pDir = (PIMAGE_DEBUG_DIRECTORY) (PointerToDebugData +
  357. p->optrs.fptr);
  358. *pDir = *(p->optrs.rgDebugDir[i]);
  359. p->optrs.rgDebugDir[i] = pDir;
  360. PointerToDebugData += sizeof(IMAGE_DEBUG_DIRECTORY);
  361. }
  362. }
  363. }
  364. // Step 3. For every debug info type, write out the debug information
  365. // and update any header information required
  366. for (i=0; i<p->optrs.cDebugDir; i++) {
  367. if (p->optrs.rgDebugDir[i] != NULL) {
  368. if (p->optrs.rgpbDebugSave[i] != NULL) {
  369. p->optrs.rgDebugDir[i]->PointerToRawData =
  370. PointerToDebugData;
  371. if (p->optrs.debugSection) {
  372. p->optrs.rgDebugDir[i]->AddressOfRawData =
  373. p->optrs.debugSection->VirtualAddress +
  374. PointerToDebugData - BaseOfDebugData;
  375. }
  376. memcpy(p->optrs.fptr + PointerToDebugData,
  377. p->optrs.rgpbDebugSave[i],
  378. p->optrs.rgDebugDir[i]->SizeOfData);
  379. if ((i == IMAGE_DEBUG_TYPE_COFF) &&
  380. (p->optrs.fileHdr != NULL)) {
  381. PIMAGE_COFF_SYMBOLS_HEADER pCoffDbgInfo;
  382. pCoffDbgInfo = (PIMAGE_COFF_SYMBOLS_HEADER)p->optrs.rgpbDebugSave[i];
  383. p->optrs.fileHdr->PointerToSymbolTable =
  384. PointerToDebugData + pCoffDbgInfo->LvaToFirstSymbol;
  385. }
  386. }
  387. PointerToDebugData += p->optrs.rgDebugDir[i]->SizeOfData;
  388. }
  389. }
  390. // Step 4. Clean up any COFF structures if we are replacing
  391. // the coff information with CV info.
  392. if ((p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_COFF] == NULL) &&
  393. (p->optrs.fileHdr != NULL)) {
  394. // Since there is no coff debug information -- clean out
  395. // both fields pointing to the debug info
  396. p->optrs.fileHdr->PointerToSymbolTable = 0;
  397. p->optrs.fileHdr->NumberOfSymbols = 0;
  398. }
  399. // Step 5. Correct the alignments if needed. If there is a real .debug
  400. // section in the file (i.e. it is mapped) then update it.
  401. if (p->optrs.debugSection) {
  402. p->optrs.debugSection->SizeOfRawData =
  403. FileAlign(PointerToDebugData - BaseOfDebugData);
  404. // update the optional header with the new image size
  405. p->optrs.optHdr->SizeOfImage =
  406. SectionAlign(p->optrs.debugSection->VirtualAddress +
  407. p->optrs.debugSection->SizeOfRawData);
  408. p->optrs.optHdr->SizeOfInitializedData +=
  409. p->optrs.debugSection->SizeOfRawData;
  410. }
  411. // calculate the new file size
  412. if (p->optrs.optHdr != NULL) {
  413. flen = FileAlign(PointerToDebugData);
  414. } else {
  415. flen = PointerToDebugData;
  416. }
  417. // finally, update the eof pointer and close the file
  418. UnmapViewOfFile( p->optrs.fptr );
  419. if (!SetFilePointer( p->optrs.hFile, flen, 0, FILE_BEGIN )) {
  420. FatalError( ERR_FILE_PTRS );
  421. }
  422. if (!SetEndOfFile( p->optrs.hFile )) {
  423. FatalError( ERR_SET_EOF );
  424. }
  425. CloseHandle( p->optrs.hFile );
  426. // Exit -- we are done.
  427. return;
  428. }
  429. void
  430. MungeDebugHeadersCoffToCv(
  431. PPOINTERS p,
  432. BOOL fAddCV
  433. )
  434. /*++
  435. Routine Description:
  436. Arguments:
  437. p - pointer to a POINTERS structure (see symcvt.h)
  438. Return Value:
  439. void
  440. --*/
  441. {
  442. if (!fAddCV) {
  443. CV_DIR(&p->optrs) = COFF_DIR(&p->optrs);
  444. COFF_DIR(&p->optrs) = 0;
  445. } else {
  446. CV_DIR(&p->optrs) = &DbgDirSpare;
  447. *(COFF_DIR(&p->optrs)) = *(COFF_DIR(&p->iptrs));
  448. };
  449. *CV_DIR(&p->optrs) = *(COFF_DIR(&p->iptrs));
  450. CV_DIR(&p->optrs)->Type = IMAGE_DEBUG_TYPE_CODEVIEW;
  451. CV_DIR(&p->optrs)->SizeOfData = p->pCvStart.size;
  452. p->optrs.rgpbDebugSave[IMAGE_DEBUG_TYPE_CODEVIEW] = p->pCvStart.ptr;
  453. return;
  454. }
  455. BOOL
  456. MapOutputFile (
  457. PPOINTERS p,
  458. char *fname,
  459. int cb
  460. )
  461. /*++
  462. Routine Description:
  463. Maps the output file specified by the fname argument and saves the
  464. file handle & file pointer in the POINTERS structure.
  465. Arguments:
  466. p - pointer to a POINTERS structure (see symcvt.h)
  467. fname - ascii string for the file name
  468. Return Value:
  469. TRUE - file mapped ok
  470. FALSE - file could not be mapped
  471. --*/
  472. {
  473. BOOL rval;
  474. HANDLE hMap = NULL;
  475. DWORD oSize;
  476. rval = FALSE;
  477. p->optrs.hFile = CreateFileA( fname,
  478. GENERIC_READ | GENERIC_WRITE,
  479. FILE_SHARE_READ | FILE_SHARE_WRITE,
  480. NULL,
  481. OPEN_ALWAYS,
  482. 0,
  483. NULL );
  484. if (p->optrs.hFile == INVALID_HANDLE_VALUE) {
  485. goto exit;
  486. }
  487. oSize = p->iptrs.fsize;
  488. if (p->pCvStart.ptr != NULL) {
  489. oSize += p->pCvStart.size;
  490. }
  491. oSize += cb;
  492. oSize += p->iptrs.cDebugDir * sizeof(IMAGE_DEBUG_DIRECTORY);
  493. hMap = CreateFileMapping( p->optrs.hFile, NULL, PAGE_READWRITE,
  494. 0, oSize, NULL );
  495. if (hMap == NULL) {
  496. goto exit;
  497. }
  498. p->optrs.fptr = MapViewOfFile( hMap, FILE_MAP_WRITE, 0, 0, 0 );
  499. CloseHandle(hMap);
  500. if (p->optrs.fptr == NULL) {
  501. goto exit;
  502. }
  503. rval = TRUE;
  504. exit:
  505. return rval;
  506. }
  507. BOOL
  508. CalculateOutputFilePointers(
  509. PIMAGEPOINTERS pi,
  510. PIMAGEPOINTERS po
  511. )
  512. /*++
  513. Routine Description:
  514. This function calculates the output file pointers based on the
  515. input file pointers. The same address is used but they are all
  516. re-based off the output file's file pointer.
  517. Arguments:
  518. p - pointer to a IMAGEPOINTERS structure (see symcvt.h)
  519. Return Value:
  520. TRUE - pointers were created
  521. FALSE - pointers could not be created
  522. --*/
  523. {
  524. int i;
  525. // fixup the pointers relative the fptr for the output file
  526. po->dosHdr = (PIMAGE_DOS_HEADER) AdjustPtr(pi->dosHdr);
  527. po->ntHdr = (PIMAGE_NT_HEADERS) AdjustPtr(pi->ntHdr);
  528. po->fileHdr = (PIMAGE_FILE_HEADER) AdjustPtr(pi->fileHdr);
  529. po->optHdr = (PIMAGE_OPTIONAL_HEADER) AdjustPtr(pi->optHdr);
  530. po->sectionHdrs = (PIMAGE_SECTION_HEADER) AdjustPtr(pi->sectionHdrs);
  531. po->sepHdr = (PIMAGE_SEPARATE_DEBUG_HEADER) AdjustPtr(pi->sepHdr);
  532. po->debugSection = (PIMAGE_SECTION_HEADER) AdjustPtr(pi->debugSection);
  533. po->AllSymbols = (PIMAGE_SYMBOL) AdjustPtr(pi->AllSymbols);
  534. po->stringTable = (PUCHAR) AdjustPtr(pi->stringTable);
  535. // move the data from the input file to the output file
  536. memcpy( po->fptr, pi->fptr, pi->fsize );
  537. po->cDebugDir = pi->cDebugDir;
  538. po->rgDebugDir = malloc(po->cDebugDir * sizeof(po->rgDebugDir[0]));
  539. memset(po->rgDebugDir, 0, po->cDebugDir * sizeof(po->rgDebugDir[0]));
  540. for (i=0; i<po->cDebugDir; i++) {
  541. po->rgDebugDir[i] = (PIMAGE_DEBUG_DIRECTORY) AdjustPtr(pi->rgDebugDir[i]);
  542. }
  543. po->rgpbDebugSave = pi->rgpbDebugSave;
  544. return TRUE;
  545. }
  546. void
  547. FatalError(
  548. int idMsg,
  549. ...
  550. )
  551. /*++
  552. Routine Description:
  553. Prints a message string to stderr and then exits.
  554. Arguments:
  555. s - message string to be printed
  556. Return Value:
  557. void
  558. --*/
  559. {
  560. va_list marker;
  561. char rgchFormat[256];
  562. char rgch[256];
  563. LoadStringA(GetModuleHandle(NULL), idMsg, rgchFormat, sizeof(rgchFormat));
  564. va_start(marker, idMsg);
  565. vsprintf(rgch, rgchFormat, marker);
  566. va_end(marker);
  567. fprintf(stderr, "%s\n", rgch);
  568. exit(1);
  569. }
  570. void
  571. ComputeChecksum(
  572. char *szExeFile
  573. )
  574. /*++
  575. Routine Description:
  576. Computes a new checksum for the image by calling imagehlp.dll
  577. Arguments:
  578. szExeFile - exe file name
  579. Return Value:
  580. void
  581. --*/
  582. {
  583. DWORD dwHeaderSum = 0;
  584. DWORD dwCheckSum = 0;
  585. HANDLE hFile;
  586. DWORD cb;
  587. IMAGE_DOS_HEADER dosHdr;
  588. IMAGE_NT_HEADERS ntHdr;
  589. if (MapFileAndCheckSumA(szExeFile, &dwHeaderSum, &dwCheckSum) != CHECKSUM_SUCCESS) {
  590. FatalError( ERR_CHECKSUM_CALC );
  591. }
  592. hFile = CreateFileA( szExeFile,
  593. GENERIC_READ | GENERIC_WRITE,
  594. FILE_SHARE_READ | FILE_SHARE_WRITE,
  595. NULL,
  596. OPEN_EXISTING,
  597. 0,
  598. NULL
  599. );
  600. // seek to the beginning of the file
  601. SetFilePointer( hFile, 0, 0, FILE_BEGIN );
  602. // read in the dos header
  603. if ((ReadFile(hFile, &dosHdr, sizeof(dosHdr), &cb, 0) == FALSE) || (cb != sizeof(dosHdr))) {
  604. FatalError( ERR_CHECKSUM_CALC );
  605. }
  606. // read in the pe header
  607. if ((dosHdr.e_magic != IMAGE_DOS_SIGNATURE) ||
  608. (SetFilePointer(hFile, dosHdr.e_lfanew, 0, FILE_BEGIN) == -1L)) {
  609. FatalError( ERR_CHECKSUM_CALC );
  610. }
  611. // read in the nt header
  612. if ((!ReadFile(hFile, &ntHdr, sizeof(ntHdr), &cb, 0)) || (cb != sizeof(ntHdr))) {
  613. FatalError( ERR_CHECKSUM_CALC );
  614. }
  615. if (SetFilePointer(hFile, dosHdr.e_lfanew, 0, FILE_BEGIN) == -1L) {
  616. FatalError( ERR_CHECKSUM_CALC );
  617. }
  618. ntHdr.OptionalHeader.CheckSum = dwCheckSum;
  619. if (!WriteFile(hFile, &ntHdr, sizeof(ntHdr), &cb, NULL)) {
  620. FatalError( ERR_CHECKSUM_CALC );
  621. }
  622. CloseHandle(hFile);
  623. return;
  624. }
  625. void
  626. MungeExeName(
  627. PPOINTERS p,
  628. char * szExeName
  629. )
  630. /*++
  631. Routine Description:
  632. description-of-function.
  633. Arguments:
  634. argument-name - Supplies | Returns description of argument.
  635. .
  636. .
  637. Return Value:
  638. None.
  639. --*/
  640. {
  641. PIMAGE_DEBUG_MISC pMiscIn;
  642. PIMAGE_DEBUG_MISC pMiscOut;
  643. int cb;
  644. int i;
  645. for (i=0; i<p->iptrs.cDebugDir; i++) {
  646. if (p->optrs.rgDebugDir[i] != 0) {
  647. *(p->optrs.rgDebugDir[i]) = *(p->iptrs.rgDebugDir[i]);
  648. }
  649. }
  650. pMiscIn = (PIMAGE_DEBUG_MISC)
  651. p->iptrs.rgpbDebugSave[IMAGE_DEBUG_TYPE_MISC];
  652. if (p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC] == NULL) {
  653. p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC] = &DbgDirSpare;
  654. memset(&DbgDirSpare, 0, sizeof(DbgDirSpare));
  655. }
  656. pMiscOut = (PIMAGE_DEBUG_MISC)
  657. p->optrs.rgpbDebugSave[IMAGE_DEBUG_TYPE_MISC] =
  658. malloc(p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC]->SizeOfData +
  659. strlen(szExeName));
  660. cb = p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC]->SizeOfData;
  661. while ( cb > 0 ) {
  662. if (pMiscIn->DataType == IMAGE_DEBUG_MISC_EXENAME) {
  663. pMiscOut->DataType = IMAGE_DEBUG_MISC_EXENAME;
  664. pMiscOut->Length = (sizeof(IMAGE_DEBUG_MISC) +
  665. strlen(szExeName) + 3) & ~3;
  666. pMiscOut->Unicode = FALSE;
  667. strcpy(&pMiscOut->Data[0], szExeName);
  668. szExeName = NULL;
  669. } else {
  670. memcpy(pMiscOut, pMiscIn, pMiscIn->Length);
  671. }
  672. p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC]->SizeOfData +=
  673. (pMiscOut->Length - pMiscIn->Length);
  674. cb -= pMiscIn->Length;
  675. pMiscIn = (PIMAGE_DEBUG_MISC) (((char *) pMiscIn) + pMiscIn->Length);
  676. pMiscOut = (PIMAGE_DEBUG_MISC) (((char *) pMiscOut) + pMiscOut->Length);
  677. }
  678. if (szExeName) {
  679. pMiscOut->DataType = IMAGE_DEBUG_MISC_EXENAME;
  680. pMiscOut->Length = (sizeof(IMAGE_DEBUG_MISC) +
  681. strlen(szExeName) + 3) & ~3;
  682. pMiscOut->Unicode = FALSE;
  683. strcpy(&pMiscOut->Data[0], szExeName);
  684. }
  685. return;
  686. }
  687. /*** DoCoffToCv
  688. *
  689. *
  690. */
  691. void DoCoffToCv(
  692. char * szInput,
  693. char * szOutput,
  694. BOOL fAddCV
  695. )
  696. {
  697. POINTERS p;
  698. // Do default checking
  699. if (szOutput == NULL) {
  700. szOutput = szInput;
  701. }
  702. // Open the input file name and setup the pointers into the file
  703. if (!MapInputFile( &p, NULL, szInput )) {
  704. FatalError( ERR_OPEN_INPUT_FILE, szInput );
  705. }
  706. // Now, if we thing we are playing with PE exes then we need
  707. // to setup the pointers into the map file
  708. if (!CalculateNtImagePointers( &p.iptrs )) {
  709. FatalError( ERR_INVALID_PE, szInput );
  710. }
  711. // We are about to try and do the coff to cv symbol conversion.
  712. //
  713. // Verify that the operation is legal.
  714. //
  715. // 1. We need to have coff debug information to start with
  716. // 2. If the debug info is not mapped then we must not
  717. // be trying to add CodeView info.
  718. if ((p.iptrs.AllSymbols == NULL) || (COFF_DIR(&p.iptrs) == NULL)) {
  719. FatalError( ERR_NO_COFF );
  720. }
  721. if (fAddCV && (p.iptrs.debugSection == 0) && (p.iptrs.sepHdr == NULL)) {
  722. FatalError( ERR_NOT_MAPPED );
  723. }
  724. // Now go out an preform the acutal conversion.
  725. if (!ConvertCoffToCv( &p )) {
  726. FatalError( ERR_COFF_TO_CV );
  727. }
  728. // Read in any additional debug information in the file
  729. ReadDebugInfo(&p);
  730. // Open the output file and adjust the pointers so that we are ok.
  731. if (!MapOutputFile( &p, szOutput, 0 )) {
  732. FatalError( ERR_MAP_FILE, szOutput );
  733. }
  734. CalculateOutputFilePointers( &p.iptrs, &p.optrs );
  735. // Munge the various debug information structures to preform the correct
  736. // operations
  737. MungeDebugHeadersCoffToCv( &p, fAddCV );
  738. // Free our handles on the input file
  739. UnMapInputFile(&p);
  740. // Write out the debug information to the end of the exe
  741. WriteDebugInfo( &p, fAddCV );
  742. // and finally compute the checksum
  743. if (p.iptrs.fileHdr != NULL) {
  744. ComputeChecksum( szOutput );
  745. }
  746. return;
  747. }
  748. /*** DoSymToCv
  749. *
  750. */
  751. void
  752. DoSymToCv(
  753. char * szInput,
  754. char * szOutput,
  755. char * szDbg,
  756. char * szSym
  757. )
  758. {
  759. POINTERS p;
  760. HANDLE hFile;
  761. DWORD cb;
  762. OFSTRUCT ofs;
  763. // Open the input file name and setup the pointers into the file
  764. if (!MapInputFile( &p, NULL, szSym )) {
  765. FatalError(ERR_OPEN_INPUT_FILE, szSym);
  766. }
  767. // Now preform the desired operation
  768. if ((szOutput == NULL) && (szDbg == NULL)) {
  769. szOutput = szInput;
  770. }
  771. ConvertSymToCv( &p );
  772. if (szOutput) {
  773. if (szOutput != szInput) {
  774. if (OpenFile(szInput, &ofs, OF_EXIST) == 0) {
  775. FatalError(ERR_OPEN_INPUT_FILE, szInput);
  776. }
  777. if (CopyFileA(szInput, szOutput, FALSE) == 0) {
  778. FatalError(ERR_OPEN_WRITE_FILE, szOutput);
  779. }
  780. }
  781. hFile = CreateFileA(szOutput, GENERIC_WRITE, 0, NULL,
  782. CREATE_ALWAYS,
  783. FILE_ATTRIBUTE_NORMAL, NULL);
  784. if (hFile == INVALID_HANDLE_VALUE) {
  785. FatalError(ERR_OPEN_WRITE_FILE, szOutput);
  786. }
  787. SetFilePointer(hFile, 0, 0, FILE_END);
  788. } else if (szDbg) {
  789. hFile = CreateFileA(szDbg, GENERIC_WRITE, 0, NULL,
  790. OPEN_ALWAYS,
  791. FILE_ATTRIBUTE_NORMAL, NULL);
  792. if (hFile == INVALID_HANDLE_VALUE) {
  793. FatalError(ERR_OPEN_WRITE_FILE, szDbg);
  794. }
  795. }
  796. WriteFile(hFile, p.pCvStart.ptr, p.pCvStart.size, &cb, NULL);
  797. CloseHandle(hFile);
  798. return;
  799. }
  800. void
  801. DoNameChange(
  802. char * szInput,
  803. char * szOutput,
  804. char * szNewName
  805. )
  806. {
  807. POINTERS p;
  808. // Open the input file name and setup the pointers into the file
  809. if (!MapInputFile( &p, NULL, szInput )) {
  810. FatalError(ERR_OPEN_INPUT_FILE, szInput);
  811. }
  812. // Now, if we thing we are playing with PE exes then we need
  813. // to setup the pointers into the map file
  814. if (!CalculateNtImagePointers( &p.iptrs )) {
  815. FatalError(ERR_INVALID_PE, szInput);
  816. }
  817. // Now preform the desired operation
  818. if (szOutput == NULL) {
  819. szOutput = szInput;
  820. }
  821. if (szNewName == NULL) {
  822. szNewName = szOutput;
  823. }
  824. if (p.iptrs.sepHdr != NULL) {
  825. FatalError(ERR_EDIT_DBG_FILE);
  826. }
  827. // Read in all of the debug information
  828. ReadDebugInfo(&p);
  829. // Open the output file and adjust the pointers.
  830. if (!MapOutputFile(&p, szOutput,
  831. sizeof(szNewName) * 2 + sizeof(IMAGE_DEBUG_MISC))) {
  832. FatalError(ERR_MAP_FILE, szOutput);
  833. }
  834. CalculateOutputFilePointers(&p.iptrs, &p.optrs);
  835. // Munge the name of the file
  836. MungeExeName(&p, szNewName);
  837. // Close the input file
  838. UnMapInputFile(&p);
  839. // Write out the debug information to the end of the exe
  840. WriteDebugInfo(&p, FALSE);
  841. // and finally compute the checksum
  842. if (p.iptrs.fileHdr != NULL) {
  843. ComputeChecksum( szOutput );
  844. }
  845. return;
  846. }
  847. void
  848. DoStrip(
  849. char * szInput,
  850. char * szOutput
  851. )
  852. {
  853. char OutputFile[_MAX_PATH];
  854. // Make sure we only have the path to the output file (it will always be
  855. // named filename.DBG)
  856. if (szOutput != NULL) {
  857. CopyFileA(szInput, szOutput, FALSE);
  858. }
  859. SplitSymbols(szOutput, NULL, OutputFile, SPLITSYM_EXTRACT_ALL);
  860. // Always delete the output file.
  861. DeleteFileA(OutputFile);
  862. return;
  863. }
  864. void
  865. DoExtract(
  866. char * szInput,
  867. char * szOutput,
  868. char * szDbgFile
  869. )
  870. {
  871. char OutputFile[_MAX_PATH];
  872. char szExt[_MAX_EXT];
  873. char szFileName[_MAX_FNAME];
  874. if (szOutput != NULL) {
  875. CopyFileA(szInput, szOutput, FALSE);
  876. szInput = _strdup(szOutput);
  877. _splitpath(szOutput, NULL, NULL, szFileName, szExt);
  878. *(szOutput + strlen(szOutput) - strlen(szFileName) - strlen(szExt)) = '\0';
  879. }
  880. SplitSymbols(szInput, szOutput, OutputFile, 0);
  881. CopyFileA(szDbgFile, OutputFile, TRUE);
  882. if (szOutput) {
  883. free(szInput);
  884. }
  885. return;
  886. }