TTExecutionInfo.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeDebugPch.h"
  6. #if ENABLE_TTD
  7. namespace TTD
  8. {
  9. TTDebuggerAbortException::TTDebuggerAbortException(uint32 abortCode, int64 optEventTime, int64 optMoveMode, const char16* staticAbortMessage)
  10. : m_abortCode(abortCode), m_optEventTime(optEventTime), m_optMoveMode(optMoveMode), m_staticAbortMessage(staticAbortMessage)
  11. {
  12. ;
  13. }
  14. TTDebuggerAbortException::~TTDebuggerAbortException()
  15. {
  16. ;
  17. }
  18. TTDebuggerAbortException TTDebuggerAbortException::CreateAbortEndOfLog(const char16* staticMessage)
  19. {
  20. return TTDebuggerAbortException(1, -1, 0, staticMessage);
  21. }
  22. TTDebuggerAbortException TTDebuggerAbortException::CreateTopLevelAbortRequest(int64 targetEventTime, int64 moveMode, const char16* staticMessage)
  23. {
  24. return TTDebuggerAbortException(2, targetEventTime, moveMode, staticMessage);
  25. }
  26. TTDebuggerAbortException TTDebuggerAbortException::CreateUncaughtExceptionAbortRequest(int64 targetEventTime, const char16* staticMessage)
  27. {
  28. return TTDebuggerAbortException(3, targetEventTime, 0, staticMessage);
  29. }
  30. bool TTDebuggerAbortException::IsEndOfLog() const
  31. {
  32. return this->m_abortCode == 1;
  33. }
  34. bool TTDebuggerAbortException::IsEventTimeMove() const
  35. {
  36. return this->m_abortCode == 2;
  37. }
  38. bool TTDebuggerAbortException::IsTopLevelException() const
  39. {
  40. return this->m_abortCode == 3;
  41. }
  42. int64 TTDebuggerAbortException::GetTargetEventTime() const
  43. {
  44. return this->m_optEventTime;
  45. }
  46. int64 TTDebuggerAbortException::GetMoveMode() const
  47. {
  48. return this->m_optMoveMode;
  49. }
  50. const char16* TTDebuggerAbortException::GetStaticAbortMessage() const
  51. {
  52. return this->m_staticAbortMessage;
  53. }
  54. Js::FunctionBody* TTDebuggerSourceLocation::UpdatePostInflateFunctionBody_Helper(Js::FunctionBody* rootBody) const
  55. {
  56. for(uint32 i = 0; i < rootBody->GetNestedCount(); ++i)
  57. {
  58. Js::ParseableFunctionInfo* ipfi = rootBody->GetNestedFunctionForExecution(i);
  59. Js::FunctionBody* ifb = JsSupport::ForceAndGetFunctionBody(ipfi);
  60. if(this->m_functionLine == ifb->GetLineNumber() && this->m_functionColumn == ifb->GetColumnNumber())
  61. {
  62. return ifb;
  63. }
  64. else
  65. {
  66. Js::FunctionBody* found = this->UpdatePostInflateFunctionBody_Helper(ifb);
  67. if(found != nullptr)
  68. {
  69. return found;
  70. }
  71. }
  72. }
  73. return nullptr;
  74. }
  75. TTDebuggerSourceLocation::TTDebuggerSourceLocation()
  76. : m_sourceScriptLogId(TTD_INVALID_LOG_PTR_ID), m_bpId(-1),
  77. m_etime(-1), m_ftime(0), m_ltime(0),
  78. m_topLevelBodyId(0), m_functionLine(0), m_functionColumn(0), m_line(0), m_column(0)
  79. {
  80. ;
  81. }
  82. TTDebuggerSourceLocation::TTDebuggerSourceLocation(const TTDebuggerSourceLocation& other)
  83. : m_sourceScriptLogId(other.m_sourceScriptLogId), m_bpId(other.m_bpId),
  84. m_etime(other.m_etime), m_ftime(other.m_ftime), m_ltime(other.m_ltime),
  85. m_topLevelBodyId(other.m_topLevelBodyId), m_functionLine(other.m_functionLine), m_functionColumn(other.m_functionColumn), m_line(other.m_line), m_column(other.m_column)
  86. {
  87. ;
  88. }
  89. TTDebuggerSourceLocation::~TTDebuggerSourceLocation()
  90. {
  91. this->Clear();
  92. }
  93. TTDebuggerSourceLocation& TTDebuggerSourceLocation::operator= (const TTDebuggerSourceLocation& other)
  94. {
  95. if(this != &other)
  96. {
  97. this->SetLocationCopy(other);
  98. }
  99. return *this;
  100. }
  101. #if ENABLE_TTD_INTERNAL_DIAGNOSTICS
  102. void TTDebuggerSourceLocation::PrintToConsole() const
  103. {
  104. if(!this->HasValue())
  105. {
  106. wprintf(_u("undef"));
  107. }
  108. else
  109. {
  110. printf("BP: { bpId: %I64i, ctx: %I64u, topId: %I32u, fline: %I32u, fcolumn: %I32u, line: %I32u, column: %I32u }", this->m_bpId, this->m_sourceScriptLogId, this->m_topLevelBodyId, this->m_functionLine, this->m_functionColumn, this->m_line, this->m_column);
  111. if(this->m_etime != -1)
  112. {
  113. printf(" TTDTime: { etime: %I64i, ftime: %I64i, ltime: %I64i }", this->m_etime, this->m_ftime, this->m_ltime);
  114. }
  115. }
  116. }
  117. #endif
  118. void TTDebuggerSourceLocation::Initialize()
  119. {
  120. this->m_sourceScriptLogId = TTD_INVALID_LOG_PTR_ID;
  121. this->m_bpId = -1;
  122. this->m_etime = -1;
  123. this->m_ftime = 0;
  124. this->m_ltime = 0;
  125. this->m_topLevelBodyId = 0;
  126. this->m_functionLine = 0;
  127. this->m_functionColumn = 0;
  128. this->m_line = 0;
  129. this->m_column = 0;
  130. }
  131. bool TTDebuggerSourceLocation::HasValue() const
  132. {
  133. return this->m_sourceScriptLogId != TTD_INVALID_LOG_PTR_ID;
  134. }
  135. bool TTDebuggerSourceLocation::HasTTDTimeValue() const
  136. {
  137. return this->m_etime != -1;
  138. }
  139. void TTDebuggerSourceLocation::Clear()
  140. {
  141. this->m_sourceScriptLogId = TTD_INVALID_LOG_PTR_ID;
  142. this->m_bpId = -1;
  143. this->m_etime = -1;
  144. this->m_ftime = 0;
  145. this->m_ltime = 0;
  146. this->m_topLevelBodyId = 0;
  147. this->m_functionLine = 0;
  148. this->m_functionColumn = 0;
  149. this->m_line = 0;
  150. this->m_column = 0;
  151. }
  152. void TTDebuggerSourceLocation::SetLocationCopy(const TTDebuggerSourceLocation& other)
  153. {
  154. this->m_sourceScriptLogId = other.m_sourceScriptLogId;
  155. this->m_bpId = other.m_bpId;
  156. this->m_etime = other.m_etime;
  157. this->m_ftime = other.m_ftime;
  158. this->m_ltime = other.m_ltime;
  159. this->m_topLevelBodyId = other.m_topLevelBodyId;
  160. this->m_functionLine = other.m_functionLine;
  161. this->m_functionColumn = other.m_functionColumn;
  162. this->m_line = other.m_line;
  163. this->m_column = other.m_column;
  164. }
  165. void TTDebuggerSourceLocation::SetLocationFromFrame(int64 topLevelETime, const SingleCallCounter& callFrame)
  166. {
  167. ULONG srcLine = 0;
  168. LONG srcColumn = -1;
  169. uint32 startOffset = callFrame.Function->GetStatementStartOffset(callFrame.CurrentStatementIndex);
  170. callFrame.Function->GetSourceLineFromStartOffset_TTD(startOffset, &srcLine, &srcColumn);
  171. this->SetLocationFull(topLevelETime, callFrame.FunctionTime, callFrame.LoopTime, callFrame.Function, (uint32)srcLine, (uint32)srcColumn);
  172. }
  173. void TTDebuggerSourceLocation::SetLocationFromFunctionEntryAnyTime(int64 topLevelETime, Js::FunctionBody* body)
  174. {
  175. ULONG srcLine = 0;
  176. LONG srcColumn = -1;
  177. uint32 startOffset = body->GetStatementStartOffset(0);
  178. body->GetSourceLineFromStartOffset_TTD(startOffset, &srcLine, &srcColumn);
  179. this->SetLocationFull(topLevelETime, -1, -1, body, (uint32)srcLine, (uint32)srcColumn);
  180. }
  181. void TTDebuggerSourceLocation::SetLocationFull(int64 etime, int64 ftime, int64 ltime, Js::FunctionBody* body, ULONG line, LONG column)
  182. {
  183. this->m_sourceScriptLogId = body->GetScriptContext()->ScriptContextLogTag;
  184. this->m_bpId = -1;
  185. this->m_etime = etime;
  186. this->m_ftime = ftime;
  187. this->m_ltime = ltime;
  188. this->m_topLevelBodyId = body->GetScriptContext()->TTDContextInfo->FindTopLevelCtrForBody(body);
  189. this->m_functionLine = body->GetLineNumber();
  190. this->m_functionColumn = body->GetColumnNumber();
  191. this->m_line = (uint32)line;
  192. this->m_column = (uint32)column;
  193. }
  194. void TTDebuggerSourceLocation::SetLocationWithBP(int64 bpId, Js::FunctionBody* body, ULONG line, LONG column)
  195. {
  196. this->m_sourceScriptLogId = body->GetScriptContext()->ScriptContextLogTag;
  197. this->m_bpId = bpId;
  198. this->m_etime = -1;
  199. this->m_ftime = -1;
  200. this->m_ltime = -1;
  201. this->m_topLevelBodyId = body->GetScriptContext()->TTDContextInfo->FindTopLevelCtrForBody(body);
  202. this->m_functionLine = body->GetLineNumber();
  203. this->m_functionColumn = body->GetColumnNumber();
  204. this->m_line = (uint32)line;
  205. this->m_column = (uint32)column;
  206. }
  207. int64 TTDebuggerSourceLocation::GetRootEventTime() const
  208. {
  209. return this->m_etime;
  210. }
  211. int64 TTDebuggerSourceLocation::GetFunctionTime() const
  212. {
  213. return this->m_ftime;
  214. }
  215. int64 TTDebuggerSourceLocation::GetLoopTime() const
  216. {
  217. return this->m_ltime;
  218. }
  219. TTD_LOG_PTR_ID TTDebuggerSourceLocation::GetScriptLogTagId() const
  220. {
  221. return this->m_sourceScriptLogId;
  222. }
  223. Js::FunctionBody* TTDebuggerSourceLocation::LoadFunctionBodyIfPossible(Js::ScriptContext* inCtx) const
  224. {
  225. Js::FunctionBody* rootBody = inCtx->TTDContextInfo->FindRootBodyByTopLevelCtr(this->m_topLevelBodyId);
  226. if(rootBody == nullptr)
  227. {
  228. return nullptr;
  229. }
  230. if(this->m_functionLine == rootBody->GetLineNumber() && this->m_functionColumn == rootBody->GetColumnNumber())
  231. {
  232. return rootBody;
  233. }
  234. else
  235. {
  236. return this->UpdatePostInflateFunctionBody_Helper(rootBody);
  237. }
  238. }
  239. int64 TTDebuggerSourceLocation::GetBPId() const
  240. {
  241. return this->m_bpId;
  242. }
  243. uint32 TTDebuggerSourceLocation::GetTopLevelBodyId() const
  244. {
  245. return this->m_topLevelBodyId;
  246. }
  247. uint32 TTDebuggerSourceLocation::GetSourceLine() const
  248. {
  249. return this->m_line;
  250. }
  251. uint32 TTDebuggerSourceLocation::GetSourceColumn() const
  252. {
  253. return this->m_column;
  254. }
  255. bool TTDebuggerSourceLocation::AreSameLocations(const TTDebuggerSourceLocation& sl1, const TTDebuggerSourceLocation& sl2)
  256. {
  257. //first check the code locations
  258. if(sl1.m_topLevelBodyId != sl2.m_topLevelBodyId || sl1.m_line != sl2.m_line || sl1.m_column != sl2.m_column)
  259. {
  260. return false;
  261. }
  262. //next check the time values
  263. if(sl1.m_etime != sl2.m_etime || sl1.m_ftime != sl2.m_ftime || sl1.m_ltime != sl2.m_ltime)
  264. {
  265. return false;
  266. }
  267. return true;
  268. }
  269. bool TTDebuggerSourceLocation::AreSameLocations_PlaceOnly(const TTDebuggerSourceLocation& sl1, const TTDebuggerSourceLocation& sl2)
  270. {
  271. return (sl1.m_topLevelBodyId == sl2.m_topLevelBodyId && sl1.m_line == sl2.m_line && sl1.m_column == sl2.m_column);
  272. }
  273. TTLastReturnLocationInfo::TTLastReturnLocationInfo()
  274. : m_isExceptionFrame(false)
  275. {
  276. this->m_lastFrame = { 0 };
  277. }
  278. void TTLastReturnLocationInfo::SetReturnLocation(const SingleCallCounter& cframe)
  279. {
  280. this->m_isExceptionFrame = false;
  281. this->m_lastFrame = cframe;
  282. }
  283. void TTLastReturnLocationInfo::SetExceptionLocation(const SingleCallCounter& cframe)
  284. {
  285. this->m_isExceptionFrame = true;
  286. this->m_lastFrame = cframe;
  287. }
  288. bool TTLastReturnLocationInfo::IsDefined() const
  289. {
  290. return this->m_lastFrame.Function != nullptr;
  291. }
  292. bool TTLastReturnLocationInfo::IsReturnLocation() const
  293. {
  294. return this->IsDefined() && !this->m_isExceptionFrame;
  295. }
  296. bool TTLastReturnLocationInfo::IsExceptionLocation() const
  297. {
  298. return this->IsDefined() && this->m_isExceptionFrame;
  299. }
  300. const SingleCallCounter& TTLastReturnLocationInfo::GetLocation() const
  301. {
  302. TTDAssert(this->IsDefined(), "Should check this!");
  303. return this->m_lastFrame;
  304. }
  305. void TTLastReturnLocationInfo::Clear()
  306. {
  307. if(this->IsDefined())
  308. {
  309. this->m_isExceptionFrame = false;
  310. this->m_lastFrame = { 0 };
  311. }
  312. }
  313. void TTLastReturnLocationInfo::ClearReturnOnly()
  314. {
  315. if(this->IsDefined() && !this->m_isExceptionFrame)
  316. {
  317. this->Clear();
  318. }
  319. }
  320. void TTLastReturnLocationInfo::ClearExceptionOnly()
  321. {
  322. if(this->IsDefined() && this->m_isExceptionFrame)
  323. {
  324. this->Clear();
  325. }
  326. }
  327. //////////////////
  328. bool ExecutionInfoManager::ShouldSuppressBreakpointsForTimeTravelMove(TTDMode mode)
  329. {
  330. return (mode & TTD::TTDMode::DebuggerSuppressBreakpoints) == TTD::TTDMode::DebuggerSuppressBreakpoints;
  331. }
  332. bool ExecutionInfoManager::ShouldRecordBreakpointsDuringTimeTravelScan(TTDMode mode)
  333. {
  334. return (mode & TTD::TTDMode::DebuggerLogBreakpoints) == TTD::TTDMode::DebuggerLogBreakpoints;
  335. }
  336. ExecutionInfoManager::ExecutionInfoManager()
  337. : m_topLevelCallbackEventTime(-1), m_runningFunctionTimeCtr(0), m_callStack(&HeapAllocator::Instance),
  338. m_debuggerNotifiedTopLevelBodies(&HeapAllocator::Instance),
  339. m_lastReturnLocation(), m_lastExceptionPropagating(false), m_lastExceptionLocation(),
  340. m_breakOnFirstUserCode(false),
  341. m_pendingTTDBP(), m_pendingTTDMoveMode(-1), m_activeBPId(-1), m_shouldRemoveWhenDone(false), m_activeTTDBP(),
  342. m_hitContinueSearchBP(false), m_continueBreakPoint(),
  343. m_unRestoredBreakpoints(&HeapAllocator::Instance)
  344. {
  345. ;
  346. }
  347. ExecutionInfoManager::~ExecutionInfoManager()
  348. {
  349. if(this->m_unRestoredBreakpoints.Count() != 0)
  350. {
  351. for(int32 i = 0; i < this->m_unRestoredBreakpoints.Count(); ++i)
  352. {
  353. HeapDelete(this->m_unRestoredBreakpoints.Item(i));
  354. }
  355. }
  356. }
  357. #if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
  358. TraceLogger* ExecutionInfoManager::GetTraceLogger()
  359. {
  360. return &(this->m_diagnosticLogger);
  361. }
  362. #endif
  363. const SingleCallCounter& ExecutionInfoManager::GetTopCallCounter() const
  364. {
  365. TTDAssert(this->m_callStack.Count() != 0, "Empty stack!");
  366. return this->m_callStack.Item(this->m_callStack.Count() - 1);
  367. }
  368. SingleCallCounter& ExecutionInfoManager::GetTopCallCounter()
  369. {
  370. TTDAssert(this->m_callStack.Count() != 0, "Empty stack!");
  371. return this->m_callStack.Item(this->m_callStack.Count() - 1);
  372. }
  373. bool ExecutionInfoManager::TryGetTopCallCallerCounter(SingleCallCounter& caller) const
  374. {
  375. if(this->m_callStack.Count() < 2)
  376. {
  377. return false;
  378. }
  379. else
  380. {
  381. caller = this->m_callStack.Item(this->m_callStack.Count() - 2);
  382. return true;
  383. }
  384. }
  385. void ExecutionInfoManager::PushCallEvent(Js::JavascriptFunction* function, uint32 argc, Js::Var* argv, bool isInFinally)
  386. {
  387. //Clear any previous last return frame info
  388. this->m_lastReturnLocation.ClearReturnOnly();
  389. this->m_runningFunctionTimeCtr++;
  390. SingleCallCounter cfinfo;
  391. cfinfo.Function = function->GetFunctionBody();
  392. #if ENABLE_TTD_INTERNAL_DIAGNOSTICS
  393. cfinfo.Name = cfinfo.Function->GetExternalDisplayName();
  394. #endif
  395. cfinfo.FunctionTime = this->m_runningFunctionTimeCtr;
  396. cfinfo.LoopTime = 0;
  397. cfinfo.CurrentStatementIndex = -1;
  398. cfinfo.CurrentStatementLoopTime = 0;
  399. cfinfo.LastStatementIndex = -1;
  400. cfinfo.LastStatementLoopTime = 0;
  401. cfinfo.CurrentStatementBytecodeMin = UINT32_MAX;
  402. cfinfo.CurrentStatementBytecodeMax = UINT32_MAX;
  403. this->m_callStack.Add(cfinfo);
  404. ////
  405. //If we are running for debugger then check if we need to set a breakpoint at entry to the first function we execute
  406. if(this->m_breakOnFirstUserCode)
  407. {
  408. this->m_breakOnFirstUserCode = false;
  409. this->m_activeTTDBP.SetLocationFromFunctionEntryAnyTime(this->m_topLevelCallbackEventTime, cfinfo.Function);
  410. this->SetActiveBP_Helper(function->GetFunctionBody()->GetScriptContext()->GetThreadContext()->TTDContext);
  411. }
  412. ////
  413. #if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
  414. this->m_diagnosticLogger.WriteCall(function, false, argc, argv, function->GetFunctionBody()->GetScriptContext()->GetThreadContext()->TTDLog->GetLastEventTime());
  415. #endif
  416. }
  417. void ExecutionInfoManager::PopCallEvent(Js::JavascriptFunction* function, Js::Var result)
  418. {
  419. this->m_lastReturnLocation.SetReturnLocation(this->m_callStack.Last());
  420. this->m_runningFunctionTimeCtr++;
  421. this->m_callStack.RemoveAtEnd();
  422. #if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
  423. this->m_diagnosticLogger.WriteReturn(function, result, function->GetFunctionBody()->GetScriptContext()->GetThreadContext()->TTDLog->GetLastEventTime());
  424. #endif
  425. }
  426. void ExecutionInfoManager::PopCallEventException(Js::JavascriptFunction* function)
  427. {
  428. //If we already have the last return as an exception then just leave it.
  429. //That is where the exception was first rasied, this return is just propagating it in this return.
  430. if(!this->m_lastReturnLocation.IsExceptionLocation())
  431. {
  432. this->m_lastReturnLocation.SetExceptionLocation(this->m_callStack.Last());
  433. }
  434. if(!m_lastExceptionPropagating)
  435. {
  436. this->m_lastExceptionLocation.SetLocationFromFrame(this->m_topLevelCallbackEventTime, this->m_callStack.Last());
  437. this->m_lastExceptionPropagating = true;
  438. }
  439. this->m_runningFunctionTimeCtr++;
  440. this->m_callStack.RemoveAtEnd();
  441. #if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
  442. this->m_diagnosticLogger.WriteReturnException(function, function->GetFunctionBody()->GetScriptContext()->GetThreadContext()->TTDLog->GetLastEventTime());
  443. #endif
  444. }
  445. void ExecutionInfoManager::ProcessCatchInfoForLastExecutedStatements()
  446. {
  447. this->m_lastReturnLocation.Clear();
  448. this->m_lastExceptionPropagating = false;
  449. }
  450. void ExecutionInfoManager::SetBreakOnFirstUserCode()
  451. {
  452. this->m_breakOnFirstUserCode = true;
  453. }
  454. void ExecutionInfoManager::SetPendingTTDStepBackMove()
  455. {
  456. this->GetPreviousTimeAndPositionForDebugger(this->m_pendingTTDBP);
  457. this->m_pendingTTDMoveMode = 0;
  458. }
  459. void ExecutionInfoManager::SetPendingTTDStepBackIntoMove()
  460. {
  461. this->GetLastExecutedTimeAndPositionForDebugger(this->m_pendingTTDBP);
  462. this->m_pendingTTDMoveMode = 0;
  463. }
  464. void ExecutionInfoManager::SetPendingTTDReverseContinueMove(uint64 moveflag)
  465. {
  466. this->m_continueBreakPoint.Clear();
  467. this->GetTimeAndPositionForDebugger(this->m_pendingTTDBP);
  468. this->m_pendingTTDMoveMode = moveflag;
  469. }
  470. void ExecutionInfoManager::SetPendingTTDUnhandledException()
  471. {
  472. this->GetLastExceptionTimeAndPositionForDebugger(this->m_pendingTTDBP);
  473. this->m_lastExceptionPropagating = false;
  474. this->m_pendingTTDMoveMode = 0;
  475. }
  476. bool ExecutionInfoManager::ProcessBPInfoPreBreak(Js::FunctionBody* fb, const EventLog* elog)
  477. {
  478. //if we aren't in debug mode then we always trigger BP's
  479. if(!fb->GetScriptContext()->ShouldPerformDebuggerAction())
  480. {
  481. return true;
  482. }
  483. //If we are in debugger mode but are suppressing BP's for movement then suppress them
  484. if(ExecutionInfoManager::ShouldSuppressBreakpointsForTimeTravelMove(elog->GetCurrentTTDMode()))
  485. {
  486. //Check if we need to record the visit to this bp
  487. if(ExecutionInfoManager::ShouldRecordBreakpointsDuringTimeTravelScan(elog->GetCurrentTTDMode()))
  488. {
  489. this->AddCurrentLocationDuringScan(elog->GetCurrentTopLevelEventTime());
  490. }
  491. return false;
  492. }
  493. //If we are in debug mode and don't have an active BP target then we treat BP's as usual
  494. if(!this->m_activeTTDBP.HasValue())
  495. {
  496. return true;
  497. }
  498. //Finally we are in debug mode and we have an active BP target so only break if the BP is satisfied
  499. const SingleCallCounter& cfinfo = this->GetTopCallCounter();
  500. //Make sure we are in the right source code (via top level body ids)
  501. if(this->m_activeTTDBP.GetTopLevelBodyId() != cfinfo.Function->GetScriptContext()->TTDContextInfo->FindTopLevelCtrForBody(cfinfo.Function))
  502. {
  503. return false;
  504. }
  505. ULONG srcLine = 0;
  506. LONG srcColumn = -1;
  507. uint32 startOffset = cfinfo.Function->GetStatementStartOffset(cfinfo.CurrentStatementIndex);
  508. cfinfo.Function->GetSourceLineFromStartOffset_TTD(startOffset, &srcLine, &srcColumn);
  509. bool locationOk = ((uint32)srcLine == this->m_activeTTDBP.GetSourceLine()) & ((uint32)srcColumn == this->m_activeTTDBP.GetSourceColumn());
  510. bool ftimeOk = (this->m_activeTTDBP.GetFunctionTime() == -1) | ((uint64)this->m_activeTTDBP.GetFunctionTime() == cfinfo.FunctionTime);
  511. bool ltimeOk = (this->m_activeTTDBP.GetLoopTime() == -1) | ((uint64)this->m_activeTTDBP.GetLoopTime() == cfinfo.CurrentStatementLoopTime);
  512. return locationOk & ftimeOk & ltimeOk;
  513. }
  514. void ExecutionInfoManager::ProcessBPInfoPostBreak(Js::FunctionBody* fb)
  515. {
  516. if(!fb->GetScriptContext()->ShouldPerformDebuggerAction())
  517. {
  518. return;
  519. }
  520. if(this->m_activeTTDBP.HasValue())
  521. {
  522. this->ClearActiveBPInfo(fb->GetScriptContext()->GetThreadContext()->TTDContext);
  523. }
  524. if(this->m_pendingTTDBP.HasValue())
  525. {
  526. //Reset any step controller logic
  527. fb->GetScriptContext()->GetThreadContext()->GetDebugManager()->stepController.Deactivate();
  528. throw TTD::TTDebuggerAbortException::CreateTopLevelAbortRequest(this->m_pendingTTDBP.GetRootEventTime(), this->m_pendingTTDMoveMode, _u("Reverse operation requested."));
  529. }
  530. }
  531. bool ExecutionInfoManager::IsLocationActiveBPAndNotExplicitBP(const TTDebuggerSourceLocation& current) const
  532. {
  533. //If we shound't remove the active BP when done then it is a user visible one so we just return false
  534. if(!this->m_shouldRemoveWhenDone)
  535. {
  536. return false;
  537. }
  538. //Check to see if the locations are the same
  539. return TTDebuggerSourceLocation::AreSameLocations_PlaceOnly(this->m_activeTTDBP, current);
  540. }
  541. void ExecutionInfoManager::AddCurrentLocationDuringScan(int64 topLevelEventTime)
  542. {
  543. TTDebuggerSourceLocation current;
  544. current.SetLocationFromFrame(topLevelEventTime, this->m_callStack.Last());
  545. if(this->m_activeTTDBP.HasValue() && TTDebuggerSourceLocation::AreSameLocations(this->m_activeTTDBP, current))
  546. {
  547. this->m_hitContinueSearchBP = true;
  548. }
  549. if(!this->m_hitContinueSearchBP && !this->IsLocationActiveBPAndNotExplicitBP(current))
  550. {
  551. this->m_continueBreakPoint.SetLocationCopy(current);
  552. }
  553. }
  554. bool ExecutionInfoManager::TryFindAndSetPreviousBP()
  555. {
  556. if(!this->m_continueBreakPoint.HasValue())
  557. {
  558. return false;
  559. }
  560. else
  561. {
  562. this->m_pendingTTDBP.SetLocationCopy(this->m_continueBreakPoint);
  563. this->m_continueBreakPoint.Clear();
  564. return true;
  565. }
  566. }
  567. //Get the target event time for the pending TTD breakpoint
  568. int64 ExecutionInfoManager::GetPendingTTDBPTargetEventTime() const
  569. {
  570. TTDAssert(this->m_pendingTTDBP.HasValue(), "We did not set the pending TTD breakpoint value?");
  571. return this->m_pendingTTDBP.GetRootEventTime();
  572. }
  573. void ExecutionInfoManager::LoadPreservedBPInfo(ThreadContext* threadContext)
  574. {
  575. while(this->m_unRestoredBreakpoints.Contains(nullptr))
  576. {
  577. this->m_unRestoredBreakpoints.Remove(nullptr);
  578. }
  579. const JsUtil::List<Js::ScriptContext*, HeapAllocator>& ctxs = threadContext->TTDContext->GetTTDContexts();
  580. for(int32 i = 0; i < ctxs.Count(); ++i)
  581. {
  582. Js::ScriptContext* ctx = ctxs.Item(i);
  583. JsUtil::List<uint32, HeapAllocator> bpIdsToDelete(&HeapAllocator::Instance);
  584. Js::ProbeContainer* probeContainer = ctx->GetDebugContext()->GetProbeContainer();
  585. probeContainer->MapProbes([&](int j, Js::Probe* pProbe)
  586. {
  587. Js::BreakpointProbe* bp = (Js::BreakpointProbe*)pProbe;
  588. if((int64)bp->GetId() != this->m_activeBPId)
  589. {
  590. Js::FunctionBody* body = bp->GetFunctionBody();
  591. int32 bpIndex = body->GetEnclosingStatementIndexFromByteCode(bp->GetBytecodeOffset());
  592. ULONG srcLine = 0;
  593. LONG srcColumn = -1;
  594. uint32 startOffset = body->GetStatementStartOffset(bpIndex);
  595. body->GetSourceLineFromStartOffset_TTD(startOffset, &srcLine, &srcColumn);
  596. TTDebuggerSourceLocation* bpLocation = TT_HEAP_NEW(TTDebuggerSourceLocation);
  597. bpLocation->SetLocationWithBP(bp->GetId(), body, srcLine, srcColumn);
  598. this->m_unRestoredBreakpoints.Add(bpLocation);
  599. bpIdsToDelete.Add(bp->GetId());
  600. }
  601. });
  602. for(int32 j = 0; j < bpIdsToDelete.Count(); ++j)
  603. {
  604. ctx->TTDHostCallbackFunctor.pfOnBPDeleteCallback(ctx->TTDHostCallbackFunctor.HostRuntime, bpIdsToDelete.Item(j));
  605. }
  606. //done with last context so release the debug document dictionary info
  607. if(i == ctxs.Count() - 1)
  608. {
  609. ctx->TTDHostCallbackFunctor.pfOnBPClearDocumentCallback(ctx->TTDHostCallbackFunctor.HostRuntime);
  610. }
  611. }
  612. }
  613. void ExecutionInfoManager::AddPreservedBPsForTopLevelLoad(uint32 topLevelBodyId, Js::FunctionBody* body)
  614. {
  615. Js::ScriptContext* ctx = body->GetScriptContext();
  616. Js::Utf8SourceInfo* utf8SourceInfo = body->GetUtf8SourceInfo();
  617. for(int32 i = 0; i < this->m_unRestoredBreakpoints.Count(); ++i)
  618. {
  619. if(this->m_unRestoredBreakpoints.Item(i) == nullptr)
  620. {
  621. continue;
  622. }
  623. const TTDebuggerSourceLocation* bpLocation = this->m_unRestoredBreakpoints.Item(i);
  624. if(bpLocation->GetTopLevelBodyId() == topLevelBodyId)
  625. {
  626. BOOL isNewBP = FALSE;
  627. ctx->TTDHostCallbackFunctor.pfOnBPRegisterCallback(ctx->TTDHostCallbackFunctor.HostRuntime, bpLocation->GetBPId(), ctx, utf8SourceInfo, bpLocation->GetSourceLine(), bpLocation->GetSourceColumn(), &isNewBP);
  628. TTDAssert(isNewBP, "We should be restoring a breapoint we removed previously!");
  629. //Now that it is set we can clear it from our list
  630. this->m_unRestoredBreakpoints.SetItem(i, nullptr);
  631. }
  632. }
  633. if(this->m_activeTTDBP.HasValue() && (this->m_activeBPId == -1) && (this->m_activeTTDBP.GetTopLevelBodyId() == topLevelBodyId))
  634. {
  635. this->SetActiveBP_Helper(body->GetScriptContext()->GetThreadContext()->TTDContext);
  636. }
  637. }
  638. void ExecutionInfoManager::UpdateLoopCountInfo()
  639. {
  640. SingleCallCounter& cfinfo = this->m_callStack.Last();
  641. cfinfo.LoopTime++;
  642. }
  643. void ExecutionInfoManager::UpdateCurrentStatementInfo(uint bytecodeOffset)
  644. {
  645. SingleCallCounter& cfinfo = this->GetTopCallCounter();
  646. if((cfinfo.CurrentStatementBytecodeMin <= bytecodeOffset) & (bytecodeOffset <= cfinfo.CurrentStatementBytecodeMax))
  647. {
  648. return;
  649. }
  650. else
  651. {
  652. Js::FunctionBody* fb = cfinfo.Function;
  653. int32 cIndex = fb->GetEnclosingStatementIndexFromByteCode(bytecodeOffset, true);
  654. TTDAssert(cIndex != -1, "Should always have a mapping.");
  655. //we moved to a new statement
  656. Js::FunctionBody::StatementMap* pstmt = fb->GetStatementMaps()->Item(cIndex);
  657. bool newstmt = (cIndex != cfinfo.CurrentStatementIndex && pstmt->byteCodeSpan.begin <= (int)bytecodeOffset && (int)bytecodeOffset <= pstmt->byteCodeSpan.end);
  658. if(newstmt)
  659. {
  660. cfinfo.LastStatementIndex = cfinfo.CurrentStatementIndex;
  661. cfinfo.LastStatementLoopTime = cfinfo.CurrentStatementLoopTime;
  662. cfinfo.CurrentStatementIndex = cIndex;
  663. cfinfo.CurrentStatementLoopTime = cfinfo.LoopTime;
  664. cfinfo.CurrentStatementBytecodeMin = (uint32)pstmt->byteCodeSpan.begin;
  665. cfinfo.CurrentStatementBytecodeMax = (uint32)pstmt->byteCodeSpan.end;
  666. #if ENABLE_FULL_BC_TRACE
  667. ULONG srcLine = 0;
  668. LONG srcColumn = -1;
  669. uint32 startOffset = cfinfo.Function->GetFunctionBody()->GetStatementStartOffset(cfinfo.CurrentStatementIndex);
  670. cfinfo.Function->GetFunctionBody()->GetSourceLineFromStartOffset_TTD(startOffset, &srcLine, &srcColumn);
  671. this->m_diagnosticLogger.WriteStmtIndex((uint32)srcLine, (uint32)srcColumn);
  672. #endif
  673. }
  674. }
  675. }
  676. void ExecutionInfoManager::GetTimeAndPositionForDebugger(TTDebuggerSourceLocation& sourceLocation) const
  677. {
  678. const SingleCallCounter& cfinfo = this->GetTopCallCounter();
  679. ULONG srcLine = 0;
  680. LONG srcColumn = -1;
  681. uint32 startOffset = cfinfo.Function->GetStatementStartOffset(cfinfo.CurrentStatementIndex);
  682. cfinfo.Function->GetSourceLineFromStartOffset_TTD(startOffset, &srcLine, &srcColumn);
  683. sourceLocation.SetLocationFull(this->m_topLevelCallbackEventTime, cfinfo.FunctionTime, cfinfo.LoopTime, cfinfo.Function, srcLine, srcColumn);
  684. }
  685. #if ENABLE_OBJECT_SOURCE_TRACKING
  686. void ExecutionInfoManager::GetTimeAndPositionForDiagnosticObjectTracking(DiagnosticOrigin& originInfo) const
  687. {
  688. const SingleCallCounter& cfinfo = this->GetTopCallCounter();
  689. ULONG srcLine = 0;
  690. LONG srcColumn = -1;
  691. uint32 startOffset = cfinfo.Function->GetStatementStartOffset(cfinfo.CurrentStatementIndex);
  692. cfinfo.Function->GetSourceLineFromStartOffset_TTD(startOffset, &srcLine, &srcColumn);
  693. SetDiagnosticOriginInformation(originInfo, srcLine, cfinfo.Function->GetFunctionBody()->GetScriptContext()->GetThreadContext()->TTDLog->GetLastEventTime(), cfinfo.FunctionTime, cfinfo.LoopTime);
  694. }
  695. #endif
  696. bool ExecutionInfoManager::GetPreviousTimeAndPositionForDebugger(TTDebuggerSourceLocation& sourceLocation) const
  697. {
  698. bool noPrevious = false;
  699. const SingleCallCounter& cfinfo = this->GetTopCallCounter();
  700. //if we are at the first statement in the function then we want the parents current
  701. Js::FunctionBody* fbody = nullptr;
  702. int32 statementIndex = -1;
  703. uint64 ftime = 0;
  704. uint64 ltime = 0;
  705. if(cfinfo.LastStatementIndex == -1)
  706. {
  707. SingleCallCounter cfinfoCaller = { 0 };
  708. bool hasCaller = this->TryGetTopCallCallerCounter(cfinfoCaller);
  709. //check if we are at the first statement in the callback event
  710. if(!hasCaller)
  711. {
  712. //Set the position info to the current statement and return true
  713. noPrevious = true;
  714. ftime = cfinfo.FunctionTime;
  715. ltime = cfinfo.CurrentStatementLoopTime;
  716. fbody = cfinfo.Function;
  717. statementIndex = cfinfo.CurrentStatementIndex;
  718. }
  719. else
  720. {
  721. ftime = cfinfoCaller.FunctionTime;
  722. ltime = cfinfoCaller.CurrentStatementLoopTime;
  723. fbody = cfinfoCaller.Function;
  724. statementIndex = cfinfoCaller.CurrentStatementIndex;
  725. }
  726. }
  727. else
  728. {
  729. ftime = cfinfo.FunctionTime;
  730. ltime = cfinfo.LastStatementLoopTime;
  731. fbody = cfinfo.Function;
  732. statementIndex = cfinfo.LastStatementIndex;
  733. }
  734. ULONG srcLine = 0;
  735. LONG srcColumn = -1;
  736. uint32 startOffset = fbody->GetStatementStartOffset(statementIndex);
  737. fbody->GetSourceLineFromStartOffset_TTD(startOffset, &srcLine, &srcColumn);
  738. sourceLocation.SetLocationFull(this->m_topLevelCallbackEventTime, ftime, ltime, fbody, srcLine, srcColumn);
  739. return noPrevious;
  740. }
  741. void ExecutionInfoManager::GetLastExecutedTimeAndPositionForDebugger(TTDebuggerSourceLocation& sourceLocation) const
  742. {
  743. const TTLastReturnLocationInfo& cframe = this->m_lastReturnLocation;
  744. if(!cframe.IsDefined())
  745. {
  746. sourceLocation.Clear();
  747. return;
  748. }
  749. else
  750. {
  751. ULONG srcLine = 0;
  752. LONG srcColumn = -1;
  753. uint32 startOffset = cframe.GetLocation().Function->GetStatementStartOffset(cframe.GetLocation().CurrentStatementIndex);
  754. cframe.GetLocation().Function->GetSourceLineFromStartOffset_TTD(startOffset, &srcLine, &srcColumn);
  755. sourceLocation.SetLocationFull(this->m_topLevelCallbackEventTime, cframe.GetLocation().FunctionTime, cframe.GetLocation().CurrentStatementLoopTime, cframe.GetLocation().Function, srcLine, srcColumn);
  756. }
  757. }
  758. void ExecutionInfoManager::GetLastExceptionTimeAndPositionForDebugger(TTDebuggerSourceLocation& sourceLocation) const
  759. {
  760. //If no exception then this will also clear sourceLocation
  761. sourceLocation.SetLocationCopy(this->m_lastExceptionLocation);
  762. }
  763. void ExecutionInfoManager::ResetCallStackForTopLevelCall(int64 topLevelCallbackEventTime)
  764. {
  765. TTDAssert(this->m_callStack.Count() == 0, "We should be at the top-level entry!!!");
  766. this->m_topLevelCallbackEventTime = topLevelCallbackEventTime;
  767. this->m_runningFunctionTimeCtr = 0;
  768. this->m_lastReturnLocation.Clear();
  769. this->m_lastExceptionLocation.Clear();
  770. }
  771. void ExecutionInfoManager::SetBPInfoForActiveSegmentContinueScan(ThreadContextTTD* ttdThreadContext)
  772. {
  773. TTDAssert(this->m_pendingTTDBP.HasValue(), "We should always set this when launching a reverse continue!");
  774. this->m_activeTTDBP.SetLocationCopy(this->m_pendingTTDBP);
  775. this->SetActiveBPInfoAsNeeded(ttdThreadContext);
  776. }
  777. void ExecutionInfoManager::ClearBPInfoForActiveSegmentContinueScan(ThreadContextTTD* ttdThreadContext)
  778. {
  779. TTDAssert(this->m_activeTTDBP.HasValue(), "We should always have this set when we complete the active segment scan.");
  780. this->m_hitContinueSearchBP = false;
  781. this->ClearActiveBPInfo(ttdThreadContext);
  782. }
  783. void ExecutionInfoManager::SetActiveBP_Helper(ThreadContextTTD* ttdThreadContext)
  784. {
  785. Js::ScriptContext* ctx = ttdThreadContext->LookupContextForScriptId(this->m_activeTTDBP.GetScriptLogTagId());
  786. Js::FunctionBody* body = this->m_activeTTDBP.LoadFunctionBodyIfPossible(ctx);
  787. if(body == nullptr)
  788. {
  789. return;
  790. }
  791. Js::Utf8SourceInfo* utf8SourceInfo = body->GetUtf8SourceInfo();
  792. Js::DebugDocument* debugDocument = utf8SourceInfo->GetDebugDocument();
  793. TTDAssert(debugDocument != nullptr, "Something went wrong with our TTD debug breakpoints.");
  794. utf8SourceInfo->EnsureLineOffsetCacheNoThrow();
  795. charcount_t charPosition = 0;
  796. charcount_t byteOffset = 0;
  797. utf8SourceInfo->GetCharPositionForLineInfo(this->m_activeTTDBP.GetSourceLine(), &charPosition, &byteOffset);
  798. long ibos = charPosition + this->m_activeTTDBP.GetSourceColumn() + 1;
  799. Js::StatementLocation statement;
  800. debugDocument->GetStatementLocation(ibos, &statement);
  801. // Don't see a use case for supporting multiple breakpoints at same location.
  802. // If a breakpoint already exists, just return that
  803. Js::BreakpointProbe* probe = debugDocument->FindBreakpoint(statement);
  804. if(probe == nullptr)
  805. {
  806. this->m_shouldRemoveWhenDone = true;
  807. probe = debugDocument->SetBreakPoint(statement, BREAKPOINT_ENABLED);
  808. }
  809. this->m_activeBPId = probe->GetId();
  810. }
  811. void ExecutionInfoManager::SetActiveBPInfoAsNeeded(ThreadContextTTD* ttdThreadContext)
  812. {
  813. if(this->m_pendingTTDBP.HasValue())
  814. {
  815. this->m_activeTTDBP.SetLocationCopy(this->m_pendingTTDBP);
  816. this->SetActiveBP_Helper(ttdThreadContext);
  817. //Finally clear the pending BP info so we don't get confused later
  818. this->m_pendingTTDMoveMode = 0;
  819. this->m_pendingTTDBP.Clear();
  820. }
  821. }
  822. void ExecutionInfoManager::ClearActiveBPInfo(ThreadContextTTD* ttdThreadContext)
  823. {
  824. TTDAssert(this->m_activeTTDBP.HasValue(), "Need to check that we actually have info to clear first.");
  825. Js::ScriptContext* ctx = ttdThreadContext->LookupContextForScriptId(this->m_activeTTDBP.GetScriptLogTagId());
  826. Js::FunctionBody* body = this->m_activeTTDBP.LoadFunctionBodyIfPossible(ctx);
  827. Js::DebugDocument* debugDocument = body->GetUtf8SourceInfo()->GetDebugDocument();
  828. Js::StatementLocation statement;
  829. if(this->m_shouldRemoveWhenDone && debugDocument->FindBPStatementLocation((UINT)this->m_activeBPId, &statement))
  830. {
  831. debugDocument->SetBreakPoint(statement, BREAKPOINT_DELETED);
  832. }
  833. this->m_activeBPId = -1;
  834. this->m_shouldRemoveWhenDone = false;
  835. this->m_activeTTDBP.Clear();
  836. }
  837. void ExecutionInfoManager::ProcessScriptLoad(Js::ScriptContext* ctx, uint32 topLevelBodyId, Js::FunctionBody* body, Js::Utf8SourceInfo* utf8SourceInfo, CompileScriptException* se)
  838. {
  839. bool newScript = !this->m_debuggerNotifiedTopLevelBodies.Contains(topLevelBodyId);
  840. //Only notify of loaded script -- eval and new script is only notified later if we need to hit a bp in it?
  841. if(se != nullptr)
  842. {
  843. ctx->TTDHostCallbackFunctor.pfOnScriptLoadCallback(ctx->TTDHostCallbackFunctor.HostContext, body, utf8SourceInfo, se, newScript);
  844. }
  845. if(newScript)
  846. {
  847. this->m_debuggerNotifiedTopLevelBodies.AddNew(topLevelBodyId);
  848. }
  849. this->AddPreservedBPsForTopLevelLoad(topLevelBodyId, body);
  850. }
  851. void ExecutionInfoManager::ProcessScriptLoad_InflateReuseBody(uint32 topLevelBodyId, Js::FunctionBody* body)
  852. {
  853. this->AddPreservedBPsForTopLevelLoad(topLevelBodyId, body);
  854. }
  855. }
  856. #endif