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.

3049 lines
77 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // General utility functions.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997-2001.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. #include <sys\types.h>
  10. #include <sys\stat.h>
  11. #define DBG_MOD_LIST 0
  12. PCSTR g_DefaultLogFileName = "dbgeng.log";
  13. char g_OpenLogFileName[MAX_PATH + 1];
  14. BOOL g_OpenLogFileAppended;
  15. int g_LogFile = -1;
  16. BOOL g_DisableErrorPrint;
  17. ULONG
  18. CheckUserInterrupt(void)
  19. {
  20. if (g_EngStatus & ENG_STATUS_USER_INTERRUPT)
  21. {
  22. g_EngStatus &= ~ENG_STATUS_USER_INTERRUPT;
  23. return TRUE;
  24. }
  25. return FALSE;
  26. }
  27. LONG
  28. MappingExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)
  29. {
  30. static ULONG s_InPageErrors = 0;
  31. ULONG Code = ExceptionInfo->ExceptionRecord->ExceptionCode;
  32. if (Code == STATUS_IN_PAGE_ERROR)
  33. {
  34. if (++s_InPageErrors < 10)
  35. {
  36. if (s_InPageErrors % 2)
  37. {
  38. WarnOut("Ignore in-page I/O error\n");
  39. FlushCallbacks();
  40. }
  41. Sleep(500);
  42. return EXCEPTION_CONTINUE_EXECUTION;
  43. }
  44. }
  45. s_InPageErrors = 0;
  46. ErrOut("Exception 0x%08x while accessing mapping\n", Code);
  47. FlushCallbacks();
  48. return EXCEPTION_EXECUTE_HANDLER;
  49. }
  50. void
  51. RemoveDelChar(PSTR Buffer)
  52. {
  53. PSTR BufferOld = Buffer;
  54. PSTR BufferNew = Buffer;
  55. while (*BufferOld)
  56. {
  57. if (*BufferOld == 0x7f)
  58. {
  59. if (BufferNew > Buffer)
  60. {
  61. BufferNew--;
  62. }
  63. }
  64. else if (*BufferOld == '\r' || *BufferOld == '\n')
  65. {
  66. *BufferNew++ = ' ';
  67. }
  68. else
  69. {
  70. *BufferNew++ = *BufferOld;
  71. }
  72. BufferOld++;
  73. }
  74. *BufferNew = '\0';
  75. }
  76. /*** error - error reporting and recovery
  77. *
  78. * Purpose:
  79. * To output an error message with a location indicator
  80. * of the problem. Once output, the command line is reset
  81. * and the command processor is restarted.
  82. *
  83. * Input:
  84. * errorcode - number of error to output
  85. *
  86. * Output:
  87. * None.
  88. *
  89. * Exceptions:
  90. * Return is made via exception to start of command processor.
  91. *
  92. *************************************************************************/
  93. static char g_Blanks[] =
  94. " "
  95. " "
  96. " "
  97. " ^ ";
  98. void
  99. ReportError(
  100. ULONG errcode,
  101. PCSTR* DescPtr
  102. )
  103. {
  104. ULONG Count = g_PromptLength + 1;
  105. PSTR Temp = g_CommandStart;
  106. PCSTR Desc;
  107. if (DescPtr != NULL)
  108. {
  109. // Clear out description so it doesn't get reused.
  110. Desc = *DescPtr;
  111. *DescPtr = NULL;
  112. }
  113. else
  114. {
  115. Desc = NULL;
  116. }
  117. if (g_DisableErrorPrint ||
  118. (g_CommandStart > g_CurCmd) ||
  119. (g_CommandStart + MAX_COMMAND < g_CurCmd))
  120. {
  121. goto SkipErrorPrint;
  122. }
  123. while (Temp < g_CurCmd)
  124. {
  125. if (*Temp++ == '\t')
  126. {
  127. Count = (Count + 7) & ~7;
  128. }
  129. else
  130. {
  131. Count++;
  132. }
  133. }
  134. ErrOut(&g_Blanks[sizeof(g_Blanks) - (Count + 1)]);
  135. if (Desc != NULL)
  136. {
  137. ErrOut("%s '%s'\n", Desc, g_CommandStart);
  138. goto SkipErrorPrint;
  139. }
  140. switch (errcode)
  141. {
  142. case OVERFLOW:
  143. ErrOut("Overflow");
  144. break;
  145. case SYNTAX:
  146. ErrOut("Syntax");
  147. break;
  148. case BADRANGE:
  149. ErrOut("Range");
  150. break;
  151. case VARDEF:
  152. ErrOut("Couldn't resolve");
  153. break;
  154. case EXTRACHARS:
  155. ErrOut("Extra character");
  156. break;
  157. case LISTSIZE:
  158. ErrOut("List size");
  159. break;
  160. case STRINGSIZE:
  161. ErrOut("String size");
  162. break;
  163. case MEMORY:
  164. ErrOut("Memory access");
  165. break;
  166. case BADREG:
  167. ErrOut("Bad register");
  168. break;
  169. case BADOPCODE:
  170. ErrOut("Bad opcode");
  171. break;
  172. case SUFFIX:
  173. ErrOut("Opcode suffix");
  174. break;
  175. case OPERAND:
  176. ErrOut("Operand");
  177. break;
  178. case ALIGNMENT:
  179. ErrOut("Alignment");
  180. break;
  181. case PREFIX:
  182. ErrOut("Opcode prefix");
  183. break;
  184. case DISPLACEMENT:
  185. ErrOut("Displacement");
  186. break;
  187. case BPLISTFULL:
  188. ErrOut("No breakpoint available");
  189. break;
  190. case BPDUPLICATE:
  191. ErrOut("Duplicate breakpoint");
  192. break;
  193. case UNIMPLEMENT:
  194. ErrOut("Unimplemented");
  195. break;
  196. case AMBIGUOUS:
  197. ErrOut("Ambiguous symbol");
  198. break;
  199. case BADTHREAD:
  200. ErrOut("Illegal thread");
  201. break;
  202. case BADPROCESS:
  203. ErrOut("Illegal process");
  204. break;
  205. case FILEREAD:
  206. ErrOut("File read");
  207. break;
  208. case LINENUMBER:
  209. ErrOut("Line number");
  210. break;
  211. case BADSEL:
  212. ErrOut("Bad selector");
  213. break;
  214. case BADSEG:
  215. ErrOut("Bad segment");
  216. break;
  217. case SYMTOOSMALL:
  218. ErrOut("Symbol only 1 character");
  219. break;
  220. case BPIONOTSUP:
  221. ErrOut("I/O breakpoints not supported");
  222. break;
  223. case NOTFOUND:
  224. ErrOut("No information found");
  225. break;
  226. case SESSIONNOTSUP:
  227. ErrOut("Operation not supported in current debug session");
  228. break;
  229. default:
  230. ErrOut("Unknown");
  231. break;
  232. }
  233. if (errcode != VARDEF && errcode != SESSIONNOTSUP)
  234. {
  235. ErrOut(" error in '%s'\n", g_CommandStart);
  236. }
  237. else
  238. {
  239. ErrOut(" '%s'\n", g_CommandStart);
  240. }
  241. SkipErrorPrint:
  242. RaiseException(COMMAND_EXCEPTION_BASE + errcode, 0, 0, NULL);
  243. }
  244. /*** HexList - parse list of hex values
  245. *
  246. * Purpose:
  247. * With the current location of the command string in
  248. * g_CurCmd, attempt to parse hex number of byte size
  249. * bytesize as bytes into the character array pointed by
  250. * parray. The value pointed by *pcount contains the bytes
  251. * of the array filled.
  252. *
  253. * Input:
  254. * g_CurCmd - start of command string
  255. * bytesize - size of items in bytes
  256. *
  257. * Output:
  258. * parray - pointer to byte array to fill
  259. * pcount - pointer to value of bytes filled
  260. *
  261. * Exceptions:
  262. * error exit:
  263. * LISTSIZE: too many items in list
  264. * SYNTAX: illegal separator of list items
  265. * OVERFLOW: item value too large
  266. *
  267. *************************************************************************/
  268. void
  269. HexList (PUCHAR parray, ULONG *pcount, ULONG bytesize)
  270. {
  271. UCHAR ch;
  272. ULONG64 value;
  273. ULONG count = 0;
  274. ULONG i;
  275. while ((ch = PeekChar()) != '\0' && ch != ';')
  276. {
  277. if (count == STRLISTSIZE)
  278. {
  279. error(LISTSIZE);
  280. }
  281. value = HexValue(bytesize);
  282. for (i = 0; i < bytesize; i++)
  283. {
  284. *parray++ = (char) value;
  285. value >>= 8;
  286. }
  287. count += bytesize;
  288. }
  289. *pcount = count;
  290. }
  291. ULONGLONG
  292. HexValue (
  293. ULONG ByteSize
  294. )
  295. {
  296. ULONGLONG Value;
  297. Value = GetExpression();
  298. // Reverse sign extension done by expression evaluator.
  299. if (ByteSize == 4 && !NeedUpper(Value))
  300. {
  301. Value = (ULONG)Value;
  302. }
  303. if (Value > (0xffffffffffffffffUI64 >> (8 * (8 - ByteSize))))
  304. {
  305. error(OVERFLOW);
  306. }
  307. return Value;
  308. }
  309. /*** AsciiList - process string for ascii list
  310. *
  311. * Purpose:
  312. * With the current location of the command string in
  313. * g_CurCmd, attempt to parse ascii characters into the
  314. * character array pointed by parray. The value pointed
  315. * by pcount contains the bytes of the array filled. The
  316. * string must start with a double quote. The string must
  317. * end with a quote or be at the end of the input line.
  318. *
  319. * Input:
  320. * g_CurCmd - start of command string
  321. *
  322. * Output:
  323. * parray - pointer to byte array to fill
  324. * pcount - pointer to value of bytes filled
  325. *
  326. * Exceptions:
  327. * error exit:
  328. * STRINGSIZE: string length too long
  329. * SYNTAX: no leading double quote
  330. *
  331. *************************************************************************/
  332. void
  333. AsciiList(PSTR parray, ULONG *pcount)
  334. {
  335. UCHAR ch;
  336. ULONG count = 0;
  337. if (PeekChar() != '"')
  338. {
  339. error(SYNTAX);
  340. }
  341. g_CurCmd++;
  342. do
  343. {
  344. ch = *g_CurCmd++;
  345. if (ch == '"')
  346. {
  347. count++;
  348. *parray++ = 0;
  349. break;
  350. }
  351. if (ch == '\0' || ch == ';')
  352. {
  353. g_CurCmd--;
  354. break;
  355. }
  356. if (count == STRLISTSIZE)
  357. {
  358. error(STRINGSIZE);
  359. }
  360. count++;
  361. *parray++ = ch;
  362. } while (1);
  363. *pcount = count;
  364. }
  365. PSTR
  366. GetEscapedChar(PSTR Str, PCHAR Raw)
  367. {
  368. switch(*Str)
  369. {
  370. case 0:
  371. error(SYNTAX);
  372. case '0':
  373. // Octal char value.
  374. *Raw = (char)strtoul(Str + 1, &Str, 8);
  375. break;
  376. case 'b':
  377. *Raw = '\b';
  378. Str++;
  379. break;
  380. case 'n':
  381. *Raw = '\n';
  382. Str++;
  383. break;
  384. case 'r':
  385. *Raw = '\r';
  386. Str++;
  387. break;
  388. case 't':
  389. *Raw = '\t';
  390. Str++;
  391. break;
  392. case 'x':
  393. // Hex char value.
  394. *Raw = (char)strtoul(Str + 1, &Str, 16);
  395. break;
  396. default:
  397. // Verbatim escape.
  398. *Raw = *Str;
  399. Str++;
  400. break;
  401. }
  402. return Str;
  403. }
  404. PSTR
  405. BufferStringValue(PSTR* Buf, ULONG Flags, PCHAR Save)
  406. {
  407. BOOL Quoted;
  408. PSTR Str;
  409. BOOL Escapes = FALSE;
  410. while (isspace(*(*Buf)))
  411. {
  412. (*Buf)++;
  413. }
  414. if (*(*Buf) == '"')
  415. {
  416. Quoted = TRUE;
  417. Str = ++(*Buf);
  418. // If the string is quoted it can always contain spaces.
  419. Flags &= ~STRV_SPACE_IS_SEPARATOR;
  420. }
  421. else
  422. {
  423. Quoted = FALSE;
  424. Str = *Buf;
  425. // Escaped characters can only be present in quoted strings.
  426. Flags &= ~STRV_ALLOW_ESCAPED_CHARACTERS;
  427. }
  428. while (*(*Buf) &&
  429. (!(Flags & STRV_SPACE_IS_SEPARATOR) || !isspace(*(*Buf))) &&
  430. (Quoted || *(*Buf) != ';') &&
  431. (!Quoted || *(*Buf) != '"'))
  432. {
  433. if (Flags & STRV_ALLOW_ESCAPED_CHARACTERS)
  434. {
  435. if (*(*Buf) == '\\')
  436. {
  437. char Raw;
  438. *Buf = GetEscapedChar((*Buf) + 1, &Raw);
  439. Escapes = TRUE;
  440. }
  441. else
  442. {
  443. (*Buf)++;
  444. }
  445. }
  446. else
  447. {
  448. (*Buf)++;
  449. }
  450. }
  451. if (Quoted && *(*Buf) != '"')
  452. {
  453. return NULL;
  454. }
  455. if (Flags & STRV_TRIM_TRAILING_SPACE)
  456. {
  457. PSTR Trim = *Buf;
  458. while (Trim > Str)
  459. {
  460. if (isspace(*--Trim))
  461. {
  462. *Trim = 0;
  463. }
  464. else
  465. {
  466. break;
  467. }
  468. }
  469. }
  470. if (Quoted && *(*Buf) == '"')
  471. {
  472. // Null the quote and advance beyond it
  473. // so that the buffer pointer is always pointing
  474. // beyond the string on exit.
  475. *(*Buf)++ = 0;
  476. // Require some kind of separator after the
  477. // string to keep things symmetric with the
  478. // non-quoted case.
  479. if (!isspace(*(*Buf)) &&
  480. *(*Buf) != ';' && *(*Buf) != 0)
  481. {
  482. *((*Buf) - 1) = '"';
  483. return NULL;
  484. }
  485. }
  486. *Save = *(*Buf);
  487. *(*Buf) = 0;
  488. if (Escapes && (Flags & STRV_COMPRESS_ESCAPED_CHARACTERS))
  489. {
  490. CompressEscapes(Str);
  491. }
  492. return Str;
  493. }
  494. PSTR
  495. StringValue(ULONG Flags, PCHAR Save)
  496. {
  497. PSTR Str = BufferStringValue((PSTR*)&g_CurCmd, Flags, Save);
  498. if (Str == NULL)
  499. {
  500. error(SYNTAX);
  501. }
  502. return Str;
  503. }
  504. void
  505. CompressEscapes(PSTR Str)
  506. {
  507. // Scan through a string for character escapes and
  508. // convert them to their escape value, packing
  509. // the rest of the string down. This allows for
  510. // in-place conversion of strings with escapes
  511. // inside the command buffer.
  512. while (*Str)
  513. {
  514. if (*Str == '\\')
  515. {
  516. char Raw;
  517. PSTR Slash = Str;
  518. Str = GetEscapedChar(Slash + 1, &Raw);
  519. // Copy raw value over backslash and pack down
  520. // trailing characters.
  521. *Slash = Raw;
  522. ULONG Len = strlen(Str) + 1;
  523. memmove(Slash + 1, Str, Len);
  524. Str = Slash + 1;
  525. }
  526. else
  527. {
  528. Str++;
  529. }
  530. }
  531. }
  532. void
  533. OpenLogFile(PCSTR File,
  534. BOOL Append)
  535. {
  536. // close existing opened log file
  537. fnLogClose();
  538. if (Append)
  539. {
  540. g_LogFile = _open(File, O_APPEND | O_CREAT | O_RDWR,
  541. S_IREAD | S_IWRITE);
  542. }
  543. else
  544. {
  545. g_LogFile = _open(File, O_APPEND | O_CREAT | O_TRUNC | O_RDWR,
  546. S_IREAD | S_IWRITE);
  547. }
  548. if (g_LogFile != -1)
  549. {
  550. dprintf("Opened log file '%s'\n", File);
  551. strncat(g_OpenLogFileName, File, sizeof(g_OpenLogFileName) - 1);
  552. g_OpenLogFileAppended = Append;
  553. NotifyChangeEngineState(DEBUG_CES_LOG_FILE, TRUE, TRUE);
  554. }
  555. else
  556. {
  557. ErrOut("log file could not be opened\n");
  558. }
  559. }
  560. void
  561. fnLogOpen(BOOL Append)
  562. {
  563. PSTR FileName;
  564. CHAR Save;
  565. if (PeekChar() && *g_CurCmd != ';')
  566. {
  567. FileName = StringValue(STRV_SPACE_IS_SEPARATOR |
  568. STRV_TRIM_TRAILING_SPACE, &Save);
  569. }
  570. else
  571. {
  572. FileName = (PSTR)g_DefaultLogFileName;
  573. }
  574. OpenLogFile(FileName, Append);
  575. *g_CurCmd = Save;
  576. }
  577. /*** fnLogClose - close log file
  578. *
  579. * Purpose:
  580. * Closes any open log file.
  581. *
  582. * Input:
  583. * g_LogFile - file handle of open log file
  584. *
  585. * Output:
  586. * None.
  587. *
  588. *************************************************************************/
  589. void
  590. fnLogClose (void)
  591. {
  592. if (g_LogFile != -1)
  593. {
  594. dprintf("closing open log file\n");
  595. _close(g_LogFile);
  596. g_LogFile = -1;
  597. g_OpenLogFileName[0] = 0;
  598. g_OpenLogFileAppended = FALSE;
  599. NotifyChangeEngineState(DEBUG_CES_LOG_FILE, FALSE, TRUE);
  600. }
  601. }
  602. /*** lprintf - log file print
  603. *
  604. * Purpose:
  605. * Print line only to log file. Used to echo input line that
  606. * is already printed on standard output by gets() function.
  607. *
  608. * Input:
  609. * g_LogFile - file handle variable of log file
  610. *
  611. * Output:
  612. * None.
  613. *
  614. *************************************************************************/
  615. void
  616. lprintf (
  617. PCSTR string
  618. )
  619. {
  620. if (g_LogFile != -1)
  621. {
  622. _write(g_LogFile, string, strlen(string));
  623. }
  624. }
  625. void
  626. RestrictModNameChars(PCSTR ModName, PSTR RewriteBuffer)
  627. {
  628. PCSTR Scan = ModName;
  629. PSTR Write = RewriteBuffer;
  630. while (*Scan)
  631. {
  632. if ((*Scan < 'a' || *Scan > 'z') &&
  633. (*Scan < 'A' || *Scan > 'Z') &&
  634. (*Scan < '0' || *Scan > '9') &&
  635. *Scan != '_')
  636. {
  637. *Write++ = '_';
  638. }
  639. else
  640. {
  641. *Write++ = *Scan;
  642. }
  643. Scan++;
  644. }
  645. *Write = 0;
  646. }
  647. PSTR
  648. PrepareImagePath(PSTR ImagePath)
  649. {
  650. // dbghelp will sometimes scan the path given to
  651. // SymLoadModule64 for the image itself. There
  652. // can be cases where the scan uses fuzzy matching,
  653. // so we want to be careful to only pass in a path
  654. // for dbghelp to use when the path can safely be
  655. // used.
  656. if ((IS_LIVE_USER_TARGET() && !IS_REMOTE_USER_TARGET()) ||
  657. IS_LOCAL_KERNEL_TARGET())
  658. {
  659. return ImagePath;
  660. }
  661. else
  662. {
  663. return (PSTR)PathTail(ImagePath);
  664. }
  665. }
  666. #define CSRSS_IMAGE_NAME "csrss.exe"
  667. #define LSASS_IMAGE_NAME "lsass.exe"
  668. #define SERVICES_IMAGE_NAME "services.exe"
  669. CHAR *
  670. AddImage(
  671. PMODULE_INFO_ENTRY ModEntry,
  672. BOOL ForceSymbolLoad
  673. )
  674. {
  675. PDEBUG_IMAGE_INFO ImageNew;
  676. PDEBUG_IMAGE_INFO *pp;
  677. IMAGEHLP_MODULE64 mi;
  678. ULONG64 LoadAddress;
  679. BOOL LoadSymbols = TRUE;
  680. BOOL ReusedExisting = FALSE;
  681. PCSTR ImagePathTail;
  682. MODLOAD_DATA mld;
  683. #if DBG_MOD_LIST
  684. dprintf("AddImage:\n"
  685. " ImagePath %s\n"
  686. " File %I64x\n"
  687. " BaseOfImage %I64x\n"
  688. " SizeOfImage %x\n"
  689. " CheckSum %x\n"
  690. " ModuleName %s\n"
  691. " ForceSymbolLoad %d\n",
  692. ModEntry->NamePtr,
  693. (ULONG64)(ULONG_PTR)File,
  694. ModEntry->Base,
  695. ModEntry->Size,
  696. ModEntry->CheckSum,
  697. ModEntry->ModuleName,
  698. ForceSymbolLoad);
  699. #endif
  700. if (ModEntry->NamePtr == NULL)
  701. {
  702. WarnOut("AddImage(NULL) fails\n");
  703. return NULL;
  704. }
  705. //
  706. // Search for existing image with same checksum at same base address.
  707. // If found, remove symbols, but leave image structure intact.
  708. //
  709. pp = &g_CurrentProcess->ImageHead;
  710. while (ImageNew = *pp)
  711. {
  712. if (ImageNew->BaseOfImage == ModEntry->Base)
  713. {
  714. VerbOut("Force unload of %s\n", ImageNew->ImagePath);
  715. SymUnloadModule64( g_CurrentProcess->Handle,
  716. ImageNew->BaseOfImage );
  717. ClearStoredTypes(ImageNew->BaseOfImage);
  718. if (IS_DUMP_WITH_MAPPED_IMAGES())
  719. {
  720. // Unmap the memory for this image.
  721. UnloadExecutableImageMemory(ImageNew);
  722. }
  723. ReusedExisting = TRUE;
  724. break;
  725. }
  726. else if (ImageNew->BaseOfImage > ModEntry->Base)
  727. {
  728. break;
  729. }
  730. pp = &ImageNew->Next;
  731. }
  732. //
  733. // If we didn't reuse an existing image, allocate
  734. // a new one.
  735. //
  736. if (!ReusedExisting)
  737. {
  738. ImageNew = (PDEBUG_IMAGE_INFO)calloc(sizeof(*ImageNew), 1);
  739. if (ImageNew == NULL)
  740. {
  741. ErrOut("Unable to allocate memory for %s symbols.\n",
  742. ModEntry->NamePtr);
  743. return NULL;
  744. }
  745. strcpy(ImageNew->ImagePath, ModEntry->NamePtr);
  746. // Module name is set later after possible renaming.
  747. ImageNew->File = ModEntry->File;
  748. ImageNew->BaseOfImage = ModEntry->Base;
  749. ImageNew->CheckSum = ModEntry->CheckSum;
  750. ImageNew->TimeDateStamp = ModEntry->TimeDateStamp;
  751. ImageNew->GoodCheckSum = TRUE;
  752. }
  753. // Always update the entry size as this allows users
  754. // to update explicit entries (.reload image.ext=base,size)
  755. // without having to unload them first.
  756. ImageNew->SizeOfImage = ModEntry->Size;
  757. ImagePathTail = PathTail(ImageNew->ImagePath);
  758. //
  759. // If we are handling a mini dump, we need to try to add the
  760. // executable's memory as well as the symbol file. We
  761. // do this right away so the image is mapped for the
  762. // below GetModnameFromImage calls.
  763. //
  764. if (IS_DUMP_WITH_MAPPED_IMAGES())
  765. {
  766. if (!LoadExecutableImageMemory(ImageNew))
  767. {
  768. // If the caller has requested that we fail on
  769. // incomplete information fail the module load.
  770. // We don't do this if we're reusing an existing
  771. // module under the assumption that it's better
  772. // to continue and try to complete the reused
  773. // image rather than deleting it.
  774. if ((g_EngOptions & DEBUG_ENGOPT_FAIL_INCOMPLETE_INFORMATION) &&
  775. !ReusedExisting)
  776. {
  777. free(ImageNew);
  778. return NULL;
  779. }
  780. }
  781. }
  782. if (IS_KERNEL_TARGET())
  783. {
  784. CHAR Buf[MAX_IMAGE_PATH];
  785. //
  786. // Determine the actual image name for kernel images which
  787. // are known to have multiple identities.
  788. //
  789. if ((ModEntry->ModuleName &&
  790. _stricmp(ModEntry->ModuleName, KERNEL_MODULE_NAME) == 0) ||
  791. ModEntry->Base == KdDebuggerData.KernBase)
  792. {
  793. if (GetModnameFromImage(ModEntry->Base, NULL, Buf, sizeof(Buf)))
  794. {
  795. strcpy(ImageNew->ImagePath, Buf);
  796. }
  797. ModEntry->ModuleName = KERNEL_MODULE_NAME;
  798. }
  799. else if (_stricmp(ImagePathTail, HAL_IMAGE_FILE_NAME) == 0)
  800. {
  801. if (GetModnameFromImage(ModEntry->Base, NULL, Buf, sizeof(Buf)))
  802. {
  803. strcpy(ImageNew->ImagePath, Buf);
  804. }
  805. ModEntry->ModuleName = HAL_MODULE_NAME;
  806. }
  807. else if (_stricmp(ImagePathTail, KDHWEXT_IMAGE_FILE_NAME) == 0)
  808. {
  809. if (GetModnameFromImage(ModEntry->Base, NULL, Buf, sizeof(Buf)))
  810. {
  811. strcpy(ImageNew->ImagePath, Buf);
  812. }
  813. ModEntry->ModuleName = KDHWEXT_MODULE_NAME;
  814. }
  815. else if (ImageNew->SizeOfImage == 0 &&
  816. ((_stricmp(ImagePathTail, NTLDR_IMAGE_NAME) == 0) ||
  817. (_stricmp(ImagePathTail, NTLDR_IMAGE_NAME ".exe") == 0) ||
  818. (_stricmp(ImagePathTail, OSLOADER_IMAGE_NAME) == 0) ||
  819. (_stricmp(ImagePathTail, OSLOADER_IMAGE_NAME ".exe") == 0) ||
  820. (_stricmp(ImagePathTail, SETUPLDR_IMAGE_NAME) == 0) ||
  821. (_stricmp(ImagePathTail, SETUPLDR_IMAGE_NAME ".exe") == 0)))
  822. {
  823. ImageNew->SizeOfImage = LDR_IMAGE_SIZE;
  824. }
  825. }
  826. else if (!IS_DUMP_TARGET())
  827. {
  828. //
  829. // When debugging CSR, LSA or Services.exe, force the use of local-only
  830. // symbols. Otherwise we can deadlock the entire machine when trying
  831. // to load the symbol file from the network.
  832. //
  833. if (IS_LOCAL_USER_TARGET() &&
  834. (_stricmp(ImagePathTail, CSRSS_IMAGE_NAME) == 0 ||
  835. _stricmp(ImagePathTail, LSASS_IMAGE_NAME) == 0 ||
  836. _stricmp(ImagePathTail, SERVICES_IMAGE_NAME) == 0))
  837. {
  838. if (g_EngOptions & DEBUG_ENGOPT_ALLOW_NETWORK_PATHS)
  839. {
  840. //
  841. // Since the user has chambered a round and pointed the barrel
  842. // of the gun at his head, we may as well tell him that it's
  843. // going to hurt if he pulls the trigger.
  844. //
  845. WarnOut("WARNING: Using network symbols with %s\n",
  846. ImagePathTail);
  847. WarnOut("WARNING: You may deadlock your machine.\n");
  848. }
  849. else
  850. {
  851. g_EngOptions |= DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS;
  852. }
  853. }
  854. if (g_EngOptions & DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS)
  855. {
  856. DWORD NetPath;
  857. NetPath = NetworkPathCheck(g_SymbolSearchPath);
  858. if (NetPath == ERROR_FILE_OFFLINE)
  859. {
  860. ErrOut("ERROR: sympath contained network references but "
  861. "they were not allowed.\n");
  862. ErrOut("Symbols not loaded for %s\n",
  863. ImagePathTail);
  864. LoadSymbols = FALSE;
  865. }
  866. else if (NetPath == ERROR_BAD_PATHNAME)
  867. {
  868. VerbOut("WARNING: sympath contains invalid references.\n");
  869. }
  870. }
  871. }
  872. if (ModEntry->ModuleName == NULL)
  873. {
  874. CreateModuleNameFromPath(ImageNew->ImagePath,
  875. ImageNew->ModuleName);
  876. RestrictModNameChars(ImageNew->ModuleName, ImageNew->ModuleName);
  877. strcpy(ImageNew->OriginalModuleName, ImageNew->ModuleName);
  878. }
  879. else
  880. {
  881. RestrictModNameChars(ModEntry->ModuleName, ImageNew->ModuleName);
  882. //
  883. // We have an alias, so keep original module name from path
  884. //
  885. CreateModuleNameFromPath(ImageNew->ImagePath,
  886. ImageNew->OriginalModuleName);
  887. RestrictModNameChars(ImageNew->OriginalModuleName,
  888. ImageNew->OriginalModuleName);
  889. }
  890. //
  891. // Check for duplicate module names.
  892. //
  893. PDEBUG_IMAGE_INFO Check;
  894. for (Check = g_CurrentProcess->ImageHead;
  895. Check != NULL;
  896. Check = Check->Next)
  897. {
  898. if (Check != ImageNew &&
  899. !_strcmpi(ImageNew->ModuleName, Check->ModuleName))
  900. {
  901. int Len = strlen(ImageNew->ModuleName);
  902. // Module names match, so qualify with the base address.
  903. // Resulting name must be unique since base addresses are.
  904. if (g_TargetMachine->m_Ptr64)
  905. {
  906. if (Len >= MAX_MODULE - 17)
  907. {
  908. Len = MAX_MODULE - 18;
  909. }
  910. sprintf(ImageNew->ModuleName + Len, "_%I64x", ModEntry->Base);
  911. }
  912. else
  913. {
  914. if (Len >= MAX_MODULE - 9)
  915. {
  916. Len = MAX_MODULE - 10;
  917. }
  918. sprintf(ImageNew->ModuleName + Len, "_%x",
  919. (ULONG)ModEntry->Base);
  920. }
  921. break;
  922. }
  923. }
  924. //
  925. // If a new image structure was allocated, add it
  926. // into the image list.
  927. //
  928. if (!ReusedExisting)
  929. {
  930. ImageNew->Next = *pp;
  931. *pp = ImageNew;
  932. g_CurrentProcess->NumberImages++;
  933. if (g_CurrentProcess->ExecutableImage == NULL)
  934. {
  935. // Try and locate the executable image entry for
  936. // the process to use as the process's name.
  937. ULONG NameLen = strlen(ImageNew->ImagePath);
  938. if (NameLen > 4 &&
  939. !_stricmp(ImageNew->ImagePath + NameLen - 4, ".exe"))
  940. {
  941. g_CurrentProcess->ExecutableImage = ImageNew;
  942. }
  943. }
  944. }
  945. //
  946. // If we do not want to load symbolic information, just return here.
  947. //
  948. if (!LoadSymbols)
  949. {
  950. return ImageNew->ImagePath;
  951. }
  952. if (ModEntry->DebugHeader)
  953. {
  954. mld.ssize = sizeof(MODLOAD_DATA);
  955. mld.ssig = DBHHEADER_DEBUGDIRS;
  956. mld.data = ModEntry->DebugHeader;
  957. mld.size = ModEntry->SizeOfDebugHeader;
  958. mld.flags = 0;;
  959. }
  960. LoadAddress = SymLoadModuleEx(g_CurrentProcess->Handle,
  961. ImageNew->File,
  962. PrepareImagePath(ImageNew->ImagePath),
  963. ImageNew->ModuleName,
  964. ImageNew->BaseOfImage,
  965. ImageNew->SizeOfImage,
  966. ModEntry->DebugHeader ? &mld : NULL,
  967. 0);
  968. if (!LoadAddress)
  969. {
  970. VerbOut("SymLoadModule(%N, %N, \"%s\", \"%s\", %s, %x) fails\n",
  971. g_CurrentProcess->Handle,
  972. ImageNew->File,
  973. ImageNew->ImagePath,
  974. ImageNew->ModuleName,
  975. FormatAddr64(ImageNew->BaseOfImage),
  976. ImageNew->SizeOfImage);
  977. // We don't want DelImage to notify of a symbol change
  978. // if this is a partially newly created image.
  979. if (!ReusedExisting)
  980. {
  981. g_EngNotify++;
  982. }
  983. DelImageByBase(g_CurrentProcess, ImageNew->BaseOfImage);
  984. if (!ReusedExisting)
  985. {
  986. g_EngNotify--;
  987. }
  988. return NULL;
  989. }
  990. if (!ImageNew->BaseOfImage)
  991. {
  992. ImageNew->BaseOfImage = LoadAddress;
  993. }
  994. if (ForceSymbolLoad)
  995. {
  996. SymLoadModule64(g_CurrentProcess->Handle,
  997. NULL,
  998. NULL,
  999. NULL,
  1000. ImageNew->BaseOfImage,
  1001. 0);
  1002. }
  1003. mi.SizeOfStruct = sizeof(mi);
  1004. if (SymGetModuleInfo64( g_CurrentProcess->Handle,
  1005. ImageNew->BaseOfImage, &mi ))
  1006. {
  1007. ImageNew->SizeOfImage = mi.ImageSize;
  1008. }
  1009. else
  1010. {
  1011. VerbOut("SymGetModuleInfo(%N, %s) fails\n",
  1012. g_CurrentProcess->Handle,
  1013. FormatAddr64(ImageNew->BaseOfImage));
  1014. // We don't want DelImage to notify of a symbol change
  1015. // if this is a partially newly created image.
  1016. if (!ReusedExisting)
  1017. {
  1018. g_EngNotify++;
  1019. }
  1020. DelImageByBase(g_CurrentProcess, ImageNew->BaseOfImage);
  1021. if (!ReusedExisting)
  1022. {
  1023. g_EngNotify--;
  1024. }
  1025. return NULL;
  1026. }
  1027. StartOutLine(DEBUG_OUTPUT_VERBOSE, OUT_LINE_NO_PREFIX);
  1028. VerbOut( "ModLoad: %s %s %-8s\n",
  1029. FormatAddr64(ImageNew->BaseOfImage),
  1030. FormatAddr64(ImageNew->BaseOfImage + ImageNew->SizeOfImage),
  1031. ImageNew->ImagePath);
  1032. NotifyChangeSymbolState(DEBUG_CSS_LOADS, ImageNew->BaseOfImage,
  1033. g_CurrentProcess);
  1034. return ImageNew->ImagePath;
  1035. }
  1036. void
  1037. DelImage(
  1038. PPROCESS_INFO Process,
  1039. PDEBUG_IMAGE_INFO Image
  1040. )
  1041. {
  1042. ULONG64 ImageBase = Image->BaseOfImage;
  1043. #if DBG_MOD_LIST
  1044. dprintf("DelImage:\n"
  1045. " ImagePath %s\n"
  1046. " BaseOfImage %I64x\n"
  1047. " SizeOfImage %x\n",
  1048. Image->ImagePath,
  1049. Image->BaseOfImage,
  1050. Image->SizeOfImage);
  1051. #endif
  1052. if (IS_DUMP_WITH_MAPPED_IMAGES())
  1053. {
  1054. // Unmap the memory for this image.
  1055. UnloadExecutableImageMemory(Image);
  1056. }
  1057. SymUnloadModule64( Process->Handle, Image->BaseOfImage );
  1058. ClearStoredTypes(Image->BaseOfImage);
  1059. if (Image->File)
  1060. {
  1061. CloseHandle( Image->File );
  1062. }
  1063. if (Process->ExecutableImage == Image)
  1064. {
  1065. Process->ExecutableImage = NULL;
  1066. }
  1067. free(Image);
  1068. Process->NumberImages--;
  1069. // Notify with this process in order to mark any resulting
  1070. // defered breakpoints due to this mod unload
  1071. NotifyChangeSymbolState(DEBUG_CSS_UNLOADS, ImageBase, Process);
  1072. }
  1073. BOOL
  1074. DelImageByName(PPROCESS_INFO Process, PCSTR Name, INAME Which)
  1075. {
  1076. PDEBUG_IMAGE_INFO Image, *pp;
  1077. pp = &Process->ImageHead;
  1078. while (Image = *pp)
  1079. {
  1080. PCSTR WhichStr;
  1081. switch(Which)
  1082. {
  1083. case INAME_IMAGE_PATH:
  1084. WhichStr = Image->ImagePath;
  1085. break;
  1086. case INAME_IMAGE_PATH_TAIL:
  1087. WhichStr = PathTail(Image->ImagePath);
  1088. break;
  1089. case INAME_MODULE:
  1090. WhichStr = Image->ModuleName;
  1091. break;
  1092. }
  1093. if (!_stricmp(WhichStr, Name))
  1094. {
  1095. *pp = Image->Next;
  1096. DelImage(Process, Image);
  1097. return TRUE;
  1098. }
  1099. else
  1100. {
  1101. pp = &Image->Next;
  1102. }
  1103. }
  1104. return FALSE;
  1105. }
  1106. BOOL
  1107. DelImageByBase(
  1108. PPROCESS_INFO pProcess,
  1109. ULONG64 BaseOfImage
  1110. )
  1111. {
  1112. PDEBUG_IMAGE_INFO Image, *pp;
  1113. pp = &pProcess->ImageHead;
  1114. while (Image = *pp)
  1115. {
  1116. if (Image->BaseOfImage == BaseOfImage)
  1117. {
  1118. *pp = Image->Next;
  1119. DelImage(pProcess, Image);
  1120. return TRUE;
  1121. }
  1122. else
  1123. {
  1124. pp = &Image->Next;
  1125. }
  1126. }
  1127. return FALSE;
  1128. }
  1129. void
  1130. DelImages(PPROCESS_INFO Process)
  1131. {
  1132. PDEBUG_IMAGE_INFO Image, NextImage;
  1133. // Suppress notifications until all images are deleted.
  1134. g_EngNotify++;
  1135. NextImage = Process->ImageHead;
  1136. Process->ImageHead = NULL;
  1137. while (NextImage)
  1138. {
  1139. Image = NextImage;
  1140. NextImage = Image->Next;
  1141. DelImage(Process, Image);
  1142. }
  1143. g_EngNotify--;
  1144. NotifyChangeSymbolState(DEBUG_CSS_UNLOADS, 0, Process);
  1145. }
  1146. void
  1147. OutputSymAddr (
  1148. ULONG64 Offset,
  1149. ULONG Flags
  1150. )
  1151. {
  1152. CHAR AddrBuffer[MAX_SYMBOL_LEN];
  1153. ULONG64 Displacement;
  1154. GetSymbolStdCall(Offset, AddrBuffer, sizeof(AddrBuffer),
  1155. &Displacement, NULL);
  1156. if ((!Displacement || (Flags & SYMADDR_FORCE)) && AddrBuffer[0])
  1157. {
  1158. dprintf("%s", AddrBuffer);
  1159. if (Displacement)
  1160. {
  1161. dprintf("+%s", FormatDisp64(Displacement));
  1162. }
  1163. if (Flags & SYMADDR_SOURCE)
  1164. {
  1165. OutputLineAddr(Offset, " [%s @ %d]");
  1166. }
  1167. if (Flags & SYMADDR_LABEL)
  1168. {
  1169. dprintf(":\n");
  1170. }
  1171. else
  1172. {
  1173. dprintf(" ");
  1174. }
  1175. }
  1176. }
  1177. void
  1178. OutputLineAddr(
  1179. ULONG64 Offset,
  1180. PCSTR Format
  1181. )
  1182. {
  1183. if ((g_SymOptions & SYMOPT_LOAD_LINES) == 0)
  1184. {
  1185. return;
  1186. }
  1187. IMAGEHLP_LINE Line;
  1188. DWORD LineDisp;
  1189. Line.SizeOfStruct = sizeof(Line);
  1190. if (SymGetLineFromAddr(g_CurrentProcess->Handle, Offset,
  1191. &LineDisp, &Line))
  1192. {
  1193. dprintf(Format, Line.FileName, Line.LineNumber);
  1194. }
  1195. }
  1196. /*** OutCurInfo - Display selected information about the current register
  1197. * state.
  1198. *
  1199. * Purpose:
  1200. * Source file lines may be shown.
  1201. * Source line information may be shown.
  1202. * Symbol information may be shown.
  1203. * The current register set may be shown.
  1204. * The instruction at the current program current may be disassembled
  1205. * with any effective address displayed.
  1206. *
  1207. * Input:
  1208. * None.
  1209. *
  1210. * Output:
  1211. * None.
  1212. *
  1213. * Notes:
  1214. * If the disassembly is of a delayed control instruction, the
  1215. * delay slot instruction is also output.
  1216. *
  1217. *************************************************************************/
  1218. void OutCurInfo(ULONG Flags, ULONG AllMask, ULONG RegMask)
  1219. {
  1220. ADDR PcValue;
  1221. ADDR DisasmAddr;
  1222. CHAR Buffer[MAX_DISASM_LEN];
  1223. BOOL EA;
  1224. if (g_CurrentProcess == NULL ||
  1225. g_CurrentProcess->CurrentThread == NULL)
  1226. {
  1227. WarnOut("WARNING: The debugger does not have a current "
  1228. "process or thread\n");
  1229. WarnOut("WARNING: Many commands will not work\n");
  1230. }
  1231. if (!IS_MACHINE_SET() ||
  1232. g_CurrentProcess == NULL ||
  1233. g_CurrentProcess->CurrentThread == NULL ||
  1234. IS_LOCAL_KERNEL_TARGET() ||
  1235. ((Flags & OCI_IGNORE_STATE) == 0 && IS_RUNNING(g_CmdState)) ||
  1236. ((IS_KERNEL_FULL_DUMP() || IS_KERNEL_SUMMARY_DUMP()) &&
  1237. KdDebuggerData.KiProcessorBlock == 0))
  1238. {
  1239. // State is not available right now.
  1240. return;
  1241. }
  1242. g_Machine->GetPC(&PcValue);
  1243. if ((Flags & (OCI_FORCE_ALL | OCI_FORCE_REG)) ||
  1244. ((g_SrcOptions & SRCOPT_LIST_SOURCE_ONLY) == 0 &&
  1245. (Flags & OCI_ALLOW_REG) &&
  1246. g_OciOutputRegs))
  1247. {
  1248. g_Machine->OutputAll(AllMask, RegMask);
  1249. }
  1250. // Output g_PrevRelatedPc address
  1251. if (Flat(g_PrevRelatedPc) && !AddrEqu(g_PrevRelatedPc, PcValue))
  1252. {
  1253. if (Flags & (OCI_FORCE_ALL | OCI_SYMBOL))
  1254. {
  1255. OutputSymAddr(Flat(g_PrevRelatedPc), SYMADDR_FORCE);
  1256. dprintf("(%s)", FormatAddr64(Flat(g_PrevRelatedPc)));
  1257. }
  1258. else
  1259. {
  1260. dprintf("%s", FormatAddr64(Flat(g_PrevRelatedPc)));
  1261. }
  1262. dprintf("\n -> ");
  1263. }
  1264. // Deliberately does not force source with force-all so that source line
  1265. // support has no effect on default operation.
  1266. if (Flags & (OCI_FORCE_ALL | OCI_FORCE_SOURCE | OCI_ALLOW_SOURCE))
  1267. {
  1268. if (g_SrcOptions & SRCOPT_LIST_SOURCE)
  1269. {
  1270. if (OutputSrcLinesAroundAddr(Flat(PcValue),
  1271. g_OciSrcBefore, g_OciSrcAfter) &&
  1272. (Flags & OCI_FORCE_ALL) == 0 &&
  1273. (g_SrcOptions & SRCOPT_LIST_SOURCE_ONLY))
  1274. {
  1275. return;
  1276. }
  1277. }
  1278. else if ((g_SrcOptions & SRCOPT_LIST_LINE) ||
  1279. (Flags & OCI_FORCE_SOURCE))
  1280. {
  1281. OutputLineAddr(Flat(PcValue));
  1282. }
  1283. }
  1284. if (Flags & (OCI_FORCE_ALL | OCI_SYMBOL))
  1285. {
  1286. OutputSymAddr(Flat(PcValue), SYMADDR_FORCE | SYMADDR_LABEL);
  1287. }
  1288. if (Flags & (OCI_FORCE_ALL | OCI_DISASM))
  1289. {
  1290. if (Flags & (OCI_FORCE_ALL | OCI_FORCE_EA))
  1291. {
  1292. EA = TRUE;
  1293. }
  1294. else if (Flags & OCI_ALLOW_EA)
  1295. {
  1296. if (IS_DUMP_TARGET() || IS_USER_TARGET())
  1297. {
  1298. // Always show the EA info.
  1299. EA = TRUE;
  1300. }
  1301. else
  1302. {
  1303. // Only show the EA information if registers were shown.
  1304. EA = g_OciOutputRegs;
  1305. }
  1306. }
  1307. else
  1308. {
  1309. EA = FALSE;
  1310. }
  1311. DisasmAddr = PcValue;
  1312. g_Machine->Disassemble(&DisasmAddr, Buffer, EA);
  1313. dprintf("%s", Buffer);
  1314. if (g_Machine->IsDelayInstruction(&PcValue))
  1315. {
  1316. g_Machine->Disassemble(&DisasmAddr, Buffer, EA);
  1317. dprintf("%s", Buffer);
  1318. }
  1319. }
  1320. }
  1321. #define MAX_FORMAT_STRINGS 8
  1322. LPSTR
  1323. FormatMachineAddr64(
  1324. MachineInfo* Machine,
  1325. ULONG64 Addr
  1326. )
  1327. /*++
  1328. Routine Description:
  1329. Format a 64 bit address, showing the high bits or not
  1330. according to various flags.
  1331. An array of static string buffers is used, returning a different
  1332. buffer for each successive call so that it may be used multiple
  1333. times in the same printf.
  1334. Arguments:
  1335. Addr - Supplies the value to format
  1336. Return Value:
  1337. A pointer to the string buffer containing the formatted number
  1338. --*/
  1339. {
  1340. static CHAR s_Strings[MAX_FORMAT_STRINGS][18];
  1341. static int s_Next = 0;
  1342. LPSTR String;
  1343. String = s_Strings[s_Next];
  1344. ++s_Next;
  1345. if (s_Next >= MAX_FORMAT_STRINGS)
  1346. {
  1347. s_Next = 0;
  1348. }
  1349. if (Machine->m_Ptr64)
  1350. {
  1351. sprintf(String, "%08x`%08x", (ULONG)(Addr >> 32), (ULONG)Addr);
  1352. }
  1353. else
  1354. {
  1355. sprintf(String, "%08x", (ULONG)Addr);
  1356. }
  1357. return String;
  1358. }
  1359. LPSTR
  1360. FormatDisp64(
  1361. ULONG64 addr
  1362. )
  1363. /*++
  1364. Routine Description:
  1365. Format a 64 bit address, showing the high bits or not
  1366. according to various flags. This version does not print
  1367. leading 0's.
  1368. An array of static string buffers is used, returning a different
  1369. buffer for each successive call so that it may be used multiple
  1370. times in the same printf.
  1371. Arguments:
  1372. addr - Supplies the value to format
  1373. Return Value:
  1374. A pointer to the string buffer containing the formatted number
  1375. --*/
  1376. {
  1377. static CHAR strings[MAX_FORMAT_STRINGS][18];
  1378. static int next = 0;
  1379. LPSTR string;
  1380. string = strings[next];
  1381. ++next;
  1382. if (next >= MAX_FORMAT_STRINGS)
  1383. {
  1384. next = 0;
  1385. }
  1386. if ((addr >> 32) != 0)
  1387. {
  1388. sprintf(string, "%x`%08x", (ULONG)(addr>>32), (ULONG)addr);
  1389. }
  1390. else
  1391. {
  1392. sprintf(string, "%x", (ULONG)addr);
  1393. }
  1394. return string;
  1395. }
  1396. DWORD
  1397. NetworkPathCheck(
  1398. LPCSTR PathList
  1399. )
  1400. /*++
  1401. Routine Description:
  1402. Checks if any members of the PathList are network paths.
  1403. Arguments:
  1404. PathList - A list of paths separated by ';' characters.
  1405. Return Values:
  1406. ERROR_SUCCESS - The path list contained no network or invalid paths.
  1407. ERROR_BAD_PATHNAME - The path list contained one or more invalid paths,
  1408. but no network paths.
  1409. ERROR_FILE_OFFLINE - The path list contained one or more network paths.
  1410. Bugs:
  1411. Any path containing the ';' character will totally confuse this function.
  1412. --*/
  1413. {
  1414. CHAR EndPath0;
  1415. CHAR EndPath1;
  1416. LPSTR EndPath;
  1417. LPSTR StartPath;
  1418. DWORD DriveType;
  1419. LPSTR Buffer = NULL;
  1420. DWORD ret = ERROR_SUCCESS;
  1421. BOOL AddedTrailingSlash = FALSE;
  1422. if (PathList == NULL ||
  1423. *PathList == '\000') {
  1424. return FALSE;
  1425. }
  1426. Buffer = (LPSTR) malloc ( strlen (PathList) + 3);
  1427. if (!Buffer) {
  1428. return ERROR_BAD_PATHNAME;
  1429. }
  1430. strcpy (Buffer, PathList);
  1431. StartPath = Buffer;
  1432. do {
  1433. if (StartPath [0] == '\\' && StartPath [1] == '\\') {
  1434. ret = ERROR_FILE_OFFLINE;
  1435. break;
  1436. }
  1437. EndPath = strchr (StartPath, ';');
  1438. if (EndPath == NULL) {
  1439. EndPath = StartPath + strlen (StartPath);
  1440. EndPath0 = *EndPath;
  1441. } else {
  1442. EndPath0 = *EndPath;
  1443. *EndPath = '\000';
  1444. }
  1445. if (EndPath [-1] != '\\') {
  1446. EndPath [0] = '\\';
  1447. EndPath1 = EndPath [1];
  1448. EndPath [1] = '\000';
  1449. AddedTrailingSlash = TRUE;
  1450. }
  1451. DriveType = GetDriveType (StartPath);
  1452. if (DriveType == DRIVE_REMOTE) {
  1453. ret = ERROR_FILE_OFFLINE;
  1454. break;
  1455. } else if (DriveType == DRIVE_UNKNOWN ||
  1456. DriveType == DRIVE_NO_ROOT_DIR) {
  1457. //
  1458. // This is not necessarily an error, but it may merit
  1459. // investigation.
  1460. //
  1461. if (ret == ERROR_SUCCESS) {
  1462. ret = ERROR_BAD_PATHNAME;
  1463. }
  1464. }
  1465. EndPath [0] = EndPath0;
  1466. if (AddedTrailingSlash) {
  1467. EndPath [1] = EndPath1;
  1468. }
  1469. AddedTrailingSlash = FALSE;
  1470. if (EndPath [ 0 ] == '\000') {
  1471. StartPath = NULL;
  1472. } else {
  1473. StartPath = &EndPath [ 1 ];
  1474. }
  1475. } while (StartPath && *StartPath != '\000');
  1476. if (Buffer) {
  1477. free ( Buffer );
  1478. Buffer = NULL;
  1479. }
  1480. return ret;
  1481. }
  1482. //----------------------------------------------------------------------------
  1483. //
  1484. // Returns either an ID value or ALL_ID_LIST. In theory
  1485. // this routine could be expanded to pass back true intervals
  1486. // so a full list could be specified.
  1487. //
  1488. // Originally built up a mask for the multi-ID case but that
  1489. // was changed to return a real ID when 32 bits became
  1490. // constraining.
  1491. //
  1492. //----------------------------------------------------------------------------
  1493. ULONG
  1494. GetIdList (void)
  1495. {
  1496. ULONG Value = 0;
  1497. CHAR ch;
  1498. CHAR Digits[5]; // allow up to four digits
  1499. int i;
  1500. //
  1501. // Change to allow more than 32 break points to be set. Use
  1502. // break point numbers instead of masks.
  1503. //
  1504. if ((ch = PeekChar()) == '*')
  1505. {
  1506. Value = ALL_ID_LIST;
  1507. g_CurCmd++;
  1508. }
  1509. else if (ch == '[')
  1510. {
  1511. Value = (ULONG)GetTermExprDesc("Breakpoint ID missing from");
  1512. }
  1513. else
  1514. {
  1515. for (i = 0; i < sizeof(Digits) - 1; i++)
  1516. {
  1517. if (ch >= '0' && ch <= '9')
  1518. {
  1519. Digits[i] = ch;
  1520. ch = *++g_CurCmd;
  1521. }
  1522. else
  1523. {
  1524. break;
  1525. }
  1526. }
  1527. Digits[i] = '\0';
  1528. if (ch == '\0' || ch == ';' || ch == ' ' || ch == '\t')
  1529. {
  1530. Value = strtol(Digits, NULL, 10);
  1531. }
  1532. else
  1533. {
  1534. error (SYNTAX);
  1535. }
  1536. }
  1537. return Value;
  1538. }
  1539. //
  1540. // Sets or appends to a semicolon-delimited path.
  1541. //
  1542. HRESULT
  1543. ChangePath(PSTR* Path, PCSTR New, BOOL Append, ULONG SymNotify)
  1544. {
  1545. ULONG NewLen, CurLen, TotLen;
  1546. PSTR NewPath;
  1547. if (New != NULL && *New != 0)
  1548. {
  1549. NewLen = strlen(New) + 1;
  1550. }
  1551. else if (Append)
  1552. {
  1553. // Nothing to append.
  1554. return S_OK;
  1555. }
  1556. else
  1557. {
  1558. NewLen = 0;
  1559. }
  1560. if (*Path == NULL || **Path == 0)
  1561. {
  1562. // Nothing to append to.
  1563. Append = FALSE;
  1564. }
  1565. if (Append)
  1566. {
  1567. CurLen = strlen(*Path) + 1;
  1568. }
  1569. else
  1570. {
  1571. CurLen = 0;
  1572. }
  1573. TotLen = CurLen + NewLen;
  1574. if (TotLen > 0)
  1575. {
  1576. NewPath = (PSTR)malloc(TotLen);
  1577. if (NewPath == NULL)
  1578. {
  1579. ErrOut("Unable to allocate memory for path\n");
  1580. return E_OUTOFMEMORY;
  1581. }
  1582. }
  1583. else
  1584. {
  1585. NewPath = NULL;
  1586. }
  1587. PSTR Cat = NewPath;
  1588. if (CurLen > 0)
  1589. {
  1590. memcpy(Cat, *Path, CurLen);
  1591. Cat[CurLen - 1] = ';';
  1592. Cat += CurLen;
  1593. }
  1594. if (NewLen > 0)
  1595. {
  1596. memcpy(Cat, New, NewLen);
  1597. }
  1598. if (*Path != NULL)
  1599. {
  1600. free(*Path);
  1601. }
  1602. *Path = NewPath;
  1603. if (SymNotify != 0)
  1604. {
  1605. NotifyChangeSymbolState(SymNotify, 0, g_CurrentProcess);
  1606. }
  1607. return S_OK;
  1608. }
  1609. PSTR
  1610. FindPathElement(PSTR Path, ULONG Element, PSTR* EltEnd)
  1611. {
  1612. PSTR Elt, Sep;
  1613. if (Path == NULL)
  1614. {
  1615. return NULL;
  1616. }
  1617. Elt = Path;
  1618. for (;;)
  1619. {
  1620. Sep = strchr(Elt, ';');
  1621. if (Sep == NULL)
  1622. {
  1623. Sep = Elt + strlen(Elt);
  1624. }
  1625. if (Element == 0)
  1626. {
  1627. break;
  1628. }
  1629. if (*Sep == 0)
  1630. {
  1631. // No more elements.
  1632. return NULL;
  1633. }
  1634. Elt = Sep + 1;
  1635. Element--;
  1636. }
  1637. *EltEnd = Sep;
  1638. return Elt;
  1639. }
  1640. void
  1641. CheckPath(PCSTR Path)
  1642. {
  1643. PCSTR EltStart;
  1644. PCSTR Scan;
  1645. BOOL Space;
  1646. if (Path == NULL)
  1647. {
  1648. return;
  1649. }
  1650. for (;;)
  1651. {
  1652. BOOL Warned = FALSE;
  1653. EltStart = Path;
  1654. Scan = EltStart;
  1655. while (isspace(*Scan))
  1656. {
  1657. Scan++;
  1658. }
  1659. if (Scan != EltStart)
  1660. {
  1661. WarnOut("WARNING: Whitespace at start of path element\n");
  1662. Warned = TRUE;
  1663. }
  1664. // Find the end of the element.
  1665. Space = FALSE;
  1666. while (*Scan && *Scan != ';')
  1667. {
  1668. Space = isspace(*Scan);
  1669. Scan++;
  1670. }
  1671. if (Space)
  1672. {
  1673. WarnOut("WARNING: Whitespace at end of path element\n");
  1674. Warned = TRUE;
  1675. }
  1676. if (Scan - EltStart >= MAX_PATH)
  1677. {
  1678. WarnOut("WARNING: Path element is longer than MAX_PATH\n");
  1679. Warned = TRUE;
  1680. }
  1681. if (!Warned)
  1682. {
  1683. char Elt[MAX_PATH];
  1684. memcpy(Elt, EltStart, Scan - EltStart);
  1685. Elt[Scan - EltStart] = 0;
  1686. if (!ValidatePathComponent(Elt))
  1687. {
  1688. WarnOut("WARNING: %s is not accessible\n", Elt);
  1689. Warned = TRUE;
  1690. }
  1691. }
  1692. if (!*Scan)
  1693. {
  1694. break;
  1695. }
  1696. Path = Scan + 1;
  1697. }
  1698. }
  1699. HRESULT
  1700. ChangeString(PSTR* Str, PULONG StrLen, PCSTR New)
  1701. {
  1702. ULONG Len;
  1703. PSTR Buf;
  1704. if (New != NULL)
  1705. {
  1706. Len = strlen(New) + 1;
  1707. Buf = new char[Len];
  1708. if (Buf == NULL)
  1709. {
  1710. return E_OUTOFMEMORY;
  1711. }
  1712. }
  1713. else
  1714. {
  1715. Buf = NULL;
  1716. Len = 0;
  1717. }
  1718. delete [] *Str;
  1719. *Str = Buf;
  1720. if (New != NULL)
  1721. {
  1722. memcpy(Buf, New, Len);
  1723. }
  1724. if (StrLen != NULL)
  1725. {
  1726. *StrLen = Len;
  1727. }
  1728. return S_OK;
  1729. }
  1730. typedef struct _FIND_MODULE_DATA {
  1731. ULONG SizeOfImage;
  1732. ULONG CheckSum;
  1733. ULONG TimeDateStamp;
  1734. PVOID FileMapping;
  1735. HANDLE FileHandle;
  1736. } FIND_MODULE_DATA, *PFIND_MODULE_DATA;
  1737. PCSTR KernelAliasList [] =
  1738. {
  1739. "ntoskrnl.exe",
  1740. "ntkrnlpa.exe",
  1741. "ntkrnlmp.exe",
  1742. "ntkrpamp.exe"
  1743. };
  1744. PCSTR ScsiAlias = "diskdump.sys";
  1745. PCSTR HalAliasList [] =
  1746. {
  1747. "hal.dll",
  1748. "hal486c.dll",
  1749. "halaacpi.dll",
  1750. "halacpi.dll",
  1751. "halapic.dll",
  1752. "halborg.dll"
  1753. "halmacpi.dll",
  1754. "halmps.dll",
  1755. "halsp.dll"
  1756. };
  1757. PCSTR KdAliasList [] =
  1758. {
  1759. "kdcom.dll",
  1760. "kd1394.dll"
  1761. };
  1762. #define MAX_ALIAS_COUNT (DIMA(HalAliasList))
  1763. PVOID
  1764. OpenMapping(
  1765. IN PCSTR FilePath,
  1766. OUT HANDLE* FileHandle
  1767. )
  1768. {
  1769. HANDLE File;
  1770. HANDLE Mapping;
  1771. PVOID View;
  1772. ULONG OldMode;
  1773. *FileHandle = NULL;
  1774. if (g_SymOptions & SYMOPT_FAIL_CRITICAL_ERRORS)
  1775. {
  1776. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  1777. }
  1778. File = CreateFile(
  1779. FilePath,
  1780. GENERIC_READ,
  1781. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1782. NULL,
  1783. OPEN_EXISTING,
  1784. 0,
  1785. NULL
  1786. );
  1787. if (g_SymOptions & SYMOPT_FAIL_CRITICAL_ERRORS)
  1788. {
  1789. SetErrorMode(OldMode);
  1790. }
  1791. if ( File == INVALID_HANDLE_VALUE )
  1792. {
  1793. return NULL;
  1794. }
  1795. Mapping = CreateFileMapping (
  1796. File,
  1797. NULL,
  1798. PAGE_READONLY,
  1799. 0,
  1800. 0,
  1801. NULL
  1802. );
  1803. if ( !Mapping )
  1804. {
  1805. CloseHandle ( File );
  1806. return FALSE;
  1807. }
  1808. View = MapViewOfFile (
  1809. Mapping,
  1810. FILE_MAP_READ,
  1811. 0,
  1812. 0,
  1813. 0
  1814. );
  1815. CloseHandle (Mapping);
  1816. *FileHandle = File;
  1817. return View;
  1818. }
  1819. PVOID
  1820. MapImageFile(
  1821. PCSTR FilePath,
  1822. ULONG SizeOfImage,
  1823. ULONG CheckSum,
  1824. ULONG TimeDateStamp,
  1825. HANDLE* FileHandle
  1826. )
  1827. {
  1828. PVOID FileMapping;
  1829. PIMAGE_NT_HEADERS NtHeader;
  1830. FileMapping = OpenMapping(FilePath, FileHandle);
  1831. NtHeader = ImageNtHeader(FileMapping);
  1832. if ((NtHeader == NULL) ||
  1833. (CheckSum && NtHeader->OptionalHeader.CheckSum &&
  1834. (NtHeader->OptionalHeader.CheckSum != CheckSum)) ||
  1835. (SizeOfImage != 0 &&
  1836. NtHeader->OptionalHeader.SizeOfImage != SizeOfImage) ||
  1837. (TimeDateStamp != 0 &&
  1838. NtHeader->FileHeader.TimeDateStamp != TimeDateStamp))
  1839. {
  1840. //
  1841. // The image data does not match the request.
  1842. //
  1843. if (g_SymOptions & SYMOPT_DEBUG)
  1844. {
  1845. ErrOut("DBGENG: %s image header does not match memory "
  1846. "image header\n", FilePath);
  1847. }
  1848. UnmapViewOfFile(FileMapping);
  1849. CloseHandle(*FileHandle);
  1850. *FileHandle = NULL;
  1851. return NULL;
  1852. }
  1853. return FileMapping;
  1854. }
  1855. BOOL CALLBACK
  1856. FindFileInPathCallback(PSTR FileName, PVOID CallerData)
  1857. {
  1858. PFIND_MODULE_DATA FindModuleData = (PFIND_MODULE_DATA)CallerData;
  1859. FindModuleData->FileMapping =
  1860. MapImageFile(FileName, FindModuleData->SizeOfImage,
  1861. (g_SymOptions & SYMOPT_EXACT_SYMBOLS) ?
  1862. FindModuleData->CheckSum : 0,
  1863. FindModuleData->TimeDateStamp,
  1864. &FindModuleData->FileHandle);
  1865. // The search stops when FALSE is returned, so
  1866. // return FALSE when we've found a match.
  1867. return FindModuleData->FileMapping == NULL;
  1868. }
  1869. BOOL
  1870. FindExecutableCallback(
  1871. HANDLE File,
  1872. PSTR FileName,
  1873. PVOID CallerData
  1874. )
  1875. {
  1876. PFIND_MODULE_DATA FindModuleData;
  1877. DBG_ASSERT ( CallerData );
  1878. FindModuleData = (PFIND_MODULE_DATA) CallerData;
  1879. FindModuleData->FileMapping =
  1880. MapImageFile(FileName, FindModuleData->SizeOfImage,
  1881. (g_SymOptions & SYMOPT_EXACT_SYMBOLS) ?
  1882. FindModuleData->CheckSum : 0,
  1883. FindModuleData->TimeDateStamp,
  1884. &FindModuleData->FileHandle);
  1885. return FindModuleData->FileMapping != NULL;
  1886. }
  1887. PVOID
  1888. FindImageFile(
  1889. IN PCSTR ImagePath,
  1890. IN ULONG SizeOfImage,
  1891. IN ULONG CheckSum,
  1892. IN ULONG TimeDateStamp,
  1893. OUT HANDLE* FileHandle,
  1894. OUT PSTR MappedImagePath
  1895. )
  1896. /*++
  1897. Routine Description:
  1898. Find the executable image on the SymbolPath that matches ModuleName,
  1899. CheckSum. This function takes care of things like renamed kernels and
  1900. hals, and multiple images with the same name on the path.
  1901. Return Values:
  1902. File mapping or NULL.
  1903. --*/
  1904. {
  1905. ULONG i;
  1906. ULONG j = 0;
  1907. HANDLE File;
  1908. ULONG AliasCount = 0;
  1909. PCSTR AliasList[MAX_ALIAS_COUNT + 3];
  1910. FIND_MODULE_DATA FindModuleData;
  1911. C_ASSERT (MAX_ALIAS_COUNT >= DIMA (KernelAliasList));
  1912. C_ASSERT (MAX_ALIAS_COUNT >= DIMA (HalAliasList));
  1913. C_ASSERT (MAX_ALIAS_COUNT >= DIMA (KdAliasList));
  1914. DBG_ASSERT ( ImagePath != NULL && ImagePath[0] != 0 );
  1915. PCSTR ModuleName = PathTail(ImagePath);
  1916. //
  1917. // Build an alias list. For normal modules, modules that are not the
  1918. // kernel, the hal or a dump driver, this list will contain exactly one
  1919. // entry with the module name. For kernel, hal and dump drivers, the
  1920. // list will contain any number of known aliases for the specific file.
  1921. //
  1922. for (i = 0; i < DIMA(KernelAliasList); i++)
  1923. {
  1924. if (!_strcmpi(ModuleName, KernelAliasList[i]))
  1925. {
  1926. //
  1927. // found a kernel alias.
  1928. //
  1929. AliasList[AliasCount++] = ModuleName;
  1930. while (j < DIMA(KernelAliasList))
  1931. {
  1932. AliasList[AliasCount++] = KernelAliasList[j++];
  1933. }
  1934. break;
  1935. }
  1936. }
  1937. if (!AliasCount)
  1938. {
  1939. for (i = 0; i < DIMA(HalAliasList); i++)
  1940. {
  1941. if (!_strcmpi(ModuleName, HalAliasList[i]))
  1942. {
  1943. //
  1944. // found a HAL alias.
  1945. //
  1946. AliasList[AliasCount++] = ModuleName;
  1947. while (j < DIMA(HalAliasList))
  1948. {
  1949. AliasList[AliasCount++] = HalAliasList[j++];
  1950. }
  1951. break;
  1952. }
  1953. }
  1954. }
  1955. if (!AliasCount)
  1956. {
  1957. for (i = 0; i < DIMA(KdAliasList); i++)
  1958. {
  1959. if (!_strcmpi(ModuleName, KdAliasList[i]))
  1960. {
  1961. //
  1962. // found a HAL alias.
  1963. //
  1964. AliasList[AliasCount++] = ModuleName;
  1965. while (j < DIMA(KdAliasList))
  1966. {
  1967. AliasList[AliasCount++] = KdAliasList[j++];
  1968. }
  1969. break;
  1970. }
  1971. }
  1972. }
  1973. if (!AliasCount)
  1974. {
  1975. if ( _strnicmp (ModuleName, "dump_scsiport", 11) == 00 )
  1976. {
  1977. AliasList[0] = ScsiAlias;
  1978. AliasCount = 1;
  1979. }
  1980. else if ( _strnicmp (ModuleName, "dump_", 5) == 00 )
  1981. {
  1982. //
  1983. // Setup dump driver alias list
  1984. //
  1985. AliasList[0] = &ModuleName[5];
  1986. AliasList[1] = ModuleName;
  1987. AliasCount = 2;
  1988. }
  1989. else
  1990. {
  1991. AliasList[0] = ModuleName;
  1992. AliasCount = 1;
  1993. }
  1994. }
  1995. //
  1996. // First try to find it in a symbol server or
  1997. // directly on the image path.
  1998. //
  1999. for (i = 0; i < AliasCount; i++)
  2000. {
  2001. FindModuleData.SizeOfImage = SizeOfImage;
  2002. FindModuleData.CheckSum = CheckSum;
  2003. FindModuleData.TimeDateStamp = TimeDateStamp;
  2004. FindModuleData.FileMapping = NULL;
  2005. FindModuleData.FileHandle = NULL;
  2006. if (SymFindFileInPath(g_CurrentProcess->Handle,
  2007. g_ExecutableImageSearchPath,
  2008. (PSTR)AliasList[i], UlongToPtr(TimeDateStamp),
  2009. SizeOfImage, 0, SSRVOPT_DWORD, MappedImagePath,
  2010. FindFileInPathCallback, &FindModuleData))
  2011. {
  2012. if (FileHandle)
  2013. {
  2014. *FileHandle = FindModuleData.FileHandle;
  2015. }
  2016. return FindModuleData.FileMapping;
  2017. }
  2018. }
  2019. //
  2020. // Initial search didn't work so do a full tree search.
  2021. //
  2022. for (i = 0; i < AliasCount; i++)
  2023. {
  2024. FindModuleData.SizeOfImage = SizeOfImage;
  2025. FindModuleData.CheckSum = CheckSum;
  2026. FindModuleData.TimeDateStamp = TimeDateStamp;
  2027. FindModuleData.FileMapping = NULL;
  2028. FindModuleData.FileHandle = NULL;
  2029. File = FindExecutableImageEx ((PSTR)AliasList[i],
  2030. g_ExecutableImageSearchPath,
  2031. MappedImagePath,
  2032. FindExecutableCallback,
  2033. &FindModuleData);
  2034. if ( File != NULL && File != INVALID_HANDLE_VALUE )
  2035. {
  2036. CloseHandle (File);
  2037. }
  2038. if ( FindModuleData.FileMapping != NULL )
  2039. {
  2040. if (FileHandle)
  2041. {
  2042. *FileHandle = FindModuleData.FileHandle;
  2043. }
  2044. return FindModuleData.FileMapping;
  2045. }
  2046. }
  2047. //
  2048. // No path searches found the image so just try
  2049. // the given path as a last-ditch check.
  2050. //
  2051. strcpy(MappedImagePath, ImagePath);
  2052. FindModuleData.FileMapping =
  2053. MapImageFile(ImagePath, SizeOfImage, CheckSum, TimeDateStamp,
  2054. FileHandle);
  2055. if (FindModuleData.FileMapping == NULL)
  2056. {
  2057. MappedImagePath[0] = 0;
  2058. }
  2059. return FindModuleData.FileMapping;
  2060. }
  2061. // User-mode minidump can be created with data segments
  2062. // embedded in the dump. If that's the case, don't map
  2063. // such sections.
  2064. #define IS_MINI_DATA_SECTION(SecHeader) \
  2065. (IS_USER_MINI_DUMP() && \
  2066. ((SecHeader)->Characteristics & IMAGE_SCN_MEM_WRITE) && \
  2067. ((SecHeader)->Characteristics & IMAGE_SCN_MEM_READ) && \
  2068. (((SecHeader)->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) || \
  2069. ((SecHeader)->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)))
  2070. #if 0
  2071. #define DBG_IMAGE_MAP
  2072. #endif
  2073. BOOL
  2074. LoadExecutableImageMemory(PDEBUG_IMAGE_INFO Image)
  2075. {
  2076. PVOID FileMapping;
  2077. HRESULT Status;
  2078. DBG_ASSERT(Image->File == NULL);
  2079. FileMapping = FindImageFile(Image->ImagePath,
  2080. Image->SizeOfImage,
  2081. Image->CheckSum,
  2082. Image->TimeDateStamp,
  2083. &Image->File,
  2084. Image->MappedImagePath);
  2085. if (FileMapping == NULL)
  2086. {
  2087. ErrOut("Unable to load image %s\n", Image->ImagePath);
  2088. return FALSE;
  2089. }
  2090. PIMAGE_NT_HEADERS Header = ImageNtHeader(FileMapping);
  2091. // Header was already validated in MapImageFile.
  2092. DBG_ASSERT(Header != NULL);
  2093. // Map the header so we have it later.
  2094. // Mark it with the image structure that this mapping is for.
  2095. if (MemoryMap_AddRegion(Image->BaseOfImage,
  2096. Header->OptionalHeader.SizeOfHeaders,
  2097. FileMapping, Image, FALSE) != S_OK)
  2098. {
  2099. UnmapViewOfFile(FileMapping);
  2100. if (Image->File != NULL)
  2101. {
  2102. CloseHandle(Image->File);
  2103. Image->File = NULL;
  2104. }
  2105. Image->MappedImagePath[0] = 0;
  2106. ErrOut("Unable to map image header memory for %s\n",
  2107. Image->ImagePath);
  2108. return FALSE;
  2109. }
  2110. PIMAGE_DATA_DIRECTORY DebugDataDir;
  2111. IMAGE_DEBUG_DIRECTORY UNALIGNED * DebugDir = NULL;
  2112. // Due to a linker bug, some images have debug data that is not
  2113. // included as part of a section. Scan the debug data directory
  2114. // and map anything that isn't already mapped.
  2115. switch(Header->OptionalHeader.Magic)
  2116. {
  2117. case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
  2118. DebugDataDir = &((PIMAGE_NT_HEADERS32)Header)->OptionalHeader.
  2119. DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
  2120. break;
  2121. case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
  2122. DebugDataDir = &((PIMAGE_NT_HEADERS64)Header)->OptionalHeader.
  2123. DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
  2124. break;
  2125. default:
  2126. DebugDataDir = NULL;
  2127. break;
  2128. }
  2129. //
  2130. // Map all the sections in the image at their
  2131. // appropriate offsets from the base address.
  2132. //
  2133. ULONG i;
  2134. #ifdef DBG_IMAGE_MAP
  2135. dprintf("Map %s: base %s, size %x, %d sections, mapping %p\n",
  2136. Image->ImagePath, FormatAddr64(Image->BaseOfImage),
  2137. Image->SizeOfImage, Header->FileHeader.NumberOfSections,
  2138. FileMapping);
  2139. #endif
  2140. PIMAGE_SECTION_HEADER SecHeader = IMAGE_FIRST_SECTION(Header);
  2141. for (i = 0; i < Header->FileHeader.NumberOfSections; i++)
  2142. {
  2143. BOOL AllowOverlap;
  2144. #ifdef DBG_IMAGE_MAP
  2145. dprintf(" %2d: %8.8s v %08x s %08x p %08x char %X\n", i,
  2146. SecHeader->Name, SecHeader->VirtualAddress,
  2147. SecHeader->SizeOfRawData, SecHeader->PointerToRawData,
  2148. SecHeader->Characteristics);
  2149. #endif
  2150. if (SecHeader->SizeOfRawData == 0)
  2151. {
  2152. // Probably a BSS section that describes
  2153. // a zero-filled data region and so is not
  2154. // present in the executable. This should really
  2155. // map to the appropriate page full of zeroes but
  2156. // for now just ignore it.
  2157. SecHeader++;
  2158. continue;
  2159. }
  2160. if (DebugDataDir != NULL &&
  2161. DebugDataDir->VirtualAddress >= SecHeader->VirtualAddress &&
  2162. DebugDataDir->VirtualAddress < SecHeader->VirtualAddress +
  2163. SecHeader->SizeOfRawData)
  2164. {
  2165. #ifdef DBG_IMAGE_MAP
  2166. dprintf(" DebugDataDir found in sec %d at %X (%X)\n",
  2167. i, DebugDataDir->VirtualAddress,
  2168. DebugDataDir->VirtualAddress - SecHeader->VirtualAddress);
  2169. #endif
  2170. DebugDir = (PIMAGE_DEBUG_DIRECTORY)
  2171. ((PUCHAR)FileMapping + (DebugDataDir->VirtualAddress -
  2172. SecHeader->VirtualAddress +
  2173. SecHeader->PointerToRawData));
  2174. }
  2175. // As a sanity check make sure that the mapped region will
  2176. // fall within the overall image bounds.
  2177. if (SecHeader->VirtualAddress >= Image->SizeOfImage ||
  2178. SecHeader->VirtualAddress + SecHeader->SizeOfRawData >
  2179. Image->SizeOfImage)
  2180. {
  2181. WarnOut("WARNING: Image %s section %d extends "
  2182. "outside of image bounds\n",
  2183. Image->ImagePath, i);
  2184. }
  2185. if (IS_MINI_DATA_SECTION(SecHeader))
  2186. {
  2187. ULONG64 DataBase;
  2188. ULONG DataSize;
  2189. // Dumps can have explicit memory regions for
  2190. // data sections to reflect changes to globals
  2191. // and so on. If the current data section already
  2192. // is completely mapped just ignore the image data.
  2193. // Otherwise map but allow overlap.
  2194. if (MemoryMap_GetRegionInfo(Image->BaseOfImage +
  2195. SecHeader->VirtualAddress,
  2196. &DataBase, &DataSize, NULL, NULL) &&
  2197. DataBase + DataSize >= Image->BaseOfImage +
  2198. SecHeader->VirtualAddress + SecHeader->SizeOfRawData)
  2199. {
  2200. SecHeader++;
  2201. continue;
  2202. }
  2203. AllowOverlap = TRUE;
  2204. }
  2205. else
  2206. {
  2207. AllowOverlap = FALSE;
  2208. }
  2209. // Mark the region with the image structure to identify the
  2210. // region as an image area.
  2211. if ((Status = MemoryMap_AddRegion(Image->BaseOfImage +
  2212. SecHeader->VirtualAddress,
  2213. SecHeader->SizeOfRawData,
  2214. (PUCHAR)FileMapping +
  2215. SecHeader->PointerToRawData,
  2216. Image, AllowOverlap)) != S_OK)
  2217. {
  2218. ErrOut("Unable to map %s section %d at %s, %s\n",
  2219. Image->ImagePath, i,
  2220. FormatAddr64(Image->BaseOfImage +
  2221. SecHeader->VirtualAddress),
  2222. FormatStatusCode(Status));
  2223. // Conflicting region data is not a critical failure
  2224. // unless the incomplete information flag is set.
  2225. if (Status != HR_REGION_CONFLICT ||
  2226. (g_EngOptions & DEBUG_ENGOPT_FAIL_INCOMPLETE_INFORMATION))
  2227. {
  2228. if (!UnloadExecutableImageMemory(Image))
  2229. {
  2230. UnmapViewOfFile(FileMapping);
  2231. if (Image->File != NULL)
  2232. {
  2233. CloseHandle(Image->File);
  2234. Image->File = NULL;
  2235. }
  2236. Image->MappedImagePath[0] = 0;
  2237. }
  2238. return FALSE;
  2239. }
  2240. }
  2241. SecHeader++;
  2242. }
  2243. if (DebugDir != NULL)
  2244. {
  2245. i = DebugDataDir->Size / sizeof(*DebugDir);
  2246. #ifdef DBG_IMAGE_MAP
  2247. dprintf(" %d debug dirs\n", i);
  2248. #endif
  2249. while (i-- > 0)
  2250. {
  2251. #ifdef DBG_IMAGE_MAP
  2252. dprintf(" Dir %d at %p\n", i, DebugDir);
  2253. #endif
  2254. // If this debug directory's data is past the size
  2255. // of the image it's a good indicator of the problem.
  2256. if (DebugDir->AddressOfRawData != 0 &&
  2257. DebugDir->PointerToRawData >= Image->SizeOfImage &&
  2258. !MemoryMap_GetRegionInfo(Image->BaseOfImage +
  2259. DebugDir->AddressOfRawData,
  2260. NULL, NULL, NULL, NULL))
  2261. {
  2262. #ifdef DBG_IMAGE_MAP
  2263. dprintf(" Mapped hidden debug data at RVA %08x, "
  2264. "size %x, ptr %08x\n",
  2265. DebugDir->AddressOfRawData, DebugDir->SizeOfData,
  2266. DebugDir->PointerToRawData);
  2267. #endif
  2268. if (MemoryMap_AddRegion(Image->BaseOfImage +
  2269. DebugDir->AddressOfRawData,
  2270. DebugDir->SizeOfData,
  2271. (PUCHAR)FileMapping +
  2272. DebugDir->PointerToRawData,
  2273. Image, FALSE) != S_OK)
  2274. {
  2275. ErrOut("Unable to map extended debug data at %s\n",
  2276. FormatAddr64(Image->BaseOfImage +
  2277. DebugDir->AddressOfRawData));
  2278. }
  2279. }
  2280. DebugDir++;
  2281. }
  2282. }
  2283. Image->MappedImageBase = FileMapping;
  2284. return TRUE;
  2285. }
  2286. BOOL
  2287. UnloadExecutableImageMemory(PDEBUG_IMAGE_INFO Image)
  2288. {
  2289. ULONG64 RegBase;
  2290. ULONG RegSize;
  2291. PVOID RegImage;
  2292. ULONG i;
  2293. // Look up the header region.
  2294. if (!MemoryMap_GetRegionInfo(Image->BaseOfImage, &RegBase, &RegSize,
  2295. NULL, &RegImage))
  2296. {
  2297. // This is expected for images which couldn't be located.
  2298. return FALSE;
  2299. }
  2300. if (RegImage != Image)
  2301. {
  2302. ErrOut("UnloadEIM: Header at %s isn't owned by %s\n",
  2303. FormatAddr64(Image->BaseOfImage), Image->ImagePath);
  2304. return FALSE;
  2305. }
  2306. PIMAGE_NT_HEADERS Header = ImageNtHeader(Image->MappedImageBase);
  2307. if (Header == NULL ||
  2308. Header->OptionalHeader.SizeOfHeaders != RegSize)
  2309. {
  2310. ErrOut("UnloadEIM %s: Unable to get image header at %s\n",
  2311. Image->ImagePath, FormatAddr64(Image->BaseOfImage));
  2312. return FALSE;
  2313. }
  2314. #ifdef DBG_IMAGE_MAP
  2315. dprintf("Unmap %s: base %s, size %x, %d sections\n",
  2316. Image->ImagePath, FormatAddr64(Image->BaseOfImage),
  2317. Image->SizeOfImage, Header->FileHeader.NumberOfSections);
  2318. #endif
  2319. PIMAGE_DATA_DIRECTORY DebugDataDir;
  2320. IMAGE_DEBUG_DIRECTORY UNALIGNED * DebugDir = NULL;
  2321. // Due to a linker bug, some images have debug data that is not
  2322. // included as part of a section. Scan the debug data directory
  2323. // and map anything that isn't already mapped.
  2324. switch(Header->OptionalHeader.Magic)
  2325. {
  2326. case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
  2327. DebugDataDir = &((PIMAGE_NT_HEADERS32)Header)->OptionalHeader.
  2328. DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
  2329. break;
  2330. case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
  2331. DebugDataDir = &((PIMAGE_NT_HEADERS64)Header)->OptionalHeader.
  2332. DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
  2333. break;
  2334. default:
  2335. DebugDataDir = NULL;
  2336. break;
  2337. }
  2338. //
  2339. // Unmap sections.
  2340. //
  2341. PIMAGE_SECTION_HEADER SecHeader = IMAGE_FIRST_SECTION(Header);
  2342. for (i = 0; i < Header->FileHeader.NumberOfSections; i++)
  2343. {
  2344. if (SecHeader->SizeOfRawData == 0)
  2345. {
  2346. SecHeader++;
  2347. continue;
  2348. }
  2349. if (DebugDataDir != NULL &&
  2350. DebugDataDir->VirtualAddress >= SecHeader->VirtualAddress &&
  2351. DebugDataDir->VirtualAddress < SecHeader->VirtualAddress +
  2352. SecHeader->SizeOfRawData)
  2353. {
  2354. ULONG Dir;
  2355. DebugDir = (PIMAGE_DEBUG_DIRECTORY)
  2356. ((PUCHAR)Image->MappedImageBase +
  2357. (DebugDataDir->VirtualAddress -
  2358. SecHeader->VirtualAddress +
  2359. SecHeader->PointerToRawData));
  2360. Dir = DebugDataDir->Size / sizeof(*DebugDir);
  2361. while (Dir-- > 0)
  2362. {
  2363. if (!IsBadReadPtr(DebugDir, sizeof(*DebugDir)) &&
  2364. DebugDir->AddressOfRawData != 0 &&
  2365. DebugDir->PointerToRawData >= Image->SizeOfImage &&
  2366. MemoryMap_GetRegionInfo(Image->BaseOfImage +
  2367. DebugDir->AddressOfRawData,
  2368. &RegBase, &RegSize, NULL,
  2369. &RegImage) &&
  2370. RegImage == Image)
  2371. {
  2372. #ifdef DBG_IMAGE_MAP
  2373. dprintf(" Unmap hidden debug data at RVA %08x, "
  2374. "size %x\n",
  2375. DebugDir->AddressOfRawData, DebugDir->SizeOfData);
  2376. #endif
  2377. MemoryMap_RemoveRegion(RegBase, RegSize);
  2378. }
  2379. DebugDir++;
  2380. }
  2381. }
  2382. // Code segments may be fragmented by the overlap handling
  2383. // splitting them up when they overlap with code memory
  2384. // areas recorded in the dump. Iterate over the sections
  2385. // and clean up everything that's tagged as coming from this
  2386. // image.
  2387. ULONG64 SecBase = Image->BaseOfImage + SecHeader->VirtualAddress;
  2388. ULONG SecSize = SecHeader->SizeOfRawData;
  2389. while (SecSize > 0)
  2390. {
  2391. if (!MemoryMap_GetRegionInfo(SecBase, &RegBase, &RegSize, NULL,
  2392. &RegImage))
  2393. {
  2394. ErrOut("UnloadEIM %s: Unable to get section %d "
  2395. "fragment at %s\n",
  2396. Image->ImagePath, i, FormatAddr64(SecBase));
  2397. break;
  2398. }
  2399. if (RegImage == Image)
  2400. {
  2401. MemoryMap_RemoveRegion(RegBase, RegSize);
  2402. }
  2403. SecBase += RegSize;
  2404. if (RegSize <= SecSize)
  2405. {
  2406. SecSize -= RegSize;
  2407. }
  2408. else
  2409. {
  2410. break;
  2411. }
  2412. }
  2413. SecHeader++;
  2414. }
  2415. MemoryMap_RemoveRegion(Image->BaseOfImage,
  2416. Header->OptionalHeader.SizeOfHeaders);
  2417. UnmapViewOfFile(Image->MappedImageBase);
  2418. Image->MappedImageBase = NULL;
  2419. CloseHandle(Image->File);
  2420. Image->File = NULL;
  2421. Image->MappedImagePath[0] = 0;
  2422. return TRUE;
  2423. }
  2424. #if DBG
  2425. void
  2426. DbgAssertionFailed(PCSTR File, int Line, PCSTR Str)
  2427. {
  2428. char Text[512];
  2429. _snprintf(Text, sizeof(Text),
  2430. "Assertion failed: %s(%d)\n %s\n",
  2431. File, Line, Str);
  2432. OutputDebugStringA(Text);
  2433. if (getenv("DBGENG_ASSERT_BREAK"))
  2434. {
  2435. DebugBreak();
  2436. }
  2437. else
  2438. {
  2439. ErrOut("%s", Text);
  2440. FlushCallbacks();
  2441. }
  2442. }
  2443. #endif // #if DBG
  2444. void
  2445. ExceptionRecordTo64(PEXCEPTION_RECORD Rec,
  2446. PEXCEPTION_RECORD64 Rec64)
  2447. {
  2448. ULONG i;
  2449. Rec64->ExceptionCode = Rec->ExceptionCode;
  2450. Rec64->ExceptionFlags = Rec->ExceptionFlags;
  2451. Rec64->ExceptionRecord = (ULONG64)Rec->ExceptionRecord;
  2452. Rec64->ExceptionAddress = (ULONG64)Rec->ExceptionAddress;
  2453. Rec64->NumberParameters = Rec->NumberParameters;
  2454. for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
  2455. {
  2456. Rec64->ExceptionInformation[i] = Rec->ExceptionInformation[i];
  2457. }
  2458. }
  2459. void
  2460. ExceptionRecord64To(PEXCEPTION_RECORD64 Rec64,
  2461. PEXCEPTION_RECORD Rec)
  2462. {
  2463. ULONG i;
  2464. Rec->ExceptionCode = Rec64->ExceptionCode;
  2465. Rec->ExceptionFlags = Rec64->ExceptionFlags;
  2466. Rec->ExceptionRecord = (PEXCEPTION_RECORD)(ULONG_PTR)
  2467. Rec64->ExceptionRecord;
  2468. Rec->ExceptionAddress = (PVOID)(ULONG_PTR)
  2469. Rec64->ExceptionAddress;
  2470. Rec->NumberParameters = Rec64->NumberParameters;
  2471. for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
  2472. {
  2473. Rec->ExceptionInformation[i] = (ULONG_PTR)
  2474. Rec64->ExceptionInformation[i];
  2475. }
  2476. }
  2477. void
  2478. MemoryBasicInformationTo64(PMEMORY_BASIC_INFORMATION Mbi,
  2479. PMEMORY_BASIC_INFORMATION64 Mbi64)
  2480. {
  2481. #ifdef _WIN64
  2482. memcpy(Mbi64, Mbi, sizeof(*Mbi64));
  2483. #else
  2484. Mbi64->BaseAddress = (ULONG64) Mbi->BaseAddress;
  2485. Mbi64->AllocationBase = (ULONG64) Mbi->AllocationBase;
  2486. Mbi64->AllocationProtect = Mbi->AllocationProtect;
  2487. Mbi64->__alignment1 = 0;
  2488. Mbi64->RegionSize = Mbi->RegionSize;
  2489. Mbi64->State = Mbi->State;
  2490. Mbi64->Protect = Mbi->Protect;
  2491. Mbi64->Type = Mbi->Type;
  2492. Mbi64->__alignment2 = 0;
  2493. #endif
  2494. }
  2495. void
  2496. MemoryBasicInformation32To64(PMEMORY_BASIC_INFORMATION32 Mbi32,
  2497. PMEMORY_BASIC_INFORMATION64 Mbi64)
  2498. {
  2499. Mbi64->BaseAddress = EXTEND64(Mbi32->BaseAddress);
  2500. Mbi64->AllocationBase = EXTEND64(Mbi32->AllocationBase);
  2501. Mbi64->AllocationProtect = Mbi32->AllocationProtect;
  2502. Mbi64->__alignment1 = 0;
  2503. Mbi64->RegionSize = Mbi32->RegionSize;
  2504. Mbi64->State = Mbi32->State;
  2505. Mbi64->Protect = Mbi32->Protect;
  2506. Mbi64->Type = Mbi32->Type;
  2507. Mbi64->__alignment2 = 0;
  2508. }
  2509. void
  2510. DebugEvent32To64(LPDEBUG_EVENT32 Event32,
  2511. LPDEBUG_EVENT64 Event64)
  2512. {
  2513. Event64->dwDebugEventCode = Event32->dwDebugEventCode;
  2514. Event64->dwProcessId = Event32->dwProcessId;
  2515. Event64->dwThreadId = Event32->dwThreadId;
  2516. Event64->__alignment = 0;
  2517. switch(Event32->dwDebugEventCode)
  2518. {
  2519. case EXCEPTION_DEBUG_EVENT:
  2520. ExceptionRecord32To64(&Event32->u.Exception.ExceptionRecord,
  2521. &Event64->u.Exception.ExceptionRecord);
  2522. Event64->u.Exception.dwFirstChance =
  2523. Event32->u.Exception.dwFirstChance;
  2524. break;
  2525. case CREATE_THREAD_DEBUG_EVENT:
  2526. Event64->u.CreateThread.hThread =
  2527. EXTEND64(Event32->u.CreateThread.hThread);
  2528. Event64->u.CreateThread.lpThreadLocalBase =
  2529. EXTEND64(Event32->u.CreateThread.lpThreadLocalBase);
  2530. Event64->u.CreateThread.lpStartAddress =
  2531. EXTEND64(Event32->u.CreateThread.lpStartAddress);
  2532. break;
  2533. case CREATE_PROCESS_DEBUG_EVENT:
  2534. Event64->u.CreateProcessInfo.hFile =
  2535. EXTEND64(Event32->u.CreateProcessInfo.hFile);
  2536. Event64->u.CreateProcessInfo.hProcess =
  2537. EXTEND64(Event32->u.CreateProcessInfo.hProcess);
  2538. Event64->u.CreateProcessInfo.hThread =
  2539. EXTEND64(Event32->u.CreateProcessInfo.hThread);
  2540. Event64->u.CreateProcessInfo.lpBaseOfImage =
  2541. EXTEND64(Event32->u.CreateProcessInfo.lpBaseOfImage);
  2542. Event64->u.CreateProcessInfo.dwDebugInfoFileOffset =
  2543. Event32->u.CreateProcessInfo.dwDebugInfoFileOffset;
  2544. Event64->u.CreateProcessInfo.nDebugInfoSize =
  2545. Event32->u.CreateProcessInfo.nDebugInfoSize;
  2546. Event64->u.CreateProcessInfo.lpThreadLocalBase =
  2547. EXTEND64(Event32->u.CreateProcessInfo.lpThreadLocalBase);
  2548. Event64->u.CreateProcessInfo.lpStartAddress =
  2549. EXTEND64(Event32->u.CreateProcessInfo.lpStartAddress);
  2550. Event64->u.CreateProcessInfo.lpImageName =
  2551. EXTEND64(Event32->u.CreateProcessInfo.lpImageName);
  2552. Event64->u.CreateProcessInfo.fUnicode =
  2553. Event32->u.CreateProcessInfo.fUnicode;
  2554. break;
  2555. case EXIT_THREAD_DEBUG_EVENT:
  2556. Event64->u.ExitThread.dwExitCode =
  2557. Event32->u.ExitThread.dwExitCode;
  2558. break;
  2559. case EXIT_PROCESS_DEBUG_EVENT:
  2560. Event64->u.ExitProcess.dwExitCode =
  2561. Event32->u.ExitProcess.dwExitCode;
  2562. break;
  2563. case LOAD_DLL_DEBUG_EVENT:
  2564. Event64->u.LoadDll.hFile =
  2565. EXTEND64(Event32->u.LoadDll.hFile);
  2566. Event64->u.LoadDll.lpBaseOfDll =
  2567. EXTEND64(Event32->u.LoadDll.lpBaseOfDll);
  2568. Event64->u.LoadDll.dwDebugInfoFileOffset =
  2569. Event32->u.LoadDll.dwDebugInfoFileOffset;
  2570. Event64->u.LoadDll.nDebugInfoSize =
  2571. Event32->u.LoadDll.nDebugInfoSize;
  2572. Event64->u.LoadDll.lpImageName =
  2573. EXTEND64(Event32->u.LoadDll.lpImageName);
  2574. Event64->u.LoadDll.fUnicode =
  2575. Event32->u.LoadDll.fUnicode;
  2576. break;
  2577. case UNLOAD_DLL_DEBUG_EVENT:
  2578. Event64->u.UnloadDll.lpBaseOfDll =
  2579. EXTEND64(Event32->u.UnloadDll.lpBaseOfDll);
  2580. break;
  2581. case OUTPUT_DEBUG_STRING_EVENT:
  2582. Event64->u.DebugString.lpDebugStringData =
  2583. EXTEND64(Event32->u.DebugString.lpDebugStringData);
  2584. Event64->u.DebugString.fUnicode =
  2585. Event32->u.DebugString.fUnicode;
  2586. Event64->u.DebugString.nDebugStringLength =
  2587. Event32->u.DebugString.nDebugStringLength;
  2588. break;
  2589. case RIP_EVENT:
  2590. Event64->u.RipInfo.dwError =
  2591. Event32->u.RipInfo.dwError;
  2592. Event64->u.RipInfo.dwType =
  2593. Event32->u.RipInfo.dwType;
  2594. break;
  2595. }
  2596. }
  2597. LPSTR
  2598. TimeToStr(
  2599. ULONG TimeDateStamp
  2600. )
  2601. {
  2602. LPSTR TimeDateStr;
  2603. // Handle invalid \ page out timestamps, since ctime blows up on
  2604. // this number
  2605. if ((TimeDateStamp == 0) || (TimeDateStamp == UNKNOWN_TIMESTAMP))
  2606. {
  2607. return "unavailable";
  2608. }
  2609. else if (IS_LIVE_KERNEL_TARGET() && TimeDateStamp == 0x49ef6f00)
  2610. {
  2611. // At boot time the shared memory data area is not
  2612. // yet initialized. The above value seems to be
  2613. // the random garbage that's there so detect it and
  2614. // ignore it. This is highly fragile but people
  2615. // keep asking about the garbage value.
  2616. return "unavailable until booted";
  2617. }
  2618. else
  2619. {
  2620. // TimeDateStamp is always a 32 bit quantity on the target,
  2621. // and we need to sign extend for 64 bit host since time_t
  2622. // has been extended to 64 bits.
  2623. time_t TDStamp = (time_t) (LONG) TimeDateStamp;
  2624. TimeDateStr = ctime((time_t *)&TDStamp);
  2625. if (TimeDateStr)
  2626. {
  2627. TimeDateStr[strlen(TimeDateStr) - 1] = 0;
  2628. }
  2629. else
  2630. {
  2631. TimeDateStr = "***** Invalid";
  2632. }
  2633. }
  2634. return TimeDateStr;
  2635. }
  2636. PCSTR
  2637. PathTail(PCSTR Path)
  2638. {
  2639. PCSTR Tail = Path + strlen(Path);
  2640. while (--Tail >= Path)
  2641. {
  2642. if (*Tail == '\\' || *Tail == '/' || *Tail == ':')
  2643. {
  2644. break;
  2645. }
  2646. }
  2647. return Tail + 1;
  2648. }
  2649. BOOL
  2650. MatchPathTails(PCSTR Path1, PCSTR Path2)
  2651. {
  2652. return _stricmp(PathTail(Path1), PathTail(Path2)) == 0;
  2653. }