2 * Copyright (C) 2008, 2013, 2014 Apple Inc. All rights reserved.
3 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
4 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "CodeBlock.h"
26 #include "DebuggerCallFrame.h"
28 #include "HeapIterationScope.h"
29 #include "Interpreter.h"
30 #include "JSCJSValueInlines.h"
31 #include "JSFunction.h"
32 #include "JSGlobalObject.h"
33 #include "JSCInlines.h"
36 #include "VMEntryScope.h"
42 struct GatherSourceProviders : public MarkedBlock::VoidFunctor {
43 HashSet<SourceProvider*> sourceProviders;
44 JSGlobalObject* m_globalObject;
46 GatherSourceProviders(JSGlobalObject* globalObject)
47 : m_globalObject(globalObject) { }
49 IterationStatus operator()(JSCell* cell)
51 JSFunction* function = jsDynamicCast<JSFunction*>(cell);
53 return IterationStatus::Continue;
55 if (function->scope()->globalObject() != m_globalObject)
56 return IterationStatus::Continue;
58 if (!function->executable()->isFunctionExecutable())
59 return IterationStatus::Continue;
61 if (function->isHostOrBuiltinFunction())
62 return IterationStatus::Continue;
65 jsCast<FunctionExecutable*>(function->executable())->source().provider());
66 return IterationStatus::Continue;
74 class DebuggerPausedScope {
76 DebuggerPausedScope(Debugger& debugger)
77 : m_debugger(debugger)
79 ASSERT(!m_debugger.m_currentDebuggerCallFrame);
80 if (m_debugger.m_currentCallFrame)
81 m_debugger.m_currentDebuggerCallFrame = DebuggerCallFrame::create(debugger.m_currentCallFrame);
84 ~DebuggerPausedScope()
86 if (m_debugger.m_currentDebuggerCallFrame) {
87 m_debugger.m_currentDebuggerCallFrame->invalidate();
88 m_debugger.m_currentDebuggerCallFrame = nullptr;
96 // This is very similar to TemporaryChange<bool>, but that cannot be used
97 // as the m_isPaused field uses only one bit.
98 class TemporaryPausedState {
100 TemporaryPausedState(Debugger& debugger)
101 : m_debugger(debugger)
103 ASSERT(!m_debugger.m_isPaused);
104 m_debugger.m_isPaused = true;
107 ~TemporaryPausedState()
109 m_debugger.m_isPaused = false;
113 Debugger& m_debugger;
116 Debugger::Debugger(VM& vm)
118 , m_pauseOnExceptionsState(DontPauseOnExceptions)
119 , m_pauseOnNextStatement(false)
121 , m_breakpointsActivated(false)
122 , m_hasHandlerForExceptionCallback(false)
123 , m_suppressAllPauses(false)
124 , m_steppingMode(SteppingModeDisabled)
125 , m_reasonForPause(NotPaused)
126 , m_pauseOnCallFrame(0)
127 , m_currentCallFrame(0)
128 , m_lastExecutedLine(UINT_MAX)
129 , m_lastExecutedSourceID(noSourceID)
130 , m_topBreakpointID(noBreakpointID)
131 , m_pausingBreakpointID(noBreakpointID)
135 Debugger::~Debugger()
137 HashSet<JSGlobalObject*>::iterator end = m_globalObjects.end();
138 for (HashSet<JSGlobalObject*>::iterator it = m_globalObjects.begin(); it != end; ++it)
139 (*it)->setDebugger(0);
142 void Debugger::attach(JSGlobalObject* globalObject)
144 ASSERT(!globalObject->debugger());
145 globalObject->setDebugger(this);
146 m_globalObjects.add(globalObject);
148 m_vm.setShouldBuildPCToCodeOriginMapping();
150 // Call sourceParsed because it will execute JavaScript in the inspector.
151 GatherSourceProviders gatherSourceProviders(globalObject);
153 HeapIterationScope iterationScope(m_vm.heap);
154 m_vm.heap.objectSpace().forEachLiveCell(iterationScope, gatherSourceProviders);
156 for (auto* sourceProvider : gatherSourceProviders.sourceProviders)
157 sourceParsed(globalObject->globalExec(), sourceProvider, -1, String());
160 void Debugger::detach(JSGlobalObject* globalObject, ReasonForDetach reason)
162 // If we're detaching from the currently executing global object, manually tear down our
163 // stack, since we won't get further debugger callbacks to do so. Also, resume execution,
164 // since there's no point in staying paused once a window closes.
165 if (m_isPaused && m_currentCallFrame && m_currentCallFrame->vmEntryGlobalObject() == globalObject) {
166 m_currentCallFrame = 0;
167 m_pauseOnCallFrame = 0;
171 ASSERT(m_globalObjects.contains(globalObject));
172 m_globalObjects.remove(globalObject);
174 // If the globalObject is destructing, then its CodeBlocks will also be
175 // destructed. There is no need to do the debugger requests clean up, and
176 // it is not safe to access those CodeBlocks at this time anyway.
177 if (reason != GlobalObjectIsDestructing)
178 clearDebuggerRequests(globalObject);
180 globalObject->setDebugger(0);
183 bool Debugger::isAttached(JSGlobalObject* globalObject)
185 return globalObject->debugger() == this;
188 class Debugger::SetSteppingModeFunctor {
190 SetSteppingModeFunctor(Debugger* debugger, SteppingMode mode)
191 : m_debugger(debugger)
196 bool operator()(CodeBlock* codeBlock)
198 if (m_debugger == codeBlock->globalObject()->debugger()) {
199 if (m_mode == SteppingModeEnabled)
200 codeBlock->setSteppingMode(CodeBlock::SteppingModeEnabled);
202 codeBlock->setSteppingMode(CodeBlock::SteppingModeDisabled);
208 Debugger* m_debugger;
212 void Debugger::setSteppingMode(SteppingMode mode)
214 if (mode == m_steppingMode)
217 m_vm.heap.completeAllDFGPlans();
219 m_steppingMode = mode;
220 SetSteppingModeFunctor functor(this, mode);
221 m_vm.heap.forEachCodeBlock(functor);
224 void Debugger::registerCodeBlock(CodeBlock* codeBlock)
226 applyBreakpoints(codeBlock);
228 codeBlock->setSteppingMode(CodeBlock::SteppingModeEnabled);
231 void Debugger::setProfilingClient(ProfilingClient* client)
233 ASSERT(!!m_profilingClient != !!client);
234 m_profilingClient = client;
237 double Debugger::willEvaluateScript()
239 return m_profilingClient->willEvaluateScript();
242 void Debugger::didEvaluateScript(double startTime, ProfilingReason reason)
244 m_profilingClient->didEvaluateScript(startTime, reason);
247 void Debugger::toggleBreakpoint(CodeBlock* codeBlock, Breakpoint& breakpoint, BreakpointState enabledOrNot)
249 ScriptExecutable* executable = codeBlock->ownerScriptExecutable();
251 SourceID sourceID = static_cast<SourceID>(executable->sourceID());
252 if (breakpoint.sourceID != sourceID)
255 unsigned line = breakpoint.line;
256 unsigned column = breakpoint.column;
258 unsigned startLine = executable->firstLine();
259 unsigned startColumn = executable->startColumn();
260 unsigned endLine = executable->lastLine();
261 unsigned endColumn = executable->endColumn();
263 // Inspector breakpoint line and column values are zero-based but the executable
264 // and CodeBlock line and column values are one-based.
266 column = column ? column + 1 : Breakpoint::unspecifiedColumn;
268 if (line < startLine || line > endLine)
270 if (column != Breakpoint::unspecifiedColumn) {
271 if (line == startLine && column < startColumn)
273 if (line == endLine && column > endColumn)
276 if (!codeBlock->hasOpDebugForLineAndColumn(line, column))
279 if (enabledOrNot == BreakpointEnabled)
280 codeBlock->addBreakpoint(1);
282 codeBlock->removeBreakpoint(1);
285 void Debugger::applyBreakpoints(CodeBlock* codeBlock)
287 BreakpointIDToBreakpointMap& breakpoints = m_breakpointIDToBreakpoint;
288 for (auto it = breakpoints.begin(); it != breakpoints.end(); ++it) {
289 Breakpoint& breakpoint = *it->value;
290 toggleBreakpoint(codeBlock, breakpoint, BreakpointEnabled);
294 class Debugger::ToggleBreakpointFunctor {
296 ToggleBreakpointFunctor(Debugger* debugger, Breakpoint& breakpoint, BreakpointState enabledOrNot)
297 : m_debugger(debugger)
298 , m_breakpoint(breakpoint)
299 , m_enabledOrNot(enabledOrNot)
303 bool operator()(CodeBlock* codeBlock)
305 if (m_debugger == codeBlock->globalObject()->debugger())
306 m_debugger->toggleBreakpoint(codeBlock, m_breakpoint, m_enabledOrNot);
311 Debugger* m_debugger;
312 Breakpoint& m_breakpoint;
313 BreakpointState m_enabledOrNot;
316 void Debugger::toggleBreakpoint(Breakpoint& breakpoint, Debugger::BreakpointState enabledOrNot)
318 m_vm.heap.completeAllDFGPlans();
320 ToggleBreakpointFunctor functor(this, breakpoint, enabledOrNot);
321 m_vm.heap.forEachCodeBlock(functor);
324 void Debugger::recompileAllJSFunctions()
326 m_vm.deleteAllCode();
329 BreakpointID Debugger::setBreakpoint(Breakpoint breakpoint, unsigned& actualLine, unsigned& actualColumn)
331 SourceID sourceID = breakpoint.sourceID;
332 unsigned line = breakpoint.line;
333 unsigned column = breakpoint.column;
335 SourceIDToBreakpointsMap::iterator it = m_sourceIDToBreakpoints.find(sourceID);
336 if (it == m_sourceIDToBreakpoints.end())
337 it = m_sourceIDToBreakpoints.set(sourceID, LineToBreakpointsMap()).iterator;
338 LineToBreakpointsMap::iterator breaksIt = it->value.find(line);
339 if (breaksIt == it->value.end())
340 breaksIt = it->value.set(line, adoptRef(new BreakpointsList)).iterator;
342 BreakpointsList& breakpoints = *breaksIt->value;
343 for (Breakpoint* current = breakpoints.head(); current; current = current->next()) {
344 if (current->column == column) {
345 // The breakpoint already exists. We're not allowed to create a new
346 // breakpoint at this location. Rather than returning the breakpointID
347 // of the pre-existing breakpoint, we need to return noBreakpointID
348 // to indicate that we're not creating a new one.
349 return noBreakpointID;
353 BreakpointID id = ++m_topBreakpointID;
354 RELEASE_ASSERT(id != noBreakpointID);
358 actualColumn = column;
360 Breakpoint* newBreakpoint = new Breakpoint(breakpoint);
361 breakpoints.append(newBreakpoint);
362 m_breakpointIDToBreakpoint.set(id, newBreakpoint);
364 toggleBreakpoint(breakpoint, BreakpointEnabled);
369 void Debugger::removeBreakpoint(BreakpointID id)
371 ASSERT(id != noBreakpointID);
373 BreakpointIDToBreakpointMap::iterator idIt = m_breakpointIDToBreakpoint.find(id);
374 ASSERT(idIt != m_breakpointIDToBreakpoint.end());
375 Breakpoint* breakpoint = idIt->value;
377 SourceID sourceID = breakpoint->sourceID;
379 SourceIDToBreakpointsMap::iterator it = m_sourceIDToBreakpoints.find(sourceID);
380 ASSERT(it != m_sourceIDToBreakpoints.end());
381 LineToBreakpointsMap::iterator breaksIt = it->value.find(breakpoint->line);
382 ASSERT(breaksIt != it->value.end());
384 toggleBreakpoint(*breakpoint, BreakpointDisabled);
386 BreakpointsList& breakpoints = *breaksIt->value;
389 for (Breakpoint* current = breakpoints.head(); current && !found; current = current->next()) {
390 if (current->id == breakpoint->id)
396 m_breakpointIDToBreakpoint.remove(idIt);
397 breakpoints.remove(breakpoint);
400 if (breakpoints.isEmpty()) {
401 it->value.remove(breaksIt);
402 if (it->value.isEmpty())
403 m_sourceIDToBreakpoints.remove(it);
407 bool Debugger::hasBreakpoint(SourceID sourceID, const TextPosition& position, Breakpoint *hitBreakpoint)
409 if (!m_breakpointsActivated)
412 SourceIDToBreakpointsMap::const_iterator it = m_sourceIDToBreakpoints.find(sourceID);
413 if (it == m_sourceIDToBreakpoints.end())
416 unsigned line = position.m_line.zeroBasedInt();
417 unsigned column = position.m_column.zeroBasedInt();
419 LineToBreakpointsMap::const_iterator breaksIt = it->value.find(line);
420 if (breaksIt == it->value.end())
424 const BreakpointsList& breakpoints = *breaksIt->value;
425 Breakpoint* breakpoint;
426 for (breakpoint = breakpoints.head(); breakpoint; breakpoint = breakpoint->next()) {
427 unsigned breakLine = breakpoint->line;
428 unsigned breakColumn = breakpoint->column;
429 // Since frontend truncates the indent, the first statement in a line must match the breakpoint (line,0).
430 ASSERT(this == m_currentCallFrame->codeBlock()->globalObject()->debugger());
431 if ((line != m_lastExecutedLine && line == breakLine && !breakColumn)
432 || (line == breakLine && column == breakColumn)) {
441 *hitBreakpoint = *breakpoint;
443 breakpoint->hitCount++;
444 if (breakpoint->ignoreCount >= breakpoint->hitCount)
447 if (breakpoint->condition.isEmpty())
450 // We cannot stop in the debugger while executing condition code,
451 // so make it looks like the debugger is already paused.
452 TemporaryPausedState pausedState(*this);
454 NakedPtr<Exception> exception;
455 DebuggerCallFrame* debuggerCallFrame = currentDebuggerCallFrame();
456 JSValue result = debuggerCallFrame->evaluate(breakpoint->condition, exception);
458 // We can lose the debugger while executing JavaScript.
459 if (!m_currentCallFrame)
463 // An erroneous condition counts as "false".
464 handleExceptionInBreakpointCondition(m_currentCallFrame, exception);
468 return result.toBoolean(m_currentCallFrame);
471 class Debugger::ClearCodeBlockDebuggerRequestsFunctor {
473 ClearCodeBlockDebuggerRequestsFunctor(Debugger* debugger)
474 : m_debugger(debugger)
478 bool operator()(CodeBlock* codeBlock)
480 if (codeBlock->hasDebuggerRequests() && m_debugger == codeBlock->globalObject()->debugger())
481 codeBlock->clearDebuggerRequests();
486 Debugger* m_debugger;
489 void Debugger::clearBreakpoints()
491 m_vm.heap.completeAllDFGPlans();
493 m_topBreakpointID = noBreakpointID;
494 m_breakpointIDToBreakpoint.clear();
495 m_sourceIDToBreakpoints.clear();
497 ClearCodeBlockDebuggerRequestsFunctor functor(this);
498 m_vm.heap.forEachCodeBlock(functor);
501 class Debugger::ClearDebuggerRequestsFunctor {
503 ClearDebuggerRequestsFunctor(JSGlobalObject* globalObject)
504 : m_globalObject(globalObject)
508 bool operator()(CodeBlock* codeBlock)
510 if (codeBlock->hasDebuggerRequests() && m_globalObject == codeBlock->globalObject())
511 codeBlock->clearDebuggerRequests();
516 JSGlobalObject* m_globalObject;
519 void Debugger::clearDebuggerRequests(JSGlobalObject* globalObject)
521 m_vm.heap.completeAllDFGPlans();
523 ClearDebuggerRequestsFunctor functor(globalObject);
524 m_vm.heap.forEachCodeBlock(functor);
527 void Debugger::setBreakpointsActivated(bool activated)
529 if (activated == m_breakpointsActivated)
532 m_breakpointsActivated = activated;
533 recompileAllJSFunctions();
536 void Debugger::setPauseOnExceptionsState(PauseOnExceptionsState pause)
538 m_pauseOnExceptionsState = pause;
541 void Debugger::setPauseOnNextStatement(bool pause)
543 m_pauseOnNextStatement = pause;
545 setSteppingMode(SteppingModeEnabled);
548 void Debugger::breakProgram()
553 if (!m_vm.topCallFrame)
556 m_pauseOnNextStatement = true;
557 setSteppingMode(SteppingModeEnabled);
558 m_currentCallFrame = m_vm.topCallFrame;
559 pauseIfNeeded(m_currentCallFrame);
562 void Debugger::continueProgram()
567 m_pauseOnNextStatement = false;
568 notifyDoneProcessingDebuggerEvents();
571 void Debugger::stepIntoStatement()
576 m_pauseOnNextStatement = true;
577 setSteppingMode(SteppingModeEnabled);
578 notifyDoneProcessingDebuggerEvents();
581 void Debugger::stepOverStatement()
586 m_pauseOnCallFrame = m_currentCallFrame;
587 notifyDoneProcessingDebuggerEvents();
590 void Debugger::stepOutOfFunction()
595 VMEntryFrame* topVMEntryFrame = m_vm.topVMEntryFrame;
596 m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->callerFrame(topVMEntryFrame) : 0;
597 notifyDoneProcessingDebuggerEvents();
600 void Debugger::updateCallFrame(CallFrame* callFrame)
602 m_currentCallFrame = callFrame;
603 SourceID sourceID = DebuggerCallFrame::sourceIDForCallFrame(callFrame);
604 if (m_lastExecutedSourceID != sourceID) {
605 m_lastExecutedLine = UINT_MAX;
606 m_lastExecutedSourceID = sourceID;
610 void Debugger::updateCallFrameAndPauseIfNeeded(CallFrame* callFrame)
612 updateCallFrame(callFrame);
613 pauseIfNeeded(callFrame);
615 m_currentCallFrame = 0;
618 void Debugger::pauseIfNeeded(CallFrame* callFrame)
623 if (m_suppressAllPauses)
626 JSGlobalObject* vmEntryGlobalObject = callFrame->vmEntryGlobalObject();
627 if (!needPauseHandling(vmEntryGlobalObject))
630 Breakpoint breakpoint;
631 bool didHitBreakpoint = false;
632 bool pauseNow = m_pauseOnNextStatement;
633 pauseNow |= (m_pauseOnCallFrame == m_currentCallFrame);
635 DebuggerPausedScope debuggerPausedScope(*this);
637 intptr_t sourceID = DebuggerCallFrame::sourceIDForCallFrame(m_currentCallFrame);
638 TextPosition position = DebuggerCallFrame::positionForCallFrame(m_currentCallFrame);
639 pauseNow |= didHitBreakpoint = hasBreakpoint(sourceID, position, &breakpoint);
640 m_lastExecutedLine = position.m_line.zeroBasedInt();
644 // Make sure we are not going to pause again on breakpoint actions by
645 // reseting the pause state before executing any breakpoint actions.
646 TemporaryPausedState pausedState(*this);
647 m_pauseOnCallFrame = 0;
648 m_pauseOnNextStatement = false;
650 if (didHitBreakpoint) {
651 handleBreakpointHit(vmEntryGlobalObject, breakpoint);
652 // Note that the actions can potentially stop the debugger, so we need to check that
653 // we still have a current call frame when we get back.
654 if (breakpoint.autoContinue || !m_currentCallFrame)
656 m_pausingBreakpointID = breakpoint.id;
660 PauseReasonDeclaration reason(*this, didHitBreakpoint ? PausedForBreakpoint : m_reasonForPause);
661 handlePause(vmEntryGlobalObject, m_reasonForPause);
662 RELEASE_ASSERT(!callFrame->hadException());
665 m_pausingBreakpointID = noBreakpointID;
667 if (!m_pauseOnNextStatement && !m_pauseOnCallFrame) {
668 setSteppingMode(SteppingModeDisabled);
669 m_currentCallFrame = nullptr;
673 void Debugger::exception(CallFrame* callFrame, JSValue exception, bool hasCatchHandler)
678 PauseReasonDeclaration reason(*this, PausedForException);
679 if (m_pauseOnExceptionsState == PauseOnAllExceptions || (m_pauseOnExceptionsState == PauseOnUncaughtExceptions && !hasCatchHandler)) {
680 m_pauseOnNextStatement = true;
681 setSteppingMode(SteppingModeEnabled);
684 m_hasHandlerForExceptionCallback = true;
685 m_currentException = exception;
686 updateCallFrameAndPauseIfNeeded(callFrame);
687 m_currentException = JSValue();
688 m_hasHandlerForExceptionCallback = false;
691 void Debugger::atStatement(CallFrame* callFrame)
696 PauseReasonDeclaration reason(*this, PausedAtStatement);
697 updateCallFrameAndPauseIfNeeded(callFrame);
700 void Debugger::callEvent(CallFrame* callFrame)
705 PauseReasonDeclaration reason(*this, PausedAfterCall);
706 updateCallFrameAndPauseIfNeeded(callFrame);
709 void Debugger::returnEvent(CallFrame* callFrame)
714 PauseReasonDeclaration reason(*this, PausedBeforeReturn);
715 updateCallFrameAndPauseIfNeeded(callFrame);
717 // detach may have been called during pauseIfNeeded
718 if (!m_currentCallFrame)
721 // Treat stepping over a return statement like stepping out.
722 if (m_currentCallFrame == m_pauseOnCallFrame) {
723 VMEntryFrame* topVMEntryFrame = m_vm.topVMEntryFrame;
724 m_pauseOnCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
727 VMEntryFrame* topVMEntryFrame = m_vm.topVMEntryFrame;
728 m_currentCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
731 void Debugger::willExecuteProgram(CallFrame* callFrame)
736 PauseReasonDeclaration reason(*this, PausedAtStartOfProgram);
737 updateCallFrameAndPauseIfNeeded(callFrame);
740 void Debugger::didExecuteProgram(CallFrame* callFrame)
745 PauseReasonDeclaration reason(*this, PausedAtEndOfProgram);
746 updateCallFrameAndPauseIfNeeded(callFrame);
748 // Treat stepping over the end of a program like stepping out.
749 if (!m_currentCallFrame)
751 if (m_currentCallFrame == m_pauseOnCallFrame) {
752 VMEntryFrame* topVMEntryFrame = m_vm.topVMEntryFrame;
753 m_pauseOnCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
754 if (!m_currentCallFrame)
757 VMEntryFrame* topVMEntryFrame = m_vm.topVMEntryFrame;
758 m_currentCallFrame = m_currentCallFrame->callerFrame(topVMEntryFrame);
761 void Debugger::didReachBreakpoint(CallFrame* callFrame)
766 PauseReasonDeclaration reason(*this, PausedForDebuggerStatement);
767 m_pauseOnNextStatement = true;
768 setSteppingMode(SteppingModeEnabled);
769 updateCallFrameAndPauseIfNeeded(callFrame);
772 DebuggerCallFrame* Debugger::currentDebuggerCallFrame() const
774 ASSERT(m_currentDebuggerCallFrame);
775 return m_currentDebuggerCallFrame.get();