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.

2824 lines
69 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // General utility functions.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997-2002.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. #include <sys\types.h>
  10. #include <sys\stat.h>
  11. PCSTR g_DefaultLogFileName = ENGINE_MOD_NAME ".log";
  12. char g_OpenLogFileName[MAX_PATH + 1];
  13. BOOL g_OpenLogFileAppended;
  14. int g_LogFile = -1;
  15. ULONG g_DisableErrorPrint;
  16. ULONG
  17. CheckUserInterrupt(void)
  18. {
  19. if (g_EngStatus & ENG_STATUS_USER_INTERRUPT)
  20. {
  21. g_EngStatus &= ~ENG_STATUS_USER_INTERRUPT;
  22. return TRUE;
  23. }
  24. return FALSE;
  25. }
  26. BOOL
  27. PollUserInterrupt(BOOL AllowPendingBreak)
  28. {
  29. // Check for a simple user interrupt.
  30. if (g_EngStatus & ENG_STATUS_USER_INTERRUPT)
  31. {
  32. return TRUE;
  33. }
  34. // If we're running and we're supposed to be breaking in,
  35. // we also consider this an interrupt to prevent long
  36. // operations from delaying the break-in.
  37. if (AllowPendingBreak &&
  38. IS_RUNNING(g_CmdState) &&
  39. (g_EngStatus & ENG_STATUS_PENDING_BREAK_IN))
  40. {
  41. return TRUE;
  42. }
  43. return FALSE;
  44. }
  45. LONG
  46. MappingExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)
  47. {
  48. static ULONG s_InPageErrors = 0;
  49. ULONG Code = ExceptionInfo->ExceptionRecord->ExceptionCode;
  50. if (Code == STATUS_IN_PAGE_ERROR)
  51. {
  52. if (++s_InPageErrors < 10)
  53. {
  54. if (s_InPageErrors % 2)
  55. {
  56. WarnOut("Ignore in-page I/O error\n");
  57. FlushCallbacks();
  58. }
  59. Sleep(500);
  60. return EXCEPTION_CONTINUE_EXECUTION;
  61. }
  62. }
  63. s_InPageErrors = 0;
  64. ErrOut("Exception 0x%08x while accessing mapping\n", Code);
  65. FlushCallbacks();
  66. return EXCEPTION_EXECUTE_HANDLER;
  67. }
  68. void
  69. RemoveDelChar(PSTR Buffer)
  70. {
  71. PSTR BufferOld = Buffer;
  72. PSTR BufferNew = Buffer;
  73. while (*BufferOld)
  74. {
  75. if (*BufferOld == 0x7f)
  76. {
  77. if (BufferNew > Buffer)
  78. {
  79. BufferNew--;
  80. }
  81. }
  82. else if (*BufferOld == '\r' || *BufferOld == '\n')
  83. {
  84. *BufferNew++ = ' ';
  85. }
  86. else
  87. {
  88. *BufferNew++ = *BufferOld;
  89. }
  90. BufferOld++;
  91. }
  92. *BufferNew = '\0';
  93. }
  94. PCSTR
  95. ErrorString(ULONG Error)
  96. {
  97. switch(Error)
  98. {
  99. case OVERFLOW:
  100. return "Overflow";
  101. case SYNTAX:
  102. return "Syntax";
  103. case BADRANGE:
  104. return "Range";
  105. case VARDEF:
  106. return "Couldn't resolve";
  107. case EXTRACHARS:
  108. return "Extra character";
  109. case LISTSIZE:
  110. return "List size";
  111. case STRINGSIZE:
  112. return "String size";
  113. case MEMORY:
  114. return "Memory access";
  115. case BADREG:
  116. return "Bad register";
  117. case BADOPCODE:
  118. return "Bad opcode";
  119. case SUFFIX:
  120. return "Opcode suffix";
  121. case OPERAND:
  122. return "Operand";
  123. case ALIGNMENT:
  124. return "Alignment";
  125. case PREFIX:
  126. return "Opcode prefix";
  127. case DISPLACEMENT:
  128. return "Displacement";
  129. case BPLISTFULL:
  130. return "No breakpoint available";
  131. case BPDUPLICATE:
  132. return "Duplicate breakpoint";
  133. case UNIMPLEMENT:
  134. return "Unimplemented";
  135. case AMBIGUOUS:
  136. return "Ambiguous symbol";
  137. case BADTHREAD:
  138. return "Illegal thread";
  139. case BADPROCESS:
  140. return "Illegal process";
  141. case FILEREAD:
  142. return "File read";
  143. case LINENUMBER:
  144. return "Line number";
  145. case BADSEL:
  146. return "Bad selector";
  147. case BADSEG:
  148. return "Bad segment";
  149. case SYMTOOSMALL:
  150. return "Symbol only 1 character";
  151. case BPIONOTSUP:
  152. return "I/O breakpoints not supported";
  153. case NOTFOUND:
  154. return "No information found";
  155. case SESSIONNOTSUP:
  156. return "Operation not supported in current debug session";
  157. case BADSYSTEM:
  158. return "Illegal system";
  159. case NOMEMORY:
  160. return "Out of memory";
  161. case TYPECONFLICT:
  162. return "Type conflict";
  163. case TYPEDATA:
  164. return "Type information missing";
  165. case NOTMEMBER:
  166. return "Type does not have given member";
  167. case IMPLERR:
  168. return "Internal implementation";
  169. case ENGBUSY:
  170. return "Engine is busy";
  171. case TARGETNOTSUP:
  172. return "Operation not supported by current debuggee";
  173. case NORUNNABLE:
  174. return "No runnable debuggees";
  175. case NOTSECURE:
  176. return "SECURE: Operation disallowed";
  177. default:
  178. return "Unknown";
  179. }
  180. }
  181. /*** error - error reporting and recovery
  182. *
  183. * Purpose:
  184. * To output an error message with a location indicator
  185. * of the problem. Once output, the command line is reset
  186. * and the command processor is restarted.
  187. *
  188. * Input:
  189. * errorcode - number of error to output
  190. *
  191. * Output:
  192. * None.
  193. *
  194. * Exceptions:
  195. * Return is made via exception to start of command processor.
  196. *
  197. *************************************************************************/
  198. char g_Blanks[] =
  199. " "
  200. " "
  201. " "
  202. " ^ ";
  203. void
  204. ReportError(
  205. ULONG Error,
  206. PCSTR* DescPtr
  207. )
  208. {
  209. ULONG Count = g_PromptLength + 1;
  210. PSTR Temp = g_CommandStart;
  211. PCSTR Desc;
  212. // Reset the expression evaluators in case we're
  213. // hitting an error during evaluation which would
  214. // otherwise leave the evaluator in an inconsistent state.
  215. ReleaseEvaluators();
  216. if (DescPtr != NULL)
  217. {
  218. // Clear out description so it doesn't get reused.
  219. Desc = *DescPtr;
  220. *DescPtr = NULL;
  221. }
  222. else
  223. {
  224. Desc = NULL;
  225. }
  226. if (g_DisableErrorPrint ||
  227. (g_CommandStart > g_CurCmd) ||
  228. (g_CommandStart + MAX_COMMAND < g_CurCmd))
  229. {
  230. goto SkipErrorPrint;
  231. }
  232. while (Temp < g_CurCmd)
  233. {
  234. if (*Temp++ == '\t')
  235. {
  236. Count = (Count + 7) & ~7;
  237. }
  238. else
  239. {
  240. Count++;
  241. }
  242. }
  243. ErrOut(&g_Blanks[sizeof(g_Blanks) - (Count + 1)]);
  244. if (Desc != NULL)
  245. {
  246. ErrOut("%s '%s'\n", Desc, g_CommandStart);
  247. }
  248. else if (Error != VARDEF && Error != SESSIONNOTSUP)
  249. {
  250. ErrOut("%s error in '%s'\n",
  251. ErrorString(Error), g_CommandStart);
  252. }
  253. else
  254. {
  255. ErrOut("%s '%s'\n", ErrorString(Error), g_CommandStart);
  256. }
  257. SkipErrorPrint:
  258. RaiseException(COMMAND_EXCEPTION_BASE + Error, 0, 0, NULL);
  259. }
  260. ULONG64
  261. HexValue(ULONG Size)
  262. {
  263. ULONG64 Value;
  264. Value = GetExpression();
  265. // Reverse sign extension done by expression evaluator.
  266. if (Size == 4 && !NeedUpper(Value))
  267. {
  268. Value = (ULONG)Value;
  269. }
  270. if (Value > (0xffffffffffffffffUI64 >> (8 * (8 - Size))))
  271. {
  272. error(OVERFLOW);
  273. }
  274. return Value;
  275. }
  276. void
  277. HexList(PUCHAR Buffer, ULONG BufferSize,
  278. ULONG EltSize, PULONG CountRet)
  279. {
  280. CHAR Ch;
  281. ULONG64 Value;
  282. ULONG Count = 0;
  283. ULONG i;
  284. while ((Ch = PeekChar()) != '\0' && Ch != ';')
  285. {
  286. if (Count >= BufferSize)
  287. {
  288. error(LISTSIZE);
  289. }
  290. Value = HexValue(EltSize);
  291. for (i = 0; i < EltSize; i++)
  292. {
  293. *Buffer++ = (UCHAR)Value;
  294. Value >>= 8;
  295. }
  296. Count += EltSize;
  297. }
  298. *CountRet = Count;
  299. }
  300. ULONG64
  301. FloatValue(ULONG Size)
  302. {
  303. int Scanned;
  304. double Value;
  305. ULONG64 RawValue;
  306. if (sscanf(g_CurCmd, "%lf%n", &Value, &Scanned) != 1)
  307. {
  308. error(SYNTAX);
  309. }
  310. g_CurCmd += Scanned;
  311. if (Size == 4)
  312. {
  313. float FloatVal = (float)Value;
  314. RawValue = *(PULONG)&FloatVal;
  315. }
  316. else
  317. {
  318. RawValue = *(PULONG64)&Value;
  319. }
  320. return RawValue;
  321. }
  322. void
  323. FloatList(PUCHAR Buffer, ULONG BufferSize,
  324. ULONG EltSize, PULONG CountRet)
  325. {
  326. CHAR Ch;
  327. ULONG64 Value;
  328. ULONG Count = 0;
  329. ULONG i;
  330. while ((Ch = PeekChar()) != '\0' && Ch != ';')
  331. {
  332. if (Count >= BufferSize)
  333. {
  334. error(LISTSIZE);
  335. }
  336. Value = FloatValue(EltSize);
  337. for (i = 0; i < EltSize; i++)
  338. {
  339. *Buffer++ = (UCHAR)Value;
  340. Value >>= 8;
  341. }
  342. Count += EltSize;
  343. }
  344. *CountRet = Count;
  345. }
  346. void
  347. AsciiList(PSTR Buffer, ULONG BufferSize,
  348. PULONG CountRet)
  349. {
  350. CHAR Ch;
  351. ULONG Count = 0;
  352. if (PeekChar() != '"')
  353. {
  354. error(SYNTAX);
  355. }
  356. g_CurCmd++;
  357. do
  358. {
  359. Ch = *g_CurCmd++;
  360. if (Ch == '"')
  361. {
  362. Count++;
  363. *Buffer++ = 0;
  364. break;
  365. }
  366. if (Ch == '\0' || Ch == ';')
  367. {
  368. g_CurCmd--;
  369. break;
  370. }
  371. if (Count >= BufferSize)
  372. {
  373. error(STRINGSIZE);
  374. }
  375. Count++;
  376. *Buffer++ = Ch;
  377. } while (1);
  378. *CountRet = Count;
  379. }
  380. PSTR
  381. GetEscapedChar(PSTR Str, PCHAR Raw)
  382. {
  383. switch(*Str)
  384. {
  385. case 0:
  386. error(SYNTAX);
  387. case '0':
  388. // Octal char value.
  389. *Raw = (char)strtoul(Str + 1, &Str, 8);
  390. break;
  391. case 'b':
  392. *Raw = '\b';
  393. Str++;
  394. break;
  395. case 'n':
  396. *Raw = '\n';
  397. Str++;
  398. break;
  399. case 'r':
  400. *Raw = '\r';
  401. Str++;
  402. break;
  403. case 't':
  404. *Raw = '\t';
  405. Str++;
  406. break;
  407. case 'x':
  408. // Hex char value.
  409. *Raw = (char)strtoul(Str + 1, &Str, 16);
  410. break;
  411. default:
  412. // Verbatim escape.
  413. *Raw = *Str;
  414. Str++;
  415. break;
  416. }
  417. return Str;
  418. }
  419. PSTR
  420. BufferStringValue(PSTR* Buf, ULONG Flags,
  421. PULONG Len, PCHAR Save)
  422. {
  423. BOOL Quoted;
  424. PSTR Str;
  425. BOOL Escapes = FALSE;
  426. while (isspace(*(*Buf)))
  427. {
  428. (*Buf)++;
  429. }
  430. if (*(*Buf) == '"')
  431. {
  432. Quoted = TRUE;
  433. Str = ++(*Buf);
  434. // If the string is quoted it can always contain spaces.
  435. Flags &= ~STRV_SPACE_IS_SEPARATOR;
  436. }
  437. else if (!*(*Buf) &&
  438. !(Flags & STRV_ALLOW_EMPTY_STRING))
  439. {
  440. // No string at all.
  441. return NULL;
  442. }
  443. else
  444. {
  445. Quoted = FALSE;
  446. Str = *Buf;
  447. // Escaped characters can only be present in quoted strings.
  448. Flags &= ~STRV_ALLOW_ESCAPED_CHARACTERS;
  449. }
  450. while (*(*Buf) &&
  451. (!(Flags & STRV_SPACE_IS_SEPARATOR) || !isspace(*(*Buf))) &&
  452. (Quoted || *(*Buf) != ';') &&
  453. (!Quoted || *(*Buf) != '"'))
  454. {
  455. if (Flags & STRV_ALLOW_ESCAPED_CHARACTERS)
  456. {
  457. if (*(*Buf) == '\\')
  458. {
  459. char Raw;
  460. *Buf = GetEscapedChar((*Buf) + 1, &Raw);
  461. Escapes = TRUE;
  462. }
  463. else
  464. {
  465. (*Buf)++;
  466. }
  467. }
  468. else
  469. {
  470. (*Buf)++;
  471. }
  472. }
  473. if (Quoted && *(*Buf) != '"')
  474. {
  475. return NULL;
  476. }
  477. if ((Flags & (STRV_TRIM_TRAILING_SPACE |
  478. STRV_NO_MODIFICATION)) == STRV_TRIM_TRAILING_SPACE)
  479. {
  480. PSTR Trim = *Buf;
  481. while (Trim > Str)
  482. {
  483. if (isspace(*--Trim))
  484. {
  485. *Trim = 0;
  486. }
  487. else
  488. {
  489. break;
  490. }
  491. }
  492. }
  493. if (Quoted && *(*Buf) == '"')
  494. {
  495. if (!(Flags & STRV_ALLOW_EMPTY_STRING) &&
  496. *Buf == Str)
  497. {
  498. return NULL;
  499. }
  500. // Require some kind of separator after the
  501. // string to keep things symmetric with the
  502. // non-quoted case.
  503. if (!isspace(*(*Buf + 1)) &&
  504. *(*Buf + 1) != ';' && *(*Buf + 1) != 0)
  505. {
  506. return NULL;
  507. }
  508. // Null the quote and advance beyond it
  509. // so that the buffer pointer is always pointing
  510. // beyond the string on exit.
  511. if (!(Flags & STRV_NO_MODIFICATION))
  512. {
  513. *(*Buf) = 0;
  514. }
  515. if (Len)
  516. {
  517. *Len = (ULONG)(*Buf - Str);
  518. }
  519. (*Buf)++;
  520. }
  521. else if (Len)
  522. {
  523. *Len = (ULONG)(*Buf - Str);
  524. }
  525. if (Flags & STRV_NO_MODIFICATION)
  526. {
  527. return Str;
  528. }
  529. *Save = *(*Buf);
  530. *(*Buf) = 0;
  531. if (Escapes && (Flags & STRV_COMPRESS_ESCAPED_CHARACTERS))
  532. {
  533. CompressEscapes(Str);
  534. }
  535. return Str;
  536. }
  537. PSTR
  538. StringValue(ULONG Flags, PCHAR Save)
  539. {
  540. ULONG Len;
  541. PSTR Str = BufferStringValue((PSTR*)&g_CurCmd, Flags, &Len, Save);
  542. if (Str == NULL)
  543. {
  544. error(SYNTAX);
  545. }
  546. return Str;
  547. }
  548. void
  549. CompressEscapes(PSTR Str)
  550. {
  551. // Scan through a string for character escapes and
  552. // convert them to their escape value, packing
  553. // the rest of the string down. This allows for
  554. // in-place conversion of strings with escapes
  555. // inside the command buffer.
  556. while (*Str)
  557. {
  558. if (*Str == '\\')
  559. {
  560. char Raw;
  561. PSTR Slash = Str;
  562. Str = GetEscapedChar(Slash + 1, &Raw);
  563. // Copy raw value over backslash and pack down
  564. // trailing characters.
  565. *Slash = Raw;
  566. ULONG Len = strlen(Str) + 1;
  567. memmove(Slash + 1, Str, Len);
  568. Str = Slash + 1;
  569. }
  570. else
  571. {
  572. Str++;
  573. }
  574. }
  575. }
  576. void
  577. OpenLogFile(PCSTR File,
  578. BOOL Append)
  579. {
  580. // Close any open log file.
  581. CloseLogFile();
  582. if (Append)
  583. {
  584. g_LogFile = _open(File, O_APPEND | O_CREAT | O_RDWR,
  585. S_IREAD | S_IWRITE);
  586. }
  587. else
  588. {
  589. g_LogFile = _open(File, O_APPEND | O_CREAT | O_TRUNC | O_RDWR,
  590. S_IREAD | S_IWRITE);
  591. }
  592. if (g_LogFile != -1)
  593. {
  594. dprintf("Opened log file '%s'\n", File);
  595. CopyString(g_OpenLogFileName, File, DIMA(g_OpenLogFileName));
  596. g_OpenLogFileAppended = Append;
  597. NotifyChangeEngineState(DEBUG_CES_LOG_FILE, TRUE, TRUE);
  598. }
  599. else
  600. {
  601. ErrOut("log file could not be opened\n");
  602. }
  603. }
  604. void
  605. CloseLogFile(void)
  606. {
  607. if (g_LogFile != -1)
  608. {
  609. dprintf("Closing open log file %s\n", g_OpenLogFileName);
  610. _close(g_LogFile);
  611. g_LogFile = -1;
  612. g_OpenLogFileName[0] = 0;
  613. g_OpenLogFileAppended = FALSE;
  614. NotifyChangeEngineState(DEBUG_CES_LOG_FILE, FALSE, TRUE);
  615. }
  616. }
  617. void
  618. ParseLogOpen(BOOL Append)
  619. {
  620. PSTR FileName;
  621. char Save;
  622. char UniqueName[MAX_PATH];
  623. BOOL AppendTime = FALSE;
  624. // Don't look for '- as that's a reasonable filename character.
  625. while (PeekChar() == '/')
  626. {
  627. switch(*++g_CurCmd)
  628. {
  629. case 't':
  630. AppendTime = TRUE;
  631. break;
  632. default:
  633. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  634. break;
  635. }
  636. g_CurCmd++;
  637. }
  638. if (PeekChar() && *g_CurCmd != ';')
  639. {
  640. FileName = StringValue(STRV_SPACE_IS_SEPARATOR |
  641. STRV_TRIM_TRAILING_SPACE, &Save);
  642. }
  643. else
  644. {
  645. FileName = (PSTR)g_DefaultLogFileName;
  646. Save = 0;
  647. }
  648. if (AppendTime)
  649. {
  650. if (!MakeFileNameUnique(FileName, UniqueName, DIMA(UniqueName),
  651. TRUE, NULL))
  652. {
  653. error(OVERFLOW);
  654. }
  655. FileName = UniqueName;
  656. }
  657. OpenLogFile(FileName, Append);
  658. if (Save)
  659. {
  660. *g_CurCmd = Save;
  661. }
  662. }
  663. void
  664. lprintf(PCSTR String)
  665. {
  666. if (g_LogFile != -1)
  667. {
  668. _write(g_LogFile, String, strlen(String));
  669. }
  670. }
  671. void
  672. OutputSymAddr(ULONG64 Offset,
  673. ULONG Flags,
  674. PCSTR Prefix)
  675. {
  676. CHAR AddrBuffer[MAX_SYMBOL_LEN];
  677. ULONG64 Displacement;
  678. GetSymbol(Offset, AddrBuffer, sizeof(AddrBuffer), &Displacement);
  679. if ((!Displacement || (Flags & SYMADDR_FORCE)) && AddrBuffer[0])
  680. {
  681. if (Prefix)
  682. {
  683. dprintf("%s", Prefix);
  684. }
  685. dprintf("%s", AddrBuffer);
  686. if (Displacement)
  687. {
  688. dprintf("+%s", FormatDisp64(Displacement));
  689. }
  690. if (Flags & SYMADDR_OFFSET)
  691. {
  692. dprintf(" (%s)", FormatAddr64(Offset));
  693. }
  694. if (Flags & SYMADDR_SOURCE)
  695. {
  696. OutputLineAddr(Offset, " [%s @ %d]");
  697. }
  698. if (Flags & SYMADDR_LABEL)
  699. {
  700. dprintf(":\n");
  701. }
  702. else
  703. {
  704. dprintf(" ");
  705. }
  706. }
  707. else if (Flags & SYMADDR_OFFSET)
  708. {
  709. if (Prefix)
  710. {
  711. dprintf("%s", Prefix);
  712. }
  713. dprintf("%s", FormatAddr64(Offset));
  714. }
  715. }
  716. BOOL
  717. OutputLineAddr(ULONG64 Offset,
  718. PCSTR Format)
  719. {
  720. if ((g_SymOptions & SYMOPT_LOAD_LINES) == 0 ||
  721. !g_Process)
  722. {
  723. return FALSE;
  724. }
  725. IMAGEHLP_LINE Line;
  726. DWORD Disp;
  727. if (GetLineFromAddr(g_Process, Offset, &Line, &Disp))
  728. {
  729. char DispStr[64];
  730. if (Disp)
  731. {
  732. PrintString(DispStr, DIMA(DispStr), "+0x%x", Disp);
  733. }
  734. else
  735. {
  736. DispStr[0] = 0;
  737. }
  738. dprintf(Format, Line.FileName, Line.LineNumber, DispStr);
  739. return TRUE;
  740. }
  741. return FALSE;
  742. }
  743. /*** OutCurInfo - Display selected information about the current register
  744. * state.
  745. *
  746. * Purpose:
  747. * Source file lines may be shown.
  748. * Source line information may be shown.
  749. * Symbol information may be shown.
  750. * The current register set may be shown.
  751. * The instruction at the current program current may be disassembled
  752. * with any effective address displayed.
  753. *
  754. * Input:
  755. * None.
  756. *
  757. * Output:
  758. * None.
  759. *
  760. * Notes:
  761. * If the disassembly is of a delayed control instruction, the
  762. * delay slot instruction is also output.
  763. *
  764. *************************************************************************/
  765. void OutCurInfo(ULONG Flags, ULONG AllMask, ULONG RegMask)
  766. {
  767. ADDR PcValue;
  768. ADDR DisasmAddr;
  769. CHAR Buffer[MAX_DISASM_LEN];
  770. BOOL EA;
  771. if (g_Process == NULL ||
  772. g_Thread == NULL)
  773. {
  774. WarnOut("WARNING: The debugger does not have a current "
  775. "process or thread\n");
  776. WarnOut("WARNING: Many commands will not work\n");
  777. }
  778. if (!IS_MACHINE_SET(g_Target) ||
  779. g_Process == NULL ||
  780. g_Thread == NULL ||
  781. IS_LOCAL_KERNEL_TARGET(g_Target) ||
  782. ((Flags & OCI_IGNORE_STATE) == 0 && IS_RUNNING(g_CmdState)) ||
  783. ((IS_KERNEL_FULL_DUMP(g_Target) || IS_KERNEL_SUMMARY_DUMP(g_Target)) &&
  784. g_Target->m_KdDebuggerData.KiProcessorBlock == 0))
  785. {
  786. // State is not available right now.
  787. return;
  788. }
  789. if (g_Thread == g_EventThread)
  790. {
  791. g_Thread->OutputEventStrings();
  792. }
  793. g_Machine->GetPC(&PcValue);
  794. if ((Flags & (OCI_FORCE_ALL | OCI_FORCE_REG)) ||
  795. ((g_SrcOptions & SRCOPT_LIST_SOURCE_ONLY) == 0 &&
  796. (Flags & OCI_ALLOW_REG) &&
  797. g_OciOutputRegs))
  798. {
  799. g_Machine->OutputAll(AllMask, RegMask);
  800. }
  801. // Output g_PrevRelatedPc address
  802. if (Flat(g_PrevRelatedPc) && !AddrEqu(g_PrevRelatedPc, PcValue))
  803. {
  804. if (Flags & (OCI_FORCE_ALL | OCI_SYMBOL))
  805. {
  806. OutputSymAddr(Flat(g_PrevRelatedPc), SYMADDR_FORCE, NULL);
  807. dprintf("(%s)", FormatAddr64(Flat(g_PrevRelatedPc)));
  808. }
  809. else
  810. {
  811. dprintf("%s", FormatAddr64(Flat(g_PrevRelatedPc)));
  812. }
  813. dprintf("\n -> ");
  814. }
  815. // Deliberately does not force source with force-all so that source line
  816. // support has no effect on default operation.
  817. if (Flags & (OCI_FORCE_ALL | OCI_FORCE_SOURCE | OCI_ALLOW_SOURCE))
  818. {
  819. if (g_SrcOptions & SRCOPT_LIST_SOURCE)
  820. {
  821. if (OutputSrcLinesAroundAddr(Flat(PcValue),
  822. g_OciSrcBefore, g_OciSrcAfter) &&
  823. (Flags & OCI_FORCE_ALL) == 0 &&
  824. (g_SrcOptions & SRCOPT_LIST_SOURCE_ONLY))
  825. {
  826. return;
  827. }
  828. }
  829. else if ((g_SrcOptions & SRCOPT_LIST_LINE) ||
  830. (Flags & OCI_FORCE_SOURCE))
  831. {
  832. OutputLineAddr(Flat(PcValue), "%s(%d)%s\n");
  833. }
  834. }
  835. if (Flags & (OCI_FORCE_ALL | OCI_SYMBOL))
  836. {
  837. OutputSymAddr(Flat(PcValue), SYMADDR_FORCE | SYMADDR_LABEL, NULL);
  838. }
  839. if (Flags & (OCI_FORCE_ALL | OCI_DISASM))
  840. {
  841. if (Flags & (OCI_FORCE_ALL | OCI_FORCE_EA))
  842. {
  843. EA = TRUE;
  844. }
  845. else if (Flags & OCI_ALLOW_EA)
  846. {
  847. if (IS_DUMP_TARGET(g_Target) || IS_USER_TARGET(g_Target))
  848. {
  849. // Always show the EA info.
  850. EA = TRUE;
  851. }
  852. else
  853. {
  854. // Only show the EA information if registers were shown.
  855. EA = g_OciOutputRegs;
  856. }
  857. }
  858. else
  859. {
  860. EA = FALSE;
  861. }
  862. DisasmAddr = PcValue;
  863. g_Machine->Disassemble(g_Process, &DisasmAddr, Buffer, EA);
  864. dprintf("%s", Buffer);
  865. if (g_Machine->IsDelayInstruction(&PcValue))
  866. {
  867. g_Machine->Disassemble(g_Process, &DisasmAddr, Buffer, EA);
  868. dprintf("%s", Buffer);
  869. }
  870. }
  871. }
  872. #define MAX_FORMAT_STRINGS 8
  873. LPSTR
  874. FormatMachineAddr64(
  875. MachineInfo* Machine,
  876. ULONG64 Addr
  877. )
  878. /*++
  879. Routine Description:
  880. Format a 64 bit address, showing the high bits or not
  881. according to various flags.
  882. An array of static string buffers is used, returning a different
  883. buffer for each successive call so that it may be used multiple
  884. times in the same printf.
  885. Arguments:
  886. Addr - Supplies the value to format
  887. Return Value:
  888. A pointer to the string buffer containing the formatted number
  889. --*/
  890. {
  891. static CHAR s_Strings[MAX_FORMAT_STRINGS][22];
  892. static int s_Next = 0;
  893. LPSTR String;
  894. String = s_Strings[s_Next];
  895. ++s_Next;
  896. if (s_Next >= MAX_FORMAT_STRINGS)
  897. {
  898. s_Next = 0;
  899. }
  900. if (!Machine)
  901. {
  902. sprintf(String, "?%08x`%08x?", (ULONG)(Addr >> 32), (ULONG)Addr);
  903. }
  904. else if (Machine->m_Ptr64)
  905. {
  906. sprintf(String, "%08x`%08x", (ULONG)(Addr >> 32), (ULONG)Addr);
  907. }
  908. else
  909. {
  910. sprintf(String, "%08x", (ULONG)Addr);
  911. }
  912. return String;
  913. }
  914. LPSTR
  915. FormatDisp64(
  916. ULONG64 addr
  917. )
  918. /*++
  919. Routine Description:
  920. Format a 64 bit address, showing the high bits or not
  921. according to various flags. This version does not print
  922. leading 0's.
  923. An array of static string buffers is used, returning a different
  924. buffer for each successive call so that it may be used multiple
  925. times in the same printf.
  926. Arguments:
  927. addr - Supplies the value to format
  928. Return Value:
  929. A pointer to the string buffer containing the formatted number
  930. --*/
  931. {
  932. static CHAR strings[MAX_FORMAT_STRINGS][20];
  933. static int next = 0;
  934. LPSTR string;
  935. string = strings[next];
  936. ++next;
  937. if (next >= MAX_FORMAT_STRINGS)
  938. {
  939. next = 0;
  940. }
  941. if ((addr >> 32) != 0)
  942. {
  943. sprintf(string, "%x`%08x", (ULONG)(addr>>32), (ULONG)addr);
  944. }
  945. else
  946. {
  947. sprintf(string, "%x", (ULONG)addr);
  948. }
  949. return string;
  950. }
  951. DWORD
  952. NetworkPathCheck(
  953. LPCSTR PathList
  954. )
  955. /*++
  956. Routine Description:
  957. Checks if any members of the PathList are network paths.
  958. Arguments:
  959. PathList - A list of paths separated by ';' characters.
  960. Return Values:
  961. ERROR_SUCCESS - The path list contained no network or invalid paths.
  962. ERROR_BAD_PATHNAME - The path list contained one or more invalid paths,
  963. but no network paths.
  964. ERROR_FILE_OFFLINE - The path list contained one or more network paths.
  965. Bugs:
  966. Any path containing the ';' character will totally confuse this function.
  967. --*/
  968. {
  969. CHAR EndPath0;
  970. CHAR EndPath1;
  971. LPSTR EndPath;
  972. LPSTR StartPath;
  973. DWORD DriveType;
  974. LPSTR Buffer = NULL;
  975. DWORD ret = ERROR_SUCCESS;
  976. BOOL AddedTrailingSlash = FALSE;
  977. if (PathList == NULL ||
  978. *PathList == '\000')
  979. {
  980. return FALSE;
  981. }
  982. Buffer = (LPSTR) malloc ( strlen (PathList) + 3);
  983. if (!Buffer)
  984. {
  985. return ERROR_BAD_PATHNAME;
  986. }
  987. strcpy (Buffer, PathList);
  988. StartPath = Buffer;
  989. do
  990. {
  991. if (StartPath [0] == '\\' && StartPath [1] == '\\')
  992. {
  993. ret = ERROR_FILE_OFFLINE;
  994. break;
  995. }
  996. EndPath = strchr (StartPath, ';');
  997. if (EndPath == NULL)
  998. {
  999. EndPath = StartPath + strlen (StartPath);
  1000. EndPath0 = *EndPath;
  1001. }
  1002. else
  1003. {
  1004. EndPath0 = *EndPath;
  1005. *EndPath = '\000';
  1006. }
  1007. if (EndPath [-1] != '\\')
  1008. {
  1009. EndPath [0] = '\\';
  1010. EndPath1 = EndPath [1];
  1011. EndPath [1] = '\000';
  1012. AddedTrailingSlash = TRUE;
  1013. }
  1014. DriveType = GetDriveType (StartPath);
  1015. if (DriveType == DRIVE_REMOTE)
  1016. {
  1017. ret = ERROR_FILE_OFFLINE;
  1018. break;
  1019. }
  1020. else if (DriveType == DRIVE_UNKNOWN ||
  1021. DriveType == DRIVE_NO_ROOT_DIR)
  1022. {
  1023. //
  1024. // This is not necessarily an error, but it may merit
  1025. // investigation.
  1026. //
  1027. if (ret == ERROR_SUCCESS)
  1028. {
  1029. ret = ERROR_BAD_PATHNAME;
  1030. }
  1031. }
  1032. EndPath [0] = EndPath0;
  1033. if (AddedTrailingSlash)
  1034. {
  1035. EndPath [1] = EndPath1;
  1036. }
  1037. AddedTrailingSlash = FALSE;
  1038. if (EndPath [ 0 ] == '\000')
  1039. {
  1040. StartPath = NULL;
  1041. }
  1042. else
  1043. {
  1044. StartPath = &EndPath [ 1 ];
  1045. }
  1046. } while (StartPath && *StartPath != '\000');
  1047. free ( Buffer );
  1048. return ret;
  1049. }
  1050. //----------------------------------------------------------------------------
  1051. //
  1052. // Returns either an ID value or ALL_ID_LIST. In theory
  1053. // this routine could be expanded to pass back true intervals
  1054. // so a full list could be specified.
  1055. //
  1056. // Originally built up a mask for the multi-ID case but that
  1057. // was changed to return a real ID when 32 bits became
  1058. // constraining.
  1059. //
  1060. //----------------------------------------------------------------------------
  1061. ULONG
  1062. GetIdList(BOOL AllowMulti)
  1063. {
  1064. ULONG Value = 0;
  1065. CHAR ch;
  1066. CHAR Digits[20];
  1067. int i;
  1068. //
  1069. // Change to allow more than 32 break points to be set. Use
  1070. // break point numbers instead of masks.
  1071. //
  1072. if ((ch = PeekChar()) == '*')
  1073. {
  1074. if (!AllowMulti)
  1075. {
  1076. error(SYNTAX);
  1077. }
  1078. Value = ALL_ID_LIST;
  1079. g_CurCmd++;
  1080. }
  1081. else if (ch == '[')
  1082. {
  1083. Value = (ULONG)GetTermExpression("Breakpoint ID missing from");
  1084. }
  1085. else
  1086. {
  1087. for (i = 0; i < sizeof(Digits) - 1; i++)
  1088. {
  1089. if (ch >= '0' && ch <= '9')
  1090. {
  1091. Digits[i] = ch;
  1092. ch = *++g_CurCmd;
  1093. }
  1094. else
  1095. {
  1096. break;
  1097. }
  1098. }
  1099. Digits[i] = '\0';
  1100. if (ch == '\0' || ch == ';' || ch == ' ' || ch == '\t')
  1101. {
  1102. Value = strtoul(Digits, NULL, 10);
  1103. }
  1104. else
  1105. {
  1106. error(SYNTAX);
  1107. }
  1108. }
  1109. return Value;
  1110. }
  1111. void
  1112. AppendComponentsToPath(PSTR Path, PCSTR Components,
  1113. BOOL Validate)
  1114. {
  1115. if (!Components || !Components[0])
  1116. {
  1117. return;
  1118. }
  1119. PSTR PathEnd;
  1120. PCSTR Comp;
  1121. PathEnd = Path + strlen(Path);
  1122. Comp = Components;
  1123. while (*Comp)
  1124. {
  1125. PCSTR CompEnd;
  1126. int CompLen;
  1127. CompEnd = strchr(Comp, ';');
  1128. if (CompEnd)
  1129. {
  1130. CompLen = (int)(CompEnd - Comp);
  1131. }
  1132. else
  1133. {
  1134. CompLen = strlen(Comp);
  1135. CompEnd = Comp + CompLen;
  1136. }
  1137. //
  1138. // Check and see if this component is already in the path.
  1139. // If it is, don't add it again.
  1140. //
  1141. PCSTR Dup, DupEnd;
  1142. int DupLen;
  1143. Dup = Path;
  1144. while (*Dup)
  1145. {
  1146. DupEnd = strchr(Dup, ';');
  1147. if (DupEnd)
  1148. {
  1149. DupLen = (int)(DupEnd - Dup);
  1150. }
  1151. else
  1152. {
  1153. DupLen = strlen(Dup);
  1154. DupEnd = Dup + DupLen;
  1155. }
  1156. if (DupLen == CompLen &&
  1157. !_memicmp(Comp, Dup, CompLen))
  1158. {
  1159. break;
  1160. }
  1161. Dup = DupEnd + (*DupEnd ? 1 : 0);
  1162. }
  1163. if (!*Dup)
  1164. {
  1165. PSTR OldPathEnd = PathEnd;
  1166. PSTR NewStart;
  1167. if (PathEnd > Path)
  1168. {
  1169. *PathEnd++ = ';';
  1170. }
  1171. NewStart = PathEnd;
  1172. memcpy(PathEnd, Comp, CompLen);
  1173. PathEnd += CompLen;
  1174. *PathEnd = 0;
  1175. if (Validate && !ValidatePathComponent(NewStart))
  1176. {
  1177. WarnOut("WARNING: %s is not accessible, ignoring\n", NewStart);
  1178. PathEnd = OldPathEnd;
  1179. *PathEnd = 0;
  1180. }
  1181. }
  1182. Comp = CompEnd + (*CompEnd ? 1 : 0);
  1183. }
  1184. }
  1185. //
  1186. // Sets or appends to a semicolon-delimited path.
  1187. //
  1188. HRESULT
  1189. ChangePath(PSTR* Path, PCSTR New, BOOL Append, ULONG SymNotify)
  1190. {
  1191. ULONG NewLen, CurLen, TotLen;
  1192. PSTR NewPath;
  1193. if (New != NULL && *New != 0)
  1194. {
  1195. NewLen = strlen(New) + 1;
  1196. }
  1197. else if (Append)
  1198. {
  1199. // Nothing to append.
  1200. return S_OK;
  1201. }
  1202. else
  1203. {
  1204. NewLen = 0;
  1205. }
  1206. if (*Path == NULL || **Path == 0)
  1207. {
  1208. // Nothing to append to.
  1209. Append = FALSE;
  1210. }
  1211. if (Append)
  1212. {
  1213. CurLen = strlen(*Path) + 1;
  1214. }
  1215. else
  1216. {
  1217. CurLen = 0;
  1218. }
  1219. TotLen = CurLen + NewLen;
  1220. if (TotLen > 0)
  1221. {
  1222. NewPath = (PSTR)malloc(TotLen);
  1223. if (NewPath == NULL)
  1224. {
  1225. ErrOut("Unable to allocate memory for path\n");
  1226. return E_OUTOFMEMORY;
  1227. }
  1228. }
  1229. else
  1230. {
  1231. NewPath = NULL;
  1232. }
  1233. PSTR Cat = NewPath;
  1234. if (CurLen > 0)
  1235. {
  1236. memcpy(Cat, *Path, CurLen);
  1237. Cat += CurLen - 1;
  1238. }
  1239. if (NewLen > 0)
  1240. {
  1241. *Cat = 0;
  1242. AppendComponentsToPath(NewPath, New, FALSE);
  1243. }
  1244. if (*Path != NULL)
  1245. {
  1246. free(*Path);
  1247. }
  1248. *Path = NewPath;
  1249. if (SymNotify != 0)
  1250. {
  1251. NotifyChangeSymbolState(SymNotify, 0, g_Process);
  1252. }
  1253. return S_OK;
  1254. }
  1255. void
  1256. CheckPath(PCSTR Path)
  1257. {
  1258. PCSTR EltStart;
  1259. PCSTR Scan;
  1260. BOOL Space;
  1261. if (!Path || !Path[0])
  1262. {
  1263. return;
  1264. }
  1265. for (;;)
  1266. {
  1267. BOOL Warned = FALSE;
  1268. EltStart = Path;
  1269. Scan = EltStart;
  1270. while (isspace(*Scan))
  1271. {
  1272. Scan++;
  1273. }
  1274. if (Scan != EltStart)
  1275. {
  1276. WarnOut("WARNING: Whitespace at start of path element\n");
  1277. Warned = TRUE;
  1278. }
  1279. // Find the end of the element.
  1280. Space = FALSE;
  1281. while (*Scan && *Scan != ';')
  1282. {
  1283. Space = isspace(*Scan);
  1284. Scan++;
  1285. }
  1286. if (Space)
  1287. {
  1288. WarnOut("WARNING: Whitespace at end of path element\n");
  1289. Warned = TRUE;
  1290. }
  1291. if (Scan - EltStart >= MAX_PATH)
  1292. {
  1293. WarnOut("WARNING: Path element is longer than MAX_PATH\n");
  1294. Warned = TRUE;
  1295. }
  1296. if (Scan == EltStart)
  1297. {
  1298. WarnOut("WARNING: Path element is empty\n");
  1299. Warned = TRUE;
  1300. }
  1301. if (!Warned)
  1302. {
  1303. char Elt[MAX_PATH];
  1304. memcpy(Elt, EltStart, Scan - EltStart);
  1305. Elt[Scan - EltStart] = 0;
  1306. if (!ValidatePathComponent(Elt))
  1307. {
  1308. WarnOut("WARNING: %s is not accessible\n", Elt);
  1309. Warned = TRUE;
  1310. }
  1311. }
  1312. if (!*Scan)
  1313. {
  1314. break;
  1315. }
  1316. Path = Scan + 1;
  1317. }
  1318. }
  1319. HRESULT
  1320. ChangeString(PSTR* Str, PULONG StrLen, PCSTR New)
  1321. {
  1322. ULONG Len;
  1323. PSTR Buf;
  1324. if (New != NULL)
  1325. {
  1326. Len = strlen(New) + 1;
  1327. Buf = new char[Len];
  1328. if (Buf == NULL)
  1329. {
  1330. return E_OUTOFMEMORY;
  1331. }
  1332. }
  1333. else
  1334. {
  1335. Buf = NULL;
  1336. Len = 0;
  1337. }
  1338. delete [] *Str;
  1339. *Str = Buf;
  1340. if (New != NULL)
  1341. {
  1342. memcpy(Buf, New, Len);
  1343. }
  1344. if (StrLen != NULL)
  1345. {
  1346. *StrLen = Len;
  1347. }
  1348. return S_OK;
  1349. }
  1350. #if DBG
  1351. void
  1352. DbgAssertionFailed(PCSTR File, int Line, PCSTR Str)
  1353. {
  1354. char Text[512];
  1355. _snprintf(Text, sizeof(Text),
  1356. "Assertion failed: %s(%d)\n %s\n",
  1357. File, Line, Str);
  1358. Text[sizeof(Text) - 1] = 0;
  1359. OutputDebugStringA(Text);
  1360. if (getenv("DBGENG_ASSERT_BREAK"))
  1361. {
  1362. DebugBreak();
  1363. }
  1364. else
  1365. {
  1366. ErrOut("%s", Text);
  1367. FlushCallbacks();
  1368. }
  1369. }
  1370. #endif // #if DBG
  1371. void
  1372. ExceptionRecordTo64(PEXCEPTION_RECORD Rec,
  1373. PEXCEPTION_RECORD64 Rec64)
  1374. {
  1375. ULONG i;
  1376. Rec64->ExceptionCode = Rec->ExceptionCode;
  1377. Rec64->ExceptionFlags = Rec->ExceptionFlags;
  1378. Rec64->ExceptionRecord = (ULONG64)Rec->ExceptionRecord;
  1379. Rec64->ExceptionAddress = (ULONG64)Rec->ExceptionAddress;
  1380. Rec64->NumberParameters = Rec->NumberParameters;
  1381. for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
  1382. {
  1383. Rec64->ExceptionInformation[i] = Rec->ExceptionInformation[i];
  1384. }
  1385. }
  1386. void
  1387. ExceptionRecord64To(PEXCEPTION_RECORD64 Rec64,
  1388. PEXCEPTION_RECORD Rec)
  1389. {
  1390. ULONG i;
  1391. Rec->ExceptionCode = Rec64->ExceptionCode;
  1392. Rec->ExceptionFlags = Rec64->ExceptionFlags;
  1393. Rec->ExceptionRecord = (PEXCEPTION_RECORD)(ULONG_PTR)
  1394. Rec64->ExceptionRecord;
  1395. Rec->ExceptionAddress = (PVOID)(ULONG_PTR)
  1396. Rec64->ExceptionAddress;
  1397. Rec->NumberParameters = Rec64->NumberParameters;
  1398. for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
  1399. {
  1400. Rec->ExceptionInformation[i] = (ULONG_PTR)
  1401. Rec64->ExceptionInformation[i];
  1402. }
  1403. }
  1404. void
  1405. MemoryBasicInformationTo64(PMEMORY_BASIC_INFORMATION Mbi,
  1406. PMEMORY_BASIC_INFORMATION64 Mbi64)
  1407. {
  1408. #ifdef _WIN64
  1409. memcpy(Mbi64, Mbi, sizeof(*Mbi64));
  1410. #else
  1411. Mbi64->BaseAddress = (ULONG64) Mbi->BaseAddress;
  1412. Mbi64->AllocationBase = (ULONG64) Mbi->AllocationBase;
  1413. Mbi64->AllocationProtect = Mbi->AllocationProtect;
  1414. Mbi64->__alignment1 = 0;
  1415. Mbi64->RegionSize = Mbi->RegionSize;
  1416. Mbi64->State = Mbi->State;
  1417. Mbi64->Protect = Mbi->Protect;
  1418. Mbi64->Type = Mbi->Type;
  1419. Mbi64->__alignment2 = 0;
  1420. #endif
  1421. }
  1422. void
  1423. MemoryBasicInformation32To64(PMEMORY_BASIC_INFORMATION32 Mbi32,
  1424. PMEMORY_BASIC_INFORMATION64 Mbi64)
  1425. {
  1426. Mbi64->BaseAddress = EXTEND64(Mbi32->BaseAddress);
  1427. Mbi64->AllocationBase = EXTEND64(Mbi32->AllocationBase);
  1428. Mbi64->AllocationProtect = Mbi32->AllocationProtect;
  1429. Mbi64->__alignment1 = 0;
  1430. Mbi64->RegionSize = Mbi32->RegionSize;
  1431. Mbi64->State = Mbi32->State;
  1432. Mbi64->Protect = Mbi32->Protect;
  1433. Mbi64->Type = Mbi32->Type;
  1434. Mbi64->__alignment2 = 0;
  1435. }
  1436. void
  1437. DebugEvent32To64(LPDEBUG_EVENT32 Event32,
  1438. LPDEBUG_EVENT64 Event64)
  1439. {
  1440. Event64->dwDebugEventCode = Event32->dwDebugEventCode;
  1441. Event64->dwProcessId = Event32->dwProcessId;
  1442. Event64->dwThreadId = Event32->dwThreadId;
  1443. Event64->__alignment = 0;
  1444. switch(Event32->dwDebugEventCode)
  1445. {
  1446. case EXCEPTION_DEBUG_EVENT:
  1447. ExceptionRecord32To64(&Event32->u.Exception.ExceptionRecord,
  1448. &Event64->u.Exception.ExceptionRecord);
  1449. Event64->u.Exception.dwFirstChance =
  1450. Event32->u.Exception.dwFirstChance;
  1451. break;
  1452. case CREATE_THREAD_DEBUG_EVENT:
  1453. Event64->u.CreateThread.hThread =
  1454. EXTEND64(Event32->u.CreateThread.hThread);
  1455. Event64->u.CreateThread.lpThreadLocalBase =
  1456. EXTEND64(Event32->u.CreateThread.lpThreadLocalBase);
  1457. Event64->u.CreateThread.lpStartAddress =
  1458. EXTEND64(Event32->u.CreateThread.lpStartAddress);
  1459. break;
  1460. case CREATE_PROCESS_DEBUG_EVENT:
  1461. Event64->u.CreateProcessInfo.hFile =
  1462. EXTEND64(Event32->u.CreateProcessInfo.hFile);
  1463. Event64->u.CreateProcessInfo.hProcess =
  1464. EXTEND64(Event32->u.CreateProcessInfo.hProcess);
  1465. Event64->u.CreateProcessInfo.hThread =
  1466. EXTEND64(Event32->u.CreateProcessInfo.hThread);
  1467. Event64->u.CreateProcessInfo.lpBaseOfImage =
  1468. EXTEND64(Event32->u.CreateProcessInfo.lpBaseOfImage);
  1469. Event64->u.CreateProcessInfo.dwDebugInfoFileOffset =
  1470. Event32->u.CreateProcessInfo.dwDebugInfoFileOffset;
  1471. Event64->u.CreateProcessInfo.nDebugInfoSize =
  1472. Event32->u.CreateProcessInfo.nDebugInfoSize;
  1473. Event64->u.CreateProcessInfo.lpThreadLocalBase =
  1474. EXTEND64(Event32->u.CreateProcessInfo.lpThreadLocalBase);
  1475. Event64->u.CreateProcessInfo.lpStartAddress =
  1476. EXTEND64(Event32->u.CreateProcessInfo.lpStartAddress);
  1477. Event64->u.CreateProcessInfo.lpImageName =
  1478. EXTEND64(Event32->u.CreateProcessInfo.lpImageName);
  1479. Event64->u.CreateProcessInfo.fUnicode =
  1480. Event32->u.CreateProcessInfo.fUnicode;
  1481. break;
  1482. case EXIT_THREAD_DEBUG_EVENT:
  1483. Event64->u.ExitThread.dwExitCode =
  1484. Event32->u.ExitThread.dwExitCode;
  1485. break;
  1486. case EXIT_PROCESS_DEBUG_EVENT:
  1487. Event64->u.ExitProcess.dwExitCode =
  1488. Event32->u.ExitProcess.dwExitCode;
  1489. break;
  1490. case LOAD_DLL_DEBUG_EVENT:
  1491. Event64->u.LoadDll.hFile =
  1492. EXTEND64(Event32->u.LoadDll.hFile);
  1493. Event64->u.LoadDll.lpBaseOfDll =
  1494. EXTEND64(Event32->u.LoadDll.lpBaseOfDll);
  1495. Event64->u.LoadDll.dwDebugInfoFileOffset =
  1496. Event32->u.LoadDll.dwDebugInfoFileOffset;
  1497. Event64->u.LoadDll.nDebugInfoSize =
  1498. Event32->u.LoadDll.nDebugInfoSize;
  1499. Event64->u.LoadDll.lpImageName =
  1500. EXTEND64(Event32->u.LoadDll.lpImageName);
  1501. Event64->u.LoadDll.fUnicode =
  1502. Event32->u.LoadDll.fUnicode;
  1503. break;
  1504. case UNLOAD_DLL_DEBUG_EVENT:
  1505. Event64->u.UnloadDll.lpBaseOfDll =
  1506. EXTEND64(Event32->u.UnloadDll.lpBaseOfDll);
  1507. break;
  1508. case OUTPUT_DEBUG_STRING_EVENT:
  1509. Event64->u.DebugString.lpDebugStringData =
  1510. EXTEND64(Event32->u.DebugString.lpDebugStringData);
  1511. Event64->u.DebugString.fUnicode =
  1512. Event32->u.DebugString.fUnicode;
  1513. Event64->u.DebugString.nDebugStringLength =
  1514. Event32->u.DebugString.nDebugStringLength;
  1515. break;
  1516. case RIP_EVENT:
  1517. Event64->u.RipInfo.dwError =
  1518. Event32->u.RipInfo.dwError;
  1519. Event64->u.RipInfo.dwType =
  1520. Event32->u.RipInfo.dwType;
  1521. break;
  1522. }
  1523. }
  1524. #define COPYSE(p64, p32, f) p64->f = (ULONG64)(LONG64)(LONG)p32->f
  1525. void
  1526. WaitStateChange32ToAny(IN PDBGKD_WAIT_STATE_CHANGE32 Ws32,
  1527. IN ULONG ControlReportSize,
  1528. OUT PDBGKD_ANY_WAIT_STATE_CHANGE WsAny)
  1529. {
  1530. WsAny->NewState = Ws32->NewState;
  1531. WsAny->ProcessorLevel = Ws32->ProcessorLevel;
  1532. WsAny->Processor = Ws32->Processor;
  1533. WsAny->NumberProcessors = Ws32->NumberProcessors;
  1534. COPYSE(WsAny, Ws32, Thread);
  1535. COPYSE(WsAny, Ws32, ProgramCounter);
  1536. memcpy(&WsAny->ControlReport, Ws32 + 1, ControlReportSize);
  1537. if (Ws32->NewState == DbgKdLoadSymbolsStateChange)
  1538. {
  1539. DbgkdLoadSymbols32To64(&Ws32->u.LoadSymbols, &WsAny->u.LoadSymbols);
  1540. }
  1541. else
  1542. {
  1543. DbgkmException32To64(&Ws32->u.Exception, &WsAny->u.Exception);
  1544. }
  1545. }
  1546. #undef COPYSE
  1547. PSTR
  1548. TimeToStr(ULONG TimeDateStamp)
  1549. {
  1550. LPSTR TimeDateStr;
  1551. // Handle invalid \ page out timestamps, since ctime blows up on
  1552. // this number
  1553. if ((TimeDateStamp == 0) || (TimeDateStamp == UNKNOWN_TIMESTAMP))
  1554. {
  1555. return "unavailable";
  1556. }
  1557. else if (IS_LIVE_KERNEL_TARGET(g_Target) && TimeDateStamp == 0x49ef6f00)
  1558. {
  1559. // At boot time the shared memory data area is not
  1560. // yet initialized. The above value seems to be
  1561. // the random garbage that's there so detect it and
  1562. // ignore it. This is highly fragile but people
  1563. // keep asking about the garbage value.
  1564. return "unavailable until booted";
  1565. }
  1566. else
  1567. {
  1568. // TimeDateStamp is always a 32 bit quantity on the target,
  1569. // and we need to sign extend for 64 bit host since time_t
  1570. // has been extended to 64 bits.
  1571. time_t TDStamp = (time_t) (LONG) TimeDateStamp;
  1572. TimeDateStr = ctime((time_t *)&TDStamp);
  1573. if (TimeDateStr)
  1574. {
  1575. TimeDateStr[strlen(TimeDateStr) - 1] = 0;
  1576. }
  1577. else
  1578. {
  1579. TimeDateStr = "***** Invalid";
  1580. }
  1581. }
  1582. return TimeDateStr;
  1583. }
  1584. PSTR LONG64FileTimeToStr(LONG64 UTCFileTimeStamp)
  1585. {
  1586. FILETIME FileTime;
  1587. FileTime.dwLowDateTime = (DWORD) UTCFileTimeStamp;
  1588. FileTime.dwHighDateTime = (DWORD)(UTCFileTimeStamp >> 32);
  1589. return FileTimeToStr(FileTime);
  1590. }
  1591. PSTR
  1592. FileTimeToStr(FILETIME UTCFileTime)
  1593. {
  1594. //
  1595. // Need to be able to store time string in this format:
  1596. // Time: Wed Dec 31 16:00:05.000 1969 (GMT-8)
  1597. // Test value: .formats 1c100d2`1a18ff24
  1598. // Should display: Fri Jun 29 12:31:32.406 2001 (GMT-7)
  1599. //
  1600. static CHAR TimeDateBuffer[39];
  1601. PSTR TimeDateStr = TimeDateBuffer;
  1602. FILETIME LocalFileTime;
  1603. SYSTEMTIME UTCSysTime, LocalSysTime;
  1604. SHORT GMTBias = 0;
  1605. //
  1606. // Note: month value is 1-based, day is 0-based
  1607. //
  1608. static LPSTR Months[] = {
  1609. "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  1610. };
  1611. static LPSTR Days[] = {
  1612. "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
  1613. };
  1614. FileTimeToLocalFileTime(&UTCFileTime, &LocalFileTime);
  1615. FileTimeToSystemTime(&LocalFileTime, &LocalSysTime);
  1616. FileTimeToSystemTime(&UTCFileTime, &UTCSysTime);
  1617. GMTBias = LocalSysTime.wHour - UTCSysTime.wHour;
  1618. ZeroMemory(TimeDateBuffer, sizeof(TimeDateBuffer) / sizeof(TimeDateBuffer[0]));
  1619. //
  1620. // Ensure this looks like valid SYSTEMTIME
  1621. //
  1622. if ( (LocalSysTime.wYear > 1600) &&
  1623. (LocalSysTime.wYear < 30827) &&
  1624. (LocalSysTime.wMonth > 0) &&
  1625. (LocalSysTime.wMonth < 13) &&
  1626. (LocalSysTime.wDayOfWeek >= 0) &&
  1627. (LocalSysTime.wDayOfWeek < 7) &&
  1628. (LocalSysTime.wDay > 0) &&
  1629. (LocalSysTime.wDay < 32) &&
  1630. (LocalSysTime.wHour > 0) &&
  1631. (LocalSysTime.wHour < 24) &&
  1632. (LocalSysTime.wMilliseconds >= 0) &&
  1633. (LocalSysTime.wMilliseconds < 1000) )
  1634. {
  1635. PrintString(TimeDateBuffer, DIMA(TimeDateBuffer),
  1636. "%s %s %2d %02d:%02d:%02d.%03d %d (GMT%c%d)",
  1637. Days[LocalSysTime.wDayOfWeek],
  1638. Months[LocalSysTime.wMonth - 1],
  1639. LocalSysTime.wDay,
  1640. LocalSysTime.wHour,
  1641. LocalSysTime.wMinute,
  1642. LocalSysTime.wSecond,
  1643. LocalSysTime.wMilliseconds,
  1644. LocalSysTime.wYear,
  1645. (GMTBias < 0) ? '-' : '+',
  1646. abs(GMTBias) );
  1647. }
  1648. else
  1649. {
  1650. PrintString(TimeDateBuffer, DIMA(TimeDateBuffer), "***** Invalid FILETIME");
  1651. }
  1652. return TimeDateStr;
  1653. }
  1654. PSTR
  1655. DurationToStr(ULONG64 Duration)
  1656. {
  1657. ULONG Seconds = FileTimeToTime(Duration);
  1658. ULONG Millis = (ULONG)(Duration - TimeToFileTime(Seconds)) / 10000;
  1659. ULONG Minutes = Seconds / 60;
  1660. ULONG Hours = Minutes / 60;
  1661. ULONG Days = Hours / 24;
  1662. static char s_Buf[128];
  1663. PrintString(s_Buf, DIMA(s_Buf), "%d days %d:%02d:%02d.%03d",
  1664. Days, Hours % 24, Minutes % 60, Seconds % 60, Millis);
  1665. return s_Buf;
  1666. }
  1667. PCSTR
  1668. PathTail(PCSTR Path)
  1669. {
  1670. PCSTR Tail = Path + strlen(Path);
  1671. while (--Tail >= Path)
  1672. {
  1673. if (*Tail == '\\' || *Tail == '/' || *Tail == ':')
  1674. {
  1675. break;
  1676. }
  1677. }
  1678. return Tail + 1;
  1679. }
  1680. PCWSTR
  1681. PathTailW(PCWSTR Path)
  1682. {
  1683. PCWSTR Tail = Path + wcslen(Path);
  1684. while (--Tail >= Path)
  1685. {
  1686. if (*Tail == L'\\' || *Tail == L'/' || *Tail == L':')
  1687. {
  1688. break;
  1689. }
  1690. }
  1691. return Tail + 1;
  1692. }
  1693. BOOL
  1694. MatchPathTails(PCSTR Path1, PCSTR Path2, BOOL Wild)
  1695. {
  1696. PCSTR Tail1 = PathTail(Path1);
  1697. PCSTR Tail2 = PathTail(Path2);
  1698. return
  1699. (!Wild && !_stricmp(Tail1, Tail2)) ||
  1700. (Wild && MatchPattern((PSTR)Tail2, (PSTR)Tail1));
  1701. }
  1702. BOOL
  1703. IsValidName(PSTR String)
  1704. {
  1705. while (*String)
  1706. {
  1707. if (*String < 0x20 || *String > 0x7e)
  1708. {
  1709. return FALSE;
  1710. }
  1711. if (isalnum(*String))
  1712. {
  1713. return TRUE;
  1714. }
  1715. ++String;
  1716. }
  1717. return FALSE;
  1718. }
  1719. BOOL
  1720. MakeFileNameUnique(PSTR OriginalName,
  1721. PSTR Buffer, ULONG BufferChars,
  1722. BOOL AppendTime, ProcessInfo* Pid)
  1723. {
  1724. SYSTEMTIME Time;
  1725. ULONG AppendAt;
  1726. PSTR Dot;
  1727. char Ext[8];
  1728. if (!CopyString(Buffer, OriginalName, BufferChars))
  1729. {
  1730. return FALSE;
  1731. }
  1732. Dot = strrchr(Buffer, '.');
  1733. if (Dot && strlen(Dot) < sizeof(Ext) - 1)
  1734. {
  1735. strcpy(Ext, Dot);
  1736. *Dot = 0;
  1737. }
  1738. else
  1739. {
  1740. Dot = NULL;
  1741. }
  1742. if (AppendTime)
  1743. {
  1744. GetLocalTime(&Time);
  1745. AppendAt = strlen(Buffer);
  1746. if (!PrintString(Buffer + AppendAt, BufferChars - AppendAt,
  1747. "_%04d-%02d-%02d_%02d-%02d-%02d-%03d",
  1748. Time.wYear, Time.wMonth, Time.wDay,
  1749. Time.wHour, Time.wMinute, Time.wSecond,
  1750. Time.wMilliseconds))
  1751. {
  1752. return FALSE;
  1753. }
  1754. }
  1755. if (Pid)
  1756. {
  1757. AppendAt = strlen(Buffer);
  1758. if (!PrintString(Buffer + AppendAt, BufferChars - AppendAt,
  1759. "_%04X", Pid->m_SystemId))
  1760. {
  1761. return FALSE;
  1762. }
  1763. }
  1764. if (Dot)
  1765. {
  1766. if (!CatString(Buffer, Ext, BufferChars))
  1767. {
  1768. return FALSE;
  1769. }
  1770. }
  1771. return TRUE;
  1772. }
  1773. BOOL
  1774. GetEngineDirectory(PSTR Buffer, ULONG BufferChars)
  1775. {
  1776. DBG_ASSERT(BufferChars >= 16);
  1777. if (!GetModuleFileName(GetModuleHandle(ENGINE_DLL_NAME),
  1778. Buffer, BufferChars))
  1779. {
  1780. // Error. Use the current directory.
  1781. strcpy(Buffer, ".");
  1782. return FALSE;
  1783. }
  1784. //
  1785. // Remove the image name.
  1786. //
  1787. PSTR Tmp = strrchr(Buffer, '\\');
  1788. if (!Tmp)
  1789. {
  1790. Tmp = strrchr(Buffer, '/');
  1791. if (!Tmp)
  1792. {
  1793. Tmp = strrchr(Buffer, ':');
  1794. if (!Tmp)
  1795. {
  1796. return TRUE;
  1797. }
  1798. Tmp++;
  1799. }
  1800. }
  1801. *Tmp = 0;
  1802. return TRUE;
  1803. }
  1804. BOOL
  1805. IsInternalPackage(void)
  1806. {
  1807. static HRESULT s_Result = E_NOINTERFACE;
  1808. char EngPath[MAX_PATH];
  1809. HANDLE TriageFile;
  1810. char TriageText[64];
  1811. ULONG Done;
  1812. if (SUCCEEDED(s_Result))
  1813. {
  1814. return s_Result == S_OK;
  1815. }
  1816. //
  1817. // Determine if this is an internal Microsoft debugger
  1818. // package. Internal packages assume the existence of
  1819. // internal servers and so on, so conservatively assume
  1820. // this is an external package unless we're sure it's
  1821. // an internal package.
  1822. //
  1823. if (!GetEngineDirectory(EngPath, DIMA(EngPath)))
  1824. {
  1825. return FALSE;
  1826. }
  1827. if (!CatString(EngPath, "\\winxp\\triage.ini", DIMA(EngPath)))
  1828. {
  1829. return FALSE;
  1830. }
  1831. TriageFile = CreateFile(EngPath, GENERIC_READ, FILE_SHARE_READ,
  1832. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  1833. NULL);
  1834. if (TriageFile == INVALID_HANDLE_VALUE)
  1835. {
  1836. // Couldn't find triage.ini, may be a system ntsd or
  1837. // just some other problem. If it's file-not-found
  1838. // we don't want to keep hitting this case so
  1839. // mark things as external.
  1840. if (GetLastError() == ERROR_FILE_NOT_FOUND)
  1841. {
  1842. s_Result = S_FALSE;
  1843. }
  1844. return FALSE;
  1845. }
  1846. s_Result = S_FALSE;
  1847. if (ReadFile(TriageFile, TriageText, sizeof(TriageText),
  1848. &Done, NULL) && Done > 17 &&
  1849. !_strnicmp(TriageText, ";internal_package", 17))
  1850. {
  1851. s_Result = S_OK;
  1852. }
  1853. CloseHandle(TriageFile);
  1854. return s_Result == S_OK;
  1855. }
  1856. void
  1857. TranslateNtPathName(PSTR Path)
  1858. {
  1859. if (Path[0] == '\\' &&
  1860. Path[1] == '?' &&
  1861. Path[2] == '?' &&
  1862. Path[3] == '\\')
  1863. {
  1864. ULONG Len = strlen(Path) + 1;
  1865. if (Path[4] == 'U' &&
  1866. Path[5] == 'N' &&
  1867. Path[6] == 'C' &&
  1868. Path[7] == '\\')
  1869. {
  1870. // Compress \??\UNC\ to \\.
  1871. memmove(Path + 1, Path + 7, Len - 7);
  1872. }
  1873. else
  1874. {
  1875. // Remove \??\.
  1876. memmove(Path, Path + 4, Len - 4);
  1877. }
  1878. }
  1879. }
  1880. //----------------------------------------------------------------------------
  1881. //
  1882. // Shell process support.
  1883. //
  1884. //----------------------------------------------------------------------------
  1885. ULONG ShellProcess::s_PipeSerialNumber;
  1886. ShellProcess::ShellProcess(void)
  1887. {
  1888. m_IoIn = NULL;
  1889. m_IoOut = NULL;
  1890. m_ProcIn = NULL;
  1891. m_ProcOut = NULL;
  1892. m_ProcErr = NULL;
  1893. m_IoSignal = NULL;
  1894. m_ProcThread = NULL;
  1895. m_Process = NULL;
  1896. m_ReaderThread = NULL;
  1897. m_DefaultTimeout = 1000;
  1898. }
  1899. ShellProcess::~ShellProcess(void)
  1900. {
  1901. Close();
  1902. }
  1903. DWORD
  1904. ShellProcess::ReaderThread(void)
  1905. {
  1906. OVERLAPPED Overlapped;
  1907. HANDLE WaitHandles[2];
  1908. DWORD Error = NO_ERROR;
  1909. UCHAR Buffer[_MAX_PATH];
  1910. DWORD BytesRead;
  1911. DWORD WaitStatus;
  1912. ZeroMemory(&Overlapped, sizeof(Overlapped));
  1913. Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  1914. if (Overlapped.hEvent == NULL)
  1915. {
  1916. return ERROR_NOT_ENOUGH_MEMORY;
  1917. }
  1918. WaitHandles[0] = Overlapped.hEvent;
  1919. WaitHandles[1] = m_Process;
  1920. //
  1921. // wait for data on handle 1.
  1922. // wait for signal on handle 2.
  1923. //
  1924. while (1)
  1925. {
  1926. //
  1927. // Initiate the read.
  1928. //
  1929. ResetEvent(Overlapped.hEvent);
  1930. if (ReadFile(m_IoOut, Buffer, sizeof(Buffer) - 1,
  1931. &BytesRead, &Overlapped))
  1932. {
  1933. //
  1934. // Read has successfully completed, print and repeat.
  1935. //
  1936. Buffer[BytesRead] = 0;
  1937. dprintf("%s", Buffer);
  1938. // Notify the main thread that output was produced.
  1939. SetEvent(m_IoSignal);
  1940. }
  1941. else
  1942. {
  1943. Error = GetLastError();
  1944. if (Error != ERROR_IO_PENDING)
  1945. {
  1946. // The pipe can be broken if the user
  1947. // does .shell_quit to abandon the child process.
  1948. // There are also some other cases, but in general
  1949. // it means that the other end of the pipe has gone
  1950. // away so we can just stop reading.
  1951. if (Error != ERROR_BROKEN_PIPE)
  1952. {
  1953. dprintf(".shell: ReadFile failed, error == %d\n", Error);
  1954. }
  1955. break;
  1956. }
  1957. Error = NO_ERROR;
  1958. // Flush output before waiting.
  1959. FlushCallbacks();
  1960. WaitStatus = WaitForMultipleObjects(2, WaitHandles, FALSE,
  1961. INFINITE);
  1962. if (WaitStatus == WAIT_OBJECT_0)
  1963. {
  1964. if (GetOverlappedResult(m_IoOut, &Overlapped,
  1965. &BytesRead, TRUE))
  1966. {
  1967. //
  1968. // Read has successfully completed
  1969. //
  1970. Buffer[BytesRead] = 0;
  1971. dprintf("%s", Buffer);
  1972. // Notify the main thread that output was produced.
  1973. SetEvent(m_IoSignal);
  1974. }
  1975. else
  1976. {
  1977. Error = GetLastError();
  1978. if (Error != ERROR_BROKEN_PIPE)
  1979. {
  1980. dprintf(".shell: GetOverlappedResult failed, "
  1981. "error == %d\n", Error);
  1982. }
  1983. break;
  1984. }
  1985. }
  1986. else if (WaitStatus == WAIT_OBJECT_0 + 1)
  1987. {
  1988. //
  1989. // process exited.
  1990. //
  1991. dprintf(".shell: Process exited\n");
  1992. break;
  1993. }
  1994. else
  1995. {
  1996. Error = GetLastError();
  1997. dprintf(".shell: WaitForMultipleObjects failed; error == %d\n",
  1998. Error);
  1999. break;
  2000. }
  2001. }
  2002. }
  2003. CloseHandle(Overlapped.hEvent);
  2004. if (!Error && m_IoIn)
  2005. {
  2006. dprintf("Press ENTER to continue\n");
  2007. }
  2008. // Flush all remaining output.
  2009. FlushCallbacks();
  2010. // Notify the main thread that output was produced.
  2011. SetEvent(m_IoSignal);
  2012. return NO_ERROR;
  2013. }
  2014. DWORD WINAPI
  2015. ShellProcess::ReaderThreadCb(LPVOID Param)
  2016. {
  2017. return ((ShellProcess*)Param)->ReaderThread();
  2018. }
  2019. BOOL
  2020. ShellProcess::CreateAsyncPipePair(OUT LPHANDLE ReadPipe,
  2021. OUT LPHANDLE WritePipe,
  2022. IN LPSECURITY_ATTRIBUTES SecAttr,
  2023. IN DWORD Size,
  2024. IN DWORD ReadMode,
  2025. IN DWORD WriteMode)
  2026. {
  2027. HANDLE ReadPipeHandle, WritePipeHandle;
  2028. CHAR PipeNameBuffer[MAX_PATH];
  2029. //
  2030. // Only one valid OpenMode flag - FILE_FLAG_OVERLAPPED
  2031. //
  2032. if ((ReadMode | WriteMode) & (~FILE_FLAG_OVERLAPPED))
  2033. {
  2034. SetLastError(ERROR_INVALID_PARAMETER);
  2035. return FALSE;
  2036. }
  2037. if (Size == 0)
  2038. {
  2039. Size = 4096;
  2040. }
  2041. sprintf(PipeNameBuffer,
  2042. "\\\\.\\Pipe\\Win32PipesEx.%08x.%08x",
  2043. GetCurrentProcessId(),
  2044. s_PipeSerialNumber++);
  2045. //
  2046. // Set the default timeout to 120 seconds
  2047. //
  2048. ReadPipeHandle = CreateNamedPipeA(PipeNameBuffer,
  2049. PIPE_ACCESS_INBOUND | ReadMode,
  2050. PIPE_TYPE_BYTE | PIPE_WAIT,
  2051. 1, // Number of pipes
  2052. Size, // Out buffer size
  2053. Size, // In buffer size
  2054. 120 * 1000, // Timeout in ms
  2055. SecAttr);
  2056. if (ReadPipeHandle == INVALID_HANDLE_VALUE)
  2057. {
  2058. return FALSE;
  2059. }
  2060. WritePipeHandle = CreateFileA(PipeNameBuffer,
  2061. GENERIC_WRITE,
  2062. 0, // No sharing
  2063. SecAttr,
  2064. OPEN_EXISTING,
  2065. FILE_ATTRIBUTE_NORMAL | WriteMode,
  2066. NULL); // Template file
  2067. if (WritePipeHandle == INVALID_HANDLE_VALUE)
  2068. {
  2069. DWORD Error = GetLastError();
  2070. CloseHandle(ReadPipeHandle);
  2071. SetLastError(Error);
  2072. return FALSE;
  2073. }
  2074. *ReadPipe = ReadPipeHandle;
  2075. *WritePipe = WritePipeHandle;
  2076. return TRUE;
  2077. }
  2078. HRESULT
  2079. ShellProcess::Start(PCSTR CmdString,
  2080. PCSTR InFile,
  2081. PCSTR OutFile,
  2082. PCSTR ErrFile)
  2083. {
  2084. SECURITY_ATTRIBUTES SecAttr;
  2085. // If output is going to a file input must
  2086. // come from a file since the user won't see
  2087. // any output to know whether input is necessary.
  2088. if (OutFile && !InFile)
  2089. {
  2090. ErrOut(".shell: Input must be redirected with output\n");
  2091. return E_INVALIDARG;
  2092. }
  2093. SecAttr.nLength = sizeof(SecAttr);
  2094. SecAttr.lpSecurityDescriptor = NULL;
  2095. SecAttr.bInheritHandle = TRUE;
  2096. //
  2097. // If the debugger always ran through stdin/stdout, we
  2098. // could just run a shell and wait for it. However, in order
  2099. // to handle fDebugOutput, we have to open pipes and manage
  2100. // the i/o stream for the shell. Since we need to have that
  2101. // code anyway, always use it.
  2102. //
  2103. if (InFile)
  2104. {
  2105. //
  2106. // Open a file for the child process to use for input.
  2107. //
  2108. m_ProcIn = CreateFile(InFile, GENERIC_READ, FILE_SHARE_READ,
  2109. &SecAttr, OPEN_EXISTING,
  2110. FILE_ATTRIBUTE_NORMAL, NULL);
  2111. if (m_ProcIn == INVALID_HANDLE_VALUE)
  2112. {
  2113. m_ProcIn = NULL;
  2114. ErrOut(".shell: Unable to open %s\n", InFile);
  2115. goto Exit;
  2116. }
  2117. }
  2118. else
  2119. {
  2120. //
  2121. // Create stdin pipe for debugger->shell.
  2122. // Neither end needs to be overlapped.
  2123. //
  2124. if (!CreateAsyncPipePair(&m_ProcIn, &m_IoIn,
  2125. &SecAttr, 0, 0, 0))
  2126. {
  2127. ErrOut(".shell: Unable to create stdin pipe.\n");
  2128. goto Exit;
  2129. }
  2130. //
  2131. // We don't want the shell to inherit our end of the pipe
  2132. // so duplicate it to a non-inheritable one.
  2133. //
  2134. if (!DuplicateHandle(GetCurrentProcess(), m_IoIn,
  2135. GetCurrentProcess(), &m_IoIn,
  2136. 0, FALSE,
  2137. DUPLICATE_SAME_ACCESS |
  2138. DUPLICATE_CLOSE_SOURCE))
  2139. {
  2140. ErrOut(".shell: Unable to duplicate stdin handle.\n");
  2141. goto Exit;
  2142. }
  2143. }
  2144. if (OutFile)
  2145. {
  2146. //
  2147. // Open a file for the child process to use for output.
  2148. //
  2149. m_ProcOut = CreateFile(OutFile, GENERIC_WRITE, 0,
  2150. &SecAttr, CREATE_ALWAYS,
  2151. FILE_ATTRIBUTE_NORMAL, NULL);
  2152. if (m_ProcOut == INVALID_HANDLE_VALUE)
  2153. {
  2154. m_ProcOut = NULL;
  2155. ErrOut(".shell: Unable to create %s\n", OutFile);
  2156. goto Exit;
  2157. }
  2158. }
  2159. else
  2160. {
  2161. //
  2162. // Create stdout shell->debugger pipe
  2163. //
  2164. if (!CreateAsyncPipePair(&m_IoOut, &m_ProcOut,
  2165. &SecAttr, 0, FILE_FLAG_OVERLAPPED, 0))
  2166. {
  2167. ErrOut(".shell: Unable to create stdout pipe.\n");
  2168. goto Exit;
  2169. }
  2170. //
  2171. // We don't want the shell to inherit our end of the pipe
  2172. // so duplicate it to a non-inheritable one.
  2173. //
  2174. if (!DuplicateHandle(GetCurrentProcess(), m_IoOut,
  2175. GetCurrentProcess(), &m_IoOut,
  2176. 0, FALSE,
  2177. DUPLICATE_SAME_ACCESS |
  2178. DUPLICATE_CLOSE_SOURCE))
  2179. {
  2180. ErrOut(".shell: Unable to duplicate local stdout handle.\n");
  2181. goto Exit;
  2182. }
  2183. }
  2184. if (ErrFile)
  2185. {
  2186. //
  2187. // Open a file for the child process to use for error output.
  2188. //
  2189. m_ProcErr = CreateFile(ErrFile, GENERIC_WRITE, 0,
  2190. &SecAttr, CREATE_ALWAYS,
  2191. FILE_ATTRIBUTE_NORMAL, NULL);
  2192. if (m_ProcErr == INVALID_HANDLE_VALUE)
  2193. {
  2194. m_ProcErr = NULL;
  2195. ErrOut(".shell: Unable to create %s\n", ErrFile);
  2196. goto Exit;
  2197. }
  2198. }
  2199. else
  2200. {
  2201. //
  2202. // Duplicate shell's stdout to a new stderr.
  2203. //
  2204. if (!DuplicateHandle(GetCurrentProcess(), m_ProcOut,
  2205. GetCurrentProcess(), &m_ProcErr,
  2206. 0, TRUE,
  2207. DUPLICATE_SAME_ACCESS))
  2208. {
  2209. ErrOut(".shell: Unable to duplicate stdout handle for stderr.\n");
  2210. goto Exit;
  2211. }
  2212. }
  2213. //
  2214. // Create an event for output monitoring.
  2215. //
  2216. m_IoSignal = CreateEvent(NULL, FALSE, FALSE, NULL);
  2217. if (m_IoSignal == NULL)
  2218. {
  2219. ErrOut(".shell: Unable to allocate event.\n");
  2220. goto Exit;
  2221. }
  2222. CHAR Shell[_MAX_PATH];
  2223. CHAR Command[2 * _MAX_PATH];
  2224. if (!GetEnvironmentVariable("SHELL", Shell, DIMA(Shell)))
  2225. {
  2226. if (!GetEnvironmentVariable("ComSpec", Shell, DIMA(Shell)))
  2227. {
  2228. strcpy(Shell, "cmd.exe");
  2229. }
  2230. }
  2231. // Skip leading whitespace on the command string.
  2232. // Some commands, such as "net use", can't handle it.
  2233. if (CmdString != NULL)
  2234. {
  2235. while (isspace(*CmdString))
  2236. {
  2237. CmdString++;
  2238. }
  2239. }
  2240. if (CmdString && *CmdString)
  2241. {
  2242. //
  2243. // If there was a command, use SHELL /c Command
  2244. //
  2245. if (!CopyString(Command, Shell, DIMA(Command)) ||
  2246. !CatString(Command, " /c \"", DIMA(Command)) ||
  2247. !CatString(Command, CmdString, DIMA(Command)) ||
  2248. !CatString(Command, "\"", DIMA(Command)))
  2249. {
  2250. ErrOut(".shell: Not enough room for command line\n");
  2251. SetLastError(ERROR_INVALID_PARAMETER);
  2252. goto Exit;
  2253. }
  2254. }
  2255. else
  2256. {
  2257. //
  2258. // If there was no command, just run the shell
  2259. //
  2260. strcpy(Command, Shell);
  2261. }
  2262. STARTUPINFO StartInfo;
  2263. PROCESS_INFORMATION ProcInfo;
  2264. ZeroMemory(&StartInfo, sizeof(StartInfo));
  2265. StartInfo.cb = sizeof(StartInfo);
  2266. StartInfo.dwFlags = STARTF_USESTDHANDLES;
  2267. StartInfo.hStdInput = m_ProcIn;
  2268. StartInfo.hStdOutput = m_ProcOut;
  2269. StartInfo.hStdError = m_ProcErr;
  2270. StartInfo.wShowWindow = SW_SHOW;
  2271. ZeroMemory(&ProcInfo, sizeof(ProcInfo));
  2272. //
  2273. // Create Child Process
  2274. //
  2275. if (!CreateProcess(NULL, Command, NULL, NULL, TRUE,
  2276. GetPriorityClass(GetCurrentProcess()),
  2277. NULL, NULL, &StartInfo, &ProcInfo))
  2278. {
  2279. if (GetLastError() == ERROR_FILE_NOT_FOUND)
  2280. {
  2281. ErrOut("%s not found\n", Shell);
  2282. }
  2283. else
  2284. {
  2285. HRESULT Status = WIN32_LAST_STATUS();
  2286. ErrOut("CreateProcess(%s) failed, %s.\n \"%s\"\n",
  2287. Command, FormatStatusCode(Status), FormatStatus(Status));
  2288. }
  2289. goto Exit;
  2290. }
  2291. m_Process = ProcInfo.hProcess;
  2292. m_ProcThread = ProcInfo.hThread;
  2293. if (m_IoOut)
  2294. {
  2295. DWORD ThreadId;
  2296. //
  2297. // Start reader thread to copy shell output
  2298. //
  2299. m_ReaderThread = CreateThread(NULL, 0, ReaderThreadCb,
  2300. this, 0, &ThreadId);
  2301. if (!m_ReaderThread)
  2302. {
  2303. ErrOut(".shell: Unable to create reader thread\n");
  2304. goto Exit;
  2305. }
  2306. }
  2307. WaitForProcessExit();
  2308. Close();
  2309. return S_OK;
  2310. Exit:
  2311. Close();
  2312. return WIN32_LAST_STATUS();
  2313. }
  2314. void
  2315. ShellProcess::WaitForProcessExit(void)
  2316. {
  2317. CHAR InputBuffer[MAX_PATH];
  2318. DWORD BytesWritten;
  2319. ULONG Timeout;
  2320. ULONG BaseTimeout;
  2321. ULONG CheckTimeout;
  2322. BOOL ProcessExited = FALSE;
  2323. //
  2324. // Feed input to shell if necessary; wait for it to exit.
  2325. //
  2326. BaseTimeout = m_IoIn ? m_DefaultTimeout : 10 * m_DefaultTimeout;
  2327. CheckTimeout = BaseTimeout / 10;
  2328. Timeout = BaseTimeout;
  2329. while (1)
  2330. {
  2331. ULONG WaitStatus;
  2332. // Give the other process a little time to run.
  2333. // This is critical when output is being piped
  2334. // across kd as GetInput causes the machine to
  2335. // sit in the kernel debugger input routine and
  2336. // nobody gets any time to run.
  2337. if (m_IoOut &&
  2338. WaitForSingleObject(m_IoSignal, CheckTimeout) == WAIT_OBJECT_0)
  2339. {
  2340. // Reset the timeout since the process seems to
  2341. // be active.
  2342. Timeout = BaseTimeout;
  2343. // Some output was produced so let the child keep
  2344. // running to keep the output flowing. If this
  2345. // was the final output of the process, though,
  2346. // go to the last input request.
  2347. if (WaitForSingleObject(m_Process, 0) != WAIT_OBJECT_0)
  2348. {
  2349. continue;
  2350. }
  2351. else if (!m_IoIn)
  2352. {
  2353. ProcessExited = TRUE;
  2354. break;
  2355. }
  2356. }
  2357. // We've run out of immediate output, so wait for a
  2358. // larger interval to give the process a reasonable
  2359. // amount of time to run. Show a message to keep
  2360. // users in the loop.
  2361. dprintf("<.shell waiting %d second(s) for process>\n",
  2362. Timeout / 1000);
  2363. FlushCallbacks();
  2364. if (m_IoOut)
  2365. {
  2366. WaitStatus = WaitForSingleObject(m_IoSignal, Timeout);
  2367. if (WaitStatus == WAIT_OBJECT_0 &&
  2368. WaitForSingleObject(m_Process, 0) != WAIT_OBJECT_0)
  2369. {
  2370. // Reset the timeout since the process seems to
  2371. // be active.
  2372. Timeout = BaseTimeout;
  2373. continue;
  2374. }
  2375. }
  2376. else
  2377. {
  2378. if (WaitForSingleObject(m_Process, Timeout) == WAIT_OBJECT_0)
  2379. {
  2380. ProcessExited = TRUE;
  2381. break;
  2382. }
  2383. }
  2384. GetInput(m_IoIn ?
  2385. "<.shell process may need input>" :
  2386. "<.shell running: .shell_quit to abandon, ENTER to wait>",
  2387. InputBuffer, DIMA(InputBuffer) - 2, GETIN_LOG_INPUT_LINE);
  2388. // The user may not want to wait, so check for
  2389. // a magic input string that'll abandon the process.
  2390. if (!_strcmpi(InputBuffer, ".shell_quit"))
  2391. {
  2392. break;
  2393. }
  2394. //
  2395. // see if client is still running
  2396. //
  2397. if (m_IoOut && WaitForSingleObject(m_Process, 0) == WAIT_OBJECT_0)
  2398. {
  2399. ProcessExited = TRUE;
  2400. break;
  2401. }
  2402. //
  2403. // GetInput always returns a string without a newline
  2404. //
  2405. if (m_IoIn)
  2406. {
  2407. strcat(InputBuffer, "\n");
  2408. if (!WriteFile(m_IoIn, InputBuffer, strlen(InputBuffer),
  2409. &BytesWritten, NULL))
  2410. {
  2411. //
  2412. // if the write fails, we're done...
  2413. //
  2414. break;
  2415. }
  2416. }
  2417. // The process has some input to chew on so
  2418. // increase the amount of time we'll wait for it.
  2419. Timeout *= 2;
  2420. }
  2421. if (ProcessExited)
  2422. {
  2423. if (!m_IoOut)
  2424. {
  2425. dprintf(".shell: Process exited\n");
  2426. }
  2427. else
  2428. {
  2429. // Give the reader thread time to finish up
  2430. // with any last input.
  2431. WaitForSingleObject(m_ReaderThread, INFINITE);
  2432. }
  2433. }
  2434. }
  2435. #define HCLOSE(Handle) \
  2436. ((Handle) ? (CloseHandle(Handle), (Handle) = NULL) : NULL)
  2437. void
  2438. ShellProcess::Close(void)
  2439. {
  2440. // Close all of the I/O handles first.
  2441. // That will make the reader thread exit if it was running.
  2442. HCLOSE(m_IoIn);
  2443. HCLOSE(m_IoOut);
  2444. HCLOSE(m_ProcIn);
  2445. HCLOSE(m_ProcOut);
  2446. HCLOSE(m_ProcErr);
  2447. // Wait for the reader thread to exit.
  2448. if (m_ReaderThread)
  2449. {
  2450. WaitForSingleObject(m_ReaderThread, INFINITE);
  2451. HCLOSE(m_ReaderThread);
  2452. }
  2453. // Now close the child process handles.
  2454. HCLOSE(m_ProcThread);
  2455. HCLOSE(m_Process);
  2456. // Close this handle after the reader thread has exited
  2457. // to avoid it using a bad handle.
  2458. HCLOSE(m_IoSignal);
  2459. }