1/* 2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) 3 * Copyright (C) 2001 Peter Kelly (pmk@post.com) 4 * Copyright (C) 2008, 2009, 2013, 2014 Apple Inc. All rights reserved. 5 * 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. 10 * 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. 15 * 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 19 * 20 */ 21 22#ifndef Debugger_h 23#define Debugger_h 24 25#include "Breakpoint.h" 26#include "DebuggerCallFrame.h" 27#include "DebuggerPrimitives.h" 28#include "JSCJSValue.h" 29#include <wtf/HashMap.h> 30#include <wtf/HashSet.h> 31#include <wtf/RefPtr.h> 32#include <wtf/text/TextPosition.h> 33 34namespace JSC { 35 36class ExecState; 37class JSGlobalObject; 38class SourceProvider; 39class VM; 40 41typedef ExecState CallFrame; 42 43class JS_EXPORT_PRIVATE Debugger { 44public: 45 Debugger(bool isInWorkerThread = false); 46 virtual ~Debugger(); 47 48 JSC::DebuggerCallFrame* currentDebuggerCallFrame() const; 49 bool hasHandlerForExceptionCallback() const 50 { 51 ASSERT(m_reasonForPause == PausedForException); 52 return m_hasHandlerForExceptionCallback; 53 } 54 JSValue currentException() 55 { 56 ASSERT(m_reasonForPause == PausedForException); 57 return m_currentException; 58 } 59 60 bool needsExceptionCallbacks() const { return m_pauseOnExceptionsState != DontPauseOnExceptions; } 61 62 void attach(JSGlobalObject*); 63 enum ReasonForDetach { 64 TerminatingDebuggingSession, 65 GlobalObjectIsDestructing 66 }; 67 virtual void detach(JSGlobalObject*, ReasonForDetach); 68 69 BreakpointID setBreakpoint(Breakpoint, unsigned& actualLine, unsigned& actualColumn); 70 void removeBreakpoint(BreakpointID); 71 void clearBreakpoints(); 72 void setBreakpointsActivated(bool); 73 void activateBreakpoints() { setBreakpointsActivated(true); } 74 void deactivateBreakpoints() { setBreakpointsActivated(false); } 75 76 enum PauseOnExceptionsState { 77 DontPauseOnExceptions, 78 PauseOnAllExceptions, 79 PauseOnUncaughtExceptions 80 }; 81 PauseOnExceptionsState pauseOnExceptionsState() const { return m_pauseOnExceptionsState; } 82 void setPauseOnExceptionsState(PauseOnExceptionsState); 83 84 void setPauseOnNextStatement(bool); 85 void breakProgram(); 86 void continueProgram(); 87 void stepIntoStatement(); 88 void stepOverStatement(); 89 void stepOutOfFunction(); 90 91 bool isPaused() { return m_isPaused; } 92 bool isStepping() const { return m_steppingMode == SteppingModeEnabled; } 93 94 virtual void sourceParsed(ExecState*, SourceProvider*, int errorLineNumber, const WTF::String& errorMessage) = 0; 95 96 void exception(CallFrame*, JSValue exceptionValue, bool hasHandler); 97 void atStatement(CallFrame*); 98 void callEvent(CallFrame*); 99 void returnEvent(CallFrame*); 100 void willExecuteProgram(CallFrame*); 101 void didExecuteProgram(CallFrame*); 102 void didReachBreakpoint(CallFrame*); 103 104 void recompileAllJSFunctions(VM*); 105 106 void registerCodeBlock(CodeBlock*); 107 108protected: 109 virtual bool needPauseHandling(JSGlobalObject*) { return false; } 110 virtual void handleBreakpointHit(const Breakpoint&) { } 111 virtual void handleExceptionInBreakpointCondition(ExecState*, JSValue exception) const { UNUSED_PARAM(exception); } 112 113 enum ReasonForPause { 114 NotPaused, 115 PausedForException, 116 PausedAtStatement, 117 PausedAfterCall, 118 PausedBeforeReturn, 119 PausedAtStartOfProgram, 120 PausedAtEndOfProgram, 121 PausedForBreakpoint 122 }; 123 124 virtual void handlePause(ReasonForPause, JSGlobalObject*) { } 125 virtual void notifyDoneProcessingDebuggerEvents() { } 126 127private: 128 typedef HashMap<BreakpointID, Breakpoint*> BreakpointIDToBreakpointMap; 129 130 typedef HashMap<unsigned, RefPtr<BreakpointsList>, WTF::IntHash<int>, WTF::UnsignedWithZeroKeyHashTraits<int>> LineToBreakpointsMap; 131 typedef HashMap<SourceID, LineToBreakpointsMap, WTF::IntHash<SourceID>, WTF::UnsignedWithZeroKeyHashTraits<SourceID>> SourceIDToBreakpointsMap; 132 133 class ClearCodeBlockDebuggerRequestsFunctor; 134 class ClearDebuggerRequestsFunctor; 135 class SetSteppingModeFunctor; 136 class ToggleBreakpointFunctor; 137 138 class PauseReasonDeclaration { 139 public: 140 PauseReasonDeclaration(Debugger& debugger, ReasonForPause reason) 141 : m_debugger(debugger) 142 { 143 m_debugger.m_reasonForPause = reason; 144 } 145 146 ~PauseReasonDeclaration() 147 { 148 m_debugger.m_reasonForPause = NotPaused; 149 } 150 private: 151 Debugger& m_debugger; 152 }; 153 154 bool hasBreakpoint(SourceID, const TextPosition&, Breakpoint* hitBreakpoint); 155 156 void updateNeedForOpDebugCallbacks(); 157 158 // These update functions are only needed because our current breakpoints are 159 // key'ed off the source position instead of the bytecode PC. This ensures 160 // that we don't break on the same line more than once. Once we switch to a 161 // bytecode PC key'ed breakpoint, we will not need these anymore and should 162 // be able to remove them. 163 void updateCallFrame(JSC::CallFrame*); 164 void updateCallFrameAndPauseIfNeeded(JSC::CallFrame*); 165 void pauseIfNeeded(JSC::CallFrame*); 166 167 enum SteppingMode { 168 SteppingModeDisabled, 169 SteppingModeEnabled 170 }; 171 void setSteppingMode(SteppingMode); 172 173 enum BreakpointState { 174 BreakpointDisabled, 175 BreakpointEnabled 176 }; 177 void toggleBreakpoint(CodeBlock*, Breakpoint&, BreakpointState); 178 void applyBreakpoints(CodeBlock*); 179 void toggleBreakpoint(Breakpoint&, BreakpointState); 180 181 void clearDebuggerRequests(JSGlobalObject*); 182 183 template<typename Functor> inline void forEachCodeBlock(Functor&); 184 185 VM* m_vm; 186 HashSet<JSGlobalObject*> m_globalObjects; 187 188 PauseOnExceptionsState m_pauseOnExceptionsState; 189 bool m_pauseOnNextStatement : 1; 190 bool m_isPaused : 1; 191 bool m_breakpointsActivated : 1; 192 bool m_hasHandlerForExceptionCallback : 1; 193 bool m_isInWorkerThread : 1; 194 SteppingMode m_steppingMode : 1; 195 196 ReasonForPause m_reasonForPause; 197 JSValue m_currentException; 198 CallFrame* m_pauseOnCallFrame; 199 CallFrame* m_currentCallFrame; 200 unsigned m_lastExecutedLine; 201 SourceID m_lastExecutedSourceID; 202 203 BreakpointID m_topBreakpointID; 204 BreakpointIDToBreakpointMap m_breakpointIDToBreakpoint; 205 SourceIDToBreakpointsMap m_sourceIDToBreakpoints; 206 207 RefPtr<JSC::DebuggerCallFrame> m_currentDebuggerCallFrame; 208 209 friend class DebuggerCallFrameScope; 210 friend class TemporaryPausedState; 211 friend class LLIntOffsetsExtractor; 212}; 213 214} // namespace JSC 215 216#endif // Debugger_h 217