DebugManager.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. #ifdef ENABLE_SCRIPT_DEBUGGING
  7. #include "Language/JavascriptStackWalker.h"
  8. namespace Js
  9. {
  10. DebugManager::DebugManager(ThreadContext* _pThreadContext, AllocationPolicyManager * allocationPolicyManager) :
  11. pCurrentInterpreterLocation(nullptr),
  12. secondaryCurrentSourceContext(0),
  13. debugSessionNumber(0),
  14. pThreadContext(_pThreadContext),
  15. isAtDispatchHalt(false),
  16. mutationNewValuePid(Js::Constants::NoProperty),
  17. mutationPropertyNamePid(Js::Constants::NoProperty),
  18. mutationTypePid(Js::Constants::NoProperty),
  19. diagnosticPageAllocator(allocationPolicyManager, Js::Configuration::Global.flags, PageAllocatorType_Diag, 0),
  20. evalCodeRegistrationCount(0),
  21. anonymousCodeRegistrationCount(0),
  22. jscriptBlockRegistrationCount(0),
  23. isDebuggerAttaching(false),
  24. nextBreakPointId(0),
  25. localsDisplayFlags(LocalsDisplayFlags_None),
  26. dispatchHaltFrameAddress(nullptr)
  27. {
  28. Assert(_pThreadContext != nullptr);
  29. #if DBG
  30. // diagnosticPageAllocator may be used in multiple thread, but it's usage is synchronized.
  31. diagnosticPageAllocator.SetDisableThreadAccessCheck();
  32. diagnosticPageAllocator.debugName = _u("Diagnostic");
  33. #endif
  34. }
  35. void DebugManager::Close()
  36. {
  37. this->diagnosticPageAllocator.Close();
  38. if (this->pConsoleScope)
  39. {
  40. this->pConsoleScope.Unroot(this->pThreadContext->GetRecycler());
  41. }
  42. #if DBG
  43. this->pThreadContext->EnsureNoReturnedValueList();
  44. #endif
  45. this->pThreadContext = nullptr;
  46. }
  47. DebugManager::~DebugManager()
  48. {
  49. Assert(this->pThreadContext == nullptr);
  50. }
  51. DebuggingFlags* DebugManager::GetDebuggingFlags()
  52. {
  53. return &this->debuggingFlags;
  54. }
  55. intptr_t DebugManager::GetDebuggingFlagsAddr() const
  56. {
  57. return (intptr_t)&this->debuggingFlags;
  58. }
  59. ReferencedArenaAdapter* DebugManager::GetDiagnosticArena()
  60. {
  61. if (pCurrentInterpreterLocation)
  62. {
  63. return pCurrentInterpreterLocation->referencedDiagnosticArena;
  64. }
  65. return nullptr;
  66. }
  67. DWORD_PTR DebugManager::AllocateSecondaryHostSourceContext()
  68. {
  69. Assert(secondaryCurrentSourceContext < ULONG_MAX);
  70. return secondaryCurrentSourceContext++; // The context is not valid, use the secondary context for identify the function body for further use.
  71. }
  72. void DebugManager::SetCurrentInterpreterLocation(InterpreterHaltState* pHaltState)
  73. {
  74. Assert(pHaltState);
  75. Assert(!pCurrentInterpreterLocation);
  76. pCurrentInterpreterLocation = pHaltState;
  77. AutoAllocatorObjectPtr<ArenaAllocator, HeapAllocator> pDiagArena(HeapNew(ArenaAllocator, _u("DiagHaltState"), this->pThreadContext->GetPageAllocator(), Js::Throw::OutOfMemory), &HeapAllocator::Instance);
  78. AutoAllocatorObjectPtr<ReferencedArenaAdapter, HeapAllocator> referencedDiagnosticArena(HeapNew(ReferencedArenaAdapter, pDiagArena), &HeapAllocator::Instance);
  79. pCurrentInterpreterLocation->referencedDiagnosticArena = referencedDiagnosticArena;
  80. pThreadContext->GetRecycler()->RegisterExternalGuestArena(pDiagArena);
  81. debugSessionNumber++;
  82. pDiagArena.Detach();
  83. referencedDiagnosticArena.Detach();
  84. }
  85. void DebugManager::UnsetCurrentInterpreterLocation()
  86. {
  87. Assert(pCurrentInterpreterLocation);
  88. if (pCurrentInterpreterLocation)
  89. {
  90. // pCurrentInterpreterLocation->referencedDiagnosticArena could be null if we ran out of memory during SetCurrentInterpreterLocation
  91. if (pCurrentInterpreterLocation->referencedDiagnosticArena)
  92. {
  93. pThreadContext->GetRecycler()->UnregisterExternalGuestArena(pCurrentInterpreterLocation->referencedDiagnosticArena->Arena());
  94. pCurrentInterpreterLocation->referencedDiagnosticArena->DeleteArena();
  95. pCurrentInterpreterLocation->referencedDiagnosticArena->Release();
  96. }
  97. pCurrentInterpreterLocation = nullptr;
  98. }
  99. }
  100. bool DebugManager::IsMatchTopFrameStackAddress(DiagStackFrame* frame) const
  101. {
  102. return (frame != nullptr) &&
  103. (this->pCurrentInterpreterLocation != nullptr) &&
  104. (this->pCurrentInterpreterLocation->topFrame != nullptr) &&
  105. (this->pCurrentInterpreterLocation->topFrame->GetStackAddress() == frame->GetStackAddress());
  106. }
  107. #ifdef ENABLE_MUTATION_BREAKPOINT
  108. MutationBreakpoint* DebugManager::GetActiveMutationBreakpoint() const
  109. {
  110. Assert(this->pCurrentInterpreterLocation);
  111. return this->pCurrentInterpreterLocation->activeMutationBP;
  112. }
  113. #endif
  114. DynamicObject* DebugManager::GetConsoleScope(ScriptContext* scriptContext)
  115. {
  116. Assert(scriptContext);
  117. if (!this->pConsoleScope)
  118. {
  119. this->pConsoleScope.Root(scriptContext->GetLibrary()->CreateConsoleScopeActivationObject(), this->pThreadContext->GetRecycler());
  120. }
  121. return (DynamicObject*)CrossSite::MarshalVar(scriptContext, (Var)this->pConsoleScope);
  122. }
  123. FrameDisplay *DebugManager::GetFrameDisplay(ScriptContext* scriptContext, DynamicObject* scopeAtZero, DynamicObject* scopeAtOne)
  124. {
  125. // The scope chain for console eval looks like:
  126. // - dummy empty object - new vars, let, consts, functions get added here
  127. // - Active scope object containing all globals visible at this break (if at break)
  128. // - Global this object so that existing properties are updated here
  129. // - Console-1 Scope - all new globals will go here (like x = 1;)
  130. // - NullFrameDisplay
  131. FrameDisplay* environment = JavascriptOperators::OP_LdFrameDisplay(this->GetConsoleScope(scriptContext), const_cast<FrameDisplay *>(&NullFrameDisplay), scriptContext);
  132. environment = JavascriptOperators::OP_LdFrameDisplay(scriptContext->GetGlobalObject()->ToThis(), environment, scriptContext);
  133. if (scopeAtOne != nullptr)
  134. {
  135. environment = JavascriptOperators::OP_LdFrameDisplay((Var)scopeAtOne, environment, scriptContext);
  136. }
  137. environment = JavascriptOperators::OP_LdFrameDisplay((Var)scopeAtZero, environment, scriptContext);
  138. return environment;
  139. }
  140. void DebugManager::UpdateConsoleScope(DynamicObject* copyFromScope, ScriptContext* scriptContext)
  141. {
  142. Assert(copyFromScope != nullptr);
  143. DynamicObject* consoleScope = this->GetConsoleScope(scriptContext);
  144. uint32 newPropCount = copyFromScope->GetPropertyCount();
  145. for (uint32 i = 0; i < newPropCount; i++)
  146. {
  147. Js::PropertyId propertyId = copyFromScope->GetPropertyId((Js::PropertyIndex)i);
  148. // For deleted properties we won't have a property id
  149. if (propertyId != Js::Constants::NoProperty)
  150. {
  151. PropertyDescriptor propertyDescriptor;
  152. BOOL gotPropertyValue = JavascriptOperators::GetOwnPropertyDescriptor(copyFromScope, propertyId, scriptContext, &propertyDescriptor);
  153. AssertMsg(gotPropertyValue, "DebugManager::UpdateConsoleScope Should have got valid value?");
  154. OUTPUT_TRACE(Js::ConsoleScopePhase, _u("Adding property '%s'\n"), scriptContext->GetPropertyName(propertyId)->GetBuffer());
  155. BOOL updateSuccess = JavascriptOperators::SetPropertyDescriptor(consoleScope, propertyId, propertyDescriptor);
  156. AssertMsg(updateSuccess, "DebugManager::UpdateConsoleScope Unable to update property value. Am I missing a scenario?");
  157. }
  158. }
  159. OUTPUT_TRACE(Js::ConsoleScopePhase, _u("Number of properties on console scope object after update are %d\n"), consoleScope->GetPropertyCount());
  160. }
  161. #if DBG
  162. void DebugManager::ValidateDebugAPICall()
  163. {
  164. Js::JavascriptStackWalker walker(this->pThreadContext->GetScriptEntryExit()->scriptContext);
  165. Js::JavascriptFunction* javascriptFunction = nullptr;
  166. if (walker.GetCaller(&javascriptFunction))
  167. {
  168. if (javascriptFunction != nullptr)
  169. {
  170. void *topJsFrameAddr = (void *)walker.GetCurrentArgv();
  171. Assert(this->dispatchHaltFrameAddress != nullptr);
  172. if (topJsFrameAddr < this->dispatchHaltFrameAddress)
  173. {
  174. // we found the script frame after the break mode.
  175. AssertMsg(false, "There are JavaScript frames between current API and dispatch halt");
  176. }
  177. }
  178. }
  179. }
  180. #endif
  181. }
  182. AutoSetDispatchHaltFlag::AutoSetDispatchHaltFlag(Js::ScriptContext *scriptContext, ThreadContext *threadContext) :
  183. m_scriptContext(scriptContext),
  184. m_threadContext(threadContext)
  185. {
  186. Assert(m_scriptContext != nullptr);
  187. Assert(m_threadContext != nullptr);
  188. Assert(!m_threadContext->GetDebugManager()->IsAtDispatchHalt());
  189. m_threadContext->GetDebugManager()->SetDispatchHalt(true);
  190. Assert(!m_scriptContext->GetDebugContext()->GetProbeContainer()->IsPrimaryBrokenToDebuggerContext());
  191. m_scriptContext->GetDebugContext()->GetProbeContainer()->SetIsPrimaryBrokenToDebuggerContext(true);
  192. }
  193. AutoSetDispatchHaltFlag::~AutoSetDispatchHaltFlag()
  194. {
  195. Assert(m_threadContext->GetDebugManager()->IsAtDispatchHalt());
  196. m_threadContext->GetDebugManager()->SetDispatchHalt(false);
  197. Assert(m_scriptContext->GetDebugContext()->GetProbeContainer()->IsPrimaryBrokenToDebuggerContext());
  198. m_scriptContext->GetDebugContext()->GetProbeContainer()->SetIsPrimaryBrokenToDebuggerContext(false);
  199. }
  200. #endif