DebugManager.cpp 9.8 KB

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