blob: 7901ca1e3c79153d2771572b88f71d5aa168ed60 [file] [log] [blame]
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001// Copyright 2006-2008 Google Inc. All Rights Reserved.
2// 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
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
33#include "code-stubs.h"
34#include "compiler.h"
35#include "debug.h"
36#include "execution.h"
37#include "global-handles.h"
38#include "natives.h"
39#include "stub-cache.h"
kasper.lund7276f142008-07-30 08:49:36 +000040#include "log.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041
42namespace v8 { namespace internal {
43
44DEFINE_bool(remote_debugging, false, "enable remote debugging");
45DEFINE_int(debug_port, 5858, "port for remote debugging");
46DEFINE_bool(trace_debug_json, false, "trace debugging JSON request/response");
47DECLARE_bool(allow_natives_syntax);
kasper.lund7276f142008-07-30 08:49:36 +000048DECLARE_bool(log_debugger);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049
50
51static void PrintLn(v8::Local<v8::Value> value) {
52 v8::Local<v8::String> s = value->ToString();
53 char* data = NewArray<char>(s->Length() + 1);
54 if (data == NULL) {
55 V8::FatalProcessOutOfMemory("PrintLn");
56 return;
57 }
58 s->WriteAscii(data);
59 PrintF("%s\n", data);
60 DeleteArray(data);
61}
62
63
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064static Handle<Code> ComputeCallDebugBreak(int argc) {
65 CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugBreak(argc), Code);
66}
67
68
69static Handle<Code> ComputeCallDebugPrepareStepIn(int argc) {
70 CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugPrepareStepIn(argc), Code);
71}
72
73
74BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
75 BreakLocatorType type) {
76 debug_info_ = debug_info;
77 type_ = type;
78 reloc_iterator_ = NULL;
79 reloc_iterator_original_ = NULL;
80 Reset(); // Initialize the rest of the member variables.
81}
82
83
84BreakLocationIterator::~BreakLocationIterator() {
85 ASSERT(reloc_iterator_ != NULL);
86 ASSERT(reloc_iterator_original_ != NULL);
87 delete reloc_iterator_;
88 delete reloc_iterator_original_;
89}
90
91
92void BreakLocationIterator::Next() {
93 AssertNoAllocation nogc;
94 ASSERT(!RinfoDone());
95
96 // Iterate through reloc info for code and original code stopping at each
97 // breakable code target.
98 bool first = break_point_ == -1;
99 while (!RinfoDone()) {
100 if (!first) RinfoNext();
101 first = false;
102 if (RinfoDone()) return;
103
104 // Update the current source position each time a source position is
105 // passed.
106 if (is_position(rmode())) {
107 position_ = rinfo()->data() - debug_info_->shared()->start_position();
108 if (is_statement_position(rmode())) {
109 statement_position_ =
110 rinfo()->data() - debug_info_->shared()->start_position();
111 }
112 ASSERT(position_ >= 0);
113 ASSERT(statement_position_ >= 0);
114 }
115
116 // Check for breakable code target. Look in the original code as setting
117 // break points can cause the code targets in the running (debugged) code to
118 // be of a different kind than in the original code.
119 if (is_code_target(rmode())) {
120 Address target = original_rinfo()->target_address();
121 Code* code = Debug::GetCodeTarget(target);
122 if (code->is_inline_cache_stub() || is_js_construct_call(rmode())) {
123 break_point_++;
124 return;
125 }
126 if (code->kind() == Code::STUB) {
127 if (type_ == ALL_BREAK_LOCATIONS) {
128 if (Debug::IsBreakStub(code)) {
129 break_point_++;
130 return;
131 }
132 } else {
133 ASSERT(type_ == SOURCE_BREAK_LOCATIONS);
134 if (Debug::IsSourceBreakStub(code)) {
135 break_point_++;
136 return;
137 }
138 }
139 }
140 }
141
142 // Check for break at return.
143 // Currently is_exit_js_frame is used on ARM.
144 if (is_js_return(rmode()) || is_exit_js_frame(rmode())) {
145 // Set the positions to the end of the function.
146 if (debug_info_->shared()->HasSourceCode()) {
147 position_ = debug_info_->shared()->end_position() -
148 debug_info_->shared()->start_position();
149 } else {
150 position_ = 0;
151 }
152 statement_position_ = position_;
153 break_point_++;
154 return;
155 }
156 }
157}
158
159
160void BreakLocationIterator::Next(int count) {
161 while (count > 0) {
162 Next();
163 count--;
164 }
165}
166
167
168// Find the break point closest to the supplied address.
169void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) {
170 // Run through all break points to locate the one closest to the address.
171 int closest_break_point = 0;
172 int distance = kMaxInt;
173 while (!Done()) {
174 // Check if this break point is closer that what was previously found.
175 if (this->pc() < pc && pc - this->pc() < distance) {
176 closest_break_point = break_point();
177 distance = pc - this->pc();
178 // Check whether we can't get any closer.
179 if (distance == 0) break;
180 }
181 Next();
182 }
183
184 // Move to the break point found.
185 Reset();
186 Next(closest_break_point);
187}
188
189
190// Find the break point closest to the supplied source position.
191void BreakLocationIterator::FindBreakLocationFromPosition(int position) {
192 // Run through all break points to locate the one closest to the source
193 // position.
194 int closest_break_point = 0;
195 int distance = kMaxInt;
196 while (!Done()) {
197 // Check if this break point is closer that what was previously found.
198 if (position <= statement_position() &&
199 statement_position() - position < distance) {
200 closest_break_point = break_point();
201 distance = statement_position() - position;
202 // Check whether we can't get any closer.
203 if (distance == 0) break;
204 }
205 Next();
206 }
207
208 // Move to the break point found.
209 Reset();
210 Next(closest_break_point);
211}
212
213
214void BreakLocationIterator::Reset() {
215 // Create relocation iterators for the two code objects.
216 if (reloc_iterator_ != NULL) delete reloc_iterator_;
217 if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_;
218 reloc_iterator_ = new RelocIterator(debug_info_->code());
219 reloc_iterator_original_ = new RelocIterator(debug_info_->original_code());
220
221 // Position at the first break point.
222 break_point_ = -1;
223 position_ = 1;
224 statement_position_ = 1;
225 Next();
226}
227
228
229bool BreakLocationIterator::Done() const {
230 return RinfoDone();
231}
232
233
234void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) {
235 // If there is not already a real break point here patch code with debug
236 // break.
237 if (!HasBreakPoint()) {
238 SetDebugBreak();
239 }
240 ASSERT(IsDebugBreak());
241 // Set the break point information.
242 DebugInfo::SetBreakPoint(debug_info_, code_position(),
243 position(), statement_position(),
244 break_point_object);
245}
246
247
248void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) {
249 // Clear the break point information.
250 DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object);
251 // If there are no more break points here remove the debug break.
252 if (!HasBreakPoint()) {
253 ClearDebugBreak();
254 ASSERT(!IsDebugBreak());
255 }
256}
257
258
259void BreakLocationIterator::SetOneShot() {
260 // If there is a real break point here no more to do.
261 if (HasBreakPoint()) {
262 ASSERT(IsDebugBreak());
263 return;
264 }
265
266 // Patch code with debug break.
267 SetDebugBreak();
268}
269
270
271void BreakLocationIterator::ClearOneShot() {
272 // If there is a real break point here no more to do.
273 if (HasBreakPoint()) {
274 ASSERT(IsDebugBreak());
275 return;
276 }
277
278 // Patch code removing debug break.
279 ClearDebugBreak();
280 ASSERT(!IsDebugBreak());
281}
282
283
284void BreakLocationIterator::SetDebugBreak() {
285 // If there is already a break point here just return. This might happen if
286 // the same code is flodded with break points twice. Flodding the same
287 // function twice might happen when stepping in a function with an exception
288 // handler as the handler and the function is the same.
289 if (IsDebugBreak()) {
290 return;
291 }
292
293 if (is_js_return(rmode())) {
294 // This path is currently only used on IA32 as JSExitFrame on ARM uses a
295 // stub.
296 // Patch the JS frame exit code with a debug break call. See
297 // VisitReturnStatement and ExitJSFrame in codegen-ia32.cc for the
298 // precise return instructions sequence.
299 ASSERT(Debug::kIa32JSReturnSequenceLength >=
300 Debug::kIa32CallInstructionLength);
301 rinfo()->patch_code_with_call(Debug::debug_break_return_entry()->entry(),
302 Debug::kIa32JSReturnSequenceLength - Debug::kIa32CallInstructionLength);
303 } else {
304 // Patch the original code with the current address as the current address
305 // might have changed by the inline caching since the code was copied.
306 original_rinfo()->set_target_address(rinfo()->target_address());
307
308 // Patch the code to invoke the builtin debug break function matching the
309 // calling convention used by the call site.
310 Handle<Code> dbgbrk_code(Debug::FindDebugBreak(rinfo()));
311 rinfo()->set_target_address(dbgbrk_code->entry());
312 }
313 ASSERT(IsDebugBreak());
314}
315
316
317void BreakLocationIterator::ClearDebugBreak() {
318 if (is_js_return(rmode())) {
319 // Restore the JS frame exit code.
320 rinfo()->patch_code(original_rinfo()->pc(),
321 Debug::kIa32JSReturnSequenceLength);
322 } else {
323 // Patch the code to the original invoke.
324 rinfo()->set_target_address(original_rinfo()->target_address());
325 }
326 ASSERT(!IsDebugBreak());
327}
328
329
330void BreakLocationIterator::PrepareStepIn() {
331 // Step in can only be prepared if currently positioned on an IC call or
332 // construct call.
333 Address target = rinfo()->target_address();
334 Code* code = Debug::GetCodeTarget(target);
335 if (code->is_call_stub()) {
336 // Step in through IC call is handled by the runtime system. Therefore make
337 // sure that the any current IC is cleared and the runtime system is
338 // called. If the executing code has a debug break at the location change
339 // the call in the original code as it is the code there that will be
340 // executed in place of the debug break call.
341 Handle<Code> stub = ComputeCallDebugPrepareStepIn(code->arguments_count());
342 if (IsDebugBreak()) {
343 original_rinfo()->set_target_address(stub->entry());
344 } else {
345 rinfo()->set_target_address(stub->entry());
346 }
347 } else {
348 // Step in through constructs call requires no changs to the running code.
349 ASSERT(is_js_construct_call(rmode()));
350 }
351}
352
353
354// Check whether the break point is at a position which will exit the function.
355bool BreakLocationIterator::IsExit() const {
356 // Currently is_exit_js_frame is used on ARM.
357 return (is_js_return(rmode()) || is_exit_js_frame(rmode()));
358}
359
360
361bool BreakLocationIterator::HasBreakPoint() {
362 return debug_info_->HasBreakPoint(code_position());
363}
364
365
366// Check whether there is a debug break at the current position.
367bool BreakLocationIterator::IsDebugBreak() {
368 if (is_js_return(rmode())) {
369 // This is IA32 specific but works as long as the ARM version
370 // still uses a stub for JSExitFrame.
371 //
372 // TODO(1240753): Make the test architecture independent or split
373 // parts of the debugger into architecture dependent files.
374 return (*(rinfo()->pc()) == 0xE8);
375 } else {
376 return Debug::IsDebugBreak(rinfo()->target_address());
377 }
378}
379
380
381Object* BreakLocationIterator::BreakPointObjects() {
382 return debug_info_->GetBreakPointObjects(code_position());
383}
384
385
386bool BreakLocationIterator::RinfoDone() const {
387 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
388 return reloc_iterator_->done();
389}
390
391
392void BreakLocationIterator::RinfoNext() {
393 reloc_iterator_->next();
394 reloc_iterator_original_->next();
395#ifdef DEBUG
396 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
397 if (!reloc_iterator_->done()) {
398 ASSERT(rmode() == original_rmode());
399 }
400#endif
401}
402
403
404bool Debug::has_break_points_ = false;
405DebugInfoListNode* Debug::debug_info_list_ = NULL;
406
407
408// Threading support.
409void Debug::ThreadInit() {
410 thread_local_.last_step_action_ = StepNone;
411 thread_local_.last_statement_position_ = kNoPosition;
412 thread_local_.step_count_ = 0;
413 thread_local_.last_fp_ = 0;
414 thread_local_.step_into_fp_ = 0;
415 thread_local_.after_break_target_ = 0;
416}
417
418
419JSCallerSavedBuffer Debug::registers_;
420Debug::ThreadLocal Debug::thread_local_;
421
422
423char* Debug::ArchiveDebug(char* storage) {
424 char* to = storage;
425 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
426 to += sizeof(ThreadLocal);
427 memcpy(to, reinterpret_cast<char*>(&registers_), sizeof(registers_));
428 ThreadInit();
429 ASSERT(to <= storage + ArchiveSpacePerThread());
430 return storage + ArchiveSpacePerThread();
431}
432
433
434char* Debug::RestoreDebug(char* storage) {
435 char* from = storage;
436 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
437 from += sizeof(ThreadLocal);
438 memcpy(reinterpret_cast<char*>(&registers_), from, sizeof(registers_));
439 ASSERT(from <= storage + ArchiveSpacePerThread());
440 return storage + ArchiveSpacePerThread();
441}
442
443
444int Debug::ArchiveSpacePerThread() {
445 return sizeof(ThreadLocal) + sizeof(registers_);
446}
447
448
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000449// Default break enabled.
450bool Debug::disable_break_ = false;
451
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000452// Default call debugger on uncaught exception.
453bool Debug::break_on_exception_ = false;
454bool Debug::break_on_uncaught_exception_ = true;
455
456Handle<Context> Debug::debug_context_ = Handle<Context>();
457Code* Debug::debug_break_return_entry_ = NULL;
458Code* Debug::debug_break_return_ = NULL;
459
460
461void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Object> obj, void* data) {
462 DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
463 RemoveDebugInfo(node->debug_info());
464#ifdef DEBUG
465 node = Debug::debug_info_list_;
466 while (node != NULL) {
467 ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data));
468 node = node->next();
469 }
470#endif
471}
472
473
474DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
475 // Globalize the request debug info object and make it weak.
476 debug_info_ = Handle<DebugInfo>::cast((GlobalHandles::Create(debug_info)));
477 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
478 this, Debug::HandleWeakDebugInfo);
479}
480
481
482DebugInfoListNode::~DebugInfoListNode() {
483 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location()));
484}
485
486
487void Debug::Setup(bool create_heap_objects) {
488 ThreadInit();
489 if (create_heap_objects) {
490 // Get code to handle entry to debug break on return.
491 debug_break_return_entry_ =
492 Builtins::builtin(Builtins::Return_DebugBreakEntry);
493 ASSERT(debug_break_return_entry_->IsCode());
494
495 // Get code to handle debug break on return.
496 debug_break_return_ =
497 Builtins::builtin(Builtins::Return_DebugBreak);
498 ASSERT(debug_break_return_->IsCode());
499 }
500}
501
502
503bool Debug::CompileDebuggerScript(int index) {
504 HandleScope scope;
505
kasper.lund44510672008-07-25 07:37:58 +0000506 // Bail out if the index is invalid.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000507 if (index == -1) {
508 return false;
509 }
kasper.lund44510672008-07-25 07:37:58 +0000510
511 // Find source and name for the requested script.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512 Handle<String> source_code = Bootstrapper::NativesSourceLookup(index);
513 Vector<const char> name = Natives::GetScriptName(index);
514 Handle<String> script_name = Factory::NewStringFromAscii(name);
515
516 // Compile the script.
517 bool allow_natives_syntax = FLAG_allow_natives_syntax;
518 FLAG_allow_natives_syntax = true;
519 Handle<JSFunction> boilerplate;
520 boilerplate = Compiler::Compile(source_code, script_name, 0, 0, NULL, NULL);
521 FLAG_allow_natives_syntax = allow_natives_syntax;
522
523 // Silently ignore stack overflows during compilation.
524 if (boilerplate.is_null()) {
525 ASSERT(Top::has_pending_exception());
526 Top::clear_pending_exception();
527 return false;
528 }
529
kasper.lund44510672008-07-25 07:37:58 +0000530 // Execute the boilerplate function in the debugger context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531 Handle<Context> context = Top::global_context();
kasper.lund44510672008-07-25 07:37:58 +0000532 bool caught_exception = false;
533 Handle<JSFunction> function =
534 Factory::NewFunctionFromBoilerplate(boilerplate, context);
535 Handle<Object> result =
536 Execution::TryCall(function, Handle<Object>(context->global()),
537 0, NULL, &caught_exception);
538
539 // Check for caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540 if (caught_exception) {
kasper.lund44510672008-07-25 07:37:58 +0000541 MessageHandler::ReportMessage("error_loading_debugger", NULL,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542 HandleVector<Object>(&result, 1));
543 return false;
544 }
545
kasper.lund44510672008-07-25 07:37:58 +0000546 // Mark this script as native and return successfully.
547 Handle<Script> script(Script::cast(function->shared()->script()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548 script->set_type(Smi::FromInt(SCRIPT_TYPE_NATIVE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549 return true;
550}
551
552
553bool Debug::Load() {
554 // Return if debugger is already loaded.
kasper.lund212ac232008-07-16 07:07:30 +0000555 if (IsLoaded()) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000556
kasper.lund44510672008-07-25 07:37:58 +0000557 // Bail out if we're already in the process of compiling the native
558 // JavaScript source code for the debugger.
559 if (Debugger::compiling_natives()) return false;
560
561 // Disable breakpoints and interrupts while compiling and running the
562 // debugger scripts including the context creation code.
563 DisableBreak disable(true);
564 PostponeInterruptsScope postpone;
565
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 // Create the debugger context.
567 HandleScope scope;
kasper.lund44510672008-07-25 07:37:58 +0000568 Handle<Context> context =
569 Bootstrapper::CreateEnvironment(Handle<Object>::null(),
570 v8::Handle<ObjectTemplate>(),
571 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572
kasper.lund44510672008-07-25 07:37:58 +0000573 // Use the debugger context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000574 SaveContext save;
kasper.lund44510672008-07-25 07:37:58 +0000575 Top::set_context(*context);
576 Top::set_security_context(*context);
577
578 // Expose the builtins object in the debugger context.
579 Handle<String> key = Factory::LookupAsciiSymbol("builtins");
580 Handle<GlobalObject> global = Handle<GlobalObject>(context->global());
581 SetProperty(global, key, Handle<Object>(global->builtins()), NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000582
583 // Compile the JavaScript for the debugger in the debugger context.
584 Debugger::set_compiling_natives(true);
kasper.lund44510672008-07-25 07:37:58 +0000585 bool caught_exception =
586 !CompileDebuggerScript(Natives::GetIndex("mirror")) ||
587 !CompileDebuggerScript(Natives::GetIndex("debug"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000588 Debugger::set_compiling_natives(false);
589
kasper.lund44510672008-07-25 07:37:58 +0000590 // Check for caught exceptions.
591 if (caught_exception) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000592
593 // Debugger loaded.
kasper.lund44510672008-07-25 07:37:58 +0000594 debug_context_ = Handle<Context>::cast(GlobalHandles::Create(*context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000595 return true;
596}
597
598
599void Debug::Unload() {
600 // Return debugger is not loaded.
601 if (!IsLoaded()) {
602 return;
603 }
604
605 // Clear debugger context global handle.
606 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location()));
607 debug_context_ = Handle<Context>();
608}
609
610
611void Debug::Iterate(ObjectVisitor* v) {
612#define VISIT(field) v->VisitPointer(reinterpret_cast<Object**>(&(field)));
613 VISIT(debug_break_return_entry_);
614 VISIT(debug_break_return_);
615#undef VISIT
616}
617
618
619Object* Debug::Break(Arguments args) {
620 HandleScope scope;
621 ASSERT(args.length() == 1);
622
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000623 // Get the top-most JavaScript frame.
624 JavaScriptFrameIterator it;
625 JavaScriptFrame* frame = it.frame();
626
627 // Just continue if breaks are disabled or debugger cannot be loaded.
628 if (disable_break() || !Load()) {
629 SetAfterBreakTarget(frame);
630 return args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000631 }
632
633 SaveBreakFrame save;
634 EnterDebuggerContext enter;
635
kasper.lund44510672008-07-25 07:37:58 +0000636 // Postpone interrupt during breakpoint processing.
637 PostponeInterruptsScope postpone;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638
639 // Get the debug info (create it if it does not exist).
640 Handle<SharedFunctionInfo> shared =
641 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
642 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
643
644 // Find the break point where execution has stopped.
645 BreakLocationIterator break_location_iterator(debug_info,
646 ALL_BREAK_LOCATIONS);
647 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
648
649 // Check whether step next reached a new statement.
650 if (!StepNextContinue(&break_location_iterator, frame)) {
651 // Decrease steps left if performing multiple steps.
652 if (thread_local_.step_count_ > 0) {
653 thread_local_.step_count_--;
654 }
655 }
656
657 // If there is one or more real break points check whether any of these are
658 // triggered.
659 Handle<Object> break_points_hit(Heap::undefined_value());
660 if (break_location_iterator.HasBreakPoint()) {
661 Handle<Object> break_point_objects =
662 Handle<Object>(break_location_iterator.BreakPointObjects());
663 break_points_hit = CheckBreakPoints(break_point_objects);
664 }
665
666 // Notify debugger if a real break point is triggered or if performing single
667 // stepping with no more steps to perform. Otherwise do another step.
668 if (!break_points_hit->IsUndefined() ||
669 (thread_local_.last_step_action_ != StepNone &&
670 thread_local_.step_count_ == 0)) {
671 // Clear all current stepping setup.
672 ClearStepping();
673
674 // Notify the debug event listeners.
675 Debugger::OnDebugBreak(break_points_hit);
676 } else if (thread_local_.last_step_action_ != StepNone) {
677 // Hold on to last step action as it is cleared by the call to
678 // ClearStepping.
679 StepAction step_action = thread_local_.last_step_action_;
680 int step_count = thread_local_.step_count_;
681
682 // Clear all current stepping setup.
683 ClearStepping();
684
685 // Set up for the remaining steps.
686 PrepareStep(step_action, step_count);
687 }
688
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000689 // Install jump to the call address which was overwritten.
690 SetAfterBreakTarget(frame);
691
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000692 return args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000693}
694
695
696// Check the break point objects for whether one or more are actually
697// triggered. This function returns a JSArray with the break point objects
698// which is triggered.
699Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
700 int break_points_hit_count = 0;
701 Handle<JSArray> break_points_hit = Factory::NewJSArray(1);
702
703 // If there are multiple break points they are in a Fixedrray.
704 ASSERT(!break_point_objects->IsUndefined());
705 if (break_point_objects->IsFixedArray()) {
706 Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
707 for (int i = 0; i < array->length(); i++) {
708 Handle<Object> o(array->get(i));
709 if (CheckBreakPoint(o)) {
710 break_points_hit->SetElement(break_points_hit_count++, *o);
711 }
712 }
713 } else {
714 if (CheckBreakPoint(break_point_objects)) {
715 break_points_hit->SetElement(break_points_hit_count++,
716 *break_point_objects);
717 }
718 }
719
720 // Return undefined if no break points where triggered.
721 if (break_points_hit_count == 0) {
722 return Factory::undefined_value();
723 }
724 return break_points_hit;
725}
726
727
728// Check whether a single break point object is triggered.
729bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
730 // Ignore check if break point object is not a JSObject.
731 if (!break_point_object->IsJSObject()) return true;
732
733 // Get the function CheckBreakPoint (defined in debug.js).
734 Handle<JSFunction> check_break_point =
735 Handle<JSFunction>(JSFunction::cast(
736 debug_context()->global()->GetProperty(
737 *Factory::LookupAsciiSymbol("IsBreakPointTriggered"))));
738
739 // Get the break id as an object.
740 Handle<Object> break_id = Factory::NewNumberFromInt(Top::break_id());
741
742 // Call HandleBreakPointx.
743 bool caught_exception = false;
744 const int argc = 2;
745 Object** argv[argc] = {
746 break_id.location(),
747 reinterpret_cast<Object**>(break_point_object.location())
748 };
749 Handle<Object> result = Execution::TryCall(check_break_point,
750 Top::builtins(), argc, argv,
751 &caught_exception);
752
753 // If exception or non boolean result handle as not triggered
754 if (caught_exception || !result->IsBoolean()) {
755 return false;
756 }
757
758 // Return whether the break point is triggered.
759 return *result == Heap::true_value();
760}
761
762
763// Check whether the function has debug information.
764bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) {
765 return !shared->debug_info()->IsUndefined();
766}
767
768
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000769// Return the debug info for this function. EnsureDebugInfo must be called
770// prior to ensure the debug info has been generated for shared.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000771Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000772 ASSERT(HasDebugInfo(shared));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773 return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info()));
774}
775
776
777void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
778 int source_position,
779 Handle<Object> break_point_object) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000780 if (!EnsureDebugInfo(shared)) {
781 // Return if retrieving debug info failed.
782 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000783 }
784
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000785 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000786 // Source positions starts with zero.
787 ASSERT(source_position >= 0);
788
789 // Find the break point and change it.
790 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
791 it.FindBreakLocationFromPosition(source_position);
792 it.SetBreakPoint(break_point_object);
793
794 // At least one active break point now.
795 ASSERT(debug_info->GetBreakPointCount() > 0);
796}
797
798
799void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
800 DebugInfoListNode* node = debug_info_list_;
801 while (node != NULL) {
802 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
803 break_point_object);
804 if (!result->IsUndefined()) {
805 // Get information in the break point.
806 BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
807 Handle<DebugInfo> debug_info = node->debug_info();
808 Handle<SharedFunctionInfo> shared(debug_info->shared());
809 int source_position = break_point_info->statement_position()->value();
810
811 // Source positions starts with zero.
812 ASSERT(source_position >= 0);
813
814 // Find the break point and clear it.
815 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
816 it.FindBreakLocationFromPosition(source_position);
817 it.ClearBreakPoint(break_point_object);
818
819 // If there are no more break points left remove the debug info for this
820 // function.
821 if (debug_info->GetBreakPointCount() == 0) {
822 RemoveDebugInfo(debug_info);
823 }
824
825 return;
826 }
827 node = node->next();
828 }
829}
830
831
832void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000833 // Make sure the function has setup the debug info.
834 if (!EnsureDebugInfo(shared)) {
835 // Return if we failed to retrieve the debug info.
836 return;
837 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000838
839 // Flood the function with break points.
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000840 BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841 while (!it.Done()) {
842 it.SetOneShot();
843 it.Next();
844 }
845}
846
847
848void Debug::FloodHandlerWithOneShot() {
849 StackFrame::Id id = Top::break_frame_id();
850 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) {
851 JavaScriptFrame* frame = it.frame();
852 if (frame->HasHandler()) {
853 Handle<SharedFunctionInfo> shared =
854 Handle<SharedFunctionInfo>(
855 JSFunction::cast(frame->function())->shared());
856 // Flood the function with the catch block with break points
857 FloodWithOneShot(shared);
858 return;
859 }
860 }
861}
862
863
864void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
865 if (type == BreakUncaughtException) {
866 break_on_uncaught_exception_ = enable;
867 } else {
868 break_on_exception_ = enable;
869 }
870}
871
872
873void Debug::PrepareStep(StepAction step_action, int step_count) {
874 HandleScope scope;
875 ASSERT(Debug::InDebugger());
876
877 // Remember this step action and count.
878 thread_local_.last_step_action_ = step_action;
879 thread_local_.step_count_ = step_count;
880
881 // Get the frame where the execution has stopped and skip the debug frame if
882 // any. The debug frame will only be present if execution was stopped due to
883 // hitting a break point. In other situations (e.g. unhandled exception) the
884 // debug frame is not present.
885 StackFrame::Id id = Top::break_frame_id();
886 JavaScriptFrameIterator frames_it(id);
887 JavaScriptFrame* frame = frames_it.frame();
888
889 // First of all ensure there is one-shot break points in the top handler
890 // if any.
891 FloodHandlerWithOneShot();
892
893 // If the function on the top frame is unresolved perform step out. This will
894 // be the case when calling unknown functions and having the debugger stopped
895 // in an unhandled exception.
896 if (!frame->function()->IsJSFunction()) {
897 // Step out: Find the calling JavaScript frame and flood it with
898 // breakpoints.
899 frames_it.Advance();
900 // Fill the function to return to with one-shot break points.
901 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
902 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
903 return;
904 }
905
906 // Get the debug info (create it if it does not exist).
907 Handle<SharedFunctionInfo> shared =
908 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000909 if (!EnsureDebugInfo(shared)) {
910 // Return if ensuring debug info failed.
911 return;
912 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000913 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
914
915 // Find the break location where execution has stopped.
916 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS);
917 it.FindBreakLocationFromAddress(frame->pc());
918
919 // Compute whether or not the target is a call target.
920 bool is_call_target = false;
921 if (is_code_target(it.rinfo()->rmode())) {
922 Address target = it.rinfo()->target_address();
923 Code* code = Debug::GetCodeTarget(target);
924 if (code->is_call_stub()) is_call_target = true;
925 }
926
927 // If this is the last break code target step out is the only posibility.
928 if (it.IsExit() || step_action == StepOut) {
929 // Step out: If there is a JavaScript caller frame, we need to
930 // flood it with breakpoints.
931 frames_it.Advance();
932 if (!frames_it.done()) {
933 // Fill the function to return to with one-shot break points.
934 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
935 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
936 }
937 } else if (!(is_call_target || is_js_construct_call(it.rmode())) ||
938 step_action == StepNext || step_action == StepMin) {
939 // Step next or step min.
940
941 // Fill the current function with one-shot break points.
942 FloodWithOneShot(shared);
943
944 // Remember source position and frame to handle step next.
945 thread_local_.last_statement_position_ =
946 debug_info->code()->SourceStatementPosition(frame->pc());
947 thread_local_.last_fp_ = frame->fp();
948 } else {
949 // Fill the current function with one-shot break points even for step in on
950 // a call target as the function called might be a native function for
951 // which step in will not stop.
952 FloodWithOneShot(shared);
953
954 // Step in or Step in min
955 it.PrepareStepIn();
956 ActivateStepIn(frame);
957 }
958}
959
960
961// Check whether the current debug break should be reported to the debugger. It
962// is used to have step next and step in only report break back to the debugger
963// if on a different frame or in a different statement. In some situations
964// there will be several break points in the same statement when the code is
965// flodded with one-shot break points. This function helps to perform several
966// steps before reporting break back to the debugger.
967bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
968 JavaScriptFrame* frame) {
969 // If the step last action was step next or step in make sure that a new
970 // statement is hit.
971 if (thread_local_.last_step_action_ == StepNext ||
972 thread_local_.last_step_action_ == StepIn) {
973 // Never continue if returning from function.
974 if (break_location_iterator->IsExit()) return false;
975
976 // Continue if we are still on the same frame and in the same statement.
977 int current_statement_position =
978 break_location_iterator->code()->SourceStatementPosition(frame->pc());
979 return thread_local_.last_fp_ == frame->fp() &&
980 thread_local_.last_statement_position_ == current_statement_position;
981 }
982
983 // No step next action - don't continue.
984 return false;
985}
986
987
988// Check whether the code object at the specified address is a debug break code
989// object.
990bool Debug::IsDebugBreak(Address addr) {
991 Code* code = GetCodeTarget(addr);
kasper.lund7276f142008-07-30 08:49:36 +0000992 return code->ic_state() == DEBUG_BREAK;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000993}
994
995
996// Check whether a code stub with the specified major key is a possible break
997// point location when looking for source break locations.
998bool Debug::IsSourceBreakStub(Code* code) {
999 CodeStub::Major major_key = code->major_key();
1000 return major_key == CodeStub::CallFunction;
1001}
1002
1003
1004// Check whether a code stub with the specified major key is a possible break
1005// location.
1006bool Debug::IsBreakStub(Code* code) {
1007 CodeStub::Major major_key = code->major_key();
1008 return major_key == CodeStub::CallFunction ||
1009 major_key == CodeStub::StackCheck;
1010}
1011
1012
1013// Find the builtin to use for invoking the debug break
1014Handle<Code> Debug::FindDebugBreak(RelocInfo* rinfo) {
1015 // Find the builtin debug break function matching the calling convention
1016 // used by the call site.
1017 RelocMode mode = rinfo->rmode();
1018
1019 if (is_code_target(mode)) {
1020 Address target = rinfo->target_address();
1021 Code* code = Debug::GetCodeTarget(target);
1022 if (code->is_inline_cache_stub()) {
1023 if (code->is_call_stub()) {
1024 return ComputeCallDebugBreak(code->arguments_count());
1025 }
1026 if (code->is_load_stub()) {
1027 return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak));
1028 }
1029 if (code->is_store_stub()) {
1030 return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak));
1031 }
1032 if (code->is_keyed_load_stub()) {
1033 Handle<Code> result =
1034 Handle<Code>(Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
1035 return result;
1036 }
1037 if (code->is_keyed_store_stub()) {
1038 Handle<Code> result =
1039 Handle<Code>(Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
1040 return result;
1041 }
1042 }
1043 if (is_js_construct_call(mode)) {
1044 Handle<Code> result =
1045 Handle<Code>(Builtins::builtin(Builtins::ConstructCall_DebugBreak));
1046 return result;
1047 }
1048 // Currently is_exit_js_frame is used on ARM.
1049 if (is_exit_js_frame(mode)) {
1050 return Handle<Code>(Builtins::builtin(Builtins::Return_DebugBreak));
1051 }
1052 if (code->kind() == Code::STUB) {
1053 ASSERT(code->major_key() == CodeStub::CallFunction ||
1054 code->major_key() == CodeStub::StackCheck);
1055 Handle<Code> result =
1056 Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak));
1057 return result;
1058 }
1059 }
1060
1061 UNREACHABLE();
1062 return Handle<Code>::null();
1063}
1064
1065
1066// Simple function for returning the source positions for active break points.
1067Handle<Object> Debug::GetSourceBreakLocations(
1068 Handle<SharedFunctionInfo> shared) {
1069 if (!HasDebugInfo(shared)) return Handle<Object>(Heap::undefined_value());
1070 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1071 if (debug_info->GetBreakPointCount() == 0) {
1072 return Handle<Object>(Heap::undefined_value());
1073 }
1074 Handle<FixedArray> locations =
1075 Factory::NewFixedArray(debug_info->GetBreakPointCount());
1076 int count = 0;
1077 for (int i = 0; i < debug_info->break_points()->length(); i++) {
1078 if (!debug_info->break_points()->get(i)->IsUndefined()) {
1079 BreakPointInfo* break_point_info =
1080 BreakPointInfo::cast(debug_info->break_points()->get(i));
1081 if (break_point_info->GetBreakPointCount() > 0) {
1082 locations->set(count++, break_point_info->statement_position());
1083 }
1084 }
1085 }
1086 return locations;
1087}
1088
1089
1090void Debug::ClearStepping() {
1091 // Clear the various stepping setup.
1092 ClearOneShot();
1093 ClearStepIn();
1094 ClearStepNext();
1095
1096 // Clear multiple step counter.
1097 thread_local_.step_count_ = 0;
1098}
1099
1100// Clears all the one-shot break points that are currently set. Normally this
1101// function is called each time a break point is hit as one shot break points
1102// are used to support stepping.
1103void Debug::ClearOneShot() {
1104 // The current implementation just runs through all the breakpoints. When the
1105 // last break point for a function is removed that function is automaticaly
1106 // removed from the list.
1107
1108 DebugInfoListNode* node = debug_info_list_;
1109 while (node != NULL) {
1110 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1111 while (!it.Done()) {
1112 it.ClearOneShot();
1113 it.Next();
1114 }
1115 node = node->next();
1116 }
1117}
1118
1119
1120void Debug::ActivateStepIn(StackFrame* frame) {
1121 thread_local_.step_into_fp_ = frame->fp();
1122}
1123
1124
1125void Debug::ClearStepIn() {
1126 thread_local_.step_into_fp_ = 0;
1127}
1128
1129
1130void Debug::ClearStepNext() {
1131 thread_local_.last_step_action_ = StepNone;
1132 thread_local_.last_statement_position_ = kNoPosition;
1133 thread_local_.last_fp_ = 0;
1134}
1135
1136
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001137bool Debug::EnsureCompiled(Handle<SharedFunctionInfo> shared) {
1138 if (shared->is_compiled()) return true;
1139 return CompileLazyShared(shared, CLEAR_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001140}
1141
1142
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001143// Ensures the debug information is present for shared.
1144bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
1145 // Return if we already have the debug info for shared.
1146 if (HasDebugInfo(shared)) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001148 // Ensure shared in compiled. Return false if this failed.
1149 if (!EnsureCompiled(shared)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001150
1151 // Create the debug info object.
1152 Handle<DebugInfo> debug_info =
1153 Handle<DebugInfo>::cast(Factory::NewStruct(DEBUG_INFO_TYPE));
1154
1155 // Get the function original code.
1156 Handle<Code> code(shared->code());
1157
1158 // Debug info contains function, a copy of the original code and the executing
1159 // code.
1160 debug_info->set_shared(*shared);
1161 debug_info->set_original_code(*Factory::CopyCode(code));
1162 debug_info->set_code(*code);
1163
1164 // Link debug info to function.
1165 shared->set_debug_info(*debug_info);
1166
1167 // Initially no active break points.
1168 debug_info->set_break_points(
1169 *Factory::NewFixedArray(Debug::kEstimatedNofBreakPointsInFunction));
1170
1171 // Add debug info to the list.
1172 DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
1173 node->set_next(debug_info_list_);
1174 debug_info_list_ = node;
1175
1176 // Now there is at least one break point.
1177 has_break_points_ = true;
1178
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001179 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180}
1181
1182
1183void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
1184 ASSERT(debug_info_list_ != NULL);
1185 // Run through the debug info objects to find this one and remove it.
1186 DebugInfoListNode* prev = NULL;
1187 DebugInfoListNode* current = debug_info_list_;
1188 while (current != NULL) {
1189 if (*current->debug_info() == *debug_info) {
1190 // Unlink from list. If prev is NULL we are looking at the first element.
1191 if (prev == NULL) {
1192 debug_info_list_ = current->next();
1193 } else {
1194 prev->set_next(current->next());
1195 }
1196 current->debug_info()->shared()->set_debug_info(Heap::undefined_value());
1197 delete current;
1198
1199 // If there are no more debug info objects there are not more break
1200 // points.
1201 has_break_points_ = debug_info_list_ != NULL;
1202
1203 return;
1204 }
1205 // Move to next in list.
1206 prev = current;
1207 current = current->next();
1208 }
1209 UNREACHABLE();
1210}
1211
1212
1213void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
1214 // Get the executing function in which the debug break occurred.
1215 Handle<SharedFunctionInfo> shared =
1216 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001217 if (!EnsureDebugInfo(shared)) {
1218 // Return if we failed to retrieve the debug info.
1219 return;
1220 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001221 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1222 Handle<Code> code(debug_info->code());
1223 Handle<Code> original_code(debug_info->original_code());
1224#ifdef DEBUG
1225 // Get the code which is actually executing.
1226 Handle<Code> frame_code(frame->FindCode());
1227 ASSERT(frame_code.is_identical_to(code));
1228#endif
1229
1230 // Find the call address in the running code. This address holds the call to
1231 // either a DebugBreakXXX or to the debug break return entry code if the
1232 // break point is still active after processing the break point.
1233 Address addr = frame->pc() - Assembler::kTargetAddrToReturnAddrDist;
1234
1235 // Check if the location is at JS exit.
1236 bool at_js_exit = false;
1237 RelocIterator it(debug_info->code());
1238 while (!it.done()) {
1239 if (is_js_return(it.rinfo()->rmode())) {
1240 at_js_exit = it.rinfo()->pc() == addr - 1;
1241 }
1242 it.next();
1243 }
1244
1245 // Handle the jump to continue execution after break point depending on the
1246 // break location.
1247 if (at_js_exit) {
1248 // First check if the call in the code is still the debug break return
1249 // entry code. If it is the break point is still active. If not the break
1250 // point was removed during break point processing.
1251 if (Assembler::target_address_at(addr) ==
1252 debug_break_return_entry()->entry()) {
1253 // Break point still active. Jump to the corresponding place in the
1254 // original code.
1255 addr += original_code->instruction_start() - code->instruction_start();
1256 }
1257
1258 // Move one byte back to where the call instruction was placed.
1259 thread_local_.after_break_target_ = addr - 1;
1260 } else {
1261 // Check if there still is a debug break call at the target address. If the
1262 // break point has been removed it will have disappeared. If it have
1263 // disappeared don't try to look in the original code as the running code
1264 // will have the right address. This takes care of the case where the last
1265 // break point is removed from the function and therefore no "original code"
1266 // is available. If the debug break call is still there find the address in
1267 // the original code.
1268 if (IsDebugBreak(Assembler::target_address_at(addr))) {
1269 // If the break point is still there find the call address which was
1270 // overwritten in the original code by the call to DebugBreakXXX.
1271
1272 // Find the corresponding address in the original code.
1273 addr += original_code->instruction_start() - code->instruction_start();
1274 }
1275
1276 // Install jump to the call address in the original code. This will be the
1277 // call which was overwritten by the call to DebugBreakXXX.
1278 thread_local_.after_break_target_ = Assembler::target_address_at(addr);
1279 }
1280}
1281
1282
1283Code* Debug::GetCodeTarget(Address target) {
1284 // Maybe this can be refactored with the stuff in ic-inl.h?
1285 Code* result =
1286 Code::cast(HeapObject::FromAddress(target - Code::kHeaderSize));
1287 return result;
1288}
1289
1290
1291bool Debug::IsDebugGlobal(GlobalObject* global) {
1292 return IsLoaded() && global == Debug::debug_context()->global();
1293}
1294
1295
1296bool Debugger::debugger_active_ = false;
1297bool Debugger::compiling_natives_ = false;
1298DebugMessageThread* Debugger::message_thread_ = NULL;
1299v8::DebugMessageHandler Debugger::debug_message_handler_ = NULL;
1300void* Debugger::debug_message_handler_data_ = NULL;
1301
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001302
1303Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
1304 int argc, Object*** argv,
1305 bool* caught_exception) {
1306 ASSERT(Top::context() == *Debug::debug_context());
1307
1308 // Create the execution state object.
1309 Handle<String> constructor_str = Factory::LookupSymbol(constructor_name);
1310 Handle<Object> constructor(Top::global()->GetProperty(*constructor_str));
1311 ASSERT(constructor->IsJSFunction());
1312 if (!constructor->IsJSFunction()) {
1313 *caught_exception = true;
1314 return Factory::undefined_value();
1315 }
1316 Handle<Object> js_object = Execution::TryCall(
1317 Handle<JSFunction>::cast(constructor),
1318 Handle<JSObject>(Debug::debug_context()->global()), argc, argv,
1319 caught_exception);
1320 return js_object;
1321}
1322
1323
1324Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
1325 // Create the execution state object.
1326 Handle<Object> break_id = Factory::NewNumberFromInt(Top::break_id());
1327 const int argc = 1;
1328 Object** argv[argc] = { break_id.location() };
1329 return MakeJSObject(CStrVector("MakeExecutionState"),
1330 argc, argv, caught_exception);
1331}
1332
1333
1334Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state,
1335 Handle<Object> break_points_hit,
1336 bool* caught_exception) {
1337 // Create the new break event object.
1338 const int argc = 2;
1339 Object** argv[argc] = { exec_state.location(),
1340 break_points_hit.location() };
1341 return MakeJSObject(CStrVector("MakeBreakEvent"),
1342 argc,
1343 argv,
1344 caught_exception);
1345}
1346
1347
1348Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
1349 Handle<Object> exception,
1350 bool uncaught,
1351 bool* caught_exception) {
1352 // Create the new exception event object.
1353 const int argc = 3;
1354 Object** argv[argc] = { exec_state.location(),
1355 exception.location(),
1356 uncaught ? Factory::true_value().location() :
1357 Factory::false_value().location()};
1358 return MakeJSObject(CStrVector("MakeExceptionEvent"),
1359 argc, argv, caught_exception);
1360}
1361
1362
1363Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
1364 bool* caught_exception) {
1365 // Create the new function event object.
1366 const int argc = 1;
1367 Object** argv[argc] = { function.location() };
1368 return MakeJSObject(CStrVector("MakeNewFunctionEvent"),
1369 argc, argv, caught_exception);
1370}
1371
1372
1373Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
1374 Handle<Object> script_function,
1375 bool* caught_exception) {
1376 // Create the compile event object.
1377 Handle<Object> exec_state = MakeExecutionState(caught_exception);
1378 Handle<Object> script_source(script->source());
1379 Handle<Object> script_name(script->name());
1380 const int argc = 3;
1381 Object** argv[argc] = { script_source.location(),
1382 script_name.location(),
1383 script_function.location() };
1384 return MakeJSObject(CStrVector("MakeCompileEvent"),
1385 argc,
1386 argv,
1387 caught_exception);
1388}
1389
1390
1391Handle<String> Debugger::ProcessRequest(Handle<Object> exec_state,
1392 Handle<Object> request,
1393 bool stopped) {
1394 // Get the function ProcessDebugRequest (declared in debug.js).
1395 Handle<JSFunction> process_denbug_request =
1396 Handle<JSFunction>(JSFunction::cast(
1397 Debug::debug_context()->global()->GetProperty(
1398 *Factory::LookupAsciiSymbol("ProcessDebugRequest"))));
1399
1400 // Call ProcessDebugRequest expect String result. The ProcessDebugRequest
1401 // will never throw an exception (see debug.js).
kasper.lund212ac232008-07-16 07:07:30 +00001402 bool caught_exception;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403 const int argc = 3;
1404 Object** argv[argc] = { exec_state.location(),
1405 request.location(),
1406 stopped ? Factory::true_value().location() :
1407 Factory::false_value().location()};
kasper.lund212ac232008-07-16 07:07:30 +00001408 Handle<Object> result = Execution::TryCall(process_denbug_request,
1409 Factory::undefined_value(),
1410 argc, argv,
1411 &caught_exception);
1412 if (caught_exception) {
1413 return Factory::empty_symbol();
1414 }
1415
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001416 return Handle<String>::cast(result);
1417}
1418
1419
1420bool Debugger::IsPlainBreakRequest(Handle<Object> request) {
1421 // Get the function IsPlainBreakRequest (defined in debug.js).
kasper.lund44510672008-07-25 07:37:58 +00001422 Handle<JSFunction> process_debug_request =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001423 Handle<JSFunction>(JSFunction::cast(
1424 Debug::debug_context()->global()->GetProperty(
1425 *Factory::LookupAsciiSymbol("IsPlainBreakRequest"))));
1426
1427 // Call ProcessDebugRequest expect String result.
kasper.lund212ac232008-07-16 07:07:30 +00001428 bool caught_exception;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001429 const int argc = 1;
1430 Object** argv[argc] = { request.location() };
kasper.lund44510672008-07-25 07:37:58 +00001431 Handle<Object> result = Execution::TryCall(process_debug_request,
kasper.lund212ac232008-07-16 07:07:30 +00001432 Factory::undefined_value(),
1433 argc, argv,
1434 &caught_exception);
1435 if (caught_exception) {
1436 return false;
1437 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001438 return *result == Heap::true_value();
1439}
1440
1441
1442void Debugger::OnException(Handle<Object> exception, bool uncaught) {
1443 HandleScope scope;
1444
1445 // Bail out based on state or if there is no listener for this event
1446 if (Debug::InDebugger()) return;
1447 if (!Debugger::EventActive(v8::Exception)) return;
1448
1449 // Bail out if exception breaks are not active
1450 if (uncaught) {
1451 // Uncaught exceptions are reported by either flags.
1452 if (!(Debug::break_on_uncaught_exception() ||
1453 Debug::break_on_exception())) return;
1454 } else {
1455 // Caught exceptions are reported is activated.
1456 if (!Debug::break_on_exception()) return;
1457 }
1458
kasper.lund212ac232008-07-16 07:07:30 +00001459 // Enter the debugger. Bail out if the debugger cannot be loaded.
1460 if (!Debug::Load()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001461 SaveBreakFrame save;
1462 EnterDebuggerContext enter;
1463
1464 // Clear all current stepping setup.
1465 Debug::ClearStepping();
1466 // Create the event data object.
1467 bool caught_exception = false;
1468 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1469 Handle<Object> event_data;
1470 if (!caught_exception) {
1471 event_data = MakeExceptionEvent(exec_state, exception, uncaught,
1472 &caught_exception);
1473 }
1474 // Bail out and don't call debugger if exception.
1475 if (caught_exception) {
1476 return;
1477 }
1478
1479 // Process debug event
1480 ProcessDebugEvent(v8::Exception, event_data);
1481 // Return to continue execution from where the exception was thrown.
1482}
1483
1484
1485void Debugger::OnDebugBreak(Handle<Object> break_points_hit) {
1486 HandleScope scope;
1487
kasper.lund212ac232008-07-16 07:07:30 +00001488 // Debugger has already been entered by caller.
1489 ASSERT(Top::context() == *Debug::debug_context());
1490
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001491 // Bail out if there is no listener for this event
1492 if (!Debugger::EventActive(v8::Break)) return;
1493
1494 // Debugger must be entered in advance.
1495 ASSERT(Top::context() == *Debug::debug_context());
1496
1497 // Create the event data object.
1498 bool caught_exception = false;
1499 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1500 Handle<Object> event_data;
1501 if (!caught_exception) {
1502 event_data = MakeBreakEvent(exec_state, break_points_hit,
1503 &caught_exception);
1504 }
1505 // Bail out and don't call debugger if exception.
1506 if (caught_exception) {
1507 return;
1508 }
1509
1510 // Process debug event
1511 ProcessDebugEvent(v8::Break, event_data);
1512}
1513
1514
1515void Debugger::OnBeforeCompile(Handle<Script> script) {
1516 HandleScope scope;
1517
1518 // Bail out based on state or if there is no listener for this event
1519 if (Debug::InDebugger()) return;
1520 if (compiling_natives()) return;
1521 if (!EventActive(v8::BeforeCompile)) return;
1522
kasper.lund212ac232008-07-16 07:07:30 +00001523 // Enter the debugger. Bail out if the debugger cannot be loaded.
1524 if (!Debug::Load()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001525 SaveBreakFrame save;
1526 EnterDebuggerContext enter;
1527
1528 // Create the event data object.
1529 bool caught_exception = false;
1530 Handle<Object> event_data = MakeCompileEvent(script,
1531 Factory::undefined_value(),
1532 &caught_exception);
1533 // Bail out and don't call debugger if exception.
1534 if (caught_exception) {
1535 return;
1536 }
1537
1538 // Process debug event
1539 ProcessDebugEvent(v8::BeforeCompile, event_data);
1540}
1541
1542
1543// Handle debugger actions when a new script is compiled.
1544void Debugger::OnAfterCompile(Handle<Script> script, Handle<JSFunction> fun) {
kasper.lund212ac232008-07-16 07:07:30 +00001545 HandleScope scope;
1546
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547 // No compile events while compiling natives.
1548 if (compiling_natives()) return;
1549
1550 // No more to do if not debugging.
1551 if (!debugger_active()) return;
1552
kasper.lund212ac232008-07-16 07:07:30 +00001553 // Enter the debugger. Bail out if the debugger cannot be loaded.
1554 if (!Debug::Load()) return;
1555 SaveBreakFrame save;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 EnterDebuggerContext enter;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001557
1558 // If debugging there might be script break points registered for this
1559 // script. Make sure that these break points are set.
1560
1561 // Get the function UpdateScriptBreakPoints (defined in debug-delay.js).
1562 Handle<Object> update_script_break_points =
1563 Handle<Object>(Debug::debug_context()->global()->GetProperty(
1564 *Factory::LookupAsciiSymbol("UpdateScriptBreakPoints")));
1565 if (!update_script_break_points->IsJSFunction()) {
1566 return;
1567 }
1568 ASSERT(update_script_break_points->IsJSFunction());
1569
1570 // Wrap the script object in a proper JS object before passing it
1571 // to JavaScript.
1572 Handle<JSValue> wrapper = GetScriptWrapper(script);
1573
1574 // Call UpdateScriptBreakPoints expect no exceptions.
kasper.lund212ac232008-07-16 07:07:30 +00001575 bool caught_exception = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576 const int argc = 1;
1577 Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) };
1578 Handle<Object> result = Execution::TryCall(
1579 Handle<JSFunction>::cast(update_script_break_points),
1580 Top::builtins(), argc, argv,
1581 &caught_exception);
1582 if (caught_exception) {
1583 return;
1584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585 // Bail out based on state or if there is no listener for this event
1586 if (Debug::InDebugger()) return;
1587 if (!Debugger::EventActive(v8::AfterCompile)) return;
1588
1589 // Create the compile state object.
1590 Handle<Object> event_data = MakeCompileEvent(script,
1591 Factory::undefined_value(),
1592 &caught_exception);
1593 // Bail out and don't call debugger if exception.
1594 if (caught_exception) {
1595 return;
1596 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597 // Process debug event
1598 ProcessDebugEvent(v8::AfterCompile, event_data);
1599}
1600
1601
1602void Debugger::OnNewFunction(Handle<JSFunction> function) {
1603 return;
1604 HandleScope scope;
1605
1606 // Bail out based on state or if there is no listener for this event
1607 if (Debug::InDebugger()) return;
1608 if (compiling_natives()) return;
1609 if (!Debugger::EventActive(v8::NewFunction)) return;
1610
kasper.lund212ac232008-07-16 07:07:30 +00001611 // Enter the debugger. Bail out if the debugger cannot be loaded.
1612 if (!Debug::Load()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613 SaveBreakFrame save;
1614 EnterDebuggerContext enter;
1615
1616 // Create the event object.
1617 bool caught_exception = false;
1618 Handle<Object> event_data = MakeNewFunctionEvent(function, &caught_exception);
1619 // Bail out and don't call debugger if exception.
1620 if (caught_exception) {
1621 return;
1622 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001623 // Process debug event.
1624 ProcessDebugEvent(v8::NewFunction, event_data);
1625}
1626
1627
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628void Debugger::ProcessDebugEvent(v8::DebugEvent event,
1629 Handle<Object> event_data) {
1630 // Create the execution state.
1631 bool caught_exception = false;
1632 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1633 if (caught_exception) {
1634 return;
1635 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001636 // First notify the builtin debugger.
1637 if (message_thread_ != NULL) {
1638 message_thread_->DebugEvent(event, exec_state, event_data);
1639 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001640 // Notify registered debug event listeners. The list can contain both C and
1641 // JavaScript functions.
1642 v8::NeanderArray listeners(Factory::debug_event_listeners());
1643 int length = listeners.length();
1644 for (int i = 0; i < length; i++) {
1645 if (listeners.get(i)->IsUndefined()) continue; // Skip deleted ones.
1646 v8::NeanderObject listener(JSObject::cast(listeners.get(i)));
1647 Handle<Object> callback_data(listener.get(1));
1648 if (listener.get(0)->IsProxy()) {
1649 // C debug event listener.
1650 Handle<Proxy> callback_obj(Proxy::cast(listener.get(0)));
1651 v8::DebugEventCallback callback =
1652 FUNCTION_CAST<v8::DebugEventCallback>(callback_obj->proxy());
1653 callback(event,
1654 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
1655 v8::Utils::ToLocal(Handle<JSObject>::cast(event_data)),
1656 v8::Utils::ToLocal(callback_data));
1657 } else {
1658 // JavaScript debug event listener.
1659 ASSERT(listener.get(0)->IsJSFunction());
1660 Handle<JSFunction> fun(JSFunction::cast(listener.get(0)));
1661
1662 // Invoke the JavaScript debug event listener.
1663 const int argc = 4;
1664 Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(),
1665 exec_state.location(),
1666 event_data.location(),
1667 callback_data.location() };
1668 Handle<Object> result = Execution::TryCall(fun, Top::global(),
1669 argc, argv, &caught_exception);
1670 if (caught_exception) {
1671 // Silently ignore exceptions from debug event listeners.
1672 }
1673 }
1674 }
1675}
1676
1677
1678void Debugger::SetMessageHandler(v8::DebugMessageHandler handler, void* data) {
1679 debug_message_handler_ = handler;
1680 debug_message_handler_data_ = data;
1681 if (!message_thread_) {
1682 message_thread_ = new DebugMessageThread();
1683 message_thread_->Start();
1684 }
1685 UpdateActiveDebugger();
1686}
1687
1688
kasper.lund7276f142008-07-30 08:49:36 +00001689// Posts an output message from the debugger to the debug_message_handler
1690// callback. This callback is part of the public API. Messages are
1691// kept internally as Vector<uint16_t> strings, which are allocated in various
1692// places and deallocated by the calling function sometime after this call.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001693void Debugger::SendMessage(Vector< uint16_t> message) {
1694 if (debug_message_handler_ != NULL) {
1695 debug_message_handler_(message.start(), message.length(),
1696 debug_message_handler_data_);
1697 }
1698}
1699
1700
1701void Debugger::ProcessCommand(Vector<const uint16_t> command) {
1702 if (message_thread_ != NULL) {
1703 message_thread_->ProcessCommand(
1704 Vector<uint16_t>(const_cast<uint16_t *>(command.start()),
1705 command.length()));
1706 }
1707}
1708
1709
1710void Debugger::UpdateActiveDebugger() {
1711 v8::NeanderArray listeners(Factory::debug_event_listeners());
1712 int length = listeners.length();
1713 bool active_listener = false;
1714 for (int i = 0; i < length && !active_listener; i++) {
1715 active_listener = !listeners.get(i)->IsUndefined();
1716 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001717 set_debugger_active((Debugger::message_thread_ != NULL &&
1718 Debugger::debug_message_handler_ != NULL) ||
1719 active_listener);
1720 if (!debugger_active() && message_thread_)
1721 message_thread_->OnDebuggerInactive();
1722}
1723
1724
1725DebugMessageThread::DebugMessageThread()
1726 : host_running_(true),
kasper.lund7276f142008-07-30 08:49:36 +00001727 command_queue_(kQueueInitialSize),
1728 message_queue_(kQueueInitialSize) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001729 command_received_ = OS::CreateSemaphore(0);
kasper.lund7276f142008-07-30 08:49:36 +00001730 message_received_ = OS::CreateSemaphore(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001731}
1732
kasper.lund7276f142008-07-30 08:49:36 +00001733// Does not free resources held by DebugMessageThread
1734// because this cannot be done thread-safely.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001735DebugMessageThread::~DebugMessageThread() {
1736}
1737
1738
kasper.lund7276f142008-07-30 08:49:36 +00001739// Puts an event coming from V8 on the queue. Creates
1740// a copy of the JSON formatted event string managed by the V8.
1741// Called by the V8 thread.
1742// The new copy of the event string is destroyed in Run().
1743void DebugMessageThread::SendMessage(Vector<uint16_t> message) {
1744 Vector<uint16_t> message_copy = message.Clone();
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001745 Logger::DebugTag("Put message on event message_queue.");
kasper.lund7276f142008-07-30 08:49:36 +00001746 message_queue_.Put(message_copy);
1747 message_received_->Signal();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001748}
1749
1750
1751void DebugMessageThread::SetEventJSONFromEvent(Handle<Object> event_data) {
1752 v8::HandleScope scope;
1753 // Call toJSONProtocol on the debug event object.
1754 v8::Local<v8::Object> api_event_data =
1755 v8::Utils::ToLocal(Handle<JSObject>::cast(event_data));
1756 v8::Local<v8::String> fun_name = v8::String::New("toJSONProtocol");
1757 v8::Local<v8::Function> fun =
1758 v8::Function::Cast(*api_event_data->Get(fun_name));
1759 v8::TryCatch try_catch;
kasper.lund7276f142008-07-30 08:49:36 +00001760 v8::Local<v8::Value> json_event = *fun->Call(api_event_data, 0, NULL);
1761 v8::Local<v8::String> json_event_string;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001762 if (!try_catch.HasCaught()) {
kasper.lund7276f142008-07-30 08:49:36 +00001763 if (!json_event->IsUndefined()) {
1764 json_event_string = json_event->ToString();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001765 if (FLAG_trace_debug_json) {
kasper.lund7276f142008-07-30 08:49:36 +00001766 PrintLn(json_event_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001767 }
kasper.lund7276f142008-07-30 08:49:36 +00001768 v8::String::Value val(json_event_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001769 Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val),
kasper.lund7276f142008-07-30 08:49:36 +00001770 json_event_string->Length());
1771 SendMessage(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001772 } else {
kasper.lund7276f142008-07-30 08:49:36 +00001773 SendMessage(Vector<uint16_t>::empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001774 }
1775 } else {
1776 PrintLn(try_catch.Exception());
kasper.lund7276f142008-07-30 08:49:36 +00001777 SendMessage(Vector<uint16_t>::empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001778 }
1779}
1780
1781
1782// Compare a two byte string to an null terminated ASCII string.
1783bool DebugMessageThread::TwoByteEqualsAscii(Vector<uint16_t> two_byte,
1784 const char* ascii) {
1785 for (int i = 0; i < two_byte.length(); i++) {
1786 if (ascii[i] == '\0') {
1787 return false;
1788 }
1789 if (two_byte[i] != static_cast<uint16_t>(ascii[i])) {
1790 return false;
1791 }
1792 }
1793 return ascii[two_byte.length()] == '\0';
1794}
1795
1796
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001797void DebugMessageThread::Run() {
kasper.lund7276f142008-07-30 08:49:36 +00001798 // Sends debug events to an installed debugger message callback.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001799 while (true) {
kasper.lund7276f142008-07-30 08:49:36 +00001800 // Wait and Get are paired so that semaphore count equals queue length.
1801 message_received_->Wait();
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001802 Logger::DebugTag("Get message from event message_queue.");
kasper.lund7276f142008-07-30 08:49:36 +00001803 Vector<uint16_t> message = message_queue_.Get();
1804 if (message.length() > 0) {
1805 Debugger::SendMessage(message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001806 }
1807 }
1808}
1809
1810
kasper.lund44510672008-07-25 07:37:58 +00001811// This method is called by the V8 thread whenever a debug event occurs in
1812// the VM.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001813void DebugMessageThread::DebugEvent(v8::DebugEvent event,
1814 Handle<Object> exec_state,
1815 Handle<Object> event_data) {
kasper.lund212ac232008-07-16 07:07:30 +00001816 if (!Debug::Load()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817
1818 // Process the individual events.
1819 bool interactive = false;
1820 switch (event) {
1821 case v8::Break:
1822 interactive = true; // Break event is always interavtive
1823 break;
1824 case v8::Exception:
1825 interactive = true; // Exception event is always interavtive
1826 break;
1827 case v8::BeforeCompile:
1828 break;
1829 case v8::AfterCompile:
1830 break;
1831 case v8::NewFunction:
1832 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001833 default:
1834 UNREACHABLE();
1835 }
1836
1837 // Done if not interactive.
1838 if (!interactive) return;
1839
1840 // Get the DebugCommandProcessor.
1841 v8::Local<v8::Object> api_exec_state =
1842 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state));
1843 v8::Local<v8::String> fun_name =
1844 v8::String::New("debugCommandProcessor");
1845 v8::Local<v8::Function> fun =
1846 v8::Function::Cast(*api_exec_state->Get(fun_name));
1847 v8::TryCatch try_catch;
1848 v8::Local<v8::Object> cmd_processor =
1849 v8::Object::Cast(*fun->Call(api_exec_state, 0, NULL));
1850 if (try_catch.HasCaught()) {
1851 PrintLn(try_catch.Exception());
1852 return;
1853 }
1854
kasper.lund7276f142008-07-30 08:49:36 +00001855 // First process all pending commands in the queue. During this processing
1856 // each message is checked to see if it is a plain break command. If there is
1857 // a plain break request in the queue or if the queue is empty a break event
1858 // is sent to the debugger.
1859 bool plain_break = false;
1860 if (command_queue_.IsEmpty()) {
1861 plain_break = true;
1862 } else {
1863 // Drain queue.
1864 while (!command_queue_.IsEmpty()) {
1865 command_received_->Wait();
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001866 Logger::DebugTag("Get command from command_queue, in drain queue loop.");
kasper.lund7276f142008-07-30 08:49:36 +00001867 Vector<uint16_t> command = command_queue_.Get();
1868 // Support for sending a break command as just "break" instead of an
1869 // actual JSON break command.
1870 // If break is made into a separate API call, function
1871 // TwoByteEqualsASCII can be removed.
1872 if (TwoByteEqualsAscii(command, "break")) {
1873 plain_break = true;
1874 continue;
1875 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001876
kasper.lund7276f142008-07-30 08:49:36 +00001877 // Get the command as a string object.
1878 Handle<String> command_string;
1879 if (!command.is_empty()) {
1880 command_string = Factory::NewStringFromTwoByte(
1881 Vector<const uint16_t>(
1882 reinterpret_cast<const uint16_t*>(
1883 command.start()),
1884 command.length()));
1885 } else {
1886 command_string = Handle<String>();
1887 }
1888
1889 // Process the request.
1890 Handle<String> message_string = Debugger::ProcessRequest(exec_state,
1891 command_string,
1892 false);
1893 // Convert text result to UTF-16 string and send it.
1894 v8::String::Value val(Utils::ToLocal(message_string));
1895 Vector<uint16_t> message(reinterpret_cast<uint16_t*>(*val),
1896 message_string->length());
1897 SendMessage(message);
1898
1899 // Check whether one of the commands is a plain break request.
1900 if (!plain_break) {
1901 plain_break = Debugger::IsPlainBreakRequest(message_string);
1902 }
1903 }
1904 }
1905
1906 // If this break event is not to go to the debugger just return.
1907 if (!plain_break) return;
1908
1909 // Notify the debugger that a debug event has occoured.
1910 host_running_ = false;
1911 SetEventJSONFromEvent(event_data);
1912
1913 // Wait for commands from the debugger.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001914 while (true) {
kasper.lund7276f142008-07-30 08:49:36 +00001915 command_received_->Wait();
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001916 Logger::DebugTag("Get command from command queue, in interactive loop.");
kasper.lund7276f142008-07-30 08:49:36 +00001917 Vector<uint16_t> command = command_queue_.Get();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918 ASSERT(!host_running_);
1919 if (!Debugger::debugger_active()) {
1920 host_running_ = true;
1921 return;
1922 }
1923
1924 // Invoke the JavaScript to convert the debug command line to a JSON
kasper.lund7276f142008-07-30 08:49:36 +00001925 // request, invoke the JSON request and convert the JSON response to a text
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 // representation.
1927 v8::Local<v8::String> fun_name;
1928 v8::Local<v8::Function> fun;
1929 v8::Local<v8::Value> args[1];
1930 v8::TryCatch try_catch;
1931 fun_name = v8::String::New("processDebugCommand");
1932 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
kasper.lund7276f142008-07-30 08:49:36 +00001933 args[0] = v8::String::New(reinterpret_cast<uint16_t*>(command.start()),
1934 command.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001935 v8::Local<v8::Value> result_val = fun->Call(cmd_processor, 1, args);
1936
1937 // Get the result of the command.
1938 v8::Local<v8::String> result_string;
1939 bool running = false;
1940 if (!try_catch.HasCaught()) {
1941 // Get the result as an object.
1942 v8::Local<v8::Object> result = v8::Object::Cast(*result_val);
1943
1944 // Log the JSON request/response.
1945 if (FLAG_trace_debug_json) {
1946 PrintLn(result->Get(v8::String::New("request")));
1947 PrintLn(result->Get(v8::String::New("response")));
1948 }
1949
1950 // Get the running state.
1951 running = result->Get(v8::String::New("running"))->ToBoolean()->Value();
1952
1953 // Get result text.
1954 v8::Local<v8::Value> text_result =
1955 result->Get(v8::String::New("response"));
1956 if (!text_result->IsUndefined()) {
1957 result_string = text_result->ToString();
1958 } else {
1959 result_string = v8::String::New("");
1960 }
1961 } else {
1962 // In case of failure the result text is the exception text.
1963 result_string = try_catch.Exception()->ToString();
1964 }
1965
1966 // Convert text result to C string.
1967 v8::String::Value val(result_string);
1968 Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val),
1969 result_string->Length());
1970
kasper.lund7276f142008-07-30 08:49:36 +00001971 // Set host_running_ correctly for nested debugger evaluations.
1972 host_running_ = running;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001973
1974 // Return the result.
kasper.lund7276f142008-07-30 08:49:36 +00001975 SendMessage(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001976
1977 // Return from debug event processing is VM should be running.
1978 if (running) {
1979 return;
1980 }
1981 }
1982}
1983
1984
kasper.lund7276f142008-07-30 08:49:36 +00001985// Puts a command coming from the public API on the queue. Creates
1986// a copy of the command string managed by the debugger. Up to this
1987// point, the command data was managed by the API client. Called
1988// by the API client thread. This is where the API client hands off
1989// processing of the command to the DebugMessageThread thread.
1990// The new copy of the command is destroyed in HandleCommand().
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991void DebugMessageThread::ProcessCommand(Vector<uint16_t> command) {
kasper.lund7276f142008-07-30 08:49:36 +00001992 Vector<uint16_t> command_copy = command.Clone();
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001993 Logger::DebugTag("Put command on command_queue.");
kasper.lund7276f142008-07-30 08:49:36 +00001994 command_queue_.Put(command_copy);
1995 // If not in a break schedule a break and send the "request queued" response.
1996 if (host_running_) {
1997 v8::Debug::DebugBreak();
1998 uint16_t buffer[14] = {'r', 'e', 'q', 'u', 'e', 's', 't', ' ',
1999 'q', 'u', 'e', 'u', 'e', 'd'};
2000 SendMessage(Vector<uint16_t>(buffer, 14));
2001 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002002 command_received_->Signal();
2003}
2004
2005
2006void DebugMessageThread::OnDebuggerInactive() {
kasper.lund7276f142008-07-30 08:49:36 +00002007 // Send an empty command to the debugger if in a break to make JavaScript run
2008 // again if the debugger is closed.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002009 if (!host_running_) {
kasper.lund7276f142008-07-30 08:49:36 +00002010 ProcessCommand(Vector<uint16_t>::empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002011 }
2012}
2013
kasper.lund7276f142008-07-30 08:49:36 +00002014
2015MessageQueue::MessageQueue(int size) : start_(0), end_(0), size_(size) {
2016 messages_ = NewArray<Vector<uint16_t> >(size);
2017}
2018
2019
2020MessageQueue::~MessageQueue() {
2021 DeleteArray(messages_);
2022}
2023
2024
2025Vector<uint16_t> MessageQueue::Get() {
2026 ASSERT(!IsEmpty());
2027 int result = start_;
2028 start_ = (start_ + 1) % size_;
2029 return messages_[result];
2030}
2031
2032
2033void MessageQueue::Put(const Vector<uint16_t>& message) {
2034 if ((end_ + 1) % size_ == start_) {
2035 Expand();
2036 }
2037 messages_[end_] = message;
2038 end_ = (end_ + 1) % size_;
2039}
2040
2041
2042void MessageQueue::Expand() {
2043 MessageQueue new_queue(size_ * 2);
2044 while (!IsEmpty()) {
2045 new_queue.Put(Get());
2046 }
2047 Vector<uint16_t>* array_to_free = messages_;
2048 *this = new_queue;
2049 new_queue.messages_ = array_to_free;
2050 // Automatic destructor called on new_queue, freeing array_to_free.
2051}
2052
2053
2054LockingMessageQueue::LockingMessageQueue(int size) : queue_(size) {
2055 lock_ = OS::CreateMutex();
2056}
2057
2058
2059LockingMessageQueue::~LockingMessageQueue() {
2060 delete lock_;
2061}
2062
2063
2064bool LockingMessageQueue::IsEmpty() const {
2065 ScopedLock sl(lock_);
2066 return queue_.IsEmpty();
2067}
2068
2069
2070Vector<uint16_t> LockingMessageQueue::Get() {
2071 ScopedLock sl(lock_);
2072 Vector<uint16_t> result = queue_.Get();
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002073 Logger::DebugEvent("Get", result);
kasper.lund7276f142008-07-30 08:49:36 +00002074 return result;
2075}
2076
2077
2078void LockingMessageQueue::Put(const Vector<uint16_t>& message) {
2079 ScopedLock sl(lock_);
2080 queue_.Put(message);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00002081 Logger::DebugEvent("Put", message);
kasper.lund7276f142008-07-30 08:49:36 +00002082}
2083
2084
2085void LockingMessageQueue::Clear() {
2086 ScopedLock sl(lock_);
2087 queue_.Clear();
2088}
2089
2090
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002091} } // namespace v8::internal