Implement code patcher for x64.
Use the code patcher for the patching of the JS return sequence used by the debugger. Added explicit instruction cache flushing in a code patching section which did not have it for completeness, even though it is not required on Intel processors. Review URL: http://codereview.chromium.org/203016 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2870 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
158dcbc39d
commit
9d2d9c596c
@ -157,6 +157,9 @@ void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
|
||||
for (int i = 0; i < instruction_count; i++) {
|
||||
*(pc_ + i) = *(instructions + i);
|
||||
}
|
||||
|
||||
// Indicate that code has changed.
|
||||
CPU::FlushICache(pc_, instruction_count);
|
||||
}
|
||||
|
||||
|
||||
@ -164,12 +167,24 @@ void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
|
||||
// Additional guard int3 instructions can be added if required.
|
||||
void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
|
||||
// Call instruction takes up 5 bytes and int3 takes up one byte.
|
||||
int code_size = 5 + guard_bytes;
|
||||
static const int kCallCodeSize = 5;
|
||||
int code_size = kCallCodeSize + guard_bytes;
|
||||
|
||||
// Create a code patcher.
|
||||
CodePatcher patcher(pc_, code_size);
|
||||
|
||||
// Add a label for checking the size of the code used for returning.
|
||||
#ifdef DEBUG
|
||||
Label check_codesize;
|
||||
patcher.masm()->bind(&check_codesize);
|
||||
#endif
|
||||
|
||||
// Patch the code.
|
||||
CodePatcher patcher(pc_, code_size);
|
||||
patcher.masm()->call(target, RelocInfo::NONE);
|
||||
|
||||
// Check that the size of the code generated is as expected.
|
||||
ASSERT_EQ(kCallCodeSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
|
||||
|
||||
// Add the requested number of int3 instructions after the call.
|
||||
for (int i = 0; i < guard_bytes; i++) {
|
||||
patcher.masm()->int3();
|
||||
|
@ -173,22 +173,32 @@ void CpuFeatures::Probe() {
|
||||
// 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.
|
||||
static const int kCallInstructionSize = 13;
|
||||
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;
|
||||
// Load register with immediate 64 and call through a register instructions
|
||||
// takes up 13 bytes and int3 takes up one byte.
|
||||
static const int kCallCodeSize = 13;
|
||||
int code_size = kCallCodeSize + guard_bytes;
|
||||
|
||||
// Create a code patcher.
|
||||
CodePatcher patcher(pc_, code_size);
|
||||
|
||||
// Add a label for checking the size of the code used for returning.
|
||||
#ifdef DEBUG
|
||||
Label check_codesize;
|
||||
patcher.masm()->bind(&check_codesize);
|
||||
#endif
|
||||
|
||||
// Patch the code.
|
||||
patcher.masm()->movq(r10, target, RelocInfo::NONE);
|
||||
patcher.masm()->call(r10);
|
||||
|
||||
// Check that the size of the code generated is as expected.
|
||||
ASSERT_EQ(kCallCodeSize,
|
||||
patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
|
||||
|
||||
// Add the requested number of int3 instructions after the call.
|
||||
for (int i = 0; i < guard_bytes; i++) {
|
||||
*(patch_site + kCallInstructionSize + i) = 0xCC; // int3
|
||||
patcher.masm()->int3();
|
||||
}
|
||||
|
||||
// Indicate that code has changed.
|
||||
CPU::FlushICache(patch_site, kCallInstructionSize + guard_bytes);
|
||||
}
|
||||
|
||||
|
||||
@ -197,6 +207,9 @@ void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
|
||||
for (int i = 0; i < instruction_count; i++) {
|
||||
*(pc_ + i) = *(instructions + i);
|
||||
}
|
||||
|
||||
// Indicate that code has changed.
|
||||
CPU::FlushICache(pc_, instruction_count);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -2087,4 +2087,25 @@ void MacroAssembler::UndoAllocationInNewSpace(Register object) {
|
||||
}
|
||||
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
CodePatcher::CodePatcher(byte* address, int size)
|
||||
: address_(address), size_(size), masm_(address, size + Assembler::kGap) {
|
||||
// Create a new macro assembler pointing to the address of the code to patch.
|
||||
// The size is adjusted with kGap on order for the assembler to generate size
|
||||
// bytes of instructions without failing with buffer size constraints.
|
||||
ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
|
||||
}
|
||||
|
||||
|
||||
CodePatcher::~CodePatcher() {
|
||||
// Indicate that code has changed.
|
||||
CPU::FlushICache(address_, size_);
|
||||
|
||||
// Check that the code was patched as expected.
|
||||
ASSERT(masm_.pc_ == address_ + size_);
|
||||
ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
|
||||
}
|
||||
#endif // ENABLE_DEBUGGER_SUPPORT
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -589,6 +589,28 @@ class MacroAssembler: public Assembler {
|
||||
};
|
||||
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
// The code patcher is used to patch (typically) small parts of code e.g. for
|
||||
// debugging and other types of instrumentation. When using the code patcher
|
||||
// the exact number of bytes specified must be emitted. Is not legal to emit
|
||||
// relocation information. If any of these constraints are violated it causes
|
||||
// an assertion.
|
||||
class CodePatcher {
|
||||
public:
|
||||
CodePatcher(byte* address, int size);
|
||||
virtual ~CodePatcher();
|
||||
|
||||
// Macro assembler to emit code.
|
||||
MacroAssembler* masm() { return &masm_; }
|
||||
|
||||
private:
|
||||
byte* address_; // The address of the code being patched.
|
||||
int size_; // Number of bytes of the expected patch size.
|
||||
MacroAssembler masm_; // Macro assembler used to generate the code.
|
||||
};
|
||||
#endif // ENABLE_DEBUGGER_SUPPORT
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Static helper functions.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user