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.

1578 lines
43 KiB

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