blob: 8822c5025ffd6607f539ba97bbdf51d6dc1d7d2f [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);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000498 static Handle<Object> Call(Handle<JSFunction> fun,
499 Handle<Object> data,
500 bool* pending_exception);
501
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000502 // Start the debugger agent listening on the provided port.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000503 static bool StartAgent(const char* name, int port);
504
505 // Stop the debugger agent.
506 static void StopAgent();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000507
ager@chromium.org71daaf62009-04-01 07:22:49 +0000508 // Unload the debugger if possible. Only called when no debugger is currently
509 // active.
510 static void UnloadDebugger();
511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512 inline static bool EventActive(v8::DebugEvent event) {
ager@chromium.org71daaf62009-04-01 07:22:49 +0000513 ScopedLock with(debugger_access_);
514
515 // Check whether the message handler was been cleared.
516 if (message_handler_cleared_) {
517 UnloadDebugger();
518 }
519
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000520 // Currently argument event is not used.
ager@chromium.org71daaf62009-04-01 07:22:49 +0000521 return !compiling_natives_ && Debugger::IsDebuggerActive();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000522 }
523
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000524 static void set_compiling_natives(bool compiling_natives) {
525 Debugger::compiling_natives_ = compiling_natives;
526 }
527 static bool compiling_natives() { return Debugger::compiling_natives_; }
mads.s.agercbaa0602008-08-14 13:41:48 +0000528 static void set_loading_debugger(bool v) { is_loading_debugger_ = v; }
529 static bool is_loading_debugger() { return Debugger::is_loading_debugger_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000530
531 private:
ager@chromium.org71daaf62009-04-01 07:22:49 +0000532 static bool IsDebuggerActive();
533
534 static Mutex* debugger_access_; // Mutex guarding debugger variables.
535 static Handle<Object> event_listener_; // Global handle to listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000536 static Handle<Object> event_listener_data_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000537 static bool compiling_natives_; // Are we compiling natives?
mads.s.agercbaa0602008-08-14 13:41:48 +0000538 static bool is_loading_debugger_; // Are we loading the debugger?
ager@chromium.org71daaf62009-04-01 07:22:49 +0000539 static bool never_unload_debugger_; // Can we unload the debugger?
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540 static DebugMessageThread* message_thread_;
ager@chromium.org381abbb2009-02-25 13:23:22 +0000541 static v8::DebugMessageHandler message_handler_;
ager@chromium.org71daaf62009-04-01 07:22:49 +0000542 static bool message_handler_cleared_; // Was message handler cleared?
ager@chromium.org381abbb2009-02-25 13:23:22 +0000543 static void* message_handler_data_;
544 static v8::DebugHostDispatchHandler host_dispatch_handler_;
545 static void* host_dispatch_handler_data_;
546
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000547 static DebuggerAgent* agent_;
548
ager@chromium.org41826e72009-03-30 13:30:57 +0000549 static const int kQueueInitialSize = 4;
550 static LockingMessageQueue command_queue_;
551 static LockingMessageQueue message_queue_;
552 static Semaphore* command_received_; // Signaled for each command received.
553 static Semaphore* message_received_; // Signalled for each message send.
554
ager@chromium.org71daaf62009-04-01 07:22:49 +0000555 friend class EnterDebugger;
ager@chromium.org381abbb2009-02-25 13:23:22 +0000556 friend class DebugMessageThread;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557};
558
559
ager@chromium.org41826e72009-03-30 13:30:57 +0000560// Thread to read messages from the message queue and invoke the debug message
561// handler in another thread as the V8 thread. This thread is started if the
562// registration of the debug message handler requested to be called in a thread
563// seperate from the V8 thread.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000564class DebugMessageThread: public Thread {
565 public:
ager@chromium.org41826e72009-03-30 13:30:57 +0000566 DebugMessageThread() : keep_running_(true) {}
567 virtual ~DebugMessageThread() {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568
kasper.lund7276f142008-07-30 08:49:36 +0000569 // Main function of DebugMessageThread thread.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000570 void Run();
ager@chromium.org41826e72009-03-30 13:30:57 +0000571 void Stop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000573 private:
ager@chromium.org41826e72009-03-30 13:30:57 +0000574 bool keep_running_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000575 DISALLOW_COPY_AND_ASSIGN(DebugMessageThread);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000576};
577
578
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000579// This class is used for entering the debugger. Create an instance in the stack
580// to enter the debugger. This will set the current break state, make sure the
581// debugger is loaded and switch to the debugger context. If the debugger for
582// some reason could not be entered FailedToEnter will return true.
583class EnterDebugger BASE_EMBEDDED {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000584 public:
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000585 EnterDebugger()
586 : prev_(Debug::debugger_entry()),
587 has_js_frames_(!it_.done()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000588 ASSERT(prev_ == NULL ? !Debug::preemption_pending() : true);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000589
590 // Link recursive debugger entry.
591 Debug::set_debugger_entry(this);
592
ager@chromium.org8bb60582008-12-11 12:02:20 +0000593 // Store the previous break id and frame id.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000594 break_id_ = Debug::break_id();
595 break_frame_id_ = Debug::break_frame_id();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000596
ager@chromium.org8bb60582008-12-11 12:02:20 +0000597 // Create the new break info. If there is no JavaScript frames there is no
598 // break frame id.
599 if (has_js_frames_) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000600 Debug::NewBreak(it_.frame()->id());
ager@chromium.org8bb60582008-12-11 12:02:20 +0000601 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000602 Debug::NewBreak(StackFrame::NO_ID);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000603 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000604
605 // Make sure that debugger is loaded and enter the debugger context.
606 load_failed_ = !Debug::Load();
607 if (!load_failed_) {
608 // NOTE the member variable save which saves the previous context before
609 // this change.
610 Top::set_context(*Debug::debug_context());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000611 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000612 }
613
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000614 ~EnterDebugger() {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000615 // Restore to the previous break state.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000616 Debug::SetBreak(break_frame_id_, break_id_);
617
618 // Request preemption when leaving the last debugger entry and a preemption
619 // had been recorded while debugging. This is to avoid starvation in some
620 // debugging scenarios.
621 if (prev_ == NULL && Debug::preemption_pending()) {
622 StackGuard::Preempt();
623 Debug::set_preemption_pending(false);
624 }
625
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000626 // If there are commands in the queue when leaving the debugger request that
627 // these commands are processed.
628 if (prev_ == NULL && Debugger::HasCommands()) {
629 StackGuard::DebugCommand();
630 }
631
ager@chromium.org71daaf62009-04-01 07:22:49 +0000632 // If leaving the debugger with the debugger no longer active unload it.
633 if (prev_ == NULL) {
634 if (!Debugger::IsDebuggerActive()) {
635 Debugger::UnloadDebugger();
636 }
637 }
638
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000639 // Leaving this debugger entry.
640 Debug::set_debugger_entry(prev_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000641 }
642
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000643 // Check whether the debugger could be entered.
644 inline bool FailedToEnter() { return load_failed_; }
645
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000646 // Check whether there are any JavaScript frames on the stack.
ager@chromium.org8bb60582008-12-11 12:02:20 +0000647 inline bool HasJavaScriptFrames() { return has_js_frames_; }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000648
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 private:
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000650 EnterDebugger* prev_; // Previous debugger entry if entered recursively.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000651 JavaScriptFrameIterator it_;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000652 const bool has_js_frames_; // Were there any JavaScript frames?
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000653 StackFrame::Id break_frame_id_; // Previous break frame id.
654 int break_id_; // Previous break id.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000655 bool load_failed_; // Did the debugger fail to load?
656 SaveContext save_; // Saves previous context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000657};
658
659
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000660// Stack allocated class for disabling break.
661class DisableBreak BASE_EMBEDDED {
662 public:
663 // Enter the debugger by storing the previous top context and setting the
664 // current top context to the debugger context.
665 explicit DisableBreak(bool disable_break) {
666 prev_disable_break_ = Debug::disable_break();
667 Debug::set_disable_break(disable_break);
668 }
669 ~DisableBreak() {
670 Debug::set_disable_break(prev_disable_break_);
671 }
672
673 private:
674 // The previous state of the disable break used to restore the value when this
675 // object is destructed.
676 bool prev_disable_break_;
677};
678
679
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000680// Debug_Address encapsulates the Address pointers used in generating debug
681// code.
682class Debug_Address {
683 public:
684 Debug_Address(Debug::AddressId id, int reg = 0)
685 : id_(id), reg_(reg) {
686 ASSERT(reg == 0 || id == Debug::k_register_address);
687 }
688
689 static Debug_Address AfterBreakTarget() {
690 return Debug_Address(Debug::k_after_break_target_address);
691 }
692
693 static Debug_Address DebugBreakReturn() {
694 return Debug_Address(Debug::k_debug_break_return_address);
695 }
696
697 static Debug_Address Register(int reg) {
698 return Debug_Address(Debug::k_register_address, reg);
699 }
700
701 Address address() const {
702 switch (id_) {
703 case Debug::k_after_break_target_address:
704 return reinterpret_cast<Address>(Debug::after_break_target_address());
705 case Debug::k_debug_break_return_address:
706 return reinterpret_cast<Address>(Debug::debug_break_return_address());
707 case Debug::k_register_address:
708 return reinterpret_cast<Address>(Debug::register_address(reg_));
709 default:
710 UNREACHABLE();
711 return NULL;
712 }
713 }
714 private:
715 Debug::AddressId id_;
716 int reg_;
717};
718
719
720} } // namespace v8::internal
721
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000722#endif // V8_V8_DEBUG_H_