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.

1356 lines
36 KiB

  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. #include <symbols.h>
  14. #include <globals.h>
  15. #define ROUNDUP(x, y) ((x + (y-1)) & ~(y-1))
  16. typedef BOOL
  17. (CALLBACK *PSEARCH_TREE_FOR_FILE_EX_CALLBACK)(
  18. LPSTR FilePath,
  19. PVOID CallerData
  20. );
  21. BOOL
  22. IMAGEAPI
  23. SearchTreeForFileEx(
  24. PSTR RootPath,
  25. PSTR InputPathName,
  26. PSTR OutputPathBuffer,
  27. PSEARCH_TREE_FOR_FILE_EX_CALLBACK Callback,
  28. PVOID CallbackData
  29. );
  30. /////////////////////////////////////////////////////////////////////////////
  31. /////////////////////////////////////////////////////////////////////////////
  32. #if !defined(_WIN64)
  33. PIMAGE_DEBUG_INFORMATION
  34. IMAGEAPI
  35. MapDebugInformation(
  36. HANDLE FileHandle,
  37. LPSTR FileName,
  38. LPSTR SymbolPath,
  39. ULONG ImageBase
  40. )
  41. // Here's what we're going to try. MapDebugInformation was only
  42. // documented as returning COFF symbolic and every user I can find
  43. // in the tree uses COFF exclusively. Rather than try to make this
  44. // api do everything possible, let's just leave it as a COFF only thing.
  45. // The new debug info api (GetDebugData) will be internal only.
  46. {
  47. PIMAGE_DEBUG_INFORMATION pIDI;
  48. CHAR szName[_MAX_FNAME];
  49. CHAR szExt[_MAX_EXT];
  50. PIMGHLP_DEBUG_DATA pIDD;
  51. PPIDI pPIDI;
  52. DWORD sections;
  53. BOOL SymbolsLoaded;
  54. HANDLE hProcess;
  55. LPSTR sz;
  56. HANDLE hdb;
  57. DWORD dw;
  58. hProcess = GetCurrentProcess();
  59. pIDD = GetDebugData(NULL, FileHandle, FileName, SymbolPath, ImageBase, NULL, NO_PE64_IMAGES);
  60. if (!pIDD)
  61. return NULL;
  62. pPIDI = (PPIDI)MemAlloc(sizeof(PIDI));
  63. if (!pPIDI)
  64. return NULL;
  65. ZeroMemory(pPIDI, sizeof(PIDI));
  66. pIDI = &pPIDI->idi;
  67. pPIDI->hdr.pIDD = pIDD;
  68. pIDI->ReservedSize = sizeof(IMAGE_DEBUG_INFORMATION);
  69. pIDI->ReservedMachine = pIDD->Machine;
  70. pIDI->ReservedCharacteristics = (USHORT)pIDD->Characteristics;
  71. pIDI->ReservedCheckSum = pIDD->CheckSum;
  72. pIDI->ReservedTimeDateStamp = pIDD->TimeDateStamp;
  73. pIDI->ReservedRomImage = pIDD->fROM;
  74. // read info
  75. InitializeListHead( &pIDI->List );
  76. pIDI->ImageBase = (ULONG)pIDD->ImageBaseFromImage;
  77. pIDI->ImageFilePath = (PSTR)MemAlloc(strlen(pIDD->ImageFilePath)+1);
  78. if (pIDI->ImageFilePath) {
  79. strcpy( pIDI->ImageFilePath, pIDD->ImageFilePath );
  80. }
  81. pIDI->ImageFileName = (PSTR)MemAlloc(strlen(pIDD->OriginalImageFileName)+1);
  82. if (pIDI->ImageFileName) {
  83. strcpy(pIDI->ImageFileName, pIDD->OriginalImageFileName);
  84. }
  85. if (pIDD->pMappedCoff) {
  86. pIDI->CoffSymbols = (PIMAGE_COFF_SYMBOLS_HEADER)MemAlloc(pIDD->cMappedCoff);
  87. if (pIDI->CoffSymbols) {
  88. memcpy(pIDI->CoffSymbols, pIDD->pMappedCoff, pIDD->cMappedCoff);
  89. }
  90. pIDI->SizeOfCoffSymbols = pIDD->cMappedCoff;
  91. }
  92. if (pIDD->pFpo) {
  93. pIDI->ReservedNumberOfFpoTableEntries = pIDD->cFpo;
  94. pIDI->ReservedFpoTableEntries = (PFPO_DATA)pIDD->pFpo;
  95. }
  96. pIDI->SizeOfImage = pIDD->SizeOfImage;
  97. if (pIDD->DbgFilePath && *pIDD->DbgFilePath) {
  98. pIDI->ReservedDebugFilePath = (PSTR)MemAlloc(strlen(pIDD->DbgFilePath)+1);
  99. if (pIDI->ReservedDebugFilePath) {
  100. strcpy(pIDI->ReservedDebugFilePath, pIDD->DbgFilePath);
  101. }
  102. }
  103. if (pIDD->pMappedCv) {
  104. pIDI->ReservedCodeViewSymbols = pIDD->pMappedCv;
  105. pIDI->ReservedSizeOfCodeViewSymbols = pIDD->cMappedCv;
  106. }
  107. // for backwards compatibility
  108. if (pIDD->ImageMap) {
  109. sections = (DWORD)((char *)pIDD->pCurrentSections - (char *)pIDD->ImageMap);
  110. pIDI->ReservedMappedBase = MapItRO(pIDD->ImageFileHandle);
  111. if (pIDI->ReservedMappedBase) {
  112. pIDI->ReservedSections = (PIMAGE_SECTION_HEADER)pIDD->pCurrentSections;
  113. pIDI->ReservedNumberOfSections = pIDD->cCurrentSections;
  114. if (pIDD->ddva) {
  115. pIDI->ReservedDebugDirectory = (PIMAGE_DEBUG_DIRECTORY)((PCHAR)pIDI->ReservedMappedBase + pIDD->ddva);
  116. pIDI->ReservedNumberOfDebugDirectories = pIDD->cdd;
  117. }
  118. }
  119. }
  120. return pIDI;
  121. }
  122. BOOL
  123. UnmapDebugInformation(
  124. PIMAGE_DEBUG_INFORMATION pIDI
  125. )
  126. {
  127. PPIDI pPIDI;
  128. if (!pIDI)
  129. return TRUE;
  130. if (pIDI->ImageFileName){
  131. MemFree(pIDI->ImageFileName);
  132. }
  133. if (pIDI->ImageFilePath) {
  134. MemFree(pIDI->ImageFilePath);
  135. }
  136. if (pIDI->ReservedDebugFilePath) {
  137. MemFree(pIDI->ReservedDebugFilePath);
  138. }
  139. if (pIDI->CoffSymbols) {
  140. MemFree(pIDI->CoffSymbols);
  141. }
  142. if (pIDI->ReservedMappedBase) {
  143. UnmapViewOfFile(pIDI->ReservedMappedBase);
  144. }
  145. pPIDI = (PPIDI)(PCHAR)((PCHAR)pIDI - sizeof(PIDI_HEADER));
  146. ReleaseDebugData(pPIDI->hdr.pIDD, IMGHLP_FREE_ALL);
  147. MemFree(pPIDI);
  148. return TRUE;
  149. }
  150. #endif
  151. LPSTR
  152. ExpandPath(
  153. LPSTR lpPath
  154. )
  155. {
  156. LPSTR p, newpath, p1, p2, p3;
  157. CHAR envvar[MAX_PATH];
  158. CHAR envstr[MAX_PATH];
  159. ULONG i, PathMax;
  160. if (!lpPath) {
  161. return(NULL);
  162. }
  163. p = lpPath;
  164. PathMax = strlen(lpPath) + MAX_PATH + 1;
  165. p2 = newpath = (LPSTR) MemAlloc( PathMax );
  166. if (!newpath) {
  167. return(NULL);
  168. }
  169. while( p && *p) {
  170. if (*p == '%') {
  171. i = 0;
  172. p++;
  173. while (p && *p && *p != '%') {
  174. envvar[i++] = *p++;
  175. }
  176. p++;
  177. envvar[i] = '\0';
  178. p1 = envstr;
  179. *p1 = 0;
  180. GetEnvironmentVariable( envvar, p1, MAX_PATH );
  181. while (p1 && *p1) {
  182. *p2++ = *p1++;
  183. if (p2 >= newpath + PathMax) {
  184. PathMax += MAX_PATH;
  185. p3 = (LPSTR)MemReAlloc(newpath, PathMax);
  186. if (!p3) {
  187. MemFree(newpath);
  188. return(NULL);
  189. } else {
  190. p2 = p3 + (p2 - newpath);
  191. newpath = p3;
  192. }
  193. }
  194. }
  195. }
  196. *p2++ = *p++;
  197. if (p2 >= newpath + PathMax) {
  198. PathMax += MAX_PATH;
  199. p3 = (LPSTR)MemReAlloc(newpath, PathMax);
  200. if (!p3) {
  201. MemFree(newpath);
  202. return(NULL);
  203. } else {
  204. p2 = p3 + (p2 - newpath);
  205. newpath = p3;
  206. }
  207. }
  208. }
  209. *p2 = '\0';
  210. return newpath;
  211. }
  212. BOOL
  213. IMAGEAPI
  214. SymFindFileInPath(
  215. HANDLE hprocess,
  216. LPSTR SearchPath,
  217. LPSTR FileName,
  218. PVOID id,
  219. DWORD two,
  220. DWORD three,
  221. DWORD flags,
  222. LPSTR FilePath,
  223. PFINDFILEINPATHCALLBACK callback,
  224. PVOID context
  225. )
  226. {
  227. PPROCESS_ENTRY pe;
  228. char path[MAX_PATH];
  229. LPSTR emark;
  230. LPSTR spath;
  231. GUID guid;
  232. GUID *pguid;
  233. BOOL rc;
  234. LPSTR p;
  235. if (!FileName || !*FileName) {
  236. SetLastError(ERROR_INVALID_PARAMETER);
  237. return FALSE;
  238. }
  239. // ignore the path...
  240. for (p = FileName + strlen(FileName); p >= FileName; p--) {
  241. if (*p == '\\') {
  242. FileName = p + 1;
  243. break;
  244. }
  245. }
  246. if (traceSubName(FileName)) // for setting debug breakpoints from DBGHELP_TOKEN
  247. dprint("debug(%s)\n", FileName);
  248. // prepare identifiers for symbol server
  249. if (flags & SSRVOPT_GUIDPTR) {
  250. pguid = (GUID *)id;
  251. } else {
  252. pguid = &guid;
  253. ZeroMemory(pguid, sizeof(GUID));
  254. if (!flags || (flags & SSRVOPT_DWORD))
  255. pguid->Data1 = PtrToUlong(id);
  256. else if (flags & SSRVOPT_DWORDPTR)
  257. pguid->Data1 = *(DWORD *)id;
  258. }
  259. // setup local copy of the symbol path
  260. *FilePath = 0;
  261. spath = NULL;
  262. if (!SearchPath || !*SearchPath) {
  263. if (hprocess) {
  264. pe = FindProcessEntry(hprocess);
  265. if (pe && pe->SymbolSearchPath) {
  266. spath = pe->SymbolSearchPath;
  267. }
  268. }
  269. } else {
  270. spath = SearchPath;
  271. }
  272. if (!spath || !*spath) {
  273. SetLastError(ERROR_INVALID_PARAMETER);
  274. return FALSE;
  275. }
  276. // for each node in the search path, look
  277. // for the file, or for it's symsrv entry
  278. do {
  279. emark = strchr(spath, ';');
  280. if (emark) {
  281. memcpy(path, spath, emark - spath);
  282. path[emark - spath] = 0;
  283. emark++;
  284. } else {
  285. strcpy(path, spath);
  286. }
  287. // look for the file in this node
  288. if (!_strnicmp(path, "SYMSRV*", 7)) {
  289. GetFileFromSymbolServer(path,
  290. FileName,
  291. pguid,
  292. two,
  293. three,
  294. FilePath);
  295. } else {
  296. EnsureTrailingBackslash(path);
  297. strcat(path, FileName);
  298. if (fileexists(path))
  299. strcpy(FilePath, path);
  300. }
  301. // if we find a file, process it.
  302. if (*FilePath) {
  303. // if no callback is specified, return with the filename filled in
  304. if (!callback)
  305. break;
  306. // otherwise call the callback
  307. rc = callback(FilePath, context);
  308. // if it returns FALSE, quit...
  309. if (!rc)
  310. break;
  311. // otherwise continue
  312. *FilePath = 0;
  313. }
  314. // continue to the next node
  315. spath = emark;
  316. } while (emark);
  317. return (*FilePath) ? TRUE : FALSE;
  318. }
  319. BOOL
  320. IMAGEAPI
  321. FindFileInPath(
  322. HANDLE hprocess,
  323. LPSTR SearchPath,
  324. LPSTR FileName,
  325. PVOID id,
  326. DWORD two,
  327. DWORD three,
  328. DWORD flags,
  329. LPSTR FilePath
  330. )
  331. {
  332. return SymFindFileInPath(hprocess, SearchPath, FileName, id, two, three, flags, FilePath, NULL, NULL);
  333. }
  334. BOOL
  335. IMAGEAPI
  336. FindFileInSearchPath(
  337. HANDLE hprocess,
  338. LPSTR SearchPath,
  339. LPSTR FileName,
  340. DWORD one,
  341. DWORD two,
  342. DWORD three,
  343. LPSTR FilePath
  344. )
  345. {
  346. return FindFileInPath(hprocess, SearchPath, FileName, UlongToPtr(one), two, three, SSRVOPT_DWORD, FilePath);
  347. }
  348. HANDLE
  349. IMAGEAPI
  350. FindExecutableImage(
  351. LPSTR FileName,
  352. LPSTR SymbolPath,
  353. LPSTR ImageFilePath
  354. )
  355. {
  356. return FindExecutableImageEx(FileName, SymbolPath, ImageFilePath, NULL, NULL);
  357. }
  358. HANDLE
  359. CheckExecutableImage(
  360. LPSTR Path,
  361. PFIND_EXE_FILE_CALLBACK Callback,
  362. PVOID CallerData,
  363. DWORD flags
  364. )
  365. {
  366. HANDLE FileHandle;
  367. SetCriticalErrorMode();
  368. dprint("FindExecutableImageEx-> Looking for %s... ", Path);
  369. FileHandle = CreateFile( Path,
  370. GENERIC_READ,
  371. g.OSVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ?
  372. (FILE_SHARE_DELETE | FILE_SHARE_READ |
  373. FILE_SHARE_WRITE) :
  374. (FILE_SHARE_READ | FILE_SHARE_WRITE),
  375. NULL,
  376. OPEN_EXISTING,
  377. 0,
  378. NULL
  379. );
  380. if (FileHandle != INVALID_HANDLE_VALUE) {
  381. if (Callback) {
  382. if (!Callback(FileHandle, Path, CallerData)) {
  383. eprint("mismatched timestamp ");
  384. if (!(flags & SYMOPT_LOAD_ANYTHING)) {
  385. eprint("\n");
  386. CloseHandle(FileHandle);
  387. FileHandle = INVALID_HANDLE_VALUE;
  388. }
  389. }
  390. }
  391. if (FileHandle != INVALID_HANDLE_VALUE) {
  392. eprint("OK\n");
  393. }
  394. } else {
  395. eprint("no file\n");
  396. }
  397. ResetCriticalErrorMode();
  398. return FileHandle;
  399. }
  400. typedef struct _FEIEP_STATE
  401. {
  402. PFIND_EXE_FILE_CALLBACK UserCb;
  403. PVOID UserCbData;
  404. DWORD flags;
  405. HANDLE Return;
  406. } FEIEP_STATE;
  407. BOOL
  408. CALLBACK
  409. FindExSearchTreeCallback(
  410. LPSTR FilePath,
  411. PVOID CallerData
  412. )
  413. {
  414. FEIEP_STATE* State = (FEIEP_STATE*)CallerData;
  415. State->Return =
  416. CheckExecutableImage(FilePath, State->UserCb, State->UserCbData,
  417. State->flags);
  418. return State->Return != INVALID_HANDLE_VALUE;
  419. }
  420. HANDLE
  421. IMAGEAPI
  422. FindExecutableImageExPass(
  423. LPSTR FileName,
  424. LPSTR SymbolPath,
  425. LPSTR ImageFilePath,
  426. PFIND_EXE_FILE_CALLBACK Callback,
  427. PVOID CallerData,
  428. DWORD flags
  429. )
  430. {
  431. LPSTR Start, End;
  432. HANDLE FileHandle = NULL;
  433. CHAR DirectoryPath[ MAX_PATH ];
  434. LPSTR NewSymbolPath = NULL;
  435. __try {
  436. __try {
  437. if (GetFullPathName( FileName, MAX_PATH, ImageFilePath, &Start )) {
  438. FileHandle = CheckExecutableImage(ImageFilePath, Callback, CallerData, flags);
  439. if (FileHandle != INVALID_HANDLE_VALUE)
  440. return FileHandle;
  441. }
  442. NewSymbolPath = ExpandPath(SymbolPath);
  443. Start = NewSymbolPath;
  444. while (Start && *Start != '\0') {
  445. FEIEP_STATE SearchTreeState;
  446. if (End = strchr( Start, ';' )) {
  447. int Len = (int)(End - Start);
  448. Len = (int)min(Len, sizeof(DirectoryPath)-1);
  449. strncpy( (PCHAR) DirectoryPath, Start, Len );
  450. DirectoryPath[ Len ] = '\0';
  451. End += 1;
  452. } else {
  453. strcpy( (PCHAR) DirectoryPath, Start );
  454. }
  455. if (!_strnicmp(DirectoryPath, "SYMSRV*", 7)) {
  456. goto next;
  457. }
  458. dprint("FindExecutableImageEx-> Searching %s for %s... ", DirectoryPath, FileName);
  459. SearchTreeState.UserCb = Callback;
  460. SearchTreeState.UserCbData = CallerData;
  461. SearchTreeState.flags = flags;
  462. if (SearchTreeForFileEx( (PCHAR) DirectoryPath, FileName, ImageFilePath, FindExSearchTreeCallback, &SearchTreeState )) {
  463. eprint("found\n");
  464. MemFree( NewSymbolPath );
  465. return SearchTreeState.Return;
  466. } else {
  467. eprint("no file\n");
  468. }
  469. next:
  470. Start = End;
  471. }
  472. } __except (EXCEPTION_EXECUTE_HANDLER) {
  473. SetLastError(ERROR_INVALID_PARAMETER);
  474. }
  475. ImageFilePath[0] = '\0';
  476. } __except (EXCEPTION_EXECUTE_HANDLER) {
  477. SetLastError(ERROR_INVALID_PARAMETER);
  478. }
  479. if (FileHandle) {
  480. CloseHandle(FileHandle);
  481. }
  482. if (NewSymbolPath) {
  483. MemFree( NewSymbolPath );
  484. }
  485. return NULL;
  486. }
  487. HANDLE
  488. IMAGEAPI
  489. FindExecutable(
  490. LPSTR FileName,
  491. LPSTR SymbolPath,
  492. LPSTR ImageFilePath,
  493. PFIND_EXE_FILE_CALLBACK Callback,
  494. PVOID CallerData,
  495. DWORD flags
  496. )
  497. {
  498. BOOL FullPath = FALSE;
  499. BOOL PathComponents = FALSE;
  500. HANDLE FileHandle;
  501. if (!FileName || !*FileName) {
  502. SetLastError(ERROR_INVALID_PARAMETER);
  503. return NULL;
  504. }
  505. //
  506. // The filename may or may not contain path components.
  507. // Determine what kind of path it is.
  508. //
  509. if ((((FileName[0] >= 'a' && FileName[0] <= 'z') ||
  510. (FileName[0] >= 'A' && FileName[0] <= 'Z')) &&
  511. FileName[1] == ':') ||
  512. FileName[0] == '\\' ||
  513. FileName[0] == '/') {
  514. FullPath = TRUE;
  515. PathComponents = TRUE;
  516. } else if (strchr(FileName, '\\') ||
  517. strchr(FileName, '/')) {
  518. PathComponents = TRUE;
  519. }
  520. // If the filename is a full path then it can be checked
  521. // for existence directly; there's no need to search
  522. // along any paths.
  523. if (FullPath) {
  524. __try {
  525. FileHandle = CheckExecutableImage(FileName, Callback, CallerData, flags);
  526. if (FileHandle != INVALID_HANDLE_VALUE) {
  527. strcpy(ImageFilePath, FileName);
  528. return FileHandle;
  529. }
  530. } __except (EXCEPTION_EXECUTE_HANDLER) {
  531. SetLastError(ERROR_INVALID_PARAMETER);
  532. return NULL;
  533. }
  534. } else {
  535. // If it's not a full path we need to do a first pass
  536. // with the filename as given. This handles relative
  537. // paths and bare filenames.
  538. FileHandle = FindExecutableImageExPass(FileName, SymbolPath,
  539. ImageFilePath, Callback,
  540. CallerData, flags);
  541. if (FileHandle != NULL) {
  542. return FileHandle;
  543. }
  544. }
  545. // If we still haven't found it and the given filename
  546. // has path components we need to strip off the path components
  547. // and try again with just the base filename.
  548. if (PathComponents) {
  549. LPSTR BaseFile;
  550. BaseFile = strrchr(FileName, '\\');
  551. if (BaseFile == NULL) {
  552. BaseFile = strrchr(FileName, '/');
  553. if (BaseFile == NULL) {
  554. // Must be <drive>:.
  555. BaseFile = FileName + 1;
  556. }
  557. }
  558. // Skip path character to point to base file.
  559. BaseFile++;
  560. return FindExecutableImageExPass(BaseFile, SymbolPath,
  561. ImageFilePath, Callback,
  562. CallerData, flags);
  563. }
  564. return NULL;
  565. }
  566. HANDLE
  567. IMAGEAPI
  568. FindExecutableImageEx(
  569. LPSTR FileName,
  570. LPSTR SymbolPath,
  571. LPSTR ImageFilePath,
  572. PFIND_EXE_FILE_CALLBACK Callback,
  573. PVOID CallerData
  574. )
  575. {
  576. HANDLE hrc;
  577. hrc = FindExecutable(FileName,
  578. SymbolPath,
  579. ImageFilePath,
  580. Callback,
  581. CallerData,
  582. 0);
  583. if (hrc)
  584. return hrc;
  585. if (g.SymOptions & SYMOPT_LOAD_ANYTHING)
  586. hrc = FindExecutable(FileName,
  587. SymbolPath,
  588. ImageFilePath,
  589. Callback,
  590. CallerData,
  591. SYMOPT_LOAD_ANYTHING);
  592. return hrc;
  593. }
  594. HANDLE
  595. IMAGEAPI
  596. FindDebugInfoFile(
  597. LPSTR FileName,
  598. LPSTR SymbolPath,
  599. LPSTR DebugFilePath
  600. )
  601. {
  602. return FindDebugInfoFileEx(FileName, SymbolPath, DebugFilePath, NULL, NULL);
  603. }
  604. HANDLE
  605. IMAGEAPI
  606. FindDebugInfoFileEx(
  607. IN LPSTR FileName,
  608. IN LPSTR SymbolPath,
  609. OUT LPSTR DebugFilePath,
  610. IN PFIND_DEBUG_FILE_CALLBACK Callback,
  611. IN PVOID CallerData
  612. )
  613. {
  614. DWORD flag;
  615. if (g.SymOptions & SYMOPT_LOAD_ANYTHING)
  616. flag = fdifRECURSIVE;
  617. else
  618. flag = 0;
  619. if (flag)
  620. dprint("RECURSIVE %s\n", FileName);
  621. return fnFindDebugInfoFileEx(FileName,
  622. SymbolPath,
  623. DebugFilePath,
  624. Callback,
  625. CallerData,
  626. flag);
  627. }
  628. HANDLE
  629. IMAGEAPI
  630. fnFindDebugInfoFileEx(
  631. IN LPSTR FileName,
  632. IN LPSTR SymbolPath,
  633. OUT LPSTR DebugFilePath,
  634. IN PFIND_DEBUG_FILE_CALLBACK Callback,
  635. IN PVOID CallerData,
  636. IN DWORD flag
  637. )
  638. /*++
  639. Routine Description:
  640. The rules are:
  641. Look for
  642. 1. <SymbolPath>\Symbols\<ext>\<filename>.dbg
  643. 3. <SymbolPath>\<ext>\<filename>.dbg
  644. 5. <SymbolPath>\<filename>.dbg
  645. 7. <FileNamePath>\<filename>.dbg
  646. Arguments:
  647. FileName - Supplies a file name in one of three forms: fully qualified,
  648. <ext>\<filename>.dbg, or just filename.dbg
  649. SymbolPath - semi-colon delimited
  650. DebugFilePath -
  651. Callback - May be NULL. Callback that indicates whether the Symbol file is valid, or whether
  652. the function should continue searching for another Symbol file.
  653. The callback returns TRUE if the Symbol file is valid, or FALSE if the function should
  654. continue searching.
  655. CallerData - May be NULL. Data passed to the callback.
  656. Flag - indicates that PDBs shouldn't be searched for
  657. Return Value:
  658. The name of the .dbg file and a handle to that file.
  659. --*/
  660. {
  661. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  662. LPSTR ExpSymbolPath = NULL, SymPathStart, PathEnd;
  663. DWORD ShareAttributes, cnt;
  664. LPSTR InitialPath, Sub1, Sub2, FileExt;
  665. CHAR FilePath[_MAX_PATH + 1];
  666. CHAR Drive[_MAX_DRIVE], Dir[_MAX_DIR], SubDirPart[_MAX_DIR], FilePart[_MAX_FNAME], Ext[_MAX_EXT];
  667. CHAR *ExtDir;
  668. DWORD i;
  669. PIMGHLP_DEBUG_DATA pIDD;
  670. BOOL found = FALSE;
  671. DWORD err = 0;
  672. GUID guid;
  673. BOOL ssrv;
  674. assert(DebugFilePath);
  675. *DebugFilePath = 0;
  676. ZeroMemory(&guid, sizeof(GUID));
  677. if (g.OSVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  678. ShareAttributes = (FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE);
  679. } else {
  680. ShareAttributes = (FILE_SHARE_READ | FILE_SHARE_WRITE);
  681. }
  682. __try {
  683. *DebugFilePath = '\0';
  684. // Step 1. What do we have?
  685. _splitpath(FileName, Drive, Dir, FilePart, Ext);
  686. if (!_stricmp(Ext, ".dbg")) {
  687. // We got a filename of the form: ext\filename.dbg. Dir holds the extension already.
  688. ExtDir = Dir;
  689. } else {
  690. // Otherwise, skip the period and null out the Dir.
  691. ExtDir = CharNext(Ext);
  692. }
  693. ExpSymbolPath = ExpandPath(SymbolPath);
  694. if (!ExpSymbolPath)
  695. return NULL;
  696. SetCriticalErrorMode();
  697. SymPathStart = ExpSymbolPath;
  698. cnt = 0;
  699. do {
  700. if (PathEnd = strchr( SymPathStart, ';' )) {
  701. *PathEnd = '\0';
  702. }
  703. ssrv = FALSE;
  704. pIDD = (PIMGHLP_DEBUG_DATA)CallerData;
  705. if (!_strnicmp(SymPathStart, "SYMSRV*", 7)) {
  706. *DebugFilePath = 0;
  707. if (!cnt && CallerData) {
  708. ssrv = TRUE;
  709. strcpy(FilePath, FilePart);
  710. strcat(FilePath, ".dbg");
  711. guid.Data1 = pIDD->TimeDateStamp;
  712. GetFileFromSymbolServer(SymPathStart,
  713. FilePath,
  714. &guid,
  715. pIDD->SizeOfImage,
  716. 0,
  717. DebugFilePath);
  718. }
  719. } else {
  720. switch (cnt) {
  721. case 0: // <SymbolPath>\symbols\<ext>\<filename>.ext
  722. InitialPath = SymPathStart;
  723. Sub1 = "symbols";
  724. Sub2 = ExtDir;
  725. break;
  726. case 1: // <SymbolPath>\<ext>\<filename>.ext
  727. InitialPath = SymPathStart;
  728. Sub1 = "";
  729. Sub2 = ExtDir;
  730. break;
  731. case 2: // <SymbolPath>\<filename>.ext
  732. InitialPath = SymPathStart;
  733. Sub1 = "";
  734. Sub2 = "";
  735. break;
  736. case 3: // <FileNamePath>\<filename>.ext - A.K.A. what was passed to us
  737. InitialPath = Drive;
  738. Sub1 = "";
  739. Sub2 = Dir;
  740. // this stops us from checking out everything in the sympath
  741. cnt++;
  742. break;
  743. }
  744. // build fully-qualified filepath to look for
  745. strcpy(FilePath, InitialPath);
  746. EnsureTrailingBackslash(FilePath);
  747. strcat(FilePath, Sub1);
  748. EnsureTrailingBackslash(FilePath);
  749. strcat(FilePath, Sub2);
  750. EnsureTrailingBackslash(FilePath);
  751. strcat(FilePath, FilePart);
  752. strcpy(DebugFilePath, FilePath);
  753. strcat(DebugFilePath, ".dbg");
  754. }
  755. // try to open the file
  756. if (*DebugFilePath) {
  757. dprint("FindDebugInfoFileEx-> Looking for %s... ", DebugFilePath);
  758. FileHandle = CreateFile(DebugFilePath,
  759. GENERIC_READ,
  760. ShareAttributes,
  761. NULL,
  762. OPEN_EXISTING,
  763. 0,
  764. NULL);
  765. // if the file opens, bail from this loop
  766. if (FileHandle != INVALID_HANDLE_VALUE) {
  767. found = TRUE;
  768. if (pIDD) {
  769. pIDD->ImageSrc = (ssrv) ? srcSymSrv : srcSearchPath;
  770. }
  771. if (!Callback) {
  772. break;
  773. } else if (Callback(FileHandle, DebugFilePath, CallerData)) {
  774. break;
  775. } else {
  776. eprint("mismatched timestamp\n");
  777. CloseHandle(FileHandle);
  778. FileHandle = INVALID_HANDLE_VALUE;
  779. }
  780. } else {
  781. err = GetLastError();
  782. switch (err)
  783. {
  784. case ERROR_FILE_NOT_FOUND:
  785. eprint("file not found\n");
  786. break;
  787. case ERROR_PATH_NOT_FOUND:
  788. eprint("path not found\n");
  789. break;
  790. default:
  791. eprint("file error 0x%x\n", err);
  792. break;
  793. }
  794. }
  795. // if file is open, bail from this loop too - else continue
  796. if (FileHandle != INVALID_HANDLE_VALUE)
  797. break;
  798. }
  799. // go to next item in the sympath
  800. if (PathEnd) {
  801. *PathEnd = ';';
  802. SymPathStart = PathEnd + 1;
  803. } else {
  804. SymPathStart = ExpSymbolPath;
  805. cnt++;
  806. }
  807. } while (cnt < 4);
  808. } __except(EXCEPTION_EXECUTE_HANDLER) {
  809. if (FileHandle != INVALID_HANDLE_VALUE) {
  810. CloseHandle(FileHandle);
  811. }
  812. FileHandle = INVALID_HANDLE_VALUE;
  813. }
  814. if (ExpSymbolPath) {
  815. MemFree(ExpSymbolPath);
  816. }
  817. if (FileHandle == INVALID_HANDLE_VALUE) {
  818. FileHandle = NULL;
  819. DebugFilePath[0] = '\0';
  820. } else {
  821. eprint("OK\n");
  822. }
  823. if (!FileHandle // if we didn't get the right file...
  824. && found // but we found some file...
  825. && (flag & fdifRECURSIVE)) // and we were told to run recursively...
  826. {
  827. // try again without timestamp checking
  828. FileHandle = fnFindDebugInfoFileEx(FileName,
  829. SymbolPath,
  830. FilePath,
  831. NULL,
  832. 0,
  833. flag);
  834. if (FileHandle && FileHandle != INVALID_HANDLE_VALUE)
  835. strcpy(DebugFilePath, FilePath);
  836. }
  837. ResetCriticalErrorMode();
  838. return FileHandle;
  839. }
  840. BOOL
  841. GetImageNameFromMiscDebugData(
  842. IN HANDLE FileHandle,
  843. IN PVOID MappedBase,
  844. IN PIMAGE_NT_HEADERS32 NtHeaders,
  845. IN PIMAGE_DEBUG_DIRECTORY DebugDirectories,
  846. IN ULONG NumberOfDebugDirectories,
  847. OUT LPSTR ImageFilePath
  848. )
  849. {
  850. IMAGE_DEBUG_MISC TempMiscData;
  851. PIMAGE_DEBUG_MISC DebugMiscData;
  852. ULONG BytesToRead, BytesRead;
  853. BOOLEAN FoundImageName;
  854. LPSTR ImageName;
  855. PIMAGE_OPTIONAL_HEADER32 OptionalHeader32 = NULL;
  856. PIMAGE_OPTIONAL_HEADER64 OptionalHeader64 = NULL;
  857. while (NumberOfDebugDirectories) {
  858. if (DebugDirectories->Type == IMAGE_DEBUG_TYPE_MISC) {
  859. break;
  860. } else {
  861. DebugDirectories += 1;
  862. NumberOfDebugDirectories -= 1;
  863. }
  864. }
  865. if (NumberOfDebugDirectories == 0) {
  866. return FALSE;
  867. }
  868. OptionalHeadersFromNtHeaders(NtHeaders, &OptionalHeader32, &OptionalHeader64);
  869. if ((OPTIONALHEADER(MajorLinkerVersion) < 3) &&
  870. (OPTIONALHEADER(MinorLinkerVersion) < 36) ) {
  871. BytesToRead = FIELD_OFFSET( IMAGE_DEBUG_MISC, Reserved );
  872. } else {
  873. BytesToRead = FIELD_OFFSET( IMAGE_DEBUG_MISC, Data );
  874. }
  875. DebugMiscData = NULL;
  876. FoundImageName = FALSE;
  877. if (MappedBase == 0) {
  878. if (SetFilePointer( FileHandle,
  879. DebugDirectories->PointerToRawData,
  880. NULL,
  881. FILE_BEGIN
  882. ) == DebugDirectories->PointerToRawData
  883. ) {
  884. if (ReadFile( FileHandle,
  885. &TempMiscData,
  886. BytesToRead,
  887. &BytesRead,
  888. NULL
  889. ) &&
  890. BytesRead == BytesToRead
  891. ) {
  892. DebugMiscData = &TempMiscData;
  893. if (DebugMiscData->DataType == IMAGE_DEBUG_MISC_EXENAME) {
  894. BytesToRead = DebugMiscData->Length - BytesToRead;
  895. BytesToRead = BytesToRead > MAX_PATH ? MAX_PATH : BytesToRead;
  896. if (ReadFile( FileHandle,
  897. ImageFilePath,
  898. BytesToRead,
  899. &BytesRead,
  900. NULL
  901. ) &&
  902. BytesRead == BytesToRead
  903. ) {
  904. FoundImageName = TRUE;
  905. }
  906. }
  907. }
  908. }
  909. } else {
  910. DebugMiscData = (PIMAGE_DEBUG_MISC)((PCHAR)MappedBase +
  911. DebugDirectories->PointerToRawData );
  912. if (DebugMiscData->DataType == IMAGE_DEBUG_MISC_EXENAME) {
  913. ImageName = (PCHAR)DebugMiscData + BytesToRead;
  914. BytesToRead = DebugMiscData->Length - BytesToRead;
  915. BytesToRead = BytesToRead > MAX_PATH ? MAX_PATH : BytesToRead;
  916. if (*ImageName != '\0' ) {
  917. memcpy( ImageFilePath, ImageName, BytesToRead );
  918. FoundImageName = TRUE;
  919. }
  920. }
  921. }
  922. return FoundImageName;
  923. }
  924. #define MAX_DEPTH 32
  925. BOOL
  926. IMAGEAPI
  927. SearchTreeForFileEx(
  928. LPSTR RootPath,
  929. LPSTR InputPathName,
  930. LPSTR OutputPathBuffer,
  931. PSEARCH_TREE_FOR_FILE_EX_CALLBACK Callback,
  932. PVOID CallbackData
  933. )
  934. {
  935. // UnSafe...
  936. PCHAR FileName;
  937. PUCHAR Prefix = (PUCHAR) "";
  938. CHAR PathBuffer[ MAX_PATH ];
  939. ULONG Depth;
  940. PCHAR PathTail[ MAX_DEPTH ];
  941. PCHAR FindHandle[ MAX_DEPTH ];
  942. LPWIN32_FIND_DATA FindFileData;
  943. UCHAR FindFileBuffer[ MAX_PATH + sizeof( WIN32_FIND_DATA ) ];
  944. BOOL Result;
  945. SetCriticalErrorMode();;
  946. strcpy( PathBuffer, RootPath );
  947. FileName = InputPathName;
  948. while (*InputPathName) {
  949. if (*InputPathName == ':' || *InputPathName == '\\' || *InputPathName == '/') {
  950. FileName = ++InputPathName;
  951. } else {
  952. InputPathName = CharNext(InputPathName);
  953. }
  954. }
  955. FindFileData = (LPWIN32_FIND_DATA)FindFileBuffer;
  956. Depth = 0;
  957. Result = FALSE;
  958. while (TRUE) {
  959. startDirectorySearch:
  960. PathTail[ Depth ] = strchr( PathBuffer, '\0' );
  961. if (PathTail[ Depth ] > PathBuffer
  962. && *CharPrev(PathBuffer, PathTail[ Depth ]) != '\\') {
  963. *(PathTail[ Depth ])++ = '\\';
  964. }
  965. strcpy( PathTail[ Depth ], "*.*" );
  966. FindHandle[ Depth ] = (PCHAR) FindFirstFile( PathBuffer, FindFileData );
  967. if (FindHandle[ Depth ] == INVALID_HANDLE_VALUE) {
  968. goto nextDirectory;
  969. }
  970. do {
  971. if (FindFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  972. if (strcmp( FindFileData->cFileName, "." ) &&
  973. strcmp( FindFileData->cFileName, ".." ) &&
  974. Depth < MAX_DEPTH
  975. ) {
  976. strcpy(PathTail[ Depth ], FindFileData->cFileName);
  977. strcat(PathTail[ Depth ], "\\");
  978. Depth++;
  979. goto startDirectorySearch;
  980. }
  981. } else
  982. if (!_stricmp( FindFileData->cFileName, FileName )) {
  983. strcpy( PathTail[ Depth ], FindFileData->cFileName );
  984. strcpy( OutputPathBuffer, PathBuffer );
  985. if (Callback != NULL) {
  986. Result = Callback(OutputPathBuffer, CallbackData);
  987. } else {
  988. Result = TRUE;
  989. }
  990. }
  991. restartDirectorySearch:
  992. if (Result) {
  993. break;
  994. }
  995. }
  996. while (FindNextFile( FindHandle[ Depth ], FindFileData ));
  997. FindClose( FindHandle[ Depth ] );
  998. nextDirectory:
  999. if (Depth == 0) {
  1000. break;
  1001. }
  1002. Depth--;
  1003. goto restartDirectorySearch;
  1004. }
  1005. ResetCriticalErrorMode();
  1006. return Result;
  1007. }
  1008. BOOL
  1009. IMAGEAPI
  1010. SearchTreeForFile(
  1011. LPSTR RootPath,
  1012. LPSTR InputPathName,
  1013. LPSTR OutputPathBuffer
  1014. )
  1015. {
  1016. return SearchTreeForFileEx(RootPath, InputPathName, OutputPathBuffer,
  1017. NULL, NULL);
  1018. }
  1019. BOOL
  1020. IMAGEAPI
  1021. MakeSureDirectoryPathExists(
  1022. LPCSTR DirPath
  1023. )
  1024. {
  1025. LPSTR p, DirCopy;
  1026. DWORD dw;
  1027. // Make a copy of the string for editing.
  1028. __try {
  1029. DirCopy = (LPSTR) MemAlloc(strlen(DirPath) + 1);
  1030. if (!DirCopy) {
  1031. return FALSE;
  1032. }
  1033. strcpy(DirCopy, DirPath);
  1034. p = DirCopy;
  1035. // If the second character in the path is "\", then this is a UNC
  1036. // path, and we should skip forward until we reach the 2nd \ in the path.
  1037. if ((*p == '\\') && (*(p+1) == '\\')) {
  1038. p++; // Skip over the first \ in the name.
  1039. p++; // Skip over the second \ in the name.
  1040. // Skip until we hit the first "\" (\\Server\).
  1041. while (*p && *p != '\\') {
  1042. p = CharNext(p);
  1043. }
  1044. // Advance over it.
  1045. if (*p) {
  1046. p++;
  1047. }
  1048. // Skip until we hit the second "\" (\\Server\Share\).
  1049. while (*p && *p != '\\') {
  1050. p = CharNext(p);
  1051. }
  1052. // Advance over it also.
  1053. if (*p) {
  1054. p++;
  1055. }
  1056. } else
  1057. // Not a UNC. See if it's <drive>:
  1058. if (*(p+1) == ':' ) {
  1059. p++;
  1060. p++;
  1061. // If it exists, skip over the root specifier
  1062. if (*p && (*p == '\\')) {
  1063. p++;
  1064. }
  1065. }
  1066. while( *p ) {
  1067. if ( *p == '\\' ) {
  1068. *p = '\0';
  1069. dw = fnGetFileAttributes(DirCopy);
  1070. // Nothing exists with this name. Try to make the directory name and error if unable to.
  1071. if ( dw == 0xffffffff ) {
  1072. if ( !CreateDirectory(DirCopy,NULL) ) {
  1073. if( GetLastError() != ERROR_ALREADY_EXISTS ) {
  1074. MemFree(DirCopy);
  1075. return FALSE;
  1076. }
  1077. }
  1078. } else {
  1079. if ( (dw & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ) {
  1080. // Something exists with this name, but it's not a directory... Error
  1081. MemFree(DirCopy);
  1082. return FALSE;
  1083. }
  1084. }
  1085. *p = '\\';
  1086. }
  1087. p = CharNext(p);
  1088. }
  1089. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1090. ImagepSetLastErrorFromStatus( GetExceptionCode() );
  1091. MemFree(DirCopy);
  1092. return(FALSE);
  1093. }
  1094. MemFree(DirCopy);
  1095. return TRUE;
  1096. }
  1097. LPAPI_VERSION
  1098. IMAGEAPI
  1099. ImagehlpApiVersion(
  1100. VOID
  1101. )
  1102. {
  1103. //
  1104. // don't tell old apps about the new version. It will
  1105. // just scare them.
  1106. //
  1107. return &g.AppVersion;
  1108. }
  1109. LPAPI_VERSION
  1110. IMAGEAPI
  1111. ImagehlpApiVersionEx(
  1112. LPAPI_VERSION av
  1113. )
  1114. {
  1115. LPAPI_VERSION ver;
  1116. __try {
  1117. ver = av;
  1118. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1119. ver = &g.AppVersion;
  1120. }
  1121. if (ver->Revision < 6) {
  1122. //
  1123. // For older debuggers, just tell them what they want to hear.
  1124. //
  1125. return ver;
  1126. }
  1127. return &g.ApiVersion;
  1128. }