📄 debug.cc.svn-base
字号:
// Copyright 2006-2008 the V8 project authors. All rights reserved.// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met://// * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following// disclaimer in the documentation and/or other materials provided// with the distribution.// * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived// from this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.#include "v8.h"#include "api.h"#include "arguments.h"#include "bootstrapper.h"#include "code-stubs.h"#include "compiler.h"#include "debug.h"#include "execution.h"#include "global-handles.h"#include "natives.h"#include "stub-cache.h"#include "log.h"namespace v8 { namespace internal {static void PrintLn(v8::Local<v8::Value> value) { v8::Local<v8::String> s = value->ToString(); char* data = NewArray<char>(s->Length() + 1); if (data == NULL) { V8::FatalProcessOutOfMemory("PrintLn"); return; } s->WriteAscii(data); PrintF("%s\n", data); DeleteArray(data);}static Handle<Code> ComputeCallDebugBreak(int argc) { CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugBreak(argc), Code);}static Handle<Code> ComputeCallDebugPrepareStepIn(int argc) { CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugPrepareStepIn(argc), Code);}BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info, BreakLocatorType type) { debug_info_ = debug_info; type_ = type; reloc_iterator_ = NULL; reloc_iterator_original_ = NULL; Reset(); // Initialize the rest of the member variables.}BreakLocationIterator::~BreakLocationIterator() { ASSERT(reloc_iterator_ != NULL); ASSERT(reloc_iterator_original_ != NULL); delete reloc_iterator_; delete reloc_iterator_original_;}void BreakLocationIterator::Next() { AssertNoAllocation nogc; ASSERT(!RinfoDone()); // Iterate through reloc info for code and original code stopping at each // breakable code target. bool first = break_point_ == -1; while (!RinfoDone()) { if (!first) RinfoNext(); first = false; if (RinfoDone()) return; // Whenever a statement position or (plain) position is passed update the // current value of these. if (RelocInfo::IsPosition(rmode())) { if (RelocInfo::IsStatementPosition(rmode())) { statement_position_ = rinfo()->data() - debug_info_->shared()->start_position(); } // Always update the position as we don't want that to be before the // statement position. position_ = rinfo()->data() - debug_info_->shared()->start_position(); ASSERT(position_ >= 0); ASSERT(statement_position_ >= 0); } // Check for breakable code target. Look in the original code as setting // break points can cause the code targets in the running (debugged) code to // be of a different kind than in the original code. if (RelocInfo::IsCodeTarget(rmode())) { Address target = original_rinfo()->target_address(); Code* code = Debug::GetCodeTarget(target); if (code->is_inline_cache_stub() || RelocInfo::IsConstructCall(rmode())) { break_point_++; return; } if (code->kind() == Code::STUB) { if (type_ == ALL_BREAK_LOCATIONS) { if (Debug::IsBreakStub(code)) { break_point_++; return; } } else { ASSERT(type_ == SOURCE_BREAK_LOCATIONS); if (Debug::IsSourceBreakStub(code)) { break_point_++; return; } } } } // Check for break at return. if (RelocInfo::IsJSReturn(rmode())) { // Set the positions to the end of the function. if (debug_info_->shared()->HasSourceCode()) { position_ = debug_info_->shared()->end_position() - debug_info_->shared()->start_position(); } else { position_ = 0; } statement_position_ = position_; break_point_++; return; } }}void BreakLocationIterator::Next(int count) { while (count > 0) { Next(); count--; }}// Find the break point closest to the supplied address.void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) { // Run through all break points to locate the one closest to the address. int closest_break_point = 0; int distance = kMaxInt; while (!Done()) { // Check if this break point is closer that what was previously found. if (this->pc() < pc && pc - this->pc() < distance) { closest_break_point = break_point(); distance = pc - this->pc(); // Check whether we can't get any closer. if (distance == 0) break; } Next(); } // Move to the break point found. Reset(); Next(closest_break_point);}// Find the break point closest to the supplied source position.void BreakLocationIterator::FindBreakLocationFromPosition(int position) { // Run through all break points to locate the one closest to the source // position. int closest_break_point = 0; int distance = kMaxInt; while (!Done()) { // Check if this break point is closer that what was previously found. if (position <= statement_position() && statement_position() - position < distance) { closest_break_point = break_point(); distance = statement_position() - position; // Check whether we can't get any closer. if (distance == 0) break; } Next(); } // Move to the break point found. Reset(); Next(closest_break_point);}void BreakLocationIterator::Reset() { // Create relocation iterators for the two code objects. if (reloc_iterator_ != NULL) delete reloc_iterator_; if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_; reloc_iterator_ = new RelocIterator(debug_info_->code()); reloc_iterator_original_ = new RelocIterator(debug_info_->original_code()); // Position at the first break point. break_point_ = -1; position_ = 1; statement_position_ = 1; Next();}bool BreakLocationIterator::Done() const { return RinfoDone();}void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) { // If there is not already a real break point here patch code with debug // break. if (!HasBreakPoint()) { SetDebugBreak(); } ASSERT(IsDebugBreak()); // Set the break point information. DebugInfo::SetBreakPoint(debug_info_, code_position(), position(), statement_position(), break_point_object);}void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) { // Clear the break point information. DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object); // If there are no more break points here remove the debug break. if (!HasBreakPoint()) { ClearDebugBreak(); ASSERT(!IsDebugBreak()); }}void BreakLocationIterator::SetOneShot() { // If there is a real break point here no more to do. if (HasBreakPoint()) { ASSERT(IsDebugBreak()); return; } // Patch code with debug break. SetDebugBreak();}void BreakLocationIterator::ClearOneShot() { // If there is a real break point here no more to do. if (HasBreakPoint()) { ASSERT(IsDebugBreak()); return; } // Patch code removing debug break. ClearDebugBreak(); ASSERT(!IsDebugBreak());}void BreakLocationIterator::SetDebugBreak() { // If there is already a break point here just return. This might happen if // the same code is flooded with break points twice. Flooding the same // function twice might happen when stepping in a function with an exception // handler as the handler and the function is the same. if (IsDebugBreak()) { return; } if (RelocInfo::IsJSReturn(rmode())) { // This path is currently only used on IA32 as JSExitFrame on ARM uses a // stub. // Patch the JS frame exit code with a debug break call. See // VisitReturnStatement and ExitJSFrame in codegen-ia32.cc for the // precise return instructions sequence. ASSERT(Debug::kIa32JSReturnSequenceLength >= Debug::kIa32CallInstructionLength); rinfo()->patch_code_with_call(Debug::debug_break_return_entry()->entry(), Debug::kIa32JSReturnSequenceLength - Debug::kIa32CallInstructionLength); } else { // Patch the original code with the current address as the current address // might have changed by the inline caching since the code was copied. original_rinfo()->set_target_address(rinfo()->target_address()); // Patch the code to invoke the builtin debug break function matching the // calling convention used by the call site. Handle<Code> dbgbrk_code(Debug::FindDebugBreak(rinfo())); rinfo()->set_target_address(dbgbrk_code->entry()); } ASSERT(IsDebugBreak());}void BreakLocationIterator::ClearDebugBreak() { if (RelocInfo::IsJSReturn(rmode())) { // Restore the JS frame exit code. rinfo()->patch_code(original_rinfo()->pc(), Debug::kIa32JSReturnSequenceLength); } else { // Patch the code to the original invoke. rinfo()->set_target_address(original_rinfo()->target_address()); } ASSERT(!IsDebugBreak());}void BreakLocationIterator::PrepareStepIn() { // Step in can only be prepared if currently positioned on an IC call or // construct call. Address target = rinfo()->target_address(); Code* code = Debug::GetCodeTarget(target); if (code->is_call_stub()) { // Step in through IC call is handled by the runtime system. Therefore make // sure that the any current IC is cleared and the runtime system is // called. If the executing code has a debug break at the location change // the call in the original code as it is the code there that will be // executed in place of the debug break call. Handle<Code> stub = ComputeCallDebugPrepareStepIn(code->arguments_count()); if (IsDebugBreak()) { original_rinfo()->set_target_address(stub->entry()); } else { rinfo()->set_target_address(stub->entry()); } } else { // Step in through constructs call requires no changes to the running code. ASSERT(RelocInfo::IsConstructCall(rmode())); }}// Check whether the break point is at a position which will exit the function.bool BreakLocationIterator::IsExit() const { return (RelocInfo::IsJSReturn(rmode()));}bool BreakLocationIterator::HasBreakPoint() { return debug_info_->HasBreakPoint(code_position());}// Check whether there is a debug break at the current position.bool BreakLocationIterator::IsDebugBreak() { if (RelocInfo::IsJSReturn(rmode())) { // This is IA32 specific but works as long as the ARM version // still uses a stub for JSExitFrame. // // TODO(1240753): Make the test architecture independent or split // parts of the debugger into architecture dependent files. return (*(rinfo()->pc()) == 0xE8); } else { return Debug::IsDebugBreak(rinfo()->target_address()); }}Object* BreakLocationIterator::BreakPointObjects() { return debug_info_->GetBreakPointObjects(code_position());}bool BreakLocationIterator::RinfoDone() const { ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done()); return reloc_iterator_->done();}void BreakLocationIterator::RinfoNext() { reloc_iterator_->next(); reloc_iterator_original_->next();#ifdef DEBUG ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done()); if (!reloc_iterator_->done()) { ASSERT(rmode() == original_rmode());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -