/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2015 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include "xenia/cpu/breakpoint.h" #include "xenia/base/string_util.h" #include "xenia/cpu/backend/backend.h" #include "xenia/cpu/backend/code_cache.h" namespace xe { namespace cpu { Breakpoint::Breakpoint(Processor* processor, AddressType address_type, uint64_t address, HitCallback hit_callback) : processor_(processor), address_type_(address_type), address_(address), hit_callback_(hit_callback) {} Breakpoint::~Breakpoint() { assert_false(installed_); } void Breakpoint::Install() { assert_false(installed_); processor_->backend()->InstallBreakpoint(this); installed_ = true; } void Breakpoint::Uninstall() { assert_true(installed_); processor_->backend()->UninstallBreakpoint(this); installed_ = false; } std::string Breakpoint::to_string() const { if (address_type_ == AddressType::kGuest) { auto str = std::string("PPC ") + xe::string_util::to_hex_string(guest_address()); auto functions = processor_->FindFunctionsWithAddress(guest_address()); if (functions.empty()) { return str; } str += " " + functions[0]->name(); return str; } else { return std::string("x64 ") + xe::string_util::to_hex_string(host_address()); } } GuestFunction* Breakpoint::guest_function() const { if (address_type_ == AddressType::kGuest) { auto functions = processor_->FindFunctionsWithAddress(guest_address()); if (functions.empty()) { return nullptr; } else if (functions[0]->is_guest()) { return static_cast(functions[0]); } return nullptr; } else { return processor_->backend()->code_cache()->LookupFunction(host_address()); } } bool Breakpoint::ContainsHostAddress(uintptr_t search_address) const { bool contains = false; ForEachHostAddress([&contains, search_address](uintptr_t host_address) { if (host_address == search_address) { contains = true; } }); return contains; } void Breakpoint::ForEachHostAddress( std::function callback) const { if (address_type_ == AddressType::kGuest) { auto guest_address = this->guest_address(); // Lookup all functions that contain this guest address and patch them. auto functions = processor_->FindFunctionsWithAddress(guest_address); if (functions.empty()) { // If function does not exist demand it, as we need someplace to put our // breakpoint. Note that this follows the same resolution rules as the // JIT, so what's returned is the function the JIT would have jumped to. auto fn = processor_->ResolveFunction(guest_address); if (!fn) { // TODO(benvanik): error out better with 'invalid breakpoint'? assert_not_null(fn); return; } functions.push_back(fn); } assert_false(functions.empty()); for (auto function : functions) { // TODO(benvanik): other function types. assert_true(function->is_guest()); auto guest_function = reinterpret_cast(function); uintptr_t host_address = guest_function->MapGuestAddressToMachineCode(guest_address); assert_not_zero(host_address); callback(host_address); } } else { // Direct host address patching. callback(host_address()); } } } // namespace cpu } // namespace xe