| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "RuntimeDebugPch.h"
- #ifdef ENABLE_SCRIPT_DEBUGGING
- #include "Language/JavascriptStackWalker.h"
- namespace Js
- {
- DebugManager::DebugManager(ThreadContext* _pThreadContext, AllocationPolicyManager * allocationPolicyManager) :
- pCurrentInterpreterLocation(nullptr),
- secondaryCurrentSourceContext(0),
- debugSessionNumber(0),
- pThreadContext(_pThreadContext),
- isAtDispatchHalt(false),
- mutationNewValuePid(Js::Constants::NoProperty),
- mutationPropertyNamePid(Js::Constants::NoProperty),
- mutationTypePid(Js::Constants::NoProperty),
- diagnosticPageAllocator(allocationPolicyManager, Js::Configuration::Global.flags, PageAllocatorType_Diag, 0),
- evalCodeRegistrationCount(0),
- anonymousCodeRegistrationCount(0),
- jscriptBlockRegistrationCount(0),
- isDebuggerAttaching(false),
- nextBreakPointId(0),
- localsDisplayFlags(LocalsDisplayFlags_None),
- dispatchHaltFrameAddress(nullptr)
- {
- Assert(_pThreadContext != nullptr);
- #if DBG
- // diagnosticPageAllocator may be used in multiple thread, but it's usage is synchronized.
- diagnosticPageAllocator.SetDisableThreadAccessCheck();
- diagnosticPageAllocator.debugName = _u("Diagnostic");
- #endif
- }
- void DebugManager::Close()
- {
- this->diagnosticPageAllocator.Close();
- if (this->pConsoleScope)
- {
- this->pConsoleScope.Unroot(this->pThreadContext->GetRecycler());
- }
- #if DBG
- this->pThreadContext->EnsureNoReturnedValueList();
- #endif
- this->pThreadContext = nullptr;
- }
- DebugManager::~DebugManager()
- {
- Assert(this->pThreadContext == nullptr);
- }
- DebuggingFlags* DebugManager::GetDebuggingFlags()
- {
- return &this->debuggingFlags;
- }
- intptr_t DebugManager::GetDebuggingFlagsAddr() const
- {
- return (intptr_t)&this->debuggingFlags;
- }
- ReferencedArenaAdapter* DebugManager::GetDiagnosticArena()
- {
- if (pCurrentInterpreterLocation)
- {
- return pCurrentInterpreterLocation->referencedDiagnosticArena;
- }
- return nullptr;
- }
- DWORD_PTR DebugManager::AllocateSecondaryHostSourceContext()
- {
- Assert(secondaryCurrentSourceContext < ULONG_MAX);
- return secondaryCurrentSourceContext++; // The context is not valid, use the secondary context for identify the function body for further use.
- }
- void DebugManager::SetCurrentInterpreterLocation(InterpreterHaltState* pHaltState)
- {
- Assert(pHaltState);
- Assert(!pCurrentInterpreterLocation);
- pCurrentInterpreterLocation = pHaltState;
- AutoAllocatorObjectPtr<ArenaAllocator, HeapAllocator> pDiagArena(HeapNew(ArenaAllocator, _u("DiagHaltState"), this->pThreadContext->GetPageAllocator(), Js::Throw::OutOfMemory), &HeapAllocator::Instance);
- AutoAllocatorObjectPtr<ReferencedArenaAdapter, HeapAllocator> referencedDiagnosticArena(HeapNew(ReferencedArenaAdapter, pDiagArena), &HeapAllocator::Instance);
- pCurrentInterpreterLocation->referencedDiagnosticArena = referencedDiagnosticArena;
- pThreadContext->GetRecycler()->RegisterExternalGuestArena(pDiagArena);
- debugSessionNumber++;
- pDiagArena.Detach();
- referencedDiagnosticArena.Detach();
- }
- void DebugManager::UnsetCurrentInterpreterLocation()
- {
- Assert(pCurrentInterpreterLocation);
- if (pCurrentInterpreterLocation)
- {
- // pCurrentInterpreterLocation->referencedDiagnosticArena could be null if we ran out of memory during SetCurrentInterpreterLocation
- if (pCurrentInterpreterLocation->referencedDiagnosticArena)
- {
- pThreadContext->GetRecycler()->UnregisterExternalGuestArena(pCurrentInterpreterLocation->referencedDiagnosticArena->Arena());
- pCurrentInterpreterLocation->referencedDiagnosticArena->DeleteArena();
- pCurrentInterpreterLocation->referencedDiagnosticArena->Release();
- }
- pCurrentInterpreterLocation = nullptr;
- }
- }
- bool DebugManager::IsMatchTopFrameStackAddress(DiagStackFrame* frame) const
- {
- return (frame != nullptr) &&
- (this->pCurrentInterpreterLocation != nullptr) &&
- (this->pCurrentInterpreterLocation->topFrame != nullptr) &&
- (this->pCurrentInterpreterLocation->topFrame->GetStackAddress() == frame->GetStackAddress());
- }
- #ifdef ENABLE_MUTATION_BREAKPOINT
- MutationBreakpoint* DebugManager::GetActiveMutationBreakpoint() const
- {
- Assert(this->pCurrentInterpreterLocation);
- return this->pCurrentInterpreterLocation->activeMutationBP;
- }
- #endif
- DynamicObject* DebugManager::GetConsoleScope(ScriptContext* scriptContext)
- {
- Assert(scriptContext);
- if (!this->pConsoleScope)
- {
- this->pConsoleScope.Root(scriptContext->GetLibrary()->CreateConsoleScopeActivationObject(), this->pThreadContext->GetRecycler());
- }
- return (DynamicObject*)CrossSite::MarshalVar(scriptContext, (Var)this->pConsoleScope);
- }
- FrameDisplay *DebugManager::GetFrameDisplay(ScriptContext* scriptContext, DynamicObject* scopeAtZero, DynamicObject* scopeAtOne)
- {
- // The scope chain for console eval looks like:
- // - dummy empty object - new vars, let, consts, functions get added here
- // - Active scope object containing all globals visible at this break (if at break)
- // - Global this object so that existing properties are updated here
- // - Console-1 Scope - all new globals will go here (like x = 1;)
- // - NullFrameDisplay
- FrameDisplay* environment = JavascriptOperators::OP_LdFrameDisplay(this->GetConsoleScope(scriptContext), const_cast<FrameDisplay *>(&NullFrameDisplay), scriptContext);
- environment = JavascriptOperators::OP_LdFrameDisplay(scriptContext->GetGlobalObject()->ToThis(), environment, scriptContext);
- if (scopeAtOne != nullptr)
- {
- environment = JavascriptOperators::OP_LdFrameDisplay((Var)scopeAtOne, environment, scriptContext);
- }
- environment = JavascriptOperators::OP_LdFrameDisplay((Var)scopeAtZero, environment, scriptContext);
- return environment;
- }
- void DebugManager::UpdateConsoleScope(DynamicObject* copyFromScope, ScriptContext* scriptContext)
- {
- Assert(copyFromScope != nullptr);
- DynamicObject* consoleScope = this->GetConsoleScope(scriptContext);
- uint32 newPropCount = copyFromScope->GetPropertyCount();
- for (uint32 i = 0; i < newPropCount; i++)
- {
- Js::PropertyId propertyId = copyFromScope->GetPropertyId((Js::PropertyIndex)i);
- // For deleted properties we won't have a property id
- if (propertyId != Js::Constants::NoProperty)
- {
- PropertyDescriptor propertyDescriptor;
- BOOL gotPropertyValue = JavascriptOperators::GetOwnPropertyDescriptor(copyFromScope, propertyId, scriptContext, &propertyDescriptor);
- AssertMsg(gotPropertyValue, "DebugManager::UpdateConsoleScope Should have got valid value?");
- OUTPUT_TRACE(Js::ConsoleScopePhase, _u("Adding property '%s'\n"), scriptContext->GetPropertyName(propertyId)->GetBuffer());
- BOOL updateSuccess = JavascriptOperators::SetPropertyDescriptor(consoleScope, propertyId, propertyDescriptor);
- AssertMsg(updateSuccess, "DebugManager::UpdateConsoleScope Unable to update property value. Am I missing a scenario?");
- }
- }
- OUTPUT_TRACE(Js::ConsoleScopePhase, _u("Number of properties on console scope object after update are %d\n"), consoleScope->GetPropertyCount());
- }
- #if DBG
- void DebugManager::ValidateDebugAPICall()
- {
- Js::JavascriptStackWalker walker(this->pThreadContext->GetScriptEntryExit()->scriptContext);
- Js::JavascriptFunction* javascriptFunction = nullptr;
- if (walker.GetCaller(&javascriptFunction))
- {
- if (javascriptFunction != nullptr)
- {
- void *topJsFrameAddr = (void *)walker.GetCurrentArgv();
- Assert(this->dispatchHaltFrameAddress != nullptr);
- if (topJsFrameAddr < this->dispatchHaltFrameAddress)
- {
- // we found the script frame after the break mode.
- AssertMsg(false, "There are JavaScript frames between current API and dispatch halt");
- }
- }
- }
- }
- #endif
- }
- AutoSetDispatchHaltFlag::AutoSetDispatchHaltFlag(Js::ScriptContext *scriptContext, ThreadContext *threadContext) :
- m_scriptContext(scriptContext),
- m_threadContext(threadContext)
- {
- Assert(m_scriptContext != nullptr);
- Assert(m_threadContext != nullptr);
- Assert(!m_threadContext->GetDebugManager()->IsAtDispatchHalt());
- m_threadContext->GetDebugManager()->SetDispatchHalt(true);
- Assert(!m_scriptContext->GetDebugContext()->GetProbeContainer()->IsPrimaryBrokenToDebuggerContext());
- m_scriptContext->GetDebugContext()->GetProbeContainer()->SetIsPrimaryBrokenToDebuggerContext(true);
- }
- AutoSetDispatchHaltFlag::~AutoSetDispatchHaltFlag()
- {
- Assert(m_threadContext->GetDebugManager()->IsAtDispatchHalt());
- m_threadContext->GetDebugManager()->SetDispatchHalt(false);
- Assert(m_scriptContext->GetDebugContext()->GetProbeContainer()->IsPrimaryBrokenToDebuggerContext());
- m_scriptContext->GetDebugContext()->GetProbeContainer()->SetIsPrimaryBrokenToDebuggerContext(false);
- }
- #endif
|