Automatically install any CPU breakpoints in any newly-defined functions if necessary.

This commit is contained in:
Dr. Chat 2015-11-27 23:00:38 -06:00 committed by Ben Vanik
parent d09e3b7953
commit 41d5b41523
6 changed files with 51 additions and 3 deletions

View File

@ -17,6 +17,7 @@
namespace xe { namespace xe {
namespace cpu { namespace cpu {
class Breakpoint; class Breakpoint;
class Function;
class GuestFunction; class GuestFunction;
class Module; class Module;
class Processor; class Processor;
@ -53,6 +54,7 @@ class Backend {
Module* module, uint32_t address) = 0; Module* module, uint32_t address) = 0;
virtual bool InstallBreakpoint(Breakpoint* bp) { return false; } virtual bool InstallBreakpoint(Breakpoint* bp) { return false; }
virtual bool InstallBreakpoint(Breakpoint* bp, Function* func) { return false; }
virtual bool UninstallBreakpoint(Breakpoint* bp) { return false; } virtual bool UninstallBreakpoint(Breakpoint* bp) { return false; }
protected: protected:

View File

@ -133,7 +133,11 @@ bool X64Backend::InstallBreakpoint(Breakpoint* bp) {
assert_true(function->is_guest()); assert_true(function->is_guest());
auto guest_function = reinterpret_cast<cpu::GuestFunction*>(function); auto guest_function = reinterpret_cast<cpu::GuestFunction*>(function);
auto code = guest_function->MapGuestAddressToMachineCode(bp->address()); auto code = guest_function->MapGuestAddressToMachineCode(bp->address());
assert_not_zero(code); if (!code) {
// This should not happen.
assert_always();
return false;
}
auto orig_bytes = auto orig_bytes =
xe::load_and_swap<uint16_t>(reinterpret_cast<void*>(code + 0x0)); xe::load_and_swap<uint16_t>(reinterpret_cast<void*>(code + 0x0));
@ -145,6 +149,24 @@ bool X64Backend::InstallBreakpoint(Breakpoint* bp) {
return true; return true;
} }
bool X64Backend::InstallBreakpoint(Breakpoint* bp, Function* func) {
assert_true(func->is_guest());
auto guest_function = reinterpret_cast<cpu::GuestFunction*>(func);
auto code = guest_function->MapGuestAddressToMachineCode(bp->address());
if (!code) {
assert_always();
return false;
}
// Assume we haven't already installed a breakpoint in this spot.
auto orig_bytes =
xe::load_and_swap<uint16_t>(reinterpret_cast<void*>(code + 0x0));
bp->backend_data().push_back({code, orig_bytes});
xe::store_and_swap<uint16_t>(reinterpret_cast<void*>(code + 0x0), 0x0F0C);
return true;
}
bool X64Backend::UninstallBreakpoint(Breakpoint* bp) { bool X64Backend::UninstallBreakpoint(Breakpoint* bp) {
for (auto pair : bp->backend_data()) { for (auto pair : bp->backend_data()) {
xe::store_and_swap<uint16_t>(reinterpret_cast<void*>(pair.first), xe::store_and_swap<uint16_t>(reinterpret_cast<void*>(pair.first),

View File

@ -63,6 +63,7 @@ class X64Backend : public Backend {
uint32_t address) override; uint32_t address) override;
bool InstallBreakpoint(Breakpoint* bp) override; bool InstallBreakpoint(Breakpoint* bp) override;
bool InstallBreakpoint(Breakpoint* bp, Function* func) override;
bool UninstallBreakpoint(Breakpoint* bp) override; bool UninstallBreakpoint(Breakpoint* bp) override;
private: private:

View File

@ -49,6 +49,18 @@ class Function : public Symbol {
void set_behavior(Behavior value) { behavior_ = value; } void set_behavior(Behavior value) { behavior_ = value; }
bool is_guest() const { return behavior_ != Behavior::kBuiltin; } bool is_guest() const { return behavior_ != Behavior::kBuiltin; }
bool ContainsAddress(uint32_t address) const {
if (!address_ || !end_address_) {
return false;
}
if (address >= address_ && address < end_address_) {
return true;
}
return false;
}
virtual bool Call(ThreadState* thread_state, uint32_t return_address) = 0; virtual bool Call(ThreadState* thread_state, uint32_t return_address) = 0;
protected: protected:

View File

@ -274,6 +274,8 @@ bool Processor::DemandFunction(Function* function) {
debugger_->OnFunctionDefined(function); debugger_->OnFunctionDefined(function);
} }
BreakpointFunctionDefined(function);
function->set_status(Symbol::Status::kDefined); function->set_status(Symbol::Status::kDefined);
symbol_status = function->status(); symbol_status = function->status();
} }
@ -402,6 +404,16 @@ void Processor::LowerIrql(Irql old_value) {
reinterpret_cast<volatile uint32_t*>(&irql_)); reinterpret_cast<volatile uint32_t*>(&irql_));
} }
void Processor::BreakpointFunctionDefined(Function* function) {
std::lock_guard<std::recursive_mutex> lock(breakpoint_lock_);
for (auto it = breakpoints_.begin(); it != breakpoints_.end(); it++) {
if (function->ContainsAddress((*it)->address())) {
backend_->InstallBreakpoint(*it, function);
}
}
}
bool Processor::InstallBreakpoint(Breakpoint* bp) { bool Processor::InstallBreakpoint(Breakpoint* bp) {
std::lock_guard<std::recursive_mutex> lock(breakpoint_lock_); std::lock_guard<std::recursive_mutex> lock(breakpoint_lock_);

View File

@ -101,8 +101,7 @@ class Processor {
std::vector<Breakpoint*> breakpoints() const { return breakpoints_; } std::vector<Breakpoint*> breakpoints() const { return breakpoints_; }
private: private:
static bool ExceptionCallbackThunk(Exception* ex, void* data); void BreakpointFunctionDefined(Function* function);
bool ExceptionCallback(Exception* ex);
bool DemandFunction(Function* function); bool DemandFunction(Function* function);