blob: 36017be4741aa803df1eec91dd36e8ea6d5f8d23 [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
ager@chromium.org41826e72009-03-30 13:30:57 +0000399// A Queue of Vector<uint16_t> objects. A thread-safe version is
400// LockingMessageQueue, based on this class.
401class MessageQueue BASE_EMBEDDED {
402 public:
403 explicit MessageQueue(int size);
404 ~MessageQueue();
405 bool IsEmpty() const { return start_ == end_; }
406 Vector<uint16_t> Get();
407 void Put(const Vector<uint16_t>& message);
408 void Clear() { start_ = end_ = 0; } // Queue is empty after Clear().
409 private:
410 // Doubles the size of the message queue, and copies the messages.
411 void Expand();
412
413 Vector<uint16_t>* messages_;
414 int start_;
415 int end_;
416 int size_; // The size of the queue buffer. Queue can hold size-1 messages.
417};
418
419
420// LockingMessageQueue is a thread-safe circular buffer of Vector<uint16_t>
421// messages. The message data is not managed by LockingMessageQueue.
422// Pointers to the data are passed in and out. Implemented by adding a
423// Mutex to MessageQueue. Includes logging of all puts and gets.
424class LockingMessageQueue BASE_EMBEDDED {
425 public:
426 explicit LockingMessageQueue(int size);
427 ~LockingMessageQueue();
428 bool IsEmpty() const;
429 Vector<uint16_t> Get();
430 void Put(const Vector<uint16_t>& message);
431 void Clear();
432 private:
433 MessageQueue queue_;
434 Mutex* lock_;
435 DISALLOW_COPY_AND_ASSIGN(LockingMessageQueue);
436};
437
438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439class DebugMessageThread;
440
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000441class Debugger {
442 public:
443 static void DebugRequest(const uint16_t* json_request, int length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444
445 static Handle<Object> MakeJSObject(Vector<const char> constructor_name,
446 int argc, Object*** argv,
447 bool* caught_exception);
448 static Handle<Object> MakeExecutionState(bool* caught_exception);
449 static Handle<Object> MakeBreakEvent(Handle<Object> exec_state,
450 Handle<Object> break_points_hit,
451 bool* caught_exception);
452 static Handle<Object> MakeExceptionEvent(Handle<Object> exec_state,
453 Handle<Object> exception,
454 bool uncaught,
455 bool* caught_exception);
456 static Handle<Object> MakeNewFunctionEvent(Handle<Object> func,
457 bool* caught_exception);
458 static Handle<Object> MakeCompileEvent(Handle<Script> script,
iposva@chromium.org245aa852009-02-10 00:49:54 +0000459 bool before,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000460 bool* caught_exception);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000461 static void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000462 static void OnException(Handle<Object> exception, bool uncaught);
463 static void OnBeforeCompile(Handle<Script> script);
464 static void OnAfterCompile(Handle<Script> script,
465 Handle<JSFunction> fun);
466 static void OnNewFunction(Handle<JSFunction> fun);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000467 static void ProcessDebugEvent(v8::DebugEvent event,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000468 Handle<Object> event_data,
469 bool auto_continue);
ager@chromium.org41826e72009-03-30 13:30:57 +0000470 static void NotifyMessageHandler(v8::DebugEvent event,
471 Handle<Object> exec_state,
472 Handle<Object> event_data,
473 bool auto_continue);
iposva@chromium.org245aa852009-02-10 00:49:54 +0000474 static void SetEventListener(Handle<Object> callback, Handle<Object> data);
ager@chromium.org41826e72009-03-30 13:30:57 +0000475 static void SetMessageHandler(v8::DebugMessageHandler handler, void* data,
476 bool message_handler_thread);
477 static void TearDown();
ager@chromium.org381abbb2009-02-25 13:23:22 +0000478 static void SetHostDispatchHandler(v8::DebugHostDispatchHandler handler,
479 void* data);
ager@chromium.org41826e72009-03-30 13:30:57 +0000480
481 // Invoke the message handler function.
482 static void InvokeMessageHandler(Vector< uint16_t> message);
483
484 // Send a message to the message handler eiher through the message thread or
485 // directly.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486 static void SendMessage(Vector<uint16_t> message);
ager@chromium.org41826e72009-03-30 13:30:57 +0000487
488 // Send the JSON message for a debug event.
489 static bool SendEventMessage(Handle<Object> event_data);
490
491 // Add a debugger command to the command queue.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000492 static void ProcessCommand(Vector<const uint16_t> command);
ager@chromium.org41826e72009-03-30 13:30:57 +0000493
494 // Check whether there are commands in the command queue.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000495 static bool HasCommands();
ager@chromium.org41826e72009-03-30 13:30:57 +0000496
ager@chromium.org381abbb2009-02-25 13:23:22 +0000497 static void ProcessHostDispatch(void* dispatch);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000498 static void UpdateActiveDebugger();
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000499 static Handle<Object> Call(Handle<JSFunction> fun,
500 Handle<Object> data,
501 bool* pending_exception);
502
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000503 // Start the debugger agent listening on the provided port.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000504 static bool StartAgent(const char* name, int port);
505
506 // Stop the debugger agent.
507 static void StopAgent();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000508
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509 inline static bool EventActive(v8::DebugEvent event) {
510 // Currently argument event is not used.
511 return !Debugger::compiling_natives_ && Debugger::debugger_active_;
512 }
513
514 static void set_debugger_active(bool debugger_active) {
515 Debugger::debugger_active_ = debugger_active;
516 }
517 static bool debugger_active() { return Debugger::debugger_active_; }
518 static void set_compiling_natives(bool compiling_natives) {
519 Debugger::compiling_natives_ = compiling_natives;
520 }
521 static bool compiling_natives() { return Debugger::compiling_natives_; }
mads.s.agercbaa0602008-08-14 13:41:48 +0000522 static void set_loading_debugger(bool v) { is_loading_debugger_ = v; }
523 static bool is_loading_debugger() { return Debugger::is_loading_debugger_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000524
525 private:
iposva@chromium.org245aa852009-02-10 00:49:54 +0000526 static Handle<Object> event_listener_; // Global handle to listener
527 static Handle<Object> event_listener_data_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000528 static bool debugger_active_; // Are there any active debugger?
529 static bool compiling_natives_; // Are we compiling natives?
mads.s.agercbaa0602008-08-14 13:41:48 +0000530 static bool is_loading_debugger_; // Are we loading the debugger?
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531 static DebugMessageThread* message_thread_;
ager@chromium.org381abbb2009-02-25 13:23:22 +0000532 static v8::DebugMessageHandler message_handler_;
533 static void* message_handler_data_;
534 static v8::DebugHostDispatchHandler host_dispatch_handler_;
535 static void* host_dispatch_handler_data_;
536
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000537 static DebuggerAgent* agent_;
538
ager@chromium.org41826e72009-03-30 13:30:57 +0000539 static const int kQueueInitialSize = 4;
540 static LockingMessageQueue command_queue_;
541 static LockingMessageQueue message_queue_;
542 static Semaphore* command_received_; // Signaled for each command received.
543 static Semaphore* message_received_; // Signalled for each message send.
544
ager@chromium.org381abbb2009-02-25 13:23:22 +0000545 friend class DebugMessageThread;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000546};
547
548
ager@chromium.org41826e72009-03-30 13:30:57 +0000549// Thread to read messages from the message queue and invoke the debug message
550// handler in another thread as the V8 thread. This thread is started if the
551// registration of the debug message handler requested to be called in a thread
552// seperate from the V8 thread.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553class DebugMessageThread: public Thread {
554 public:
ager@chromium.org41826e72009-03-30 13:30:57 +0000555 DebugMessageThread() : keep_running_(true) {}
556 virtual ~DebugMessageThread() {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557
kasper.lund7276f142008-07-30 08:49:36 +0000558 // Main function of DebugMessageThread thread.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559 void Run();
ager@chromium.org41826e72009-03-30 13:30:57 +0000560 void Stop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000561
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000562 private:
ager@chromium.org41826e72009-03-30 13:30:57 +0000563 bool keep_running_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000564 DISALLOW_COPY_AND_ASSIGN(DebugMessageThread);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000565};
566
567
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000568// This class is used for entering the debugger. Create an instance in the stack
569// to enter the debugger. This will set the current break state, make sure the
570// debugger is loaded and switch to the debugger context. If the debugger for
571// some reason could not be entered FailedToEnter will return true.
572class EnterDebugger BASE_EMBEDDED {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000573 public:
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000574 EnterDebugger()
575 : prev_(Debug::debugger_entry()),
576 has_js_frames_(!it_.done()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000577 ASSERT(prev_ == NULL ? !Debug::preemption_pending() : true);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000578
579 // Link recursive debugger entry.
580 Debug::set_debugger_entry(this);
581
ager@chromium.org8bb60582008-12-11 12:02:20 +0000582 // Store the previous break id and frame id.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000583 break_id_ = Debug::break_id();
584 break_frame_id_ = Debug::break_frame_id();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000585
ager@chromium.org8bb60582008-12-11 12:02:20 +0000586 // Create the new break info. If there is no JavaScript frames there is no
587 // break frame id.
588 if (has_js_frames_) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000589 Debug::NewBreak(it_.frame()->id());
ager@chromium.org8bb60582008-12-11 12:02:20 +0000590 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000591 Debug::NewBreak(StackFrame::NO_ID);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000592 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000593
594 // Make sure that debugger is loaded and enter the debugger context.
595 load_failed_ = !Debug::Load();
596 if (!load_failed_) {
597 // NOTE the member variable save which saves the previous context before
598 // this change.
599 Top::set_context(*Debug::debug_context());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000600 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000601 }
602
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000603 ~EnterDebugger() {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000604 // Restore to the previous break state.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000605 Debug::SetBreak(break_frame_id_, break_id_);
606
607 // Request preemption when leaving the last debugger entry and a preemption
608 // had been recorded while debugging. This is to avoid starvation in some
609 // debugging scenarios.
610 if (prev_ == NULL && Debug::preemption_pending()) {
611 StackGuard::Preempt();
612 Debug::set_preemption_pending(false);
613 }
614
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000615 // If there are commands in the queue when leaving the debugger request that
616 // these commands are processed.
617 if (prev_ == NULL && Debugger::HasCommands()) {
618 StackGuard::DebugCommand();
619 }
620
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000621 // Leaving this debugger entry.
622 Debug::set_debugger_entry(prev_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 }
624
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000625 // Check whether the debugger could be entered.
626 inline bool FailedToEnter() { return load_failed_; }
627
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000628 // Check whether there are any JavaScript frames on the stack.
ager@chromium.org8bb60582008-12-11 12:02:20 +0000629 inline bool HasJavaScriptFrames() { return has_js_frames_; }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000630
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000631 private:
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000632 EnterDebugger* prev_; // Previous debugger entry if entered recursively.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633 JavaScriptFrameIterator it_;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000634 const bool has_js_frames_; // Were there any JavaScript frames?
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000635 StackFrame::Id break_frame_id_; // Previous break frame id.
636 int break_id_; // Previous break id.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000637 bool load_failed_; // Did the debugger fail to load?
638 SaveContext save_; // Saves previous context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639};
640
641
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000642// Stack allocated class for disabling break.
643class DisableBreak BASE_EMBEDDED {
644 public:
645 // Enter the debugger by storing the previous top context and setting the
646 // current top context to the debugger context.
647 explicit DisableBreak(bool disable_break) {
648 prev_disable_break_ = Debug::disable_break();
649 Debug::set_disable_break(disable_break);
650 }
651 ~DisableBreak() {
652 Debug::set_disable_break(prev_disable_break_);
653 }
654
655 private:
656 // The previous state of the disable break used to restore the value when this
657 // object is destructed.
658 bool prev_disable_break_;
659};
660
661
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000662// Debug_Address encapsulates the Address pointers used in generating debug
663// code.
664class Debug_Address {
665 public:
666 Debug_Address(Debug::AddressId id, int reg = 0)
667 : id_(id), reg_(reg) {
668 ASSERT(reg == 0 || id == Debug::k_register_address);
669 }
670
671 static Debug_Address AfterBreakTarget() {
672 return Debug_Address(Debug::k_after_break_target_address);
673 }
674
675 static Debug_Address DebugBreakReturn() {
676 return Debug_Address(Debug::k_debug_break_return_address);
677 }
678
679 static Debug_Address Register(int reg) {
680 return Debug_Address(Debug::k_register_address, reg);
681 }
682
683 Address address() const {
684 switch (id_) {
685 case Debug::k_after_break_target_address:
686 return reinterpret_cast<Address>(Debug::after_break_target_address());
687 case Debug::k_debug_break_return_address:
688 return reinterpret_cast<Address>(Debug::debug_break_return_address());
689 case Debug::k_register_address:
690 return reinterpret_cast<Address>(Debug::register_address(reg_));
691 default:
692 UNREACHABLE();
693 return NULL;
694 }
695 }
696 private:
697 Debug::AddressId id_;
698 int reg_;
699};
700
701
702} } // namespace v8::internal
703
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000704#endif // V8_V8_DEBUG_H_