X64: Let debugger patch JSReturn with a debug break.
Review URL: http://codereview.chromium.org/155286 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2421 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
e0ac466589
commit
b019600dce
@ -363,6 +363,10 @@ class Debug {
|
||||
static const int kIa32CallInstructionLength = 5;
|
||||
static const int kIa32JSReturnSequenceLength = 6;
|
||||
|
||||
// The x64 JS return sequence is padded with int3 to make it large
|
||||
// enough to hold a call instruction when the debugger patches it.
|
||||
static const int kX64JSReturnSequenceLength = 13;
|
||||
|
||||
// Code generator routines.
|
||||
static void GenerateLoadICDebugBreak(MacroAssembler* masm);
|
||||
static void GenerateStoreICDebugBreak(MacroAssembler* masm);
|
||||
|
@ -73,45 +73,8 @@ XMMRegister xmm14 = { 14 };
|
||||
XMMRegister xmm15 = { 15 };
|
||||
|
||||
|
||||
Operand::Operand(Register base, int32_t disp): rex_(0) {
|
||||
len_ = 1;
|
||||
if (base.is(rsp) || base.is(r12)) {
|
||||
// SIB byte is needed to encode (rsp + offset) or (r12 + offset).
|
||||
set_sib(times_1, rsp, base);
|
||||
}
|
||||
|
||||
if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
|
||||
set_modrm(0, base);
|
||||
} else if (is_int8(disp)) {
|
||||
set_modrm(1, base);
|
||||
set_disp8(disp);
|
||||
} else {
|
||||
set_modrm(2, base);
|
||||
set_disp32(disp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Operand::Operand(Register base,
|
||||
Register index,
|
||||
ScaleFactor scale,
|
||||
int32_t disp): rex_(0) {
|
||||
ASSERT(!index.is(rsp));
|
||||
len_ = 1;
|
||||
set_sib(scale, index, base);
|
||||
if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
|
||||
// This call to set_modrm doesn't overwrite the REX.B (or REX.X) bits
|
||||
// possibly set by set_sib.
|
||||
set_modrm(0, rsp);
|
||||
} else if (is_int8(disp)) {
|
||||
set_modrm(1, rsp);
|
||||
set_disp8(disp);
|
||||
} else {
|
||||
set_modrm(2, rsp);
|
||||
set_disp32(disp);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of CpuFeatures
|
||||
|
||||
// The required user mode extensions in X64 are (from AMD64 ABI Table A.1):
|
||||
// fpu, tsc, cx8, cmov, mmx, sse, sse2, fxsr, syscall
|
||||
@ -193,6 +156,71 @@ void CpuFeatures::Probe() {
|
||||
ASSERT(IsSupported(CMOV));
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of RelocInfo
|
||||
|
||||
// Patch the code at the current PC with a call to the target address.
|
||||
// Additional guard int3 instructions can be added if required.
|
||||
void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
|
||||
// Call instruction takes up 13 bytes and int3 takes up one byte.
|
||||
Address patch_site = pc_;
|
||||
Memory::uint16_at(patch_site) = 0xBA49u; // movq r10, imm64
|
||||
// Write "0x00, call r10" starting at last byte of address. We overwrite
|
||||
// the 0x00 later, and this lets us write a uint32.
|
||||
Memory::uint32_at(patch_site + 9) = 0xD2FF4900u; // 0x00, call r10
|
||||
Memory::Address_at(patch_site + 2) = target;
|
||||
|
||||
// Add the requested number of int3 instructions after the call.
|
||||
for (int i = 0; i < guard_bytes; i++) {
|
||||
*(patch_site + 13 + i) = 0xCC; // int3
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of Operand
|
||||
|
||||
Operand::Operand(Register base, int32_t disp): rex_(0) {
|
||||
len_ = 1;
|
||||
if (base.is(rsp) || base.is(r12)) {
|
||||
// SIB byte is needed to encode (rsp + offset) or (r12 + offset).
|
||||
set_sib(times_1, rsp, base);
|
||||
}
|
||||
|
||||
if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
|
||||
set_modrm(0, base);
|
||||
} else if (is_int8(disp)) {
|
||||
set_modrm(1, base);
|
||||
set_disp8(disp);
|
||||
} else {
|
||||
set_modrm(2, base);
|
||||
set_disp32(disp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Operand::Operand(Register base,
|
||||
Register index,
|
||||
ScaleFactor scale,
|
||||
int32_t disp): rex_(0) {
|
||||
ASSERT(!index.is(rsp));
|
||||
len_ = 1;
|
||||
set_sib(scale, index, base);
|
||||
if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
|
||||
// This call to set_modrm doesn't overwrite the REX.B (or REX.X) bits
|
||||
// possibly set by set_sib.
|
||||
set_modrm(0, rsp);
|
||||
} else if (is_int8(disp)) {
|
||||
set_modrm(1, rsp);
|
||||
set_disp8(disp);
|
||||
} else {
|
||||
set_modrm(2, rsp);
|
||||
set_disp32(disp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of Assembler
|
||||
|
||||
|
@ -355,14 +355,19 @@ void CodeGenerator::GenerateReturnSequence(Result* return_value) {
|
||||
// receiver.
|
||||
frame_->Exit();
|
||||
masm_->ret((scope_->num_parameters() + 1) * kPointerSize);
|
||||
// Add padding that will be overwritten by a debugger breakpoint.
|
||||
// frame_->Exit() generates "movq rsp, rbp; pop rbp" length 5.
|
||||
// "ret k" has length 2.
|
||||
const int kPadding = Debug::kX64JSReturnSequenceLength - 5 - 2;
|
||||
for (int i = 0; i < kPadding; ++i) {
|
||||
masm_->int3();
|
||||
}
|
||||
DeleteFrame();
|
||||
|
||||
// TODO(x64): introduce kX64JSReturnSequenceLength and enable assert.
|
||||
|
||||
// Check that the size of the code used for returning matches what is
|
||||
// expected by the debugger.
|
||||
// ASSERT_EQ(Debug::kIa32JSReturnSequenceLength,
|
||||
// masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
|
||||
ASSERT_EQ(Debug::kX64JSReturnSequenceLength,
|
||||
masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,8 +38,10 @@ namespace internal {
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
|
||||
bool Debug::IsDebugBreakAtReturn(v8::internal::RelocInfo* rinfo) {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
|
||||
// 11th byte of patch is 0x49, 11th byte of JS return is 0xCC (int3).
|
||||
ASSERT(*(rinfo->pc() + 10) == 0x49 || *(rinfo->pc() + 10) == 0xCC);
|
||||
return (*(rinfo->pc() + 10) == 0x49);
|
||||
}
|
||||
|
||||
void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
|
||||
|
Loading…
Reference in New Issue
Block a user