Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ThreadDebugger.h
Go to the documentation of this file.
1 /* Copyright (C) 2013 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef INCLUDED_THREADDEBUGGER
19 #define INCLUDED_THREADDEBUGGER
20 
21 #include "DebuggingServer.h"
22 #include "ScriptInterface.h"
24 
25 // These Breakpoint classes are not implemented threadsafe. The class using the Breakpoints is responsible to make sure that
26 // only one thread accesses the Breakpoint at a time
28 {
29 public:
31 
32  uint m_UserLine;
33  std::string m_Filename;
34 };
35 
36 // Only use this with one ScriptInterface/CThreadDebugger!
38 {
39 public:
42  , m_Script(NULL)
43  , m_Pc(NULL)
44  , m_ToRemove(false)
45  { }
46 
48  : CBreakPoint(breakPoint) // using default copy constructor
50  , m_Script(NULL)
51  , m_Pc(NULL)
52  , m_ToRemove(false)
53  { }
54 
56  JSScript* m_Script;
57  jsbytecode* m_Pc;
58  bool m_ToRemove;
59 };
60 
62 
63 struct ThreadDebugger_impl;
64 
66 {
67 public:
70 
71  /** @brief Initialize the object (required before using the object!).
72  *
73  * @param id A unique identifier greater than 0 for the object inside its CDebuggingServer object.
74  * @param name A name that will be can be displayed by the UI to identify the thread.
75  * @param pScriptInterface Pointer to a scriptinterface. All Hooks, breakpoint traps etc. will be registered in this
76  * scriptinterface and will be called by the thread this scriptinterface is running in.
77  * @param pDebuggingServer Pointer to the DebuggingServer object this Object should belong to.
78  *
79  * @return Return value.
80  */
81  void Initialize(uint id, std::string name, ScriptInterface* pScriptInterface, CDebuggingServer* pDebuggingServer);
82 
83 
84  // A bunch of hooks used to get information from spidermonkey.
85  // These hooks are used internally only but have to be public because they need to be accessible from the global hook functions.
86  // Spidermonkey requires function pointers as hooks, which only works if the functions are global or static (not part of an object).
87  // These global functions in ThreadDebugger.cpp are just wrappers for the following member functions.
88 
89  /** Simply calls BreakHandler with BREAK_SRC_TRAP */
90  JSTrapStatus TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, jsval closure);
91  /** Hook to capture exceptions and breakpoints in code (throw "Breakpoint";) */
92  JSTrapStatus ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval);
93  /** All other hooks call this one if the execution should be paused. It puts the program in a wait-loop and
94  * waits for weak-up events (continue, step etc.). */
95  JSTrapStatus BreakHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, jsval closure, BREAK_SRC breakSrc);
96  JSTrapStatus StepHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure);
97  JSTrapStatus StepIntoHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure);
98  JSTrapStatus StepOutHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure);
99  /** This is an interrup-hook that can be called multiple times per line of code and is used to break into the execution
100  * without previously setting a breakpoint and to break other threads when one thread triggers a breakpoint */
101  JSTrapStatus CheckForBreakRequestHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure);
102  /** The callback function which gets executed for each new script that gets loaded and each function inside a script.
103  * We use it for "Execute-Hooks" and "Call-Hooks" in terms of Spidermonkey.
104  * This hook actually sets the traps (Breakpoints) "on the fly" that have been defined by the user previously.
105  */
106  void ExecuteHook(JSContext *cx, const char *filename, unsigned lineno, JSScript *script, JSFunction *fun, void *callerdata);
107  /** This hook is used to update the mapping between filename plus line-numbers and jsbytecode pointers */
108  void NewScriptHook(JSContext *cx, const char *filename, unsigned lineno, JSScript *script, JSFunction *fun, void *callerdata);
109  /** This hook makes sure that invalid mappings between filename plus line-number and jsbytecode points get deleted */
110  void DestroyScriptHook(JSContext *cx, JSScript *script);
111 
112 
113  void ClearTrap(CActiveBreakPoint* activeBreakPoint);
114 
115  /** @brief Checks if a mapping for the specified filename and line number exists in this CThreadDebugger's context
116  */
117  bool CheckIfMappingPresent(std::string filename, uint line);
118 
119  /** @brief Checks if a mapping exists for each breakpoint in the list of breakpoints that aren't set yet.
120  * If there is a mapping, it removes the breakpoint from the list of unset breakpoints (from CDebuggingServer),
121  * adds it to the list of active breakpoints (CThreadDebugger) and sets a trap.
122  * Threading: m_Mutex is locked in this call
123  */
124  void SetAllNewTraps();
125 
126  /** @brief Sets a new trap and stores the information in the CActiveBreakPoint pointer
127  * Make sure that a mapping exists before calling this function
128  * Threading: Locking m_Mutex is required by the callee
129  */
130  void SetNewTrap(CActiveBreakPoint* activeBreakPoint, std::string filename, uint line);
131 
132  /** @brief Toggle a breakpoint if it's active in this threadDebugger object.
133  * Threading: Locking m_Mutex is required by the callee
134  *
135  * @param filename full vfs path to the script filename
136  * @param userLine linenumber where the USER set the breakpoint (UserLine)
137  *
138  * @return true if the breakpoint's state was changed
139  */
140  bool ToggleBreakPoint(std::string filename, uint userLine);
141 
142 
143  void GetCallstack(std::stringstream& response);
144  void GetStackFrameData(std::stringstream& response, uint nestingLevel, STACK_INFO stackInfoKind);
145 
146  /** @brief Compares the object's associated scriptinterface with the pointer passed as parameter.
147  * @return true if equal
148  */
149  bool CompareScriptInterfacePtr(ScriptInterface* pScriptInterface) const;
150 
151  // Getter/Setters for members that need to be threadsafe
152  std::string GetBreakFileName();
153  bool GetIsInBreak();
154  uint GetLastBreakLine();
155  std::string GetName();
156  uint GetID();
157  void ContinueExecution();
158  void SetNextDbgCmd(DBGCMD dbgCmd);
160  // The callee is responsible for locking m_Mutex
161  void AddStackInfoRequest(STACK_INFO requestType, uint nestingLevel, SDL_sem* semaphore);
162 
163 
164 private:
165  // Getters/Setters for members that need to be threadsafe
166  void SetBreakFileName(std::string breakFileName);
167  void SetLastBreakLine(uint breakLine);
168  void SetIsInBreak(bool isInBreak);
169 
170  // Other threadsafe functions
171  void SaveCallstack();
172 
173  /// Used only in the scriptinterface's thread.
174  void ClearTrapsToRemove();
175  bool CurrentFrameIsChildOf(JSStackFrame* pParentFrame);
176  void ReturnActiveBreakPoints(jsbytecode* pBytecode);
177  void SaveStackFrameData(STACK_INFO stackInfo, uint nestingLevel);
178  std::string StringifyCyclicJSON(jsval obj, bool indent);
179 
180  std::auto_ptr<ThreadDebugger_impl> m;
181 };
182 
183 #endif // INCLUDED_THREADDEBUGGER
void SDL_sem
Definition: wsdl.h:109
std::auto_ptr< ThreadDebugger_impl > m
void ReturnActiveBreakPoints(jsbytecode *pBytecode)
STACK_INFO
JSScript * m_Script
void SetLastBreakLine(uint breakLine)
bool CurrentFrameIsChildOf(JSStackFrame *pParentFrame)
JSTrapStatus StepOutHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure)
JSTrapStatus ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval)
Hook to capture exceptions and breakpoints in code (throw &quot;Breakpoint&quot;;)
JSTrapStatus StepIntoHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure)
bool CheckIfMappingPresent(std::string filename, uint line)
Checks if a mapping for the specified filename and line number exists in this CThreadDebugger&#39;s conte...
void SetAllNewTraps()
Checks if a mapping exists for each breakpoint in the list of breakpoints that aren&#39;t set yet...
void ClearTrap(CActiveBreakPoint *activeBreakPoint)
bool CompareScriptInterfacePtr(ScriptInterface *pScriptInterface) const
Compares the object&#39;s associated scriptinterface with the pointer passed as parameter.
JSTrapStatus CheckForBreakRequestHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure)
This is an interrup-hook that can be called multiple times per line of code and is used to break into...
std::string m_Filename
void SetNextDbgCmd(DBGCMD dbgCmd)
void Initialize(uint id, std::string name, ScriptInterface *pScriptInterface, CDebuggingServer *pDebuggingServer)
Initialize the object (required before using the object!).
void ContinueExecution()
void DestroyScriptHook(JSContext *cx, JSScript *script)
This hook makes sure that invalid mappings between filename plus line-number and jsbytecode points ge...
bool ToggleBreakPoint(std::string filename, uint userLine)
Toggle a breakpoint if it&#39;s active in this threadDebugger object.
jsbytecode * m_Pc
void GetStackFrameData(std::stringstream &response, uint nestingLevel, STACK_INFO stackInfoKind)
void SaveStackFrameData(STACK_INFO stackInfo, uint nestingLevel)
JSTrapStatus BreakHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, jsval closure, BREAK_SRC breakSrc)
All other hooks call this one if the execution should be paused.
void ClearTrapsToRemove()
Used only in the scriptinterface&#39;s thread.
void NewScriptHook(JSContext *cx, const char *filename, unsigned lineno, JSScript *script, JSFunction *fun, void *callerdata)
This hook is used to update the mapping between filename plus line-numbers and jsbytecode pointers...
std::string StringifyCyclicJSON(jsval obj, bool indent)
void ExecuteHook(JSContext *cx, const char *filename, unsigned lineno, JSScript *script, JSFunction *fun, void *callerdata)
The callback function which gets executed for each new script that gets loaded and each function insi...
std::string GetBreakFileName()
void GetCallstack(std::stringstream &response)
void SetNewTrap(CActiveBreakPoint *activeBreakPoint, std::string filename, uint line)
Sets a new trap and stores the information in the CActiveBreakPoint pointer Make sure that a mapping ...
std::string GetName()
DBGCMD
Abstraction around a SpiderMonkey JSContext.
void SetBreakFileName(std::string breakFileName)
CActiveBreakPoint(CBreakPoint breakPoint)
JSTrapStatus TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, jsval closure)
Simply calls BreakHandler with BREAK_SRC_TRAP.
void SetIsInBreak(bool isInBreak)
JSTrapStatus StepHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, void *closure)
void AddStackInfoRequest(STACK_INFO requestType, uint nestingLevel, SDL_sem *semaphore)
BREAK_SRC