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.

1796 lines
46 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Handles stepping, tracing and go.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997-2002.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "ntsdp.hpp"
  9. #define DBG_KWT 0
  10. #define DBG_UWT 0
  11. Breakpoint* g_GoBreakpoints[MAX_GO_BPS];
  12. ULONG g_NumGoBreakpoints;
  13. // Pass count of trace breakpoint.
  14. ULONG g_StepTracePassCount;
  15. ULONG64 g_StepTraceInRangeStart = (ULONG64)-1;
  16. ULONG64 g_StepTraceInRangeEnd;
  17. BOOL g_StepTraceToCall;
  18. IMAGEHLP_LINE64 g_SrcLine; // Current source line for step/trace
  19. BOOL g_SrcLineValid; // Validity of SrcLine information
  20. BOOL g_WatchTrace;
  21. BOOL g_WatchWhole;
  22. ADDR g_WatchTarget;
  23. ULONG64 g_WatchInitialSP;
  24. ULONG64 g_WatchBeginCurFunc = 1;
  25. ULONG64 g_WatchEndCurFunc;
  26. WatchFunctions g_WatchFunctions;
  27. void
  28. ResetStepTrace(void)
  29. {
  30. g_WatchBeginCurFunc = 1;
  31. g_WatchEndCurFunc = 0;
  32. g_WatchTrace = FALSE;
  33. g_WatchInitialSP = 0;
  34. g_StepTraceInRangeStart = (ULONG64)-1;
  35. g_StepTraceInRangeEnd = 0;
  36. g_StepTraceToCall = FALSE;
  37. }
  38. //----------------------------------------------------------------------------
  39. //
  40. // WatchFunctions.
  41. //
  42. //----------------------------------------------------------------------------
  43. WatchFunctions::WatchFunctions(void)
  44. {
  45. m_Started = FALSE;
  46. SetDefaultParameters();
  47. }
  48. void
  49. WatchFunctions::Start(void)
  50. {
  51. ULONG i;
  52. m_TotalInstr = 0;
  53. m_TotalWatchTraceEvents = 0;
  54. m_TotalWatchThreadMismatches = 0;
  55. for (i = 0; i < WF_BUCKETS; i++)
  56. {
  57. m_Funcs[i] = NULL;
  58. }
  59. m_Sorted = NULL;
  60. m_CallTop = NULL;
  61. m_CallBot = NULL;
  62. m_CallLevel = 0;
  63. m_Started = TRUE;
  64. }
  65. void
  66. WatchFunctions::End(PADDR PcAddr)
  67. {
  68. g_StepTracePassCount = 0;
  69. g_EngStatus &= ~ENG_STATUS_USER_INTERRUPT;
  70. g_Target->ClearBreakIn();
  71. if (!m_Started)
  72. {
  73. return;
  74. }
  75. ULONG TotalInstr;
  76. if (IS_KERNEL_TARGET(g_Target))
  77. {
  78. PDBGKD_TRACE_DATA td = (PDBGKD_TRACE_DATA)g_StateChangeData;
  79. if (g_WatchWhole)
  80. {
  81. if (td[1].s.Instructions == TRACE_DATA_INSTRUCTIONS_BIG)
  82. {
  83. TotalInstr = td[2].LongNumber;
  84. }
  85. else
  86. {
  87. TotalInstr = td[1].s.Instructions;
  88. }
  89. }
  90. else
  91. {
  92. BOOL StepOver;
  93. if (PcAddr != NULL)
  94. {
  95. g_Target->ProcessWatchTraceEvent(td, PcAddr, &StepOver);
  96. }
  97. while (m_CallTop != NULL)
  98. {
  99. PopCall();
  100. }
  101. TotalInstr = m_TotalInstr;
  102. }
  103. g_BreakpointsSuspended = FALSE;
  104. g_WatchInitialSP = 0;
  105. }
  106. else
  107. {
  108. if (m_CallTop != NULL)
  109. {
  110. OutputCall(m_CallTop, WCALL_OTHER);
  111. }
  112. while (m_CallTop != NULL)
  113. {
  114. PopCall();
  115. }
  116. TotalInstr = m_TotalInstr;
  117. if (m_OutputCalls)
  118. {
  119. dprintf("\n");
  120. }
  121. }
  122. m_Started = FALSE;
  123. if (m_OutputSummary)
  124. {
  125. dprintf("%d instructions were executed in %d events "
  126. "(%d from other threads)\n",
  127. TotalInstr,
  128. m_TotalWatchTraceEvents,
  129. m_TotalWatchThreadMismatches);
  130. if (!g_WatchWhole)
  131. {
  132. OutputFunctions();
  133. }
  134. if (!IS_KERNEL_TARGET(g_Target))
  135. {
  136. OutputSysCallFunctions();
  137. }
  138. dprintf("\n");
  139. }
  140. Clear();
  141. }
  142. void
  143. WatchFunctions::OutputFunctions(void)
  144. {
  145. WatchFunction* Func;
  146. dprintf("\n%-43.43s Invocations MinInst MaxInst AvgInst\n",
  147. "Function Name");
  148. for (Func = m_Sorted; Func != NULL; Func = Func->Sort)
  149. {
  150. dprintf("%-47.47s%8d%8d%8d%8d\n",
  151. Func->Symbol, Func->Calls,
  152. Func->MinInstr, Func->MaxInstr,
  153. Func->Calls ? Func->TotalInstr / Func->Calls : 0);
  154. }
  155. }
  156. void
  157. WatchFunctions::OutputSysCallFunctions(void)
  158. {
  159. WatchFunction* Func;
  160. ULONG TotalSysCalls = 0;
  161. for (Func = m_Sorted; Func != NULL; Func = Func->Sort)
  162. {
  163. TotalSysCalls += Func->SystemCalls;
  164. }
  165. if (TotalSysCalls == 1)
  166. {
  167. dprintf("\n%d system call was executed\n", TotalSysCalls);
  168. }
  169. else
  170. {
  171. dprintf("\n%d system calls were executed\n", TotalSysCalls);
  172. }
  173. if (TotalSysCalls == 0)
  174. {
  175. return;
  176. }
  177. dprintf("\nCalls System Call\n");
  178. for (Func = m_Sorted; Func != NULL; Func = Func->Sort)
  179. {
  180. if (Func->SystemCalls > 0)
  181. {
  182. dprintf("%5d %s\n", Func->SystemCalls, Func->Symbol);
  183. }
  184. }
  185. }
  186. WatchFunction*
  187. WatchFunctions::FindAlways(PSTR Sym, ULONG64 Start)
  188. {
  189. WatchFunction* Func = Find(Sym);
  190. if (Func == NULL)
  191. {
  192. Func = Add(Sym, Start);
  193. }
  194. return Func;
  195. }
  196. WatchCallStack*
  197. WatchFunctions::PushCall(WatchFunction* Func)
  198. {
  199. WatchCallStack* Call = new WatchCallStack;
  200. if (Call != NULL)
  201. {
  202. ZeroMemory(Call, sizeof(*Call));
  203. Call->Prev = m_CallTop;
  204. Call->Next = NULL;
  205. if (m_CallTop == NULL)
  206. {
  207. m_CallBot = Call;
  208. }
  209. else
  210. {
  211. m_CallTop->Next = Call;
  212. m_CallLevel++;
  213. }
  214. m_CallTop = Call;
  215. Call->Func = Func;
  216. Call->Level = m_CallLevel;
  217. }
  218. return Call;
  219. }
  220. void
  221. WatchFunctions::PopCall(void)
  222. {
  223. if (m_CallTop == NULL)
  224. {
  225. return;
  226. }
  227. WatchCallStack* Call = m_CallTop;
  228. if (Call->Prev != NULL)
  229. {
  230. Call->Prev->Next = Call->Next;
  231. }
  232. else
  233. {
  234. m_CallBot = Call->Next;
  235. }
  236. if (Call->Next != NULL)
  237. {
  238. Call->Next->Prev = Call->Prev;
  239. }
  240. else
  241. {
  242. m_CallTop = Call->Prev;
  243. }
  244. m_CallLevel = m_CallTop != NULL ? m_CallTop->Level : 0;
  245. ReuseCall(Call, NULL);
  246. delete Call;
  247. }
  248. #define MAXPCOFFSET 10
  249. WatchCallStack*
  250. WatchFunctions::PopCallsToCallSite(PADDR Pc)
  251. {
  252. WatchCallStack* Call = m_CallTop;
  253. while (Call != NULL)
  254. {
  255. if ((Flat(*Pc) - Flat(Call->CallSite)) < MAXPCOFFSET)
  256. {
  257. break;
  258. }
  259. Call = Call->Prev;
  260. }
  261. if (Call == NULL)
  262. {
  263. // No matching call site found.
  264. return NULL;
  265. }
  266. // Pop off calls above the call site.
  267. while (m_CallTop != Call)
  268. {
  269. PopCall();
  270. }
  271. return m_CallTop;
  272. }
  273. WatchCallStack*
  274. WatchFunctions::PopCallsToFunctionStart(ULONG64 Start)
  275. {
  276. WatchCallStack* Call = m_CallTop;
  277. while (Call != NULL)
  278. {
  279. if (Start == Call->Func->StartOffset)
  280. {
  281. break;
  282. }
  283. Call = Call->Prev;
  284. }
  285. if (Call == NULL)
  286. {
  287. // No matching calling function found.
  288. return NULL;
  289. }
  290. // Pop off calls above the calling function.
  291. while (m_CallTop != Call)
  292. {
  293. PopCall();
  294. }
  295. return m_CallTop;
  296. }
  297. void
  298. WatchFunctions::ReuseCall(WatchCallStack* Call,
  299. WatchFunction* ReinitFunc)
  300. {
  301. if (Call->Prev != NULL)
  302. {
  303. Call->Prev->ChildInstrCount +=
  304. Call->InstrCount + Call->ChildInstrCount;
  305. }
  306. WatchFunction* Func = Call->Func;
  307. if (Func != NULL)
  308. {
  309. Func->Calls++;
  310. Func->TotalInstr += Call->InstrCount;
  311. m_TotalInstr += Call->InstrCount;
  312. if (Func->MinInstr > Call->InstrCount)
  313. {
  314. Func->MinInstr = Call->InstrCount;
  315. }
  316. if (Func->MaxInstr < Call->InstrCount)
  317. {
  318. Func->MaxInstr = Call->InstrCount;
  319. }
  320. }
  321. ZeroMemory(&Call->CallSite, sizeof(Call->CallSite));
  322. Call->Func = ReinitFunc;
  323. Call->Level = m_CallLevel;
  324. Call->InstrCount = 0;
  325. Call->ChildInstrCount = 0;
  326. }
  327. #define MAX_INDENT_LEVEL 50
  328. void
  329. WatchFunctions::IndentForCall(WatchCallStack* Call)
  330. {
  331. LONG i;
  332. if (Call->Level < MAX_INDENT_LEVEL)
  333. {
  334. for (i = 0; i < Call->Level; i++)
  335. {
  336. dprintf(" ");
  337. }
  338. }
  339. else
  340. {
  341. for (i = 0; i < MAX_INDENT_LEVEL + 1; i++)
  342. {
  343. dprintf(" ");
  344. }
  345. }
  346. }
  347. void
  348. WatchFunctions::OutputCall(WatchCallStack* Call, WATCH_CALL_TYPE Type)
  349. {
  350. if (!m_OutputCalls)
  351. {
  352. return;
  353. }
  354. dprintf("%5ld %5ld [%3ld]", Call->InstrCount, Call->ChildInstrCount,
  355. Call->Level);
  356. IndentForCall(Call);
  357. dprintf(" %s", Call->Func->Symbol);
  358. if (Type == WCALL_RETURN && m_OutputReturnValues)
  359. {
  360. dprintf(" %s = %s",
  361. RegNameFromIndex(g_Machine->m_RetRegIndex),
  362. FormatDisp64(g_Machine->GetRetReg()));
  363. }
  364. else if (Type == WCALL_CALL && m_OutputCallAddrs)
  365. {
  366. dprintf("\n ");
  367. IndentForCall(Call);
  368. dprintf(" call at ");
  369. dprintAddr(&Call->CallSite);
  370. OutputLineAddr(Flat(Call->CallSite), "[%s @ %d]");
  371. }
  372. dprintf("\n");
  373. }
  374. void
  375. WatchFunctions::SetDefaultParameters(void)
  376. {
  377. m_MaxCallLevelAllowed = 0x7fffffff;
  378. m_OutputReturnValues = FALSE;
  379. m_OutputCallAddrs = FALSE;
  380. m_OutputCalls = TRUE;
  381. m_OutputSummary = TRUE;
  382. }
  383. void
  384. WatchFunctions::ParseParameters(void)
  385. {
  386. SetDefaultParameters();
  387. while (PeekChar() == '-' || *g_CurCmd == '/')
  388. {
  389. g_CurCmd++;
  390. switch(*g_CurCmd)
  391. {
  392. case 'l':
  393. if (IS_KERNEL_TARGET(g_Target))
  394. {
  395. error(SESSIONNOTSUP);
  396. }
  397. g_CurCmd++;
  398. m_MaxCallLevelAllowed = (LONG)GetExpression();
  399. break;
  400. case 'n':
  401. g_CurCmd++;
  402. switch(*g_CurCmd)
  403. {
  404. case 'c':
  405. m_OutputCalls = FALSE;
  406. break;
  407. case 's':
  408. m_OutputSummary = FALSE;
  409. break;
  410. default:
  411. ErrOut("Unknown -n option '%c'\n", *g_CurCmd);
  412. break;
  413. }
  414. g_CurCmd++;
  415. break;
  416. case 'o':
  417. g_CurCmd++;
  418. switch(*g_CurCmd)
  419. {
  420. case 'a':
  421. if (IS_KERNEL_TARGET(g_Target))
  422. {
  423. error(SESSIONNOTSUP);
  424. }
  425. m_OutputCallAddrs = TRUE;
  426. break;
  427. case 'r':
  428. if (IS_KERNEL_TARGET(g_Target))
  429. {
  430. error(SESSIONNOTSUP);
  431. }
  432. m_OutputReturnValues = TRUE;
  433. break;
  434. default:
  435. ErrOut("Unknown -o option '%c'\n", *g_CurCmd);
  436. break;
  437. }
  438. g_CurCmd++;
  439. break;
  440. default:
  441. ErrOut("Unknown option '%c'\n", *g_CurCmd);
  442. g_CurCmd++;
  443. break;
  444. }
  445. }
  446. }
  447. WatchFunction*
  448. WatchFunctions::Add(PSTR Sym, ULONG64 Start)
  449. {
  450. WatchFunction* Func = new WatchFunction;
  451. if (Func == NULL)
  452. {
  453. return NULL;
  454. }
  455. ZeroMemory(Func, sizeof(*Func));
  456. Func->StartOffset = Start;
  457. Func->MinInstr = -1;
  458. Func->SymbolLength = strlen(Sym);
  459. CopyString(Func->Symbol, Sym, DIMA(Func->Symbol));
  460. //
  461. // Add into appropriate hash bucket.
  462. //
  463. // Hash under full name as that's what searches will
  464. // hash with.
  465. int Bucket = Hash(Sym, Func->SymbolLength);
  466. Func->Next = m_Funcs[Bucket];
  467. m_Funcs[Bucket] = Func;
  468. //
  469. // Add into sorted list.
  470. //
  471. WatchFunction* Cur, *Prev;
  472. Prev = NULL;
  473. for (Cur = m_Sorted; Cur != NULL; Cur = Cur->Sort)
  474. {
  475. if (strcmp(Func->Symbol, Cur->Symbol) <= 0)
  476. {
  477. break;
  478. }
  479. Prev = Cur;
  480. }
  481. Func->Sort = Cur;
  482. if (Prev == NULL)
  483. {
  484. m_Sorted = Func;
  485. }
  486. else
  487. {
  488. Prev->Sort = Func;
  489. }
  490. return Func;
  491. }
  492. WatchFunction*
  493. WatchFunctions::Find(PSTR Sym)
  494. {
  495. int SymLen = strlen(Sym);
  496. int Bucket = Hash(Sym, SymLen);
  497. WatchFunction* Func = m_Funcs[Bucket];
  498. while (Func != NULL)
  499. {
  500. if (SymLen == Func->SymbolLength &&
  501. !strncmp(Sym, Func->Symbol, sizeof(Func->Symbol) - 1))
  502. {
  503. break;
  504. }
  505. Func = Func->Next;
  506. }
  507. return Func;
  508. }
  509. void
  510. WatchFunctions::Clear(void)
  511. {
  512. ULONG i;
  513. for (i = 0; i < WF_BUCKETS; i++)
  514. {
  515. WatchFunction* Func;
  516. while (m_Funcs[i] != NULL)
  517. {
  518. Func = m_Funcs[i]->Next;
  519. delete m_Funcs[i];
  520. m_Funcs[i] = Func;
  521. }
  522. }
  523. m_Sorted = NULL;
  524. }
  525. //----------------------------------------------------------------------------
  526. //
  527. // TargetInfo watch trace methods.
  528. //
  529. //----------------------------------------------------------------------------
  530. HRESULT
  531. TargetInfo::InitializeTargetControlledStepping(void)
  532. {
  533. // Nothing to do.
  534. return S_OK;
  535. }
  536. //----------------------------------------------------------------------------
  537. //
  538. // ConnLiveKernelTargetInfo watch trace methods.
  539. //
  540. //----------------------------------------------------------------------------
  541. typedef struct _TRACE_DATA_SYM
  542. {
  543. ULONG64 SymMin;
  544. ULONG64 SymMax;
  545. } TRACE_DATA_SYM, *PTRACE_DATA_SYM;
  546. TRACE_DATA_SYM TraceDataSyms[256];
  547. UCHAR NextTraceDataSym = 0; // what's the next one to be replaced
  548. UCHAR NumTraceDataSyms = 0; // how many are valid?
  549. HRESULT
  550. ConnLiveKernelTargetInfo::InitializeTargetControlledStepping(void)
  551. {
  552. ULONG64 SpecialCalls[10];
  553. PULONG64 Call = SpecialCalls;
  554. g_SrcLineValid = FALSE;
  555. g_StepTracePassCount = 0xfffffffe;
  556. // Set the special calls (overkill, once per boot
  557. // would be enough, but this is easier).
  558. if (!GetOffsetFromSym(m_ProcessHead,
  559. "hal!KfLowerIrql", Call, NULL) &&
  560. !GetOffsetFromSym(m_ProcessHead,
  561. "hal!KeLowerIrql", Call, NULL))
  562. {
  563. ErrOut("Cannot find hal!KfLowerIrql/KeLowerIrql\n");
  564. }
  565. else
  566. {
  567. Call++;
  568. }
  569. if (!GetOffsetFromSym(m_ProcessHead,
  570. "hal!KfReleaseSpinLock", Call, NULL) &&
  571. !GetOffsetFromSym(m_ProcessHead,
  572. "hal!KeReleaseSpinLock", Call, NULL))
  573. {
  574. ErrOut("Cannot find hal!KfReleaseSpinLock/KeReleaseSpinLock\n");
  575. }
  576. else
  577. {
  578. Call++;
  579. }
  580. #define GetSymWithErr(s) \
  581. if (!GetOffsetFromSym(m_ProcessHead, \
  582. s, Call, NULL)) \
  583. { \
  584. ErrOut("Cannot find " s "\n"); \
  585. } \
  586. else \
  587. { \
  588. Call++; \
  589. }
  590. GetSymWithErr("hal!HalRequestSoftwareInterrupt");
  591. if (g_Target->m_SystemVersion >= NT_SVER_W2K)
  592. {
  593. GetSymWithErr("hal!ExReleaseFastMutex");
  594. GetSymWithErr("hal!KeReleaseQueuedSpinLock");
  595. if (m_SystemVersion >= NT_SVER_XP)
  596. {
  597. GetSymWithErr("hal!KeReleaseInStackQueuedSpinLock");
  598. }
  599. }
  600. GetSymWithErr("nt!SwapContext");
  601. GetSymWithErr("nt!KiCallUserMode");
  602. // Removed in .NET server
  603. if (m_SystemVersion < NT_SVER_NET_SERVER)
  604. {
  605. GetSymWithErr("nt!KiUnlockDispatcherDatabase");
  606. }
  607. DBG_ASSERT((ULONG)(Call - SpecialCalls) <=
  608. sizeof(SpecialCalls) / sizeof(SpecialCalls[0]));
  609. DBGKD_MANIPULATE_STATE64 m;
  610. m.ApiNumber = DbgKdClearSpecialCallsApi;
  611. m.ReturnStatus = STATUS_PENDING;
  612. m_Transport->WritePacket(&m, sizeof(m),
  613. PACKET_TYPE_KD_STATE_MANIPULATE,
  614. NULL, 0);
  615. InvalidateMemoryCaches(FALSE);
  616. PULONG64 Send = SpecialCalls;
  617. while (Send < Call)
  618. {
  619. m.ApiNumber = DbgKdSetSpecialCallApi;
  620. m.ReturnStatus = STATUS_PENDING;
  621. m.u.SetSpecialCall.SpecialCall = *Send++;
  622. m_Transport->WritePacket(&m, sizeof(m),
  623. PACKET_TYPE_KD_STATE_MANIPULATE,
  624. NULL, 0);
  625. }
  626. KdOut("DbgKdSetSpecialCalls returns 0x00000000\n");
  627. return S_OK;
  628. }
  629. void
  630. ConnLiveKernelTargetInfo::InitializeWatchTrace(void)
  631. {
  632. ADDR SpAddr;
  633. g_Machine->GetSP(&SpAddr);
  634. g_WatchInitialSP = Flat(SpAddr);
  635. g_BreakpointsSuspended = TRUE;
  636. NextTraceDataSym = 0;
  637. NumTraceDataSyms = 0;
  638. }
  639. LONG
  640. SymNumFor(ULONG64 Pc)
  641. {
  642. long index;
  643. for ( index = 0; index < NumTraceDataSyms; index++ )
  644. {
  645. if ( (TraceDataSyms[index].SymMin <= Pc) &&
  646. (TraceDataSyms[index].SymMax > Pc) )
  647. {
  648. return index;
  649. }
  650. }
  651. return -1;
  652. }
  653. VOID
  654. PotentialNewSymbol(ULONG64 Pc)
  655. {
  656. if ( -1 != SymNumFor(Pc) )
  657. {
  658. return; // we've already seen this one
  659. }
  660. TraceDataSyms[NextTraceDataSym].SymMin = g_WatchBeginCurFunc;
  661. TraceDataSyms[NextTraceDataSym].SymMax = g_WatchEndCurFunc;
  662. //
  663. // Bump the "next" pointer, wrapping if necessary. Also bump the
  664. // "valid" pointer if we need to.
  665. //
  666. NextTraceDataSym = (NextTraceDataSym + 1) %
  667. (sizeof(TraceDataSyms) / sizeof(TraceDataSyms[0]));;
  668. if ( NumTraceDataSyms < NextTraceDataSym )
  669. {
  670. NumTraceDataSyms = NextTraceDataSym;
  671. }
  672. }
  673. void
  674. ConnLiveKernelTargetInfo::ProcessWatchTraceEvent(PDBGKD_TRACE_DATA TraceData,
  675. PADDR PcAddr,
  676. PBOOL StepOver)
  677. {
  678. //
  679. // All of the real information is captured in the TraceData unions
  680. // sent to us by the kernel. Here we have two main jobs:
  681. //
  682. // 1) Print out the data in the TraceData record.
  683. // 2) See if we need up update the SymNum table before
  684. // returning to the kernel.
  685. //
  686. char SymName[MAX_SYMBOL_LEN];
  687. ULONG index;
  688. ULONG64 qw;
  689. ADDR CurSP;
  690. // Kernel mode always traces.
  691. *StepOver = FALSE;
  692. g_WatchFunctions.RecordEvent();
  693. g_Machine->GetSP(&CurSP);
  694. if (AddrEqu(g_WatchTarget, *PcAddr) && (Flat(CurSP) >= g_WatchInitialSP))
  695. {
  696. //
  697. // HACK HACK HACK
  698. //
  699. // fix up the last trace entry.
  700. //
  701. ULONG lastEntry = TraceData[0].LongNumber;
  702. if (lastEntry != 0)
  703. {
  704. TraceData[lastEntry].s.LevelChange = -1;
  705. // this is wrong if we
  706. // filled the symbol table!
  707. TraceData[lastEntry].s.SymbolNumber = 0;
  708. }
  709. }
  710. for ( index = 1; index < TraceData[0].LongNumber; index++ )
  711. {
  712. WatchFunction* Func;
  713. WatchCallStack* Call;
  714. ULONG64 SymOff = TraceDataSyms[TraceData[index].s.SymbolNumber].SymMin;
  715. GetSymbol(SymOff, SymName, sizeof(SymName), &qw);
  716. if (!SymName[0])
  717. {
  718. SymName[0] = '0';
  719. SymName[1] = 'x';
  720. strcpy(SymName + 2, FormatAddr64(SymOff));
  721. qw = 0;
  722. }
  723. #if DBG_KWT
  724. dprintf("!%2d: lev %2d instr %4u %s %s\n",
  725. index,
  726. TraceData[index].s.LevelChange,
  727. TraceData[index].s.Instructions ==
  728. TRACE_DATA_INSTRUCTIONS_BIG ?
  729. TraceData[index + 1].LongNumber :
  730. TraceData[index].s.Instructions,
  731. FormatAddr64(SymOff), SymName);
  732. #endif
  733. Func = g_WatchFunctions.FindAlways(SymName, SymOff - qw);
  734. if (Func == NULL)
  735. {
  736. ErrOut("Unable to allocate watch function\n");
  737. goto Flush;
  738. }
  739. Call = g_WatchFunctions.GetTopCall();
  740. if (Call == NULL || TraceData[index].s.LevelChange > 0)
  741. {
  742. if (Call == NULL)
  743. {
  744. // Treat the initial entry as a pseudo-call to
  745. // get it pushed.
  746. TraceData[index].s.LevelChange = 1;
  747. }
  748. while (TraceData[index].s.LevelChange != 0)
  749. {
  750. Call = g_WatchFunctions.PushCall(Func);
  751. if (Call == NULL)
  752. {
  753. ErrOut("Unable to allocate watch call level\n");
  754. goto Flush;
  755. }
  756. TraceData[index].s.LevelChange--;
  757. }
  758. }
  759. else if (TraceData[index].s.LevelChange < 0)
  760. {
  761. while (TraceData[index].s.LevelChange != 0)
  762. {
  763. g_WatchFunctions.PopCall();
  764. TraceData[index].s.LevelChange++;
  765. }
  766. // The level change may not actually be accurate, so
  767. // attempt to match up the current symbol offset with
  768. // some level of the call stack.
  769. Call = g_WatchFunctions.PopCallsToFunctionStart(SymOff);
  770. if (Call == NULL)
  771. {
  772. WarnOut(">> Unable to match return to %s\n", SymName);
  773. Call = g_WatchFunctions.GetTopCall();
  774. }
  775. }
  776. else
  777. {
  778. // We just made a horizontal call.
  779. g_WatchFunctions.ReuseCall(Call, Func);
  780. }
  781. ULONG InstrCount;
  782. if (TraceData[index].s.Instructions == TRACE_DATA_INSTRUCTIONS_BIG)
  783. {
  784. InstrCount = TraceData[++index].LongNumber;
  785. }
  786. else
  787. {
  788. InstrCount = TraceData[index].s.Instructions;
  789. }
  790. if (Call != NULL)
  791. {
  792. Call->InstrCount += InstrCount;
  793. g_WatchFunctions.OutputCall(Call, WCALL_OTHER);
  794. }
  795. }
  796. //
  797. // now see if we need to add a new symbol
  798. //
  799. index = SymNumFor(Flat(*PcAddr));
  800. if (-1 == index)
  801. {
  802. /* yup, add the symbol */
  803. GetAdjacentSymOffsets(Flat(*PcAddr),
  804. &g_WatchBeginCurFunc, &g_WatchEndCurFunc);
  805. if ((g_WatchBeginCurFunc == 0) ||
  806. (g_WatchEndCurFunc == (ULONG64)-1))
  807. {
  808. // Couldn't determine function, fake up
  809. // a single-byte function.
  810. g_WatchBeginCurFunc = g_WatchEndCurFunc = Flat(*PcAddr);
  811. }
  812. PotentialNewSymbol(Flat(*PcAddr));
  813. }
  814. else
  815. {
  816. g_WatchBeginCurFunc = TraceDataSyms[index].SymMin;
  817. g_WatchEndCurFunc = TraceDataSyms[index].SymMax;
  818. }
  819. if ((g_WatchBeginCurFunc <= Flat(g_WatchTarget)) &&
  820. (Flat(g_WatchTarget) < g_WatchEndCurFunc))
  821. {
  822. // The "exit" address is in the symbol range;
  823. // fix it so this isn't the case.
  824. if (Flat(*PcAddr) < Flat(g_WatchTarget))
  825. {
  826. g_WatchEndCurFunc = Flat(g_WatchTarget);
  827. }
  828. else
  829. {
  830. g_WatchBeginCurFunc = Flat(g_WatchTarget) + 1;
  831. }
  832. }
  833. Flush:
  834. FlushCallbacks();
  835. }
  836. //----------------------------------------------------------------------------
  837. //
  838. // UserTargetInfo watch trace methods.
  839. //
  840. //----------------------------------------------------------------------------
  841. LONG g_DeferredLevelChange;
  842. void
  843. LiveUserTargetInfo::InitializeWatchTrace(void)
  844. {
  845. g_DeferredLevelChange = 0;
  846. }
  847. void
  848. LiveUserTargetInfo::ProcessWatchTraceEvent(PDBGKD_TRACE_DATA TraceData,
  849. PADDR PcAddr,
  850. PBOOL StepOver)
  851. {
  852. WatchFunction* Func;
  853. WatchCallStack* Call;
  854. ULONG64 Disp64;
  855. CHAR Disasm[MAX_DISASM_LEN];
  856. // Default to tracing in.
  857. *StepOver = FALSE;
  858. g_WatchFunctions.RecordEvent();
  859. //
  860. // Get current function and see if it matches current. If so, bump
  861. // count in current, otherwise, update to new level
  862. //
  863. GetSymbol(Flat(*PcAddr), Disasm, sizeof(Disasm), &Disp64);
  864. // If there's no symbol for the current address create a
  865. // fake symbol for the instruction address.
  866. if (!Disasm[0])
  867. {
  868. Disasm[0] = '0';
  869. Disasm[1] = 'x';
  870. strcpy(Disasm + 2, FormatAddr64(Flat(*PcAddr)));
  871. Disp64 = 0;
  872. }
  873. Func = g_WatchFunctions.FindAlways(Disasm, Flat(*PcAddr) - Disp64);
  874. if (Func == NULL)
  875. {
  876. ErrOut("Unable to allocate watch symbol\n");
  877. goto Flush;
  878. }
  879. ADDR PcCopy;
  880. PcCopy = *PcAddr;
  881. g_Machine->Disassemble(g_Process, &PcCopy, Disasm, FALSE);
  882. Call = g_WatchFunctions.GetTopCall();
  883. if (Call == NULL)
  884. {
  885. //
  886. // First symbol in the list
  887. //
  888. Call = g_WatchFunctions.PushCall(Func);
  889. if (Call == NULL)
  890. {
  891. ErrOut("Unable to allocate watch symbol\n");
  892. goto Flush;
  893. }
  894. // At least one instruction must have executed
  895. // in this call to register it so initialize to one.
  896. // Also, one instruction was executed to get to the
  897. // first trace point so count it here.
  898. Call->InstrCount += 2;
  899. }
  900. else
  901. {
  902. if (g_DeferredLevelChange < 0)
  903. {
  904. g_DeferredLevelChange = 0;
  905. g_WatchFunctions.OutputCall(Call, WCALL_RETURN);
  906. // We have to see if this is really returning to a call site.
  907. // We do this because of try-finally funnies
  908. LONG OldLevel = g_WatchFunctions.GetCallLevel();
  909. WatchCallStack* CallSite =
  910. g_WatchFunctions.PopCallsToCallSite(PcAddr);
  911. if (CallSite == NULL)
  912. {
  913. WarnOut(">> No match on ret %s\n", Disasm);
  914. }
  915. else
  916. {
  917. if (OldLevel - 1 != CallSite->Level)
  918. {
  919. WarnOut(">> More than one level popped %d -> %d\n",
  920. OldLevel, CallSite->Level);
  921. }
  922. ZeroMemory(&CallSite->CallSite, sizeof(CallSite->CallSite));
  923. Call = CallSite;
  924. }
  925. }
  926. if (Call->Func == Func && g_DeferredLevelChange == 0)
  927. {
  928. Call->InstrCount++;
  929. }
  930. else
  931. {
  932. g_WatchFunctions.OutputCall(Call, g_DeferredLevelChange > 0 ?
  933. WCALL_CALL : WCALL_OTHER);
  934. if (g_DeferredLevelChange > 0)
  935. {
  936. g_DeferredLevelChange = 0;
  937. Call = g_WatchFunctions.PushCall(Func);
  938. if (Call == NULL)
  939. {
  940. ErrOut("Unable to allocate watch symbol\n");
  941. goto Flush;
  942. }
  943. }
  944. else
  945. {
  946. g_WatchFunctions.ReuseCall(Call, Func);
  947. }
  948. // At least one instruction must have executed
  949. // in this call to register it so initialize to one.
  950. Call->InstrCount++;
  951. }
  952. }
  953. #if DBG_UWT
  954. dprintf("! %3d %s", Call != NULL ? Call->InstrCount : -1, Disasm);
  955. #endif
  956. //
  957. // Adjust watch level to compensate for kernel-mode callbacks
  958. //
  959. if (Call->InstrCount == 1)
  960. {
  961. if (!_stricmp(Call->Func->Symbol,
  962. "ntdll!_KiUserCallBackDispatcher"))
  963. {
  964. g_WatchFunctions.ChangeCallLevel(1);
  965. Call->Level = g_WatchFunctions.GetCallLevel();
  966. }
  967. else if (!_stricmp(Call->Func->Symbol, "ntdll!_ZwCallbackReturn"))
  968. {
  969. g_WatchFunctions.ChangeCallLevel(-2);
  970. Call->Level = g_WatchFunctions.GetCallLevel();
  971. }
  972. }
  973. if (g_Machine->IsCallDisasm(Disasm))
  974. {
  975. if (g_WatchFunctions.GetCallLevel() >=
  976. g_WatchFunctions.m_MaxCallLevelAllowed)
  977. {
  978. // We're at the maximum allowed depth
  979. // so just step over the call.
  980. *StepOver = TRUE;
  981. }
  982. else
  983. {
  984. Call->CallSite = *PcAddr;
  985. g_DeferredLevelChange = 1;
  986. }
  987. }
  988. else if (g_Machine->IsReturnDisasm(Disasm))
  989. {
  990. g_DeferredLevelChange = -1;
  991. }
  992. else if (g_Machine->IsSystemCallDisasm(Disasm))
  993. {
  994. PSTR CallName;
  995. WatchCallStack* SysCall = Call;
  996. CallName = strchr(Call->Func->Symbol, '!');
  997. if (!CallName)
  998. {
  999. CallName = Call->Func->Symbol;
  1000. }
  1001. else
  1002. {
  1003. CallName++;
  1004. }
  1005. if (!strcmp(Call->Func->Symbol, "SharedUserData!SystemCallStub"))
  1006. {
  1007. // We're in a Windows XP system call thunk
  1008. // and the interesting system call symbol is the previous level.
  1009. SysCall = Call->Prev;
  1010. }
  1011. if (SysCall != NULL)
  1012. {
  1013. SysCall->Func->SystemCalls++;
  1014. // ZwRaiseException returns out two levels after the call.
  1015. if (!_stricmp(SysCall->Func->Symbol, "ntdll!ZwRaiseException") ||
  1016. !_stricmp(SysCall->Func->Symbol, "ntdll!_ZwRaiseException"))
  1017. {
  1018. g_WatchFunctions.ChangeCallLevel(-1);
  1019. }
  1020. }
  1021. g_WatchFunctions.ChangeCallLevel(-1);
  1022. }
  1023. Flush:
  1024. FlushCallbacks();
  1025. }
  1026. //----------------------------------------------------------------------------
  1027. //
  1028. // Support functions.
  1029. //
  1030. //----------------------------------------------------------------------------
  1031. void
  1032. ParseStepTrace(ThreadInfo* Thread,
  1033. BOOL ThreadFreeze,
  1034. char StepType)
  1035. {
  1036. ADDR Addr1;
  1037. ULONG64 Value2;
  1038. char Ch;
  1039. CHAR AddrBuffer[MAX_SYMBOL_LEN];
  1040. ULONG64 Displacement;
  1041. BOOL ToCall = FALSE;
  1042. // If there's an outstanding request for input don't
  1043. // allow the execution status of the engine to change
  1044. // as it could lead to a wait which cannot
  1045. // be carried out in this situation. It's better to fail
  1046. // this call and have the caller try again.
  1047. if (g_InputNesting >= 1)
  1048. {
  1049. error(ENGBUSY);
  1050. }
  1051. if (!IS_CUR_MACHINE_ACCESSIBLE())
  1052. {
  1053. error(BADTHREAD);
  1054. }
  1055. if (!g_Target->m_DynamicEvents)
  1056. {
  1057. error(TARGETNOTSUP);
  1058. }
  1059. if (IS_LIVE_USER_TARGET(g_Target))
  1060. {
  1061. TargetInfo* Target;
  1062. ForAllLayersToTarget()
  1063. {
  1064. if (Target->m_AllProcessFlags & ENG_PROC_EXAMINED)
  1065. {
  1066. ErrOut("The debugger is not attached to some processes so\n"
  1067. "process execution cannot be monitored\n");
  1068. return;
  1069. }
  1070. else if (Target->m_BreakInTimeout)
  1071. {
  1072. ErrOut("Due to the break-in timeout the debugger "
  1073. "cannot step or trace\n");
  1074. return;
  1075. }
  1076. }
  1077. }
  1078. if (StepType == 'w')
  1079. {
  1080. if (IS_KERNEL_TARGET(g_Target) &&
  1081. g_Target->m_MachineType != IMAGE_FILE_MACHINE_I386)
  1082. {
  1083. error(UNIMPLEMENT);
  1084. }
  1085. if ((PeekChar() == 't') ||
  1086. (IS_KERNEL_TARGET(g_Target) && PeekChar() == 'w'))
  1087. {
  1088. g_WatchTrace = TRUE;
  1089. g_WatchWhole = *g_CurCmd == 'w';
  1090. g_WatchBeginCurFunc = g_WatchEndCurFunc = 0;
  1091. g_CurCmd++;
  1092. g_WatchFunctions.ParseParameters();
  1093. }
  1094. else
  1095. {
  1096. error(SYNTAX);
  1097. }
  1098. }
  1099. else
  1100. {
  1101. g_WatchTrace = FALSE;
  1102. //
  1103. // if next character is 'b' and command is 't' perform branch trace
  1104. //
  1105. Ch = PeekChar();
  1106. Ch = (char)tolower(Ch);
  1107. if (StepType == 't' && Ch == 'b')
  1108. {
  1109. if (!g_Machine->IsStepStatusSupported(DEBUG_STATUS_STEP_BRANCH))
  1110. {
  1111. error(TARGETNOTSUP);
  1112. }
  1113. StepType = 'b';
  1114. g_CurCmd++;
  1115. }
  1116. else if (Ch == 'c')
  1117. {
  1118. // Step/trace to next call.
  1119. ToCall = TRUE;
  1120. g_CurCmd++;
  1121. }
  1122. //
  1123. // if next character is 'r', toggle flag to output registers
  1124. // on display on breakpoint.
  1125. //
  1126. Ch = PeekChar();
  1127. if (tolower(Ch) == 'r')
  1128. {
  1129. g_CurCmd++;
  1130. g_OciOutputRegs = !g_OciOutputRegs;
  1131. }
  1132. }
  1133. g_Machine->GetPC(&Addr1); // default to current PC
  1134. if (PeekChar() == '=')
  1135. {
  1136. g_CurCmd++;
  1137. GetAddrExpression(SEGREG_CODE, &Addr1);
  1138. }
  1139. Value2 = 1;
  1140. if ((Ch = PeekChar()) != '\0' && Ch != ';')
  1141. {
  1142. Value2 = GetExpression();
  1143. }
  1144. else if (StepType == 'w')
  1145. {
  1146. GetSymbol(Flat(Addr1),
  1147. AddrBuffer, sizeof(AddrBuffer), &Displacement);
  1148. if (Displacement == 0 && AddrBuffer[ 0 ] != '\0')
  1149. {
  1150. ADDR Addr2;
  1151. g_Machine->GetRetAddr(&Addr2);
  1152. Value2 = Flat(Addr2);
  1153. dprintf("Tracing %s to return address %s\n",
  1154. AddrBuffer,
  1155. FormatAddr64(Value2));
  1156. if (g_WatchWhole)
  1157. {
  1158. g_WatchBeginCurFunc = Value2;
  1159. g_WatchEndCurFunc = 0;
  1160. }
  1161. }
  1162. }
  1163. if (((LONG)Value2 <= 0) && (!g_WatchTrace))
  1164. {
  1165. error(SYNTAX);
  1166. }
  1167. SetExecStepTrace(&Addr1,
  1168. Value2, // count or watch end address
  1169. Thread,
  1170. ThreadFreeze,
  1171. ToCall,
  1172. StepType);
  1173. }
  1174. //
  1175. // Returns TRUE if the current step/trace should be passed over.
  1176. //
  1177. BOOL
  1178. StepTracePass(PADDR PcAddr)
  1179. {
  1180. if (g_StepTraceToCall)
  1181. {
  1182. char Disasm[MAX_DISASM_LEN];
  1183. ADDR Addr = *PcAddr;
  1184. // We're tracing by call instructions. Pass if
  1185. // the current instruction isn't a call. If we
  1186. // can't disassemble stop stepping as we don't
  1187. // want to miss something.
  1188. if (g_Machine->Disassemble(g_Process, &Addr, Disasm, FALSE) &&
  1189. !g_Machine->IsCallDisasm(Disasm) &&
  1190. !g_Machine->IsSystemCallDisasm(Disasm))
  1191. {
  1192. return TRUE;
  1193. }
  1194. }
  1195. // If we have valid source line information and we're stepping
  1196. // by source line, check and see if we moved from one line to another.
  1197. if ((g_SrcOptions & SRCOPT_STEP_SOURCE) && g_SrcLineValid)
  1198. {
  1199. IMAGEHLP_LINE64 Line;
  1200. ULONG Disp;
  1201. ULONG64 Disp64;
  1202. SYMBOL_INFO SymInfo = {0};
  1203. if (GetLineFromAddr(g_Process, Flat(*PcAddr), &Line, &Disp))
  1204. {
  1205. if (Line.LineNumber == g_SrcLine.LineNumber)
  1206. {
  1207. // The common case is that we're still in the same line,
  1208. // so check for a name match by pointer as a very quick
  1209. // trivial accept. If there's a mismatch we need to
  1210. // do the hard comparison.
  1211. if (Line.FileName == g_SrcLine.FileName ||
  1212. _strcmpi(Line.FileName, g_SrcLine.FileName) == 0)
  1213. {
  1214. // We're still on the same line so don't treat
  1215. // this as motion.
  1216. return TRUE;
  1217. }
  1218. }
  1219. // We've changed lines so we drop one from the pass count.
  1220. // SrcLine also needs to be updated.
  1221. g_SrcLine = Line;
  1222. }
  1223. else if (SymFromAddr(g_Process->m_SymHandle,
  1224. Flat(*PcAddr),
  1225. &Disp64,
  1226. &SymInfo) &&
  1227. SymInfo.Tag == SymTagThunk)
  1228. {
  1229. // If we're on a thunk we just go ahead and keep
  1230. // stepping so that things don't stop in compiler-
  1231. // generated intermediaries like incremental compilation
  1232. // thunks.
  1233. return TRUE;
  1234. }
  1235. else
  1236. {
  1237. // If we can't get line number information for the current
  1238. // address we treat it as a transition on the theory that
  1239. // it's better to stop than to skip interesting code.
  1240. g_SrcLineValid = FALSE;
  1241. }
  1242. }
  1243. if (--g_StepTracePassCount > 0)
  1244. {
  1245. if (!g_WatchFunctions.IsStarted())
  1246. {
  1247. // If the engine doesn't break for some other reason
  1248. // on this intermediate step it should output the
  1249. // step information to show the user the stepping
  1250. // path.
  1251. g_EngDefer |= ENG_DEFER_OUTPUT_CURRENT_INFO;
  1252. }
  1253. return TRUE;
  1254. }
  1255. return FALSE;
  1256. }
  1257. void
  1258. SetExecStepTrace(PADDR StartAddr,
  1259. ULONG64 PassCount,
  1260. ThreadInfo* Thread,
  1261. BOOL ThreadFreeze,
  1262. BOOL ToCall,
  1263. char StepType)
  1264. {
  1265. // If we're stepping a particular thread it better
  1266. // be the current context thread so that the machine
  1267. // activity occurs on the appropriate thread.
  1268. DBG_ASSERT(Thread == NULL || Thread == g_Target->m_RegContextThread);
  1269. if ((g_SrcOptions & SRCOPT_STEP_SOURCE) && fFlat(*StartAddr))
  1270. {
  1271. ULONG Disp;
  1272. // Get the current line information so it's possible to
  1273. // tell when the line changes.
  1274. g_SrcLineValid = GetLineFromAddr(g_Process, Flat(*StartAddr),
  1275. &g_SrcLine, &Disp);
  1276. }
  1277. g_Machine->SetPC(StartAddr);
  1278. g_StepTracePassCount = (ULONG)PassCount;
  1279. g_StepTraceToCall = ToCall;
  1280. SelectExecutionThread(Thread,
  1281. ThreadFreeze ? SELTHREAD_THREAD : SELTHREAD_ANY);
  1282. if (StepType == 'w')
  1283. {
  1284. ULONG NextMachine;
  1285. g_Target->InitializeWatchTrace();
  1286. g_WatchFunctions.Start();
  1287. g_WatchTarget = *StartAddr;
  1288. g_Machine->GetNextOffset(g_Process, TRUE,
  1289. &g_WatchTarget, &NextMachine);
  1290. if (Flat(g_WatchTarget) != OFFSET_TRACE || PassCount != 1)
  1291. {
  1292. g_Target->InitializeTargetControlledStepping();
  1293. g_StepTracePassCount = 0xfffffff;
  1294. if (PassCount != 1)
  1295. {
  1296. Flat(g_WatchTarget) = PassCount;
  1297. }
  1298. }
  1299. StepType = 't';
  1300. }
  1301. g_CmdState = StepType;
  1302. switch(StepType)
  1303. {
  1304. case 'b':
  1305. g_ExecutionStatusRequest = DEBUG_STATUS_STEP_BRANCH;
  1306. break;
  1307. case 't':
  1308. g_ExecutionStatusRequest = DEBUG_STATUS_STEP_INTO;
  1309. break;
  1310. case 'p':
  1311. default:
  1312. g_ExecutionStatusRequest = DEBUG_STATUS_STEP_OVER;
  1313. break;
  1314. }
  1315. if (Thread)
  1316. {
  1317. g_StepTraceBp->m_Process = Thread->m_Process;
  1318. g_StepTraceBp->m_MatchThread = Thread;
  1319. }
  1320. else
  1321. {
  1322. g_StepTraceBp->m_Process = g_Process;
  1323. g_StepTraceBp->m_MatchThread = g_Thread;
  1324. }
  1325. if (StepType == 'b')
  1326. {
  1327. // Assume that taken branch trace is always performed by
  1328. // hardware so set the g_StepTraceBp address to OFFSET_TRACE
  1329. // (the value returned by GetNextOffset to signal the
  1330. // hardware stepping mode).
  1331. DBG_ASSERT(g_Machine->
  1332. IsStepStatusSupported(DEBUG_STATUS_STEP_BRANCH));
  1333. ADDRFLAT(g_StepTraceBp->GetAddr(), OFFSET_TRACE);
  1334. }
  1335. else
  1336. {
  1337. ULONG NextMachine;
  1338. g_Machine->GetNextOffset(g_Process, g_CmdState == 'p',
  1339. g_StepTraceBp->GetAddr(),
  1340. &NextMachine);
  1341. g_StepTraceBp->SetProcType(NextMachine);
  1342. }
  1343. GetCurrentMemoryOffsets(&g_StepTraceInRangeStart,
  1344. &g_StepTraceInRangeEnd);
  1345. g_StepTraceBp->m_Flags |= DEBUG_BREAKPOINT_ENABLED;
  1346. g_StepTraceCmdState = g_CmdState;
  1347. g_EngStatus &= ~ENG_STATUS_USER_INTERRUPT;
  1348. NotifyChangeEngineState(DEBUG_CES_EXECUTION_STATUS,
  1349. g_ExecutionStatusRequest, TRUE);
  1350. }
  1351. void
  1352. SetExecGo(ULONG ExecStatus,
  1353. PADDR StartAddr,
  1354. ThreadInfo* Thread,
  1355. BOOL ThreadFreeze,
  1356. ULONG BpCount,
  1357. PADDR BpArray,
  1358. PCSTR BpCmd)
  1359. {
  1360. ULONG Count;
  1361. // If we're resuming a particular thread it better
  1362. // be the current context thread so that the machine
  1363. // activity occurs on the appropriate thread.
  1364. DBG_ASSERT(Thread == NULL || Thread == g_Target->m_RegContextThread);
  1365. if (IS_CUR_CONTEXT_ACCESSIBLE())
  1366. {
  1367. g_Machine->SetPC(StartAddr);
  1368. }
  1369. // Remove old go breakpoints.
  1370. for (Count = 0; Count < g_NumGoBreakpoints; Count++)
  1371. {
  1372. if (g_GoBreakpoints[Count] != NULL)
  1373. {
  1374. RemoveBreakpoint(g_GoBreakpoints[Count]);
  1375. g_GoBreakpoints[Count] = NULL;
  1376. }
  1377. }
  1378. DBG_ASSERT(BpCount <= MAX_GO_BPS);
  1379. g_NumGoBreakpoints = BpCount;
  1380. // Add new go breakpoints.
  1381. for (Count = 0; Count < g_NumGoBreakpoints; Count++)
  1382. {
  1383. HRESULT Status;
  1384. // First try to put the breakpoint at an ID up
  1385. // and out of the way of user breakpoints.
  1386. Status = AddBreakpoint(NULL, g_Machine, DEBUG_BREAKPOINT_CODE |
  1387. BREAKPOINT_HIDDEN, 10000 + Count,
  1388. &g_GoBreakpoints[Count]);
  1389. if (Status != S_OK)
  1390. {
  1391. // That didn't work so try letting the engine
  1392. // pick an ID.
  1393. Status =
  1394. AddBreakpoint(NULL, g_Machine, DEBUG_BREAKPOINT_CODE |
  1395. BREAKPOINT_HIDDEN, DEBUG_ANY_ID,
  1396. &g_GoBreakpoints[Count]);
  1397. }
  1398. if (Status != S_OK)
  1399. {
  1400. WarnOut("Temp bp at ");
  1401. MaskOutAddr(DEBUG_OUTPUT_WARNING, BpArray);
  1402. WarnOut("failed.\n");
  1403. }
  1404. else
  1405. {
  1406. // Matches must be allowed so that temporary breakpoints
  1407. // don't interfere with permanent breakpoints.
  1408. g_GoBreakpoints[Count]->SetAddr(BpArray,
  1409. BREAKPOINT_ALLOW_MATCH);
  1410. g_GoBreakpoints[Count]->m_Flags |=
  1411. (DEBUG_BREAKPOINT_GO_ONLY |
  1412. DEBUG_BREAKPOINT_ENABLED);
  1413. }
  1414. if (BpCmd &&
  1415. g_GoBreakpoints[Count]->SetCommand(BpCmd) != S_OK)
  1416. {
  1417. WarnOut("Unable to set go breakpoint command\n");
  1418. }
  1419. BpArray++;
  1420. }
  1421. g_CmdState = 'g';
  1422. if (Thread == NULL || Thread == g_StepTraceBp->m_MatchThread)
  1423. {
  1424. g_StepTraceBp->m_Flags &= ~DEBUG_BREAKPOINT_ENABLED;
  1425. }
  1426. g_ExecutionStatusRequest = ExecStatus;
  1427. SelectExecutionThread(Thread,
  1428. ThreadFreeze ? SELTHREAD_THREAD : SELTHREAD_ANY);
  1429. NotifyChangeEngineState(DEBUG_CES_EXECUTION_STATUS, ExecStatus, TRUE);
  1430. }
  1431. void
  1432. ParseGoCmd(ThreadInfo* Thread,
  1433. BOOL ThreadFreeze)
  1434. {
  1435. ULONG BpCount;
  1436. ADDR BpAddr[MAX_GO_BPS];
  1437. CHAR Ch;
  1438. ADDR PcAddr;
  1439. CHAR Ch2;
  1440. ULONG ExecStatus;
  1441. if (!AnyEventsPossible())
  1442. {
  1443. error(NORUNNABLE);
  1444. }
  1445. // If there's an outstanding request for input don't
  1446. // allow the execution status of the engine to change
  1447. // as it could lead to a wait which cannot
  1448. // be carried out in this situation. It's better to fail
  1449. // this call and have the caller try again.
  1450. if (g_InputNesting >= 1)
  1451. {
  1452. error(ENGBUSY);
  1453. }
  1454. if (AllProcessFlags() & ENG_PROC_EXAMINED)
  1455. {
  1456. ErrOut("The debugger is not attached so "
  1457. "process execution cannot be monitored\n");
  1458. return;
  1459. }
  1460. if (IS_RUNNING(g_CmdState))
  1461. {
  1462. ErrOut("Debuggee is busy, cannot go\n");
  1463. return;
  1464. }
  1465. ExecStatus = DEBUG_STATUS_GO;
  1466. Ch = (CHAR)tolower(*g_CurCmd);
  1467. if (Ch == 'h' || Ch == 'n')
  1468. {
  1469. Ch2 = *(g_CurCmd + 1);
  1470. if (Ch2 == ' ' || Ch2 == '\t' || Ch2 == '\0')
  1471. {
  1472. g_CurCmd++;
  1473. ExecStatus = Ch == 'h' ? DEBUG_STATUS_GO_HANDLED :
  1474. DEBUG_STATUS_GO_NOT_HANDLED;
  1475. }
  1476. }
  1477. g_PrefixSymbols = TRUE;
  1478. if (IS_CUR_CONTEXT_ACCESSIBLE())
  1479. {
  1480. g_Machine->GetPC(&PcAddr); // default to current PC
  1481. }
  1482. else
  1483. {
  1484. ZeroMemory(&PcAddr, sizeof(PcAddr));
  1485. }
  1486. if (PeekChar() == '=')
  1487. {
  1488. g_CurCmd++;
  1489. GetAddrExpression(SEGREG_CODE, &PcAddr);
  1490. }
  1491. BpCount = 0;
  1492. while ((Ch = PeekChar()) != '\0' && Ch != ';')
  1493. {
  1494. ULONG AddrSpace, AddrFlags;
  1495. if (BpCount == DIMA(BpAddr))
  1496. {
  1497. error(LISTSIZE);
  1498. }
  1499. GetAddrExpression(SEGREG_CODE, BpAddr + (BpCount++));
  1500. if (g_Target->
  1501. QueryAddressInformation(g_Process, Flat(BpAddr[BpCount - 1]),
  1502. DBGKD_QUERY_MEMORY_VIRTUAL,
  1503. &AddrSpace, &AddrFlags) != S_OK)
  1504. {
  1505. ErrOut("Invalid breakpoint address\n");
  1506. error(MEMORY);
  1507. }
  1508. if (AddrSpace == DBGKD_QUERY_MEMORY_SESSION ||
  1509. !(AddrFlags & DBGKD_QUERY_MEMORY_WRITE) ||
  1510. (AddrFlags & DBGKD_QUERY_MEMORY_FIXED))
  1511. {
  1512. ErrOut("Software breakpoints cannot be used on session code, "
  1513. "ROM code or other\nread-only memory. "
  1514. "Use hardware execution breakpoints (ba e) instead.\n");
  1515. error(MEMORY);
  1516. }
  1517. }
  1518. g_PrefixSymbols = FALSE;
  1519. if (IS_USER_TARGET(g_Target))
  1520. {
  1521. g_LastCommand[0] = '\0'; // null out g command
  1522. }
  1523. //
  1524. // Check for trailing commands so that they can be attached
  1525. // to any go breakpoints that are being created.
  1526. //
  1527. PCSTR BpCmd = g_CurCmd;
  1528. if (g_EngStatus & ENG_STATUS_NO_AUTO_WAIT)
  1529. {
  1530. while (*BpCmd == ';' || *BpCmd == ' ' || *BpCmd == '\t')
  1531. {
  1532. BpCmd++;
  1533. }
  1534. if (!*BpCmd)
  1535. {
  1536. BpCmd = NULL;
  1537. }
  1538. }
  1539. else
  1540. {
  1541. // Auto-waiting is enabled so just let the auto-wait
  1542. // handle trailing commands.
  1543. BpCmd = NULL;
  1544. }
  1545. SetExecGo(ExecStatus, &PcAddr, Thread, ThreadFreeze,
  1546. BpCount, BpAddr, BpCmd);
  1547. }