📄 debug.cc.svn-base
字号:
return; } Handle<DebugInfo> debug_info = GetDebugInfo(shared); // Source positions starts with zero. ASSERT(source_position >= 0); // Find the break point and change it. BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS); it.FindBreakLocationFromPosition(source_position); it.SetBreakPoint(break_point_object); // At least one active break point now. ASSERT(debug_info->GetBreakPointCount() > 0);}void Debug::ClearBreakPoint(Handle<Object> break_point_object) { DebugInfoListNode* node = debug_info_list_; while (node != NULL) { Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(), break_point_object); if (!result->IsUndefined()) { // Get information in the break point. BreakPointInfo* break_point_info = BreakPointInfo::cast(result); Handle<DebugInfo> debug_info = node->debug_info(); Handle<SharedFunctionInfo> shared(debug_info->shared()); int source_position = break_point_info->statement_position()->value(); // Source positions starts with zero. ASSERT(source_position >= 0); // Find the break point and clear it. BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS); it.FindBreakLocationFromPosition(source_position); it.ClearBreakPoint(break_point_object); // If there are no more break points left remove the debug info for this // function. if (debug_info->GetBreakPointCount() == 0) { RemoveDebugInfo(debug_info); } return; } node = node->next(); }}void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) { // Make sure the function has setup the debug info. if (!EnsureDebugInfo(shared)) { // Return if we failed to retrieve the debug info. return; } // Flood the function with break points. BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS); while (!it.Done()) { it.SetOneShot(); it.Next(); }}void Debug::FloodHandlerWithOneShot() { StackFrame::Id id = Top::break_frame_id(); for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) { JavaScriptFrame* frame = it.frame(); if (frame->HasHandler()) { Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>( JSFunction::cast(frame->function())->shared()); // Flood the function with the catch block with break points FloodWithOneShot(shared); return; } }}void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) { if (type == BreakUncaughtException) { break_on_uncaught_exception_ = enable; } else { break_on_exception_ = enable; }}void Debug::PrepareStep(StepAction step_action, int step_count) { HandleScope scope; ASSERT(Debug::InDebugger()); // Remember this step action and count. thread_local_.last_step_action_ = step_action; thread_local_.step_count_ = step_count; // Get the frame where the execution has stopped and skip the debug frame if // any. The debug frame will only be present if execution was stopped due to // hitting a break point. In other situations (e.g. unhandled exception) the // debug frame is not present. StackFrame::Id id = Top::break_frame_id(); JavaScriptFrameIterator frames_it(id); JavaScriptFrame* frame = frames_it.frame(); // First of all ensure there is one-shot break points in the top handler // if any. FloodHandlerWithOneShot(); // If the function on the top frame is unresolved perform step out. This will // be the case when calling unknown functions and having the debugger stopped // in an unhandled exception. if (!frame->function()->IsJSFunction()) { // Step out: Find the calling JavaScript frame and flood it with // breakpoints. frames_it.Advance(); // Fill the function to return to with one-shot break points. JSFunction* function = JSFunction::cast(frames_it.frame()->function()); FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared())); return; } // Get the debug info (create it if it does not exist). Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared()); if (!EnsureDebugInfo(shared)) { // Return if ensuring debug info failed. return; } Handle<DebugInfo> debug_info = GetDebugInfo(shared); // Find the break location where execution has stopped. BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS); it.FindBreakLocationFromAddress(frame->pc()); // Compute whether or not the target is a call target. bool is_call_target = false; if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) { Address target = it.rinfo()->target_address(); Code* code = Debug::GetCodeTarget(target); if (code->is_call_stub()) is_call_target = true; } // If this is the last break code target step out is the only possibility. if (it.IsExit() || step_action == StepOut) { // Step out: If there is a JavaScript caller frame, we need to // flood it with breakpoints. frames_it.Advance(); if (!frames_it.done()) { // Fill the function to return to with one-shot break points. JSFunction* function = JSFunction::cast(frames_it.frame()->function()); FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared())); } } else if (!(is_call_target || RelocInfo::IsConstructCall(it.rmode())) || step_action == StepNext || step_action == StepMin) { // Step next or step min. // Fill the current function with one-shot break points. FloodWithOneShot(shared); // Remember source position and frame to handle step next. thread_local_.last_statement_position_ = debug_info->code()->SourceStatementPosition(frame->pc()); thread_local_.last_fp_ = frame->fp(); } else { // Fill the current function with one-shot break points even for step in on // a call target as the function called might be a native function for // which step in will not stop. FloodWithOneShot(shared); // Step in or Step in min it.PrepareStepIn(); ActivateStepIn(frame); }}// Check whether the current debug break should be reported to the debugger. It// is used to have step next and step in only report break back to the debugger// if on a different frame or in a different statement. In some situations// there will be several break points in the same statement when the code is// flooded with one-shot break points. This function helps to perform several// steps before reporting break back to the debugger.bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator, JavaScriptFrame* frame) { // If the step last action was step next or step in make sure that a new // statement is hit. if (thread_local_.last_step_action_ == StepNext || thread_local_.last_step_action_ == StepIn) { // Never continue if returning from function. if (break_location_iterator->IsExit()) return false; // Continue if we are still on the same frame and in the same statement. int current_statement_position = break_location_iterator->code()->SourceStatementPosition(frame->pc()); return thread_local_.last_fp_ == frame->fp() && thread_local_.last_statement_position_ == current_statement_position; } // No step next action - don't continue. return false;}// Check whether the code object at the specified address is a debug break code// object.bool Debug::IsDebugBreak(Address addr) { Code* code = GetCodeTarget(addr); return code->ic_state() == DEBUG_BREAK;}// Check whether a code stub with the specified major key is a possible break// point location when looking for source break locations.bool Debug::IsSourceBreakStub(Code* code) { CodeStub::Major major_key = code->major_key(); return major_key == CodeStub::CallFunction;}// Check whether a code stub with the specified major key is a possible break// location.bool Debug::IsBreakStub(Code* code) { CodeStub::Major major_key = code->major_key(); return major_key == CodeStub::CallFunction || major_key == CodeStub::StackCheck;}// Find the builtin to use for invoking the debug breakHandle<Code> Debug::FindDebugBreak(RelocInfo* rinfo) { // Find the builtin debug break function matching the calling convention // used by the call site. RelocInfo::Mode mode = rinfo->rmode(); if (RelocInfo::IsCodeTarget(mode)) { Address target = rinfo->target_address(); Code* code = Debug::GetCodeTarget(target); if (code->is_inline_cache_stub()) { if (code->is_call_stub()) { return ComputeCallDebugBreak(code->arguments_count()); } if (code->is_load_stub()) { return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak)); } if (code->is_store_stub()) { return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak)); } if (code->is_keyed_load_stub()) { Handle<Code> result = Handle<Code>(Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak)); return result; } if (code->is_keyed_store_stub()) { Handle<Code> result = Handle<Code>(Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak)); return result; } } if (RelocInfo::IsConstructCall(mode)) { Handle<Code> result = Handle<Code>(Builtins::builtin(Builtins::ConstructCall_DebugBreak)); return result; } if (code->kind() == Code::STUB) { ASSERT(code->major_key() == CodeStub::CallFunction || code->major_key() == CodeStub::StackCheck); Handle<Code> result = Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak)); return result; } } UNREACHABLE(); return Handle<Code>::null();}// Simple function for returning the source positions for active break points.Handle<Object> Debug::GetSourceBreakLocations( Handle<SharedFunctionInfo> shared) { if (!HasDebugInfo(shared)) return Handle<Object>(Heap::undefined_value()); Handle<DebugInfo> debug_info = GetDebugInfo(shared); if (debug_info->GetBreakPointCount() == 0) { return Handle<Object>(Heap::undefined_value()); } Handle<FixedArray> locations = Factory::NewFixedArray(debug_info->GetBreakPointCount()); int count = 0; for (int i = 0; i < debug_info->break_points()->length(); i++) { if (!debug_info->break_points()->get(i)->IsUndefined()) { BreakPointInfo* break_point_info = BreakPointInfo::cast(debug_info->break_points()->get(i)); if (break_point_info->GetBreakPointCount() > 0) { locations->set(count++, break_point_info->statement_position()); } } } return locations;}void Debug::ClearStepping() { // Clear the various stepping setup. ClearOneShot(); ClearStepIn(); ClearStepNext(); // Clear multiple step counter. thread_local_.step_count_ = 0;}// Clears all the one-shot break points that are currently set. Normally this// function is called each time a break point is hit as one shot break points// are used to support stepping.void Debug::ClearOneShot() { // The current implementation just runs through all the breakpoints. When the // last break point for a function is removed that function is automatically // removed from the list. DebugInfoListNode* node = debug_info_list_; while (node != NULL) { BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS); while (!it.Done()) { it.ClearOneShot(); it.Next(); } node = node->next(); }}void Debug::ActivateStepIn(StackFrame* frame) { thread_local_.step_into_fp_ = frame->fp();}void Debug::ClearStepIn() { thread_local_.step_into_fp_ = 0;}void Debug::ClearStepNext() { thread_local_.last_step_action_ = StepNone; thread_local_.last_statement_position_ = RelocInfo::kNoPosition; thread_local_.last_fp_ = 0;}bool Debug::EnsureCompiled(Handle<SharedFunctionInfo> shared) { if (shared->is_compiled()) return true; return CompileLazyShared(shared, CLEAR_EXCEPTION);}// Ensures the debug information is present for shared.bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) { // Return if we already have the debug info for shared. if (HasDebugInfo(shared)) return true; // Ensure shared in compiled. Return false if this failed. if (!EnsureCompiled(shared)) return false; // Create the debug info object. Handle<DebugInfo> debug_info = Factory::NewDebugInfo(shared); // Add debug info to the list. DebugInfoListNode* node = new DebugInfoListNode(*debug_info); node->set_next(debug_info_list_); debug_info_list_ = node; // Now there is at least one break point. has_break_points_ = true; return true;}void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) { ASSERT(debug_info_list_ != NULL); // Run through the debug info objects to find this one and remove it. DebugInfoListNode* prev = NULL; DebugInfoListNode* current = debug_info_list_; while (current != NULL) { if (*current->debug_info() == *debug_info) { // Unlink from list. If prev is NULL we are looking at the first element. if (prev == NULL) { debug_info_list_ = current->next(); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -