blob: 9f4e0472ff800eac52448a153eedc86f914c674f [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
ager@chromium.org9258b6b2008-09-11 09:11:10 +000028#ifndef V8_V8_DEBUG_H_
29#define V8_V8_DEBUG_H_
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000030
ager@chromium.orgc27e4e72008-09-04 13:52:27 +000031#include "../include/v8-debug.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "assembler.h"
33#include "code-stubs.h"
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000034#include "debug-agent.h"
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000035#include "execution.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "factory.h"
37#include "platform.h"
38#include "string-stream.h"
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000039#include "v8threads.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040
41
42namespace v8 { namespace internal {
43
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000044
45// Forward declarations.
46class EnterDebugger;
47
48
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049// Step actions. NOTE: These values are in macros.py as well.
50enum StepAction {
51 StepNone = -1, // Stepping not prepared.
52 StepOut = 0, // Step out of the current function.
53 StepNext = 1, // Step to the next statement in the current function.
54 StepIn = 2, // Step into new functions invoked or the next statement
55 // in the current function.
56 StepMin = 3, // Perform a minimum step in the current function.
57 StepInMin = 4 // Step into new functions invoked or perform a minimum step
58 // in the current function.
59};
60
61
62// Type of exception break. NOTE: These values are in macros.py as well.
63enum ExceptionBreakType {
64 BreakException = 0,
65 BreakUncaughtException = 1
66};
67
68
69// Type of exception break. NOTE: These values are in macros.py as well.
70enum BreakLocatorType {
71 ALL_BREAK_LOCATIONS = 0,
72 SOURCE_BREAK_LOCATIONS = 1
73};
74
75
76// Class for iterating through the break points in a function and changing
77// them.
78class BreakLocationIterator {
79 public:
80 explicit BreakLocationIterator(Handle<DebugInfo> debug_info,
81 BreakLocatorType type);
82 virtual ~BreakLocationIterator();
83
84 void Next();
85 void Next(int count);
86 void FindBreakLocationFromAddress(Address pc);
87 void FindBreakLocationFromPosition(int position);
88 void Reset();
89 bool Done() const;
90 void SetBreakPoint(Handle<Object> break_point_object);
91 void ClearBreakPoint(Handle<Object> break_point_object);
92 void SetOneShot();
93 void ClearOneShot();
94 void PrepareStepIn();
95 bool IsExit() const;
96 bool HasBreakPoint();
97 bool IsDebugBreak();
98 Object* BreakPointObjects();
ager@chromium.org381abbb2009-02-25 13:23:22 +000099 void ClearAllDebugBreak();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101
102 inline int code_position() { return pc() - debug_info_->code()->entry(); }
103 inline int break_point() { return break_point_; }
104 inline int position() { return position_; }
105 inline int statement_position() { return statement_position_; }
106 inline Address pc() { return reloc_iterator_->rinfo()->pc(); }
107 inline Code* code() { return debug_info_->code(); }
108 inline RelocInfo* rinfo() { return reloc_iterator_->rinfo(); }
ager@chromium.org236ad962008-09-25 09:45:57 +0000109 inline RelocInfo::Mode rmode() const {
110 return reloc_iterator_->rinfo()->rmode();
111 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112 inline RelocInfo* original_rinfo() {
113 return reloc_iterator_original_->rinfo();
114 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000115 inline RelocInfo::Mode original_rmode() const {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000116 return reloc_iterator_original_->rinfo()->rmode();
117 }
118
119 protected:
120 bool RinfoDone() const;
121 void RinfoNext();
122
123 BreakLocatorType type_;
124 int break_point_;
125 int position_;
126 int statement_position_;
127 Handle<DebugInfo> debug_info_;
128 RelocIterator* reloc_iterator_;
129 RelocIterator* reloc_iterator_original_;
130
131 private:
132 void SetDebugBreak();
133 void ClearDebugBreak();
iposva@chromium.org245aa852009-02-10 00:49:54 +0000134 bool IsDebugBreakAtReturn();
135 void SetDebugBreakAtReturn();
136 void ClearDebugBreakAtReturn();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000137
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000138 DISALLOW_COPY_AND_ASSIGN(BreakLocationIterator);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000139};
140
141
142// Linked list holding debug info objects. The debug info objects are kept as
143// weak handles to avoid a debug info object to keep a function alive.
144class DebugInfoListNode {
145 public:
146 explicit DebugInfoListNode(DebugInfo* debug_info);
147 virtual ~DebugInfoListNode();
148
149 DebugInfoListNode* next() { return next_; }
150 void set_next(DebugInfoListNode* next) { next_ = next; }
151 Handle<DebugInfo> debug_info() { return debug_info_; }
152
153 private:
154 // Global (weak) handle to the debug info object.
155 Handle<DebugInfo> debug_info_;
156
157 // Next pointer for linked list.
158 DebugInfoListNode* next_;
159};
160
161
162// This class contains the debugger support. The main purpose is to handle
163// setting break points in the code.
164//
165// This class controls the debug info for all functions which currently have
166// active breakpoints in them. This debug info is held in the heap root object
167// debug_info which is a FixedArray. Each entry in this list is of class
168// DebugInfo.
169class Debug {
170 public:
171 static void Setup(bool create_heap_objects);
172 static bool Load();
173 static void Unload();
174 static bool IsLoaded() { return !debug_context_.is_null(); }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000175 static bool InDebugger() { return thread_local_.debugger_entry_ != NULL; }
176 static void PreemptionWhileInDebugger();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000177 static void Iterate(ObjectVisitor* v);
178
179 static Object* Break(Arguments args);
180 static void SetBreakPoint(Handle<SharedFunctionInfo> shared,
181 int source_position,
182 Handle<Object> break_point_object);
183 static void ClearBreakPoint(Handle<Object> break_point_object);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000184 static void ClearAllBreakPoints();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000185 static void FloodWithOneShot(Handle<SharedFunctionInfo> shared);
186 static void FloodHandlerWithOneShot();
187 static void ChangeBreakOnException(ExceptionBreakType type, bool enable);
188 static void PrepareStep(StepAction step_action, int step_count);
189 static void ClearStepping();
190 static bool StepNextContinue(BreakLocationIterator* break_location_iterator,
191 JavaScriptFrame* frame);
192 static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared);
193 static bool HasDebugInfo(Handle<SharedFunctionInfo> shared);
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000194
ager@chromium.org32912102009-01-16 10:38:43 +0000195 // Returns whether the operation succeeded.
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000196 static bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared);
197
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000198 static bool IsDebugBreak(Address addr);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000199 static bool IsDebugBreakAtReturn(RelocInfo* rinfo);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000200
201 // Check whether a code stub with the specified major key is a possible break
202 // point location.
203 static bool IsSourceBreakStub(Code* code);
204 static bool IsBreakStub(Code* code);
205
206 // Find the builtin to use for invoking the debug break
207 static Handle<Code> FindDebugBreak(RelocInfo* rinfo);
208
209 static Handle<Object> GetSourceBreakLocations(
210 Handle<SharedFunctionInfo> shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000211
212 // Getter for the debug_context.
213 inline static Handle<Context> debug_context() { return debug_context_; }
214
215 // Check whether a global object is the debug global object.
216 static bool IsDebugGlobal(GlobalObject* global);
217
218 // Fast check to see if any break points are active.
219 inline static bool has_break_points() { return has_break_points_; }
220
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000221 static void NewBreak(StackFrame::Id break_frame_id);
222 static void SetBreak(StackFrame::Id break_frame_id, int break_id);
223 static StackFrame::Id break_frame_id() {
224 return thread_local_.break_frame_id_;
225 }
226 static int break_id() { return thread_local_.break_id_; }
227
228
229
230
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000231 static bool StepInActive() { return thread_local_.step_into_fp_ != 0; }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000232 static void HandleStepIn(Handle<JSFunction> function,
233 Address fp,
234 bool is_constructor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235 static Address step_in_fp() { return thread_local_.step_into_fp_; }
236 static Address* step_in_fp_addr() { return &thread_local_.step_into_fp_; }
237
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000238 static EnterDebugger* debugger_entry() {
239 return thread_local_.debugger_entry_;
240 }
241 static void set_debugger_entry(EnterDebugger* entry) {
242 thread_local_.debugger_entry_ = entry;
243 }
244
245 static bool preemption_pending() {
246 return thread_local_.preemption_pending_;
247 }
248 static void set_preemption_pending(bool preemption_pending) {
249 thread_local_.preemption_pending_ = preemption_pending;
250 }
251
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000252 // Getter and setter for the disable break state.
253 static bool disable_break() { return disable_break_; }
254 static void set_disable_break(bool disable_break) {
255 disable_break_ = disable_break;
256 }
257
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000258 // Getters for the current exception break state.
259 static bool break_on_exception() { return break_on_exception_; }
260 static bool break_on_uncaught_exception() {
261 return break_on_uncaught_exception_;
262 }
263
264 enum AddressId {
265 k_after_break_target_address,
266 k_debug_break_return_address,
267 k_register_address
268 };
269
270 // Support for setting the address to jump to when returning from break point.
271 static Address* after_break_target_address() {
272 return reinterpret_cast<Address*>(&thread_local_.after_break_target_);
273 }
274
275 // Support for saving/restoring registers when handling debug break calls.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000276 static Object** register_address(int r) {
277 return &registers_[r];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000278 }
279
kasper.lund7276f142008-07-30 08:49:36 +0000280 // Address of the debug break return entry code.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000281 static Code* debug_break_return_entry() { return debug_break_return_entry_; }
282
283 // Support for getting the address of the debug break on return code.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000284 static Code** debug_break_return_address() {
285 return &debug_break_return_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000286 }
287
288 static const int kEstimatedNofDebugInfoEntries = 16;
289 static const int kEstimatedNofBreakPointsInFunction = 16;
290
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000291 static void HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000292
293 friend class Debugger;
ager@chromium.org381abbb2009-02-25 13:23:22 +0000294 friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc
295 friend void CheckDebuggerUnloaded(bool check_functions); // In test-debug.cc
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000296
297 // Threading support.
298 static char* ArchiveDebug(char* to);
299 static char* RestoreDebug(char* from);
300 static int ArchiveSpacePerThread();
301
ager@chromium.org32912102009-01-16 10:38:43 +0000302 // Mirror cache handling.
303 static void ClearMirrorCache();
304
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000305 // Code generation assumptions.
306 static const int kIa32CallInstructionLength = 5;
307 static const int kIa32JSReturnSequenceLength = 6;
308
ager@chromium.org8bb60582008-12-11 12:02:20 +0000309 // Code generator routines.
310 static void GenerateLoadICDebugBreak(MacroAssembler* masm);
311 static void GenerateStoreICDebugBreak(MacroAssembler* masm);
312 static void GenerateKeyedLoadICDebugBreak(MacroAssembler* masm);
313 static void GenerateKeyedStoreICDebugBreak(MacroAssembler* masm);
314 static void GenerateConstructCallDebugBreak(MacroAssembler* masm);
315 static void GenerateReturnDebugBreak(MacroAssembler* masm);
316 static void GenerateReturnDebugBreakEntry(MacroAssembler* masm);
317 static void GenerateStubNoRegistersDebugBreak(MacroAssembler* masm);
318
319 // Called from stub-cache.cc.
320 static void GenerateCallICDebugBreak(MacroAssembler* masm);
321
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000322 private:
323 static bool CompileDebuggerScript(int index);
324 static void ClearOneShot();
325 static void ActivateStepIn(StackFrame* frame);
326 static void ClearStepIn();
327 static void ClearStepNext();
ager@chromium.org32912102009-01-16 10:38:43 +0000328 // Returns whether the compile succeeded.
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000329 static bool EnsureCompiled(Handle<SharedFunctionInfo> shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000330 static void RemoveDebugInfo(Handle<DebugInfo> debug_info);
331 static void SetAfterBreakTarget(JavaScriptFrame* frame);
332 static Handle<Object> CheckBreakPoints(Handle<Object> break_point);
333 static bool CheckBreakPoint(Handle<Object> break_point_object);
334
335 // Global handle to debug context where all the debugger JavaScript code is
336 // loaded.
337 static Handle<Context> debug_context_;
338
339 // Boolean state indicating whether any break points are set.
340 static bool has_break_points_;
341 static DebugInfoListNode* debug_info_list_;
342
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000343 static bool disable_break_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000344 static bool break_on_exception_;
345 static bool break_on_uncaught_exception_;
346
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000347 // Per-thread data.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000348 class ThreadLocal {
349 public:
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000350 // Counter for generating next break id.
351 int break_count_;
352
353 // Current break id.
354 int break_id_;
355
356 // Frame id for the frame of the current break.
357 StackFrame::Id break_frame_id_;
358
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000359 // Step action for last step performed.
360 StepAction last_step_action_;
361
362 // Source statement position from last step next action.
363 int last_statement_position_;
364
365 // Number of steps left to perform before debug event.
366 int step_count_;
367
368 // Frame pointer from last step next action.
369 Address last_fp_;
370
371 // Frame pointer for frame from which step in was performed.
372 Address step_into_fp_;
373
374 // Storage location for jump when exiting debug break calls.
375 Address after_break_target_;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000376
377 // Top debugger entry.
378 EnterDebugger* debugger_entry_;
379
380 // Preemption happened while debugging.
381 bool preemption_pending_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000382 };
383
384 // Storage location for registers when handling debug break calls
385 static JSCallerSavedBuffer registers_;
386 static ThreadLocal thread_local_;
387 static void ThreadInit();
388
389 // Code object for debug break return entry code.
390 static Code* debug_break_return_entry_;
391
392 // Code to call for handling debug break on return.
393 static Code* debug_break_return_;
394
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000395 DISALLOW_COPY_AND_ASSIGN(Debug);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396};
397
398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399class DebugMessageThread;
400
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401class Debugger {
402 public:
403 static void DebugRequest(const uint16_t* json_request, int length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404
405 static Handle<Object> MakeJSObject(Vector<const char> constructor_name,
406 int argc, Object*** argv,
407 bool* caught_exception);
408 static Handle<Object> MakeExecutionState(bool* caught_exception);
409 static Handle<Object> MakeBreakEvent(Handle<Object> exec_state,
410 Handle<Object> break_points_hit,
411 bool* caught_exception);
412 static Handle<Object> MakeExceptionEvent(Handle<Object> exec_state,
413 Handle<Object> exception,
414 bool uncaught,
415 bool* caught_exception);
416 static Handle<Object> MakeNewFunctionEvent(Handle<Object> func,
417 bool* caught_exception);
418 static Handle<Object> MakeCompileEvent(Handle<Script> script,
iposva@chromium.org245aa852009-02-10 00:49:54 +0000419 bool before,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000420 bool* caught_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000421 static void OnDebugBreak(Handle<Object> break_points_hit);
422 static void OnException(Handle<Object> exception, bool uncaught);
423 static void OnBeforeCompile(Handle<Script> script);
424 static void OnAfterCompile(Handle<Script> script,
425 Handle<JSFunction> fun);
426 static void OnNewFunction(Handle<JSFunction> fun);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000427 static void ProcessDebugEvent(v8::DebugEvent event,
428 Handle<Object> event_data);
iposva@chromium.org245aa852009-02-10 00:49:54 +0000429 static void SetEventListener(Handle<Object> callback, Handle<Object> data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000430 static void SetMessageHandler(v8::DebugMessageHandler handler, void* data);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000431 static void SetHostDispatchHandler(v8::DebugHostDispatchHandler handler,
432 void* data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000433 static void SendMessage(Vector<uint16_t> message);
434 static void ProcessCommand(Vector<const uint16_t> command);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000435 static void ProcessHostDispatch(void* dispatch);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000436 static void UpdateActiveDebugger();
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000437 static Handle<Object> Call(Handle<JSFunction> fun,
438 Handle<Object> data,
439 bool* pending_exception);
440
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000441 // Start the debugger agent listening on the provided port.
442 static bool StartAgent(int port);
443
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444 inline static bool EventActive(v8::DebugEvent event) {
445 // Currently argument event is not used.
446 return !Debugger::compiling_natives_ && Debugger::debugger_active_;
447 }
448
449 static void set_debugger_active(bool debugger_active) {
450 Debugger::debugger_active_ = debugger_active;
451 }
452 static bool debugger_active() { return Debugger::debugger_active_; }
453 static void set_compiling_natives(bool compiling_natives) {
454 Debugger::compiling_natives_ = compiling_natives;
455 }
456 static bool compiling_natives() { return Debugger::compiling_natives_; }
mads.s.agercbaa0602008-08-14 13:41:48 +0000457 static void set_loading_debugger(bool v) { is_loading_debugger_ = v; }
458 static bool is_loading_debugger() { return Debugger::is_loading_debugger_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000459
460 private:
iposva@chromium.org245aa852009-02-10 00:49:54 +0000461 static Handle<Object> event_listener_; // Global handle to listener
462 static Handle<Object> event_listener_data_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000463 static bool debugger_active_; // Are there any active debugger?
464 static bool compiling_natives_; // Are we compiling natives?
mads.s.agercbaa0602008-08-14 13:41:48 +0000465 static bool is_loading_debugger_; // Are we loading the debugger?
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000466 static DebugMessageThread* message_thread_;
ager@chromium.org381abbb2009-02-25 13:23:22 +0000467 static v8::DebugMessageHandler message_handler_;
468 static void* message_handler_data_;
469 static v8::DebugHostDispatchHandler host_dispatch_handler_;
470 static void* host_dispatch_handler_data_;
471
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000472 static DebuggerAgent* agent_;
473
ager@chromium.org381abbb2009-02-25 13:23:22 +0000474 friend class DebugMessageThread;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000475};
476
477
kasper.lund7276f142008-07-30 08:49:36 +0000478// A Queue of Vector<uint16_t> objects. A thread-safe version is
479// LockingMessageQueue, based on this class.
480class MessageQueue BASE_EMBEDDED {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000481 public:
kasper.lund7276f142008-07-30 08:49:36 +0000482 explicit MessageQueue(int size);
483 ~MessageQueue();
484 bool IsEmpty() const { return start_ == end_; }
485 Vector<uint16_t> Get();
486 void Put(const Vector<uint16_t>& message);
487 void Clear() { start_ = end_ = 0; } // Queue is empty after Clear().
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000488 private:
kasper.lund7276f142008-07-30 08:49:36 +0000489 // Doubles the size of the message queue, and copies the messages.
490 void Expand();
491
492 Vector<uint16_t>* messages_;
493 int start_;
494 int end_;
495 int size_; // The size of the queue buffer. Queue can hold size-1 messages.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000496};
497
498
kasper.lund7276f142008-07-30 08:49:36 +0000499// LockingMessageQueue is a thread-safe circular buffer of Vector<uint16_t>
500// messages. The message data is not managed by LockingMessageQueue.
501// Pointers to the data are passed in and out. Implemented by adding a
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000502// Mutex to MessageQueue. Includes logging of all puts and gets.
kasper.lund7276f142008-07-30 08:49:36 +0000503class LockingMessageQueue BASE_EMBEDDED {
504 public:
505 explicit LockingMessageQueue(int size);
506 ~LockingMessageQueue();
507 bool IsEmpty() const;
508 Vector<uint16_t> Get();
509 void Put(const Vector<uint16_t>& message);
510 void Clear();
511 private:
kasper.lund7276f142008-07-30 08:49:36 +0000512 MessageQueue queue_;
513 Mutex* lock_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000514 DISALLOW_COPY_AND_ASSIGN(LockingMessageQueue);
kasper.lund7276f142008-07-30 08:49:36 +0000515};
516
517
518/* This class is the data for a running thread that serializes
519 * event messages and command processing for the debugger.
520 * All uncommented methods are called only from this message thread.
521 */
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000522class DebugMessageThread: public Thread {
523 public:
kasper.lund7276f142008-07-30 08:49:36 +0000524 DebugMessageThread(); // Called from API thread.
525 virtual ~DebugMessageThread(); // Never called.
526 // Called by V8 thread. Reports events from V8 VM.
527 // Also handles command processing in stopped state of V8,
528 // when host_running_ is false.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000529 void DebugEvent(v8::DebugEvent,
530 Handle<Object> exec_state,
531 Handle<Object> event_data);
kasper.lund7276f142008-07-30 08:49:36 +0000532 // Puts event on the output queue. Called by V8.
533 // This is where V8 hands off
534 // processing of the event to the DebugMessageThread thread,
535 // which forwards it to the debug_message_handler set by the API.
536 void SendMessage(Vector<uint16_t> event_json);
537 // Formats an event into JSON, and calls SendMessage.
ager@chromium.org8bb60582008-12-11 12:02:20 +0000538 bool SetEventJSONFromEvent(Handle<Object> event_data);
kasper.lund7276f142008-07-30 08:49:36 +0000539 // Puts a command coming from the public API on the queue. Called
540 // by the API client thread. This is where the API client hands off
541 // processing of the command to the DebugMessageThread thread.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542 void ProcessCommand(Vector<uint16_t> command);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000543 void ProcessHostDispatch(void* dispatch);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000544 void OnDebuggerInactive();
545
kasper.lund7276f142008-07-30 08:49:36 +0000546 // Main function of DebugMessageThread thread.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000547 void Run();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548
kasper.lund7276f142008-07-30 08:49:36 +0000549 bool host_running_; // Is the debugging host running or stopped?
550 Semaphore* command_received_; // Non-zero when command queue is non-empty.
551 Semaphore* message_received_; // Exactly equal to message queue length.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000552 private:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553 bool TwoByteEqualsAscii(Vector<uint16_t> two_byte, const char* ascii);
554
kasper.lund7276f142008-07-30 08:49:36 +0000555 static const int kQueueInitialSize = 4;
556 LockingMessageQueue command_queue_;
557 LockingMessageQueue message_queue_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000558 DISALLOW_COPY_AND_ASSIGN(DebugMessageThread);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559};
560
561
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000562// This class is used for entering the debugger. Create an instance in the stack
563// to enter the debugger. This will set the current break state, make sure the
564// debugger is loaded and switch to the debugger context. If the debugger for
565// some reason could not be entered FailedToEnter will return true.
566class EnterDebugger BASE_EMBEDDED {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000567 public:
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000568 EnterDebugger()
569 : prev_(Debug::debugger_entry()),
570 has_js_frames_(!it_.done()) {
571 ASSERT(!Debug::preemption_pending());
572
573 // Link recursive debugger entry.
574 Debug::set_debugger_entry(this);
575
576 // If a preemption is pending when first entering the debugger clear it as
577 // we don't want preemption happening while executing JavaScript in the
578 // debugger. When recursively entering the debugger the preemption flag
579 // cannot be set as this is disabled while in the debugger (see
580 // RuntimePreempt).
581 if (prev_ == NULL && StackGuard::IsPreempted()) {
582 StackGuard::Continue(PREEMPT);
583 }
584 ASSERT(!StackGuard::IsPreempted());
585
ager@chromium.org8bb60582008-12-11 12:02:20 +0000586 // Store the previous break id and frame id.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000587 break_id_ = Debug::break_id();
588 break_frame_id_ = Debug::break_frame_id();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000589
ager@chromium.org8bb60582008-12-11 12:02:20 +0000590 // Create the new break info. If there is no JavaScript frames there is no
591 // break frame id.
592 if (has_js_frames_) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000593 Debug::NewBreak(it_.frame()->id());
ager@chromium.org8bb60582008-12-11 12:02:20 +0000594 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000595 Debug::NewBreak(StackFrame::NO_ID);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000596 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000597
598 // Make sure that debugger is loaded and enter the debugger context.
599 load_failed_ = !Debug::Load();
600 if (!load_failed_) {
601 // NOTE the member variable save which saves the previous context before
602 // this change.
603 Top::set_context(*Debug::debug_context());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000604 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000605 }
606
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000607 ~EnterDebugger() {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000608 // Restore to the previous break state.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000609 Debug::SetBreak(break_frame_id_, break_id_);
610
611 // Request preemption when leaving the last debugger entry and a preemption
612 // had been recorded while debugging. This is to avoid starvation in some
613 // debugging scenarios.
614 if (prev_ == NULL && Debug::preemption_pending()) {
615 StackGuard::Preempt();
616 Debug::set_preemption_pending(false);
617 }
618
619 // Leaving this debugger entry.
620 Debug::set_debugger_entry(prev_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000621 }
622
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000623 // Check whether the debugger could be entered.
624 inline bool FailedToEnter() { return load_failed_; }
625
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000626 // Check whether there are any JavaScript frames on the stack.
ager@chromium.org8bb60582008-12-11 12:02:20 +0000627 inline bool HasJavaScriptFrames() { return has_js_frames_; }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000628
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000629 private:
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000630 EnterDebugger* prev_; // Previous debugger entry if entered recursively.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000631 JavaScriptFrameIterator it_;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000632 const bool has_js_frames_; // Were there any JavaScript frames?
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633 StackFrame::Id break_frame_id_; // Previous break frame id.
634 int break_id_; // Previous break id.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000635 bool load_failed_; // Did the debugger fail to load?
636 SaveContext save_; // Saves previous context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000637};
638
639
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000640// Stack allocated class for disabling break.
641class DisableBreak BASE_EMBEDDED {
642 public:
643 // Enter the debugger by storing the previous top context and setting the
644 // current top context to the debugger context.
645 explicit DisableBreak(bool disable_break) {
646 prev_disable_break_ = Debug::disable_break();
647 Debug::set_disable_break(disable_break);
648 }
649 ~DisableBreak() {
650 Debug::set_disable_break(prev_disable_break_);
651 }
652
653 private:
654 // The previous state of the disable break used to restore the value when this
655 // object is destructed.
656 bool prev_disable_break_;
657};
658
659
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000660// Debug_Address encapsulates the Address pointers used in generating debug
661// code.
662class Debug_Address {
663 public:
664 Debug_Address(Debug::AddressId id, int reg = 0)
665 : id_(id), reg_(reg) {
666 ASSERT(reg == 0 || id == Debug::k_register_address);
667 }
668
669 static Debug_Address AfterBreakTarget() {
670 return Debug_Address(Debug::k_after_break_target_address);
671 }
672
673 static Debug_Address DebugBreakReturn() {
674 return Debug_Address(Debug::k_debug_break_return_address);
675 }
676
677 static Debug_Address Register(int reg) {
678 return Debug_Address(Debug::k_register_address, reg);
679 }
680
681 Address address() const {
682 switch (id_) {
683 case Debug::k_after_break_target_address:
684 return reinterpret_cast<Address>(Debug::after_break_target_address());
685 case Debug::k_debug_break_return_address:
686 return reinterpret_cast<Address>(Debug::debug_break_return_address());
687 case Debug::k_register_address:
688 return reinterpret_cast<Address>(Debug::register_address(reg_));
689 default:
690 UNREACHABLE();
691 return NULL;
692 }
693 }
694 private:
695 Debug::AddressId id_;
696 int reg_;
697};
698
699
700} } // namespace v8::internal
701
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000702#endif // V8_V8_DEBUG_H_