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.

1451 lines
45 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Command-line parsing and main routine.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999-2002.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "pch.cpp"
  9. #pragma hdrstop
  10. #include "conio.hpp"
  11. #include "engine.hpp"
  12. #include "ini.hpp"
  13. #include "main.hpp"
  14. // Values set from command-line arguments.
  15. BOOL g_RemoteClient;
  16. BOOL g_DetachOnExitRequired;
  17. BOOL g_DetachOnExitImplied;
  18. BOOL g_SetInterruptAfterStart;
  19. PVOID g_DumpFiles[MAX_DUMP_FILES];
  20. PSTR g_DumpFilesAnsi[MAX_DUMP_FILES];
  21. ULONG g_NumDumpFiles;
  22. PVOID g_DumpInfoFiles[MAX_DUMP_FILES];
  23. ULONG g_DumpInfoTypes[MAX_DUMP_FILES];
  24. ULONG g_NumDumpInfoFiles;
  25. PSTR g_InitialCommand;
  26. PSTR g_ConnectOptions;
  27. PVOID g_CommandLinePtr;
  28. ULONG g_CommandLineCharSize;
  29. PSTR g_RemoteOptions;
  30. PSTR g_ProcessServer;
  31. PSTR g_ProcNameToDebug;
  32. ULONG g_IoRequested = IO_CONSOLE;
  33. ULONG g_IoMode;
  34. ULONG g_CreateFlags = DEBUG_ONLY_THIS_PROCESS;
  35. ULONG g_AttachKernelFlags = DEBUG_ATTACH_KERNEL_CONNECTION;
  36. ULONG g_PidToDebug;
  37. ULONG64 g_EventToSignal;
  38. ULONG g_HistoryLines = 10000;
  39. ULONG g_AttachProcessFlags = DEBUG_ATTACH_DEFAULT;
  40. PSTR g_DebuggerName = DEBUGGER_NAME;
  41. PSTR g_InitialInputFile = "ntsd.ini";
  42. FILE* g_InputFile;
  43. FILE* g_OldInputFiles[MAX_INPUT_NESTING];
  44. ULONG g_NextOldInputFile;
  45. // Command line temporaries.
  46. int g_Argc;
  47. PSTR* g_Argv;
  48. PSTR g_CurArg = "program name";
  49. PVOID g_CmdPtrStart, g_CmdPtr, g_PrevCmdPtr;
  50. void
  51. ExecuteCmd(PSTR Cmd, char CmdExtra, char Sep, PSTR Args)
  52. {
  53. PSTR CmdLine;
  54. char Buffer[MAX_PATH * 2];
  55. if (!CopyString(Buffer, Cmd, DIMA(Buffer)))
  56. {
  57. return;
  58. }
  59. CmdLine = Buffer + strlen(Buffer);
  60. if (CmdLine + strlen(Args) + 2 > Buffer + sizeof(Buffer))
  61. {
  62. ConOut("Command too long\n");
  63. return;
  64. }
  65. if (CmdExtra)
  66. {
  67. *CmdLine++ = CmdExtra;
  68. }
  69. if (Sep)
  70. {
  71. *CmdLine++ = Sep;
  72. }
  73. strcpy(CmdLine, Args);
  74. g_DbgControl->Execute(DEBUG_OUTCTL_IGNORE, Buffer,
  75. DEBUG_EXECUTE_NOT_LOGGED);
  76. }
  77. char g_BlanksForPadding[] =
  78. " "
  79. " "
  80. " ";
  81. enum
  82. {
  83. UM = 1,
  84. KM = 2,
  85. AM = 3,
  86. };
  87. struct CMD_OPTION
  88. {
  89. ULONG Flags;
  90. PSTR Option;
  91. PSTR Desc;
  92. };
  93. CMD_OPTION g_CmdOptions[] =
  94. {
  95. UM, "<command-line>", "command to run under the debugger",
  96. AM, "-?", "displays command line help text",
  97. UM, "--", "equivalent to -G -g -o -p -1 -d -pd",
  98. UM, "-2", "creates a separate console window for debuggee",
  99. AM, "-a<DllName>", "adds a default extension DLL",
  100. KM, "-b", "break into kernel when connection is established",
  101. AM, "-bonc", "request break in after session started",
  102. AM, "-c \"<command>\"", "executes the given debugger command "
  103. "at the first debugger prompt",
  104. AM, "-cf <file>", "specifies a script file to be processed "
  105. "at the first debugger prompt",
  106. AM, "-clines <#>",
  107. "number of lines of output history retrieved by a remote client",
  108. UM, "-d", "sends all debugger output to kernel debugger via DbgPrint\n"
  109. "input is requested from the kernel debugger via DbgPrompt\n"
  110. "-d cannot be used with debugger remoting\n"
  111. "-d can only be used when the kernel debugger is enabled",
  112. UM, "-ddefer", "sends all debugger output to kernel debugger "
  113. "via DbgPrint\n"
  114. "input is requested from the kernel debugger via DbgPrompt "
  115. "unless there are remote clients that can provide input\n"
  116. "-ddefer can only be used when the kernel debugger is enabled\n"
  117. "-ddefer should be used with -server",
  118. KM, "-d", "breaks into kernel on first module load",
  119. AM, "-ee <name>", "set default expression evaluator\n"
  120. "<name> can be MASM or C++",
  121. AM, "-failinc", "causes incomplete symbol and module loads to fail",
  122. UM, "-g", "ignores initial breakpoint in debuggee",
  123. UM, "-G", "ignores final breakpoint at process termination",
  124. UM, "-hd", "specifies that the debug heap should not be used "
  125. "for created processes. This only works on Windows XP and later",
  126. AM, "-i <ImagePath>",
  127. "specifies the location of the executables that generated "
  128. "the fault (see _NT_EXECUTABLE_IMAGE_PATH)",
  129. UM, "-isd", "sets the CREATE_IGNORE_SYSTEM_DEFAULT flag in "
  130. "STARTUPINFO.dwFlags during CreateProcess",
  131. KM, "-k <Options>",
  132. "tells the debugger how to connect to the target\n"
  133. "com:modem connects through a modem\n"
  134. "com:port=id,baud=rate connects through a COM port\n"
  135. " id: com port name, of the form com2 or \\\\.\\com12\n"
  136. " rate: valid baudrate value, such as 57600\n"
  137. "1394:channel=chan connects over 1394\n"
  138. " chan: 1394 channel number, must match channel used at boot",
  139. KM, "-kl", "tell the debugger to connect to the local machine",
  140. KM, "-kx <Options>",
  141. "tells the debugger to connect to an eXDI driver",
  142. AM, "-lines", "requests that line number information be used if present",
  143. AM, "-loga <logfile>", "appends to a log file",
  144. AM, "-logo <logfile>", "opens a new log file",
  145. KM, "-m", "serial port is a modem, watch for carrier detect",
  146. AM, "-myob", "ignores version mismatches in DBGHELP.DLL",
  147. AM, "-n", "enables verbose output from symbol handler",
  148. AM, "-noio", "disables all I/O for dedicated remoting servers",
  149. AM, "-noshell", "disables the .shell (!!) command",
  150. UM, "-o", "debugs all processes launched by debuggee",
  151. UM, "-p <pid>", "specifies the decimal process ID to attach to",
  152. UM, "-pb", "specifies that the debugger should not break in at attach",
  153. UM, "-pd", "specifies that the debugger should automatically detach",
  154. UM, "-pe", "specifies that any attach should be to an existing debug port",
  155. UM, "-pn <name>", "specifies the name of the process to attach to",
  156. UM, "-pr", "specifies that the debugger should resume on attach",
  157. UM, "-premote <transport>:server=<name>,<params>",
  158. "specifies the process server to connect to\n"
  159. "transport arguments are given as with remoting",
  160. UM, "-pt <#>", "specifies the interrupt timeout",
  161. UM, "-pv", "specifies that any attach should be noninvasive",
  162. UM, "-pvr",
  163. "specifies that any attach should be noninvasive and nonsuspending",
  164. AM, "-QR \\\\<machine>", "queries for remote servers",
  165. UM, "-r <BreakErrorLevel>",
  166. "specifies the (0-3) error level to break on (see SetErrorLevel)",
  167. KM, "-r", "display registers",
  168. AM, "-remote <transport>:server=<name>,<params>",
  169. "lets you connect to a debugger session started with -server\n"
  170. "must be the first argument if present\n"
  171. " transport: tcp | npipe | ssl | spipe | 1394 | com\n"
  172. " name: machine name on which the debug server was created\n"
  173. " params: parameters the debugger server was created with\n"
  174. " for tcp use: port=<socket port #>\n"
  175. " for npipe use: pipe=<name of pipe>\n"
  176. " for 1394 use: channel=<channel #>\n"
  177. " for com use: port=<COM port>,baud=<baud rate>,\n"
  178. " channel=<channel #>\n"
  179. " for ssl and spipe see the documentation\n"
  180. " example: ... -remote npipe:server=yourmachine,pipe=foobar",
  181. UM, "-robp", "allows breakpoints to be set in read-only memory",
  182. UM, "-rtl", "uses RtlCreateUserProcess instead of Win32 CreateProcess",
  183. AM, "-s", "disables lazy symbol loading",
  184. AM, "-sdce", "pops up dialogs for critical errors",
  185. AM, "-secure", "disallows operations dangerous for the host",
  186. AM, "-server <transport>:<params>",
  187. "creates a debugger session other people can connect to\n"
  188. "must be the first argument if present\n"
  189. " transport: tcp | npipe | ssl | spipe | 1394 | com\n"
  190. " params: connection parameterization\n"
  191. " for tcp use: port=<socket port #>\n"
  192. " for npipe use: pipe=<name of pipe>\n"
  193. " for 1394 use: channel=<channel #>\n"
  194. " for com use: port=<COM port>,baud=<baud rate>,\n"
  195. " channel=<channel #>\n"
  196. " for ssl and spipe see the documentation\n"
  197. " example: ... -server npipe:pipe=foobar",
  198. AM, "-ses", "enables strict symbol loading",
  199. AM, "-sfce", "fails critical errors encountered during file searching",
  200. AM, "-sflags <flags>", "sets symbol flags from a numeric argument",
  201. AM, "-sicv", "ignores the CV record when symbol loading",
  202. AM, "-sins", "ignores the symbol path environment variables",
  203. AM, "-snc", "converts :: to __ in symbol names",
  204. AM, "-snul", "disables automatic symbol loading for unqualified names",
  205. AM, "-srcpath <SourcePath>", "specifies the source search path",
  206. AM, "-sup", "enables full public symbol searches",
  207. UM, "-t <PrintErrorLevel>",
  208. "specifies the (0-3) error level to display (see SetErrorLevel)",
  209. AM, "-v", "enables verbose output from debugger",
  210. UM, "-w", "specifies to debug 16 bit applications in a separate VDM",
  211. AM, "-wake <pid>", "wakes up a sleeping debugger and exits",
  212. UM, "-x", "sets second-chance break on AV exceptions",
  213. KM, "-x",
  214. "same as -b, except uses an initial command of eb NtGlobalFlag 9;g",
  215. UM, "-x{e|d|n|i} <event>", "sets the break status for the specified event",
  216. AM, "-y <SymbolsPath>",
  217. "specifies the symbol search path (see _NT_SYMBOL_PATH)",
  218. AM, "-z <CrashDmpFile>",
  219. "specifies the name of a crash dump file to debug",
  220. AM, "-zp <CrashPageFile>", "specifies the name of a page.dmp file "
  221. "to use with a crash dump",
  222. };
  223. void
  224. Usage(void)
  225. {
  226. int i;
  227. int Width = 78;
  228. // Dump an initial debug message about the invalid command
  229. // line. This will show up on kd if kd is hooked up,
  230. // handling the case of an ntsd -d with bad parameters
  231. // where the console may not be useful.
  232. OutputDebugStringA(g_DebuggerName);
  233. OutputDebugStringA(": Bad command line: '");
  234. OutputDebugStringA(GetCommandLineA());
  235. OutputDebugStringA("'\n");
  236. ConOut("usage: %s [options]\n", g_DebuggerName);
  237. ConOut("\nOptions:\n\n");
  238. for (i = 0; i < DIMA(g_CmdOptions); i++)
  239. {
  240. int StartCol;
  241. #ifdef KERNEL
  242. if (g_CmdOptions[i].Flags == UM)
  243. {
  244. continue;
  245. }
  246. #else
  247. if (g_CmdOptions[i].Flags == KM)
  248. {
  249. continue;
  250. }
  251. #endif
  252. ConOut(" %s ", g_CmdOptions[i].Option);
  253. StartCol = 3 + strlen(g_CmdOptions[i].Option);
  254. if (StartCol > 30)
  255. {
  256. ConOut("\n ");
  257. StartCol = 4;
  258. }
  259. //
  260. // Split description up and indent every line.
  261. //
  262. int Col;
  263. PSTR Start, Scan, LastSpace;
  264. Start = g_CmdOptions[i].Desc;
  265. for (;;)
  266. {
  267. // Scan until we run out of room or hit a newline/end.
  268. Scan = Start;
  269. LastSpace = NULL;
  270. Col = StartCol;
  271. while (*Scan && *Scan != '\n' && Col < Width)
  272. {
  273. if (*Scan == ' ')
  274. {
  275. LastSpace = Scan;
  276. while (*(LastSpace + 1) == ' ')
  277. {
  278. LastSpace++;
  279. }
  280. }
  281. Scan++;
  282. Col++;
  283. }
  284. if (*Scan && *Scan != '\n')
  285. {
  286. Scan = LastSpace;
  287. }
  288. ConOut("%.*s\n", (int)(Scan - Start), Start);
  289. if (!*Scan)
  290. {
  291. break;
  292. }
  293. ConOut("%.*s", StartCol, g_BlanksForPadding);
  294. Start = Scan + 1;
  295. }
  296. }
  297. ConOut("\n");
  298. ConOut("Environment Variables:\n\n");
  299. ConOut(" _NT_SYMBOL_PATH=[Drive:][Path]\n");
  300. ConOut(" Specify symbol image path.\n\n");
  301. ConOut(" _NT_ALT_SYMBOL_PATH=[Drive:][Path]\n");
  302. ConOut(" Specify an alternate symbol image path.\n\n");
  303. ConOut(" _NT_DEBUGGER_EXTENSION_PATH=[Drive:][Path]\n");
  304. ConOut(" Specify a path which should be searched first for extensions dlls\n\n");
  305. ConOut(" _NT_EXECUTABLE_IMAGE_PATH=[Drive:][Path]\n");
  306. ConOut(" Specify executable image path.\n\n");
  307. ConOut(" _NT_SOURCE_PATH=[Drive:][Path]\n");
  308. ConOut(" Specify source file path.\n\n");
  309. ConOut(" _NT_DEBUG_LOG_FILE_OPEN=filename\n");
  310. ConOut(" If specified, all output will be written to this file from offset 0.\n\n");
  311. ConOut(" _NT_DEBUG_LOG_FILE_APPEND=filename\n");
  312. ConOut(" If specified, all output will be APPENDed to this file.\n\n");
  313. ConOut(" _NT_DEBUG_HISTORY_SIZE=size\n");
  314. ConOut(" Specifies the size of a server's output history in kilobytes\n");
  315. #ifdef KERNEL
  316. ConOut(" _NT_DEBUG_BUS=1394\n");
  317. ConOut(" Specifies the type of BUS the kernel debugger will use to communicate with the target\n\n");
  318. ConOut(" _NT_DEBUG_1394_CHANNEL=number\n");
  319. ConOut(" Specifies the channel to be used over the 1394 bus\n\n");
  320. ConOut(" _NT_DEBUG_PORT=com[1|2|...]\n");
  321. ConOut(" Specify which com port to use. (Default = com1)\n\n");
  322. ConOut(" _NT_DEBUG_BAUD_RATE=baud rate\n");
  323. ConOut(" Specify the baud rate used by debugging serial port. (Default = 19200)\n\n");
  324. ConOut(" _NT_DEBUG_CACHE_SIZE=x\n");
  325. ConOut(" If specified, gives the number of bytes cached on debugger side\n");
  326. ConOut(" of kernel debugger serial connection (default is 102400).\n\n");
  327. ConOut(" KDQUIET=anything\n" );
  328. ConOut(" If defined, disables obnoxious warning message displayed when user\n");
  329. ConOut(" presses Ctrl-C\n\n");
  330. #endif
  331. ConOut("\n");
  332. ConOut("Control Keys:\n\n");
  333. #ifdef KERNEL
  334. ConOut(" <Ctrl-A><Enter> Toggle BaudRate\n");
  335. #endif
  336. ConOut(" <Ctrl-B><Enter> Quit debugger\n");
  337. ConOut(" <Ctrl-C> Break into Target\n");
  338. #ifdef KERNEL
  339. ConOut(" <Ctrl-D><Enter> Display debugger debugging information\n");
  340. ConOut(" <Ctrl-F><Enter> Force a break into the kernel (same as Ctrl-C)\n");
  341. #else
  342. ConOut(" <Ctrl-F><Enter> Force a break into debuggee (same as Ctrl-C)\n");
  343. #endif
  344. #ifdef KERNEL
  345. ConOut(" <Ctrl-K><Enter> Toggle Initial Breakpoint\n");
  346. #endif
  347. ConOut(" <Ctrl-P><Enter> Debug Current debugger\n");
  348. #ifdef KERNEL
  349. ConOut(" <Ctrl-R><Enter> Resynchronize target and host\n");
  350. #endif
  351. ConOut(" <Ctrl-V><Enter> Toggle Verbose mode\n");
  352. ConOut(" <Ctrl-W><Enter> Print version information\n");
  353. }
  354. void
  355. SkipCommandWhite(void)
  356. {
  357. if (g_CommandLineCharSize == sizeof(WCHAR))
  358. {
  359. while (*(PWSTR)g_CmdPtr == L' ' || *(PWSTR)g_CmdPtr == L'\t')
  360. {
  361. g_CmdPtr = (PVOID)((PWSTR)g_CmdPtr + 1);
  362. }
  363. }
  364. else
  365. {
  366. while (*(PSTR)g_CmdPtr == ' ' || *(PSTR)g_CmdPtr == '\t')
  367. {
  368. g_CmdPtr = (PVOID)((PSTR)g_CmdPtr + 1);
  369. }
  370. }
  371. }
  372. PSTR
  373. GetArg(void)
  374. {
  375. if (g_Argc == 0)
  376. {
  377. Usage();
  378. ErrorExit("Missing argument for %s\n", g_CurArg);
  379. }
  380. g_Argc--;
  381. g_CurArg = *g_Argv;
  382. g_Argv++;
  383. //
  384. // Move forward in the command string to skip over
  385. // the argument just consumed from argv. This is complicated
  386. // by quoting that may be present in the command string
  387. // that was filtered by the CRT.
  388. //
  389. SkipCommandWhite();
  390. g_PrevCmdPtr = g_CmdPtr;
  391. int NumSlash;
  392. BOOL InQuote = FALSE;
  393. for (;;)
  394. {
  395. // Rules: 2N backslashes + " ==> N backslashes and begin/end quote
  396. // 2N+1 backslashes + " ==> N backslashes + literal "
  397. // N backslashes ==> N backslashes
  398. NumSlash = 0;
  399. while ((g_CommandLineCharSize == sizeof(WCHAR) &&
  400. *(PWSTR)g_CmdPtr == L'\\') ||
  401. (g_CommandLineCharSize == sizeof(CHAR) &&
  402. *(PSTR)g_CmdPtr == '\\'))
  403. {
  404. // Count number of backslashes for use below
  405. g_CmdPtr = (PVOID)((ULONG_PTR)g_CmdPtr + g_CommandLineCharSize);
  406. ++NumSlash;
  407. }
  408. if ((g_CommandLineCharSize == sizeof(WCHAR) &&
  409. *(PWSTR)g_CmdPtr == L'"') ||
  410. (g_CommandLineCharSize == sizeof(CHAR) &&
  411. *(PSTR)g_CmdPtr == '"'))
  412. {
  413. // If 2N backslashes before, start/end quote, otherwise
  414. // copy literally
  415. if (NumSlash % 2 == 0)
  416. {
  417. if (InQuote)
  418. {
  419. if ((g_CommandLineCharSize == sizeof(WCHAR) &&
  420. *((PWSTR)g_CmdPtr + 1) == L'"') ||
  421. (g_CommandLineCharSize == sizeof(CHAR) &&
  422. *((PSTR)g_CmdPtr + 1) == '"'))
  423. {
  424. // Double quote inside quoted string
  425. g_CmdPtr = (PVOID)
  426. ((ULONG_PTR)g_CmdPtr + g_CommandLineCharSize);
  427. }
  428. }
  429. InQuote = !InQuote;
  430. }
  431. }
  432. // If at end of arg, break loop
  433. if ((g_CommandLineCharSize == sizeof(WCHAR) &&
  434. (*(PWSTR)g_CmdPtr == 0 ||
  435. (!InQuote &&
  436. (*(PWSTR)g_CmdPtr == L' ' || *(PWSTR)g_CmdPtr == L'\t')))) ||
  437. (g_CommandLineCharSize == sizeof(CHAR) &&
  438. (*(PSTR)g_CmdPtr == 0 ||
  439. (!InQuote &&
  440. (*(PSTR)g_CmdPtr == ' ' && *(PSTR)g_CmdPtr == '\t')))))
  441. {
  442. SkipCommandWhite();
  443. break;
  444. }
  445. g_CmdPtr = (PVOID)((ULONG_PTR)g_CmdPtr + g_CommandLineCharSize);
  446. }
  447. return g_CurArg;
  448. }
  449. PVOID
  450. GetRawArg(BOOL ForceAnsi, PSTR* AnsiArg)
  451. {
  452. PSTR Arg = GetArg();
  453. if (AnsiArg)
  454. {
  455. *AnsiArg = Arg;
  456. }
  457. if (ForceAnsi || g_CommandLineCharSize == sizeof(CHAR))
  458. {
  459. return Arg;
  460. }
  461. //
  462. // We have a Unicode command line and the GetArg
  463. // call just parsed through an argument on it. g_PrevCmdPtr
  464. // points to the first char and g_CmdPtr points to the
  465. // terminating char. Strip quotes and force a zero
  466. // terminator.
  467. //
  468. if (g_CmdPtr == g_CmdPtrStart)
  469. {
  470. // This shouldn't happen as we think we have an argument.
  471. ErrorExit("Missing argument for %s\n", g_CurArg);
  472. }
  473. PWSTR End = (PWSTR)g_CmdPtr - 1;
  474. while (*End == L' ' || *End == L'\t')
  475. {
  476. End--;
  477. }
  478. if (*End == L'"')
  479. {
  480. End--;
  481. }
  482. *(End + 1) = 0;
  483. if (*(PWCHAR)g_PrevCmdPtr == L'"')
  484. {
  485. return (PWCHAR)g_PrevCmdPtr + 1;
  486. }
  487. else
  488. {
  489. return g_PrevCmdPtr;
  490. }
  491. }
  492. void
  493. ParseCommandLine(int Argc, PCHAR* Argv, PVOID CmdPtr)
  494. {
  495. PSTR Arg;
  496. BOOL ShowUsage = FALSE;
  497. ULONG OutMask;
  498. ULONG SystemErrorBreak;
  499. ULONG SystemErrorOutput;
  500. BOOL CheckMoreArgs = FALSE;
  501. g_Argc = Argc;
  502. g_Argv = Argv;
  503. g_CmdPtrStart = CmdPtr;
  504. g_CmdPtr = g_CmdPtrStart;
  505. // Skip program name.
  506. GetArg();
  507. // Check for remote arguments. They must
  508. // be the first arguments if present at all.
  509. if (g_Argc > 0)
  510. {
  511. if (!_strcmpi(*g_Argv, "-remote"))
  512. {
  513. GetArg();
  514. g_RemoteOptions = GetArg();
  515. g_RemoteClient = TRUE;
  516. ConnectEngine(g_RemoteOptions);
  517. }
  518. else if (!_strcmpi(*g_Argv, "-server"))
  519. {
  520. GetArg();
  521. g_RemoteOptions = GetArg();
  522. }
  523. }
  524. if (g_DbgClient == NULL)
  525. {
  526. // We didn't connect to a remote session so create
  527. // a new local session.
  528. CreateEngine(g_RemoteOptions);
  529. }
  530. if (!g_RemoteClient)
  531. {
  532. // Establish defaults.
  533. #ifdef KERNEL
  534. g_DbgControl->SetEngineOptions(0);
  535. #else
  536. g_DbgControl->SetEngineOptions(DEBUG_ENGOPT_INITIAL_BREAK |
  537. DEBUG_ENGOPT_FINAL_BREAK);
  538. #endif
  539. g_DbgSymbols->SetSymbolOptions(SYMOPT_CASE_INSENSITIVE |
  540. SYMOPT_UNDNAME |
  541. SYMOPT_OMAP_FIND_NEAREST |
  542. SYMOPT_DEFERRED_LOADS |
  543. SYMOPT_AUTO_PUBLICS |
  544. SYMOPT_NO_IMAGE_SEARCH |
  545. SYMOPT_FAIL_CRITICAL_ERRORS |
  546. SYMOPT_NO_PROMPTS);
  547. // Process the ini file for the base settings.
  548. ReadIniFile(&g_CreateFlags);
  549. }
  550. g_DbgClient->GetOutputMask(&OutMask);
  551. // Now process command line arguments.
  552. while (g_Argc > 0)
  553. {
  554. if (!CheckMoreArgs || !Arg[1])
  555. {
  556. Arg = GetArg();
  557. if (Arg[0] != '-' && Arg[0] != '/')
  558. {
  559. // Put argument back.
  560. g_Argv--;
  561. g_Argc++;
  562. g_CmdPtr = g_PrevCmdPtr;
  563. break;
  564. }
  565. // -remote and -server must be the first
  566. // arguments. Check for them later to
  567. // give a specific error message.
  568. if (!_strcmpi(Arg, "-remote") ||
  569. !_strcmpi(Arg, "-server"))
  570. {
  571. ConOut("%s: %s must be the first argument\n",
  572. g_DebuggerName, Arg);
  573. ShowUsage = TRUE;
  574. break;
  575. }
  576. }
  577. CheckMoreArgs = FALSE;
  578. Arg++;
  579. switch(tolower(Arg[0]))
  580. {
  581. case '?':
  582. ShowUsage = TRUE;
  583. break;
  584. case 'a':
  585. ULONG64 Handle;
  586. g_DbgControl->AddExtension(Arg + 1, DEBUG_EXTENSION_AT_ENGINE,
  587. &Handle);
  588. break;
  589. case 'b':
  590. if (!_stricmp(Arg, "bonc"))
  591. {
  592. g_SetInterruptAfterStart = TRUE;
  593. break;
  594. }
  595. #ifdef KERNEL
  596. else
  597. {
  598. g_DbgControl->AddEngineOptions(DEBUG_ENGOPT_INITIAL_BREAK);
  599. if (g_RemoteClient)
  600. {
  601. // The engine may already be waiting so just ask
  602. // for a breakin immediately.
  603. g_DbgControl->SetInterrupt(DEBUG_INTERRUPT_ACTIVE);
  604. }
  605. CheckMoreArgs = TRUE;
  606. }
  607. #endif
  608. break;
  609. case 'c':
  610. if (!_stricmp(Arg, "clines"))
  611. {
  612. g_HistoryLines = atoi(GetArg());
  613. }
  614. else if (!_stricmp(Arg, "cf"))
  615. {
  616. g_InitialInputFile = GetArg();
  617. }
  618. else
  619. {
  620. g_InitialCommand = GetArg();
  621. }
  622. break;
  623. case 'e':
  624. if (!_stricmp(Arg, "ee"))
  625. {
  626. if (!g_DbgControl3)
  627. {
  628. goto BadSwitch;
  629. }
  630. if (g_DbgControl3->
  631. SetExpressionSyntaxByName(GetArg()) != S_OK)
  632. {
  633. goto BadSwitch;
  634. }
  635. }
  636. else
  637. {
  638. #ifndef KERNEL
  639. //
  640. // undocumented
  641. //
  642. if (g_RemoteClient)
  643. {
  644. goto BadSwitch;
  645. }
  646. if (g_EventToSignal)
  647. {
  648. ErrorExit("%s: Event to signal redefined\n",
  649. g_DebuggerName);
  650. }
  651. // event to signal takes decimal argument
  652. Arg = GetArg();
  653. sscanf(Arg, "%I64d", &g_EventToSignal);
  654. if (!g_EventToSignal)
  655. {
  656. ErrorExit("%s: bad EventToSignal '%s'\n",
  657. g_DebuggerName, Arg);
  658. }
  659. g_DbgControl->SetNotifyEventHandle(g_EventToSignal);
  660. break;
  661. #else
  662. goto BadSwitch;
  663. #endif
  664. }
  665. break;
  666. case 'f':
  667. if (!_stricmp(Arg, "failinc"))
  668. {
  669. g_DbgControl->
  670. AddEngineOptions(DEBUG_ENGOPT_FAIL_INCOMPLETE_INFORMATION);
  671. g_DbgSymbols->
  672. AddSymbolOptions(SYMOPT_EXACT_SYMBOLS);
  673. }
  674. else
  675. {
  676. goto BadSwitch;
  677. }
  678. break;
  679. case 'g':
  680. if (Arg[0] == 'g')
  681. {
  682. g_DbgControl->RemoveEngineOptions(DEBUG_ENGOPT_INITIAL_BREAK);
  683. }
  684. else
  685. {
  686. g_DbgControl->RemoveEngineOptions(DEBUG_ENGOPT_FINAL_BREAK);
  687. }
  688. CheckMoreArgs = TRUE;
  689. break;
  690. case 'i':
  691. if (!_stricmp(Arg, "isd"))
  692. {
  693. g_CreateFlags |= CREATE_IGNORE_SYSTEM_DEFAULT;
  694. }
  695. else
  696. {
  697. g_DbgSymbols->SetImagePath(GetArg());
  698. }
  699. break;
  700. case 'l':
  701. if (_stricmp(Arg, "lines") == 0)
  702. {
  703. g_DbgSymbols->AddSymbolOptions(SYMOPT_LOAD_LINES);
  704. }
  705. else if (!_stricmp(Arg, "loga") ||
  706. !_stricmp(Arg, "logo"))
  707. {
  708. g_DbgControl->OpenLogFile(GetArg(), Arg[3] == 'a');
  709. }
  710. else
  711. {
  712. goto BadSwitch;
  713. }
  714. break;
  715. case 'm':
  716. if (_stricmp(Arg, "myob") == 0)
  717. {
  718. g_DbgControl->
  719. AddEngineOptions(DEBUG_ENGOPT_IGNORE_DBGHELP_VERSION);
  720. }
  721. #ifdef KERNEL
  722. else if (Arg[1] == 0 && !g_RemoteClient)
  723. {
  724. g_ConnectOptions = "com:modem";
  725. }
  726. #endif
  727. else
  728. {
  729. goto BadSwitch;
  730. }
  731. break;
  732. case 'n':
  733. if (_strnicmp (Arg, "netsyms", 7) == 0)
  734. {
  735. //
  736. // undocumented
  737. // netsyms:{yes|no} allow or disallow loading symbols from a network path
  738. //
  739. Arg += 8; // skip over ':' as well.
  740. if (_stricmp (Arg, "no") == 0)
  741. {
  742. g_DbgControl->
  743. RemoveEngineOptions(DEBUG_ENGOPT_ALLOW_NETWORK_PATHS);
  744. g_DbgControl->
  745. AddEngineOptions(DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS);
  746. }
  747. else if (_stricmp (Arg, "yes") == 0)
  748. {
  749. g_DbgControl->RemoveEngineOptions
  750. (DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS);
  751. g_DbgControl->
  752. AddEngineOptions(DEBUG_ENGOPT_ALLOW_NETWORK_PATHS);
  753. }
  754. break;
  755. }
  756. else if (g_RemoteOptions != NULL && !g_RemoteClient &&
  757. !_stricmp(Arg, "noio"))
  758. {
  759. g_IoRequested = IO_NONE;
  760. }
  761. else if (!_stricmp(Arg, "noshell"))
  762. {
  763. g_DbgControl->
  764. AddEngineOptions(DEBUG_ENGOPT_DISALLOW_SHELL_COMMANDS);
  765. }
  766. else if (Arg[1] == 0)
  767. {
  768. g_DbgSymbols->AddSymbolOptions(SYMOPT_DEBUG);
  769. break;
  770. }
  771. else
  772. {
  773. goto BadSwitch;
  774. }
  775. break;
  776. case 'q':
  777. if (Arg[0] != 'Q' || Arg[1] != 'R')
  778. {
  779. goto BadSwitch;
  780. }
  781. Arg = GetArg();
  782. ConOut("Servers on %s:\n", Arg);
  783. if (g_DbgClient->OutputServers(DEBUG_OUTCTL_ALL_CLIENTS, Arg,
  784. DEBUG_SERVERS_ALL) != S_OK)
  785. {
  786. ConOut("Unable to query %s\n", Arg);
  787. }
  788. ExitDebugger(0);
  789. case 's':
  790. if (!_stricmp(Arg, "srcpath"))
  791. {
  792. g_DbgSymbols->SetSourcePath(GetArg());
  793. }
  794. else if (!_stricmp(Arg, "sdce"))
  795. {
  796. g_DbgSymbols->RemoveSymbolOptions(SYMOPT_FAIL_CRITICAL_ERRORS);
  797. }
  798. else if (!_stricmp(Arg, "secure"))
  799. {
  800. if (g_DbgSymbols->
  801. AddSymbolOptions(SYMOPT_SECURE) != S_OK)
  802. {
  803. ConOut("Unable to secure operation\n");
  804. ExitDebugger(0);
  805. }
  806. }
  807. else if (!_stricmp(Arg, "ses"))
  808. {
  809. g_DbgSymbols->AddSymbolOptions(SYMOPT_EXACT_SYMBOLS);
  810. }
  811. else if (!_stricmp(Arg, "sfce"))
  812. {
  813. g_DbgSymbols->AddSymbolOptions(SYMOPT_FAIL_CRITICAL_ERRORS);
  814. }
  815. else if (!_stricmp(Arg, "sflags"))
  816. {
  817. g_DbgSymbols->SetSymbolOptions(strtoul(GetArg(), NULL, 0));
  818. }
  819. else if (!_stricmp(Arg, "sicv"))
  820. {
  821. g_DbgSymbols->AddSymbolOptions(SYMOPT_IGNORE_CVREC);
  822. }
  823. else if (!_stricmp(Arg, "sins"))
  824. {
  825. g_DbgSymbols->AddSymbolOptions(SYMOPT_IGNORE_NT_SYMPATH);
  826. }
  827. else if (!_stricmp(Arg, "snc"))
  828. {
  829. g_DbgSymbols->AddSymbolOptions(SYMOPT_NO_CPP);
  830. }
  831. else if (!_stricmp(Arg, "snul"))
  832. {
  833. g_DbgSymbols->AddSymbolOptions(SYMOPT_NO_UNQUALIFIED_LOADS);
  834. }
  835. else if (!_stricmp(Arg, "sup"))
  836. {
  837. g_DbgSymbols->RemoveSymbolOptions(SYMOPT_AUTO_PUBLICS |
  838. SYMOPT_NO_PUBLICS);
  839. }
  840. else
  841. {
  842. g_DbgSymbols->RemoveSymbolOptions(SYMOPT_DEFERRED_LOADS);
  843. CheckMoreArgs = TRUE;
  844. }
  845. break;
  846. case 'v':
  847. OutMask |= DEBUG_OUTPUT_VERBOSE;
  848. g_DbgClient->SetOutputMask(OutMask);
  849. g_DbgControl->SetLogMask(OutMask);
  850. CheckMoreArgs = TRUE;
  851. break;
  852. case 'y':
  853. g_DbgSymbols->SetSymbolPath(GetArg());
  854. break;
  855. case 'z':
  856. if (g_RemoteClient)
  857. {
  858. goto BadSwitch;
  859. }
  860. if (Arg[1] == 'p')
  861. {
  862. if (g_NumDumpInfoFiles == MAX_DUMP_FILES)
  863. {
  864. ConOut("%s: Too many dump files, %s ignored\n",
  865. g_DebuggerName, GetArg());
  866. }
  867. else
  868. {
  869. g_DumpInfoFiles[g_NumDumpInfoFiles] =
  870. GetRawArg(!g_CanOpenUnicodeDump, NULL);
  871. g_DumpInfoTypes[g_NumDumpInfoFiles] =
  872. DEBUG_DUMP_FILE_PAGE_FILE_DUMP;
  873. g_NumDumpInfoFiles++;
  874. }
  875. }
  876. else if (Arg[1])
  877. {
  878. goto BadSwitch;
  879. }
  880. else
  881. {
  882. if (g_NumDumpFiles == MAX_DUMP_FILES)
  883. {
  884. ConOut("%s: Too many dump files, %s ignored\n",
  885. g_DebuggerName, GetArg());
  886. }
  887. else
  888. {
  889. g_DumpFiles[g_NumDumpFiles] =
  890. GetRawArg(!g_CanOpenUnicodeDump,
  891. &g_DumpFilesAnsi[g_NumDumpFiles]);
  892. g_NumDumpFiles++;
  893. }
  894. }
  895. break;
  896. #ifndef KERNEL
  897. case '2':
  898. if (g_RemoteClient)
  899. {
  900. goto BadSwitch;
  901. }
  902. g_CreateFlags |= CREATE_NEW_CONSOLE;
  903. break;
  904. case '-':
  905. if (g_RemoteClient)
  906. {
  907. goto BadSwitch;
  908. }
  909. // '--' is the equivalent of -G -g -o -p -1 -netsyms:no -d -pd
  910. if (g_PidToDebug || g_ProcNameToDebug != NULL)
  911. {
  912. ErrorExit("%s: attach process redefined\n", g_DebuggerName);
  913. }
  914. g_CreateFlags |= DEBUG_PROCESS;
  915. g_CreateFlags &= ~DEBUG_ONLY_THIS_PROCESS;
  916. g_DbgSymbols->AddSymbolOptions(SYMOPT_DEFERRED_LOADS);
  917. g_DbgControl->RemoveEngineOptions(DEBUG_ENGOPT_INITIAL_BREAK |
  918. DEBUG_ENGOPT_FINAL_BREAK);
  919. g_IoRequested = IO_DEBUG;
  920. g_PidToDebug = CSRSS_PROCESS_ID;
  921. g_ProcNameToDebug = NULL;
  922. g_DetachOnExitImplied = TRUE;
  923. break;
  924. case 'd':
  925. if (!g_RemoteClient &&
  926. !_stricmp(Arg, "ddefer"))
  927. {
  928. g_IoRequested = IO_DEBUG_DEFER;
  929. break;
  930. }
  931. if (g_RemoteOptions != NULL)
  932. {
  933. ErrorExit("%s: Cannot use -d with debugger remoting\n",
  934. g_DebuggerName);
  935. }
  936. g_IoRequested = IO_DEBUG;
  937. CheckMoreArgs = TRUE;
  938. break;
  939. case 'h':
  940. if (Arg[1] == 'd')
  941. {
  942. g_CreateFlags |= DEBUG_CREATE_PROCESS_NO_DEBUG_HEAP;
  943. }
  944. else
  945. {
  946. goto BadSwitch;
  947. }
  948. break;
  949. case 'o':
  950. if (g_RemoteClient)
  951. {
  952. goto BadSwitch;
  953. }
  954. g_CreateFlags |= DEBUG_PROCESS;
  955. g_CreateFlags &= ~DEBUG_ONLY_THIS_PROCESS;
  956. CheckMoreArgs = TRUE;
  957. break;
  958. case 'p':
  959. if (g_RemoteClient)
  960. {
  961. goto BadSwitch;
  962. }
  963. if (!_stricmp(Arg, "premote"))
  964. {
  965. g_ProcessServer = GetArg();
  966. break;
  967. }
  968. else if (Arg[1] == 'b')
  969. {
  970. g_AttachProcessFlags |= DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK;
  971. break;
  972. }
  973. else if (Arg[1] == 'd')
  974. {
  975. g_DetachOnExitRequired = TRUE;
  976. break;
  977. }
  978. else if (Arg[1] == 'e')
  979. {
  980. g_AttachProcessFlags = DEBUG_ATTACH_EXISTING;
  981. break;
  982. }
  983. else if (Arg[1] == 'r')
  984. {
  985. g_AttachProcessFlags |= DEBUG_ATTACH_INVASIVE_RESUME_PROCESS;
  986. break;
  987. }
  988. else if (Arg[1] == 't')
  989. {
  990. g_DbgControl->SetInterruptTimeout(atoi(GetArg()));
  991. break;
  992. }
  993. else if (Arg[1] == 'v')
  994. {
  995. g_AttachProcessFlags = DEBUG_ATTACH_NONINVASIVE;
  996. if (Arg[2] == 'r')
  997. {
  998. g_AttachProcessFlags |=
  999. DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND;
  1000. }
  1001. break;
  1002. }
  1003. if (g_PidToDebug || g_ProcNameToDebug != NULL)
  1004. {
  1005. ErrorExit("%s: attach process redefined\n", g_DebuggerName);
  1006. }
  1007. if (Arg[1] == 'n')
  1008. {
  1009. // Process name.
  1010. g_ProcNameToDebug = GetArg();
  1011. g_PidToDebug = 0;
  1012. }
  1013. else
  1014. {
  1015. // pid debug takes decimal argument
  1016. g_ProcNameToDebug = NULL;
  1017. Arg = GetArg();
  1018. if (Arg[0] == '-' && Arg[1] == '1' && Arg[2] == 0)
  1019. {
  1020. g_IoRequested = IO_DEBUG;
  1021. g_PidToDebug = CSRSS_PROCESS_ID;
  1022. }
  1023. else
  1024. {
  1025. PSTR End;
  1026. if (Arg[0] == '0' &&
  1027. (Arg[1] == 'x' || Arg[1] == 'X'))
  1028. {
  1029. g_PidToDebug = strtoul(Arg, &End, 0);
  1030. }
  1031. else
  1032. {
  1033. g_PidToDebug = strtoul(Arg, &End, 10);
  1034. }
  1035. }
  1036. if (!g_PidToDebug)
  1037. {
  1038. ErrorExit("%s: bad pid '%s'\n", g_DebuggerName, Arg);
  1039. }
  1040. }
  1041. break;
  1042. case 'r':
  1043. if (!_stricmp(Arg, "robp"))
  1044. {
  1045. g_DbgControl->
  1046. AddEngineOptions(DEBUG_ENGOPT_ALLOW_READ_ONLY_BREAKPOINTS);
  1047. break;
  1048. }
  1049. else if (!_stricmp(Arg, "rtl"))
  1050. {
  1051. g_CreateFlags |= DEBUG_CREATE_PROCESS_THROUGH_RTL;
  1052. break;
  1053. }
  1054. else if (Arg[1] != 0)
  1055. {
  1056. goto BadSwitch;
  1057. }
  1058. // Rip flags takes single-char decimal argument
  1059. Arg = GetArg();
  1060. SystemErrorBreak = strtoul(Arg, &Arg, 10);
  1061. if (SystemErrorBreak > 3)
  1062. {
  1063. ErrorExit("%s: bad Rip level '%ld'\n",
  1064. g_DebuggerName, SystemErrorBreak);
  1065. SystemErrorBreak = 0;
  1066. }
  1067. else
  1068. {
  1069. SystemErrorOutput = SystemErrorBreak;
  1070. }
  1071. g_DbgControl->SetSystemErrorControl(SystemErrorOutput,
  1072. SystemErrorBreak);
  1073. break;
  1074. case 't':
  1075. // Rip flags takes single-char decimal argument
  1076. Arg = GetArg();
  1077. SystemErrorOutput = strtoul(Arg, &Arg, 10);
  1078. if (SystemErrorOutput > 3)
  1079. {
  1080. ErrorExit("%s: bad Rip level '%ld'\n",
  1081. g_DebuggerName, SystemErrorOutput);
  1082. SystemErrorOutput = 0;
  1083. }
  1084. g_DbgControl->SetSystemErrorControl(SystemErrorOutput,
  1085. SystemErrorBreak);
  1086. break;
  1087. case 'x':
  1088. if (Arg[1] == 0)
  1089. {
  1090. g_DbgControl->Execute(DEBUG_OUTCTL_IGNORE, "sxd av",
  1091. DEBUG_EXECUTE_NOT_LOGGED);
  1092. }
  1093. else
  1094. {
  1095. // Turn "-x. arg" into "sx. arg" and execute
  1096. // it to update the engine state.
  1097. ExecuteCmd("sx", Arg[1], ' ', GetArg());
  1098. }
  1099. break;
  1100. case 'w':
  1101. if (!_stricmp(Arg, "wake"))
  1102. {
  1103. ULONG Pid = strtoul(GetArg(), &Arg, 10);
  1104. if (!SetPidEvent(Pid, OPEN_EXISTING))
  1105. {
  1106. ErrorExit("Process %d is not a sleeping debugger\n", Pid);
  1107. }
  1108. else
  1109. {
  1110. ExitDebugger(0);
  1111. }
  1112. }
  1113. if (g_RemoteClient)
  1114. {
  1115. goto BadSwitch;
  1116. }
  1117. g_CreateFlags |= CREATE_SEPARATE_WOW_VDM;
  1118. CheckMoreArgs = TRUE;
  1119. break;
  1120. #else // #ifndef KERNEL
  1121. case 'd':
  1122. g_DbgControl->AddEngineOptions(DEBUG_ENGOPT_INITIAL_MODULE_BREAK);
  1123. CheckMoreArgs = TRUE;
  1124. break;
  1125. case 'k':
  1126. if (tolower(Arg[1]) == 'l')
  1127. {
  1128. g_AttachKernelFlags = DEBUG_ATTACH_LOCAL_KERNEL;
  1129. }
  1130. else if (tolower(Arg[1]) == 'x')
  1131. {
  1132. g_AttachKernelFlags = DEBUG_ATTACH_EXDI_DRIVER;
  1133. g_ConnectOptions = GetArg();
  1134. }
  1135. else
  1136. {
  1137. g_ConnectOptions = GetArg();
  1138. }
  1139. break;
  1140. case 'p':
  1141. goto BadSwitch;
  1142. case 'r':
  1143. OutMask ^= DEBUG_OUTPUT_PROMPT_REGISTERS;
  1144. g_DbgClient->SetOutputMask(OutMask);
  1145. g_DbgControl->SetLogMask(OutMask);
  1146. CheckMoreArgs = TRUE;
  1147. break;
  1148. case 'w':
  1149. if (!_stricmp(Arg, "wake"))
  1150. {
  1151. ULONG Pid = strtoul(GetArg(), &Arg, 10);
  1152. if (!SetPidEvent(Pid, OPEN_EXISTING))
  1153. {
  1154. ErrorExit("Process %d is not a sleeping debugger\n", Pid);
  1155. }
  1156. else
  1157. {
  1158. ExitDebugger(0);
  1159. }
  1160. }
  1161. goto BadSwitch;
  1162. case 'x':
  1163. g_DbgControl->AddEngineOptions(DEBUG_ENGOPT_INITIAL_BREAK);
  1164. g_InitialCommand = "eb nt!NtGlobalFlag 9;g";
  1165. CheckMoreArgs = TRUE;
  1166. break;
  1167. #endif // #ifndef KERNEL
  1168. default:
  1169. BadSwitch:
  1170. ConOut("%s: Invalid switch '%c'\n", g_DebuggerName, Arg[0]);
  1171. ShowUsage = TRUE;
  1172. break;
  1173. }
  1174. }
  1175. #ifndef KERNEL
  1176. if (g_RemoteClient)
  1177. {
  1178. if (g_Argc > 0)
  1179. {
  1180. ShowUsage = TRUE;
  1181. }
  1182. }
  1183. else if (g_Argc > 0)
  1184. {
  1185. // Assume remaining arguments are a process execution
  1186. // command line.
  1187. g_CommandLinePtr = g_CmdPtr;
  1188. }
  1189. else if ((g_PidToDebug == 0) && (g_ProcNameToDebug == NULL) &&
  1190. (g_NumDumpFiles == 0))
  1191. {
  1192. // User-mode debuggers require a dump file,
  1193. // process attachment or created process.
  1194. ShowUsage = TRUE;
  1195. }
  1196. #else
  1197. if (g_Argc > 0)
  1198. {
  1199. // Kernel debuggers can't start user-mode processes.
  1200. ShowUsage = TRUE;
  1201. }
  1202. #endif
  1203. if (ShowUsage)
  1204. {
  1205. Usage();
  1206. ErrorExit(NULL);
  1207. }
  1208. }
  1209. int
  1210. __cdecl
  1211. main (
  1212. int Argc,
  1213. PCHAR* Argv
  1214. )
  1215. {
  1216. HRESULT Hr;
  1217. PVOID CmdPtr;
  1218. MakeHelpFileName("debugger.chm");
  1219. CmdPtr = GetCommandLineW();
  1220. if (CmdPtr)
  1221. {
  1222. g_CommandLineCharSize = sizeof(WCHAR);
  1223. }
  1224. else
  1225. {
  1226. CmdPtr = GetCommandLineA();
  1227. g_CommandLineCharSize = sizeof(CHAR);
  1228. }
  1229. ParseCommandLine(Argc, Argv, CmdPtr);
  1230. InitializeIo(g_InitialInputFile);
  1231. #ifndef KERNEL
  1232. if (g_NumDumpFiles == 0)
  1233. {
  1234. // Increase the priority for live debugging so
  1235. // that the debugger is responsive for break-in.
  1236. SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
  1237. }
  1238. #endif
  1239. g_IoMode = g_IoRequested;
  1240. switch(g_IoMode)
  1241. {
  1242. case IO_DEBUG:
  1243. case IO_DEBUG_DEFER:
  1244. if (g_DbgClient2 != NULL)
  1245. {
  1246. if (g_DbgClient2->IsKernelDebuggerEnabled() != S_OK)
  1247. {
  1248. Usage();
  1249. ErrorExit(NULL);
  1250. }
  1251. }
  1252. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  1253. break;
  1254. case IO_CONSOLE:
  1255. CreateConsole();
  1256. break;
  1257. }
  1258. if (g_IoMode != IO_NONE)
  1259. {
  1260. // XXX drewb - Win9x doesn't support named pipes so
  1261. // the separate input thread currently can't be used.
  1262. // This makes remoting work very poorly and so should
  1263. // be fixed by creating a simple internal pipe implementation.
  1264. if (g_PlatformId == VER_PLATFORM_WIN32_NT)
  1265. {
  1266. // Don't bother creating a separate thread for non-remoted
  1267. // ntsd and cdb. This avoids problems with .remote
  1268. // and multiple threads reading the console.
  1269. #ifndef KERNEL
  1270. if (g_RemoteOptions != NULL)
  1271. #endif
  1272. {
  1273. CreateInputThread();
  1274. }
  1275. }
  1276. else if (g_RemoteOptions != NULL)
  1277. {
  1278. ErrorExit("Remoting with I/O is "
  1279. "not currently supported on Win9x\n");
  1280. }
  1281. }
  1282. if (!g_RemoteClient)
  1283. {
  1284. if (g_RemoteOptions)
  1285. {
  1286. ConOut("Server started with '%s'\n", g_RemoteOptions);
  1287. }
  1288. InitializeSession();
  1289. }
  1290. else
  1291. {
  1292. ConOut("Connected to server with '%s'\n", g_RemoteOptions);
  1293. // Use a heuristic of 45 characters per line.
  1294. g_DbgClient->ConnectSession(DEBUG_CONNECT_SESSION_DEFAULT,
  1295. g_HistoryLines * 45);
  1296. }
  1297. if (g_SetInterruptAfterStart)
  1298. {
  1299. g_DbgControl->SetInterrupt(DEBUG_INTERRUPT_ACTIVE);
  1300. }
  1301. ULONG Code = S_OK;
  1302. if (MainLoop())
  1303. {
  1304. // The session ended so return the exit code of the
  1305. // last process that exited.
  1306. Code = g_LastProcessExitCode;
  1307. }
  1308. ExitDebugger(Code);
  1309. return Code;
  1310. }