Files
Xenia-Canary/src/xenia/cpu/breakpoint.h
Ben Vanik 6777ce6668 Reconcile debugger and save state stuff into a single implementation.
Fixes #497 and fixes #496.
Still rough edges, but at least less duplication.
2016-01-18 11:48:21 -08:00

136 lines
4.1 KiB
C++

/**
******************************************************************************
* 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. *
******************************************************************************
*/
#ifndef XENIA_CPU_BREAKPOINT_H_
#define XENIA_CPU_BREAKPOINT_H_
#include "xenia/cpu/processor.h"
namespace xe {
namespace cpu {
class Breakpoint {
public:
enum class AddressType {
kGuest,
kHost,
};
typedef std::function<void(Breakpoint*, ThreadDebugInfo*, uint64_t)>
HitCallback;
Breakpoint(Processor* processor, AddressType address_type, uint64_t address,
HitCallback hit_callback);
~Breakpoint();
AddressType address_type() const { return address_type_; }
uint64_t address() const { return address_; }
uint32_t guest_address() const {
assert_true(address_type_ == AddressType::kGuest);
return static_cast<uint32_t>(address_);
}
uintptr_t host_address() const {
assert_true(address_type_ == AddressType::kHost);
return static_cast<uintptr_t>(address_);
}
// Whether the breakpoint has been enabled by the user.
bool is_enabled() const { return enabled_; }
// Toggles the breakpoint state.
// Assumes the caller holds the global lock.
void set_enabled(bool is_enabled) {
enabled_ = is_enabled;
if (!enabled_ && installed_) {
Uninstall();
} else if (enabled_ && !installed_ && !suspend_count_) {
Install();
}
}
// Whether the breakpoint is currently installed and active.
bool is_installed() const { return installed_; }
std::string to_string() const;
// Returns a guest function that contains the guest address, if any.
// If there are multiple functions that contain the address a random one will
// be returned. If this is a host-address code breakpoint this will attempt to
// find a function with that address and otherwise return nullptr.
GuestFunction* guest_function() const;
// Returns true if this breakpoint, when installed, contains the given host
// address.
bool ContainsHostAddress(uintptr_t search_address) const;
// Enumerates all host addresses that correspond to this breakpoint.
// If this is a host type it will return the single host address, if it is a
// guest type it may return multiple host addresses.
void ForEachHostAddress(std::function<void(uintptr_t)> callback) const;
// CPU backend data. Implementation specific - DO NOT TOUCH THIS!
std::vector<std::pair<uint64_t, uint64_t>> backend_data() const {
return backend_data_;
}
std::vector<std::pair<uint64_t, uint64_t>>& backend_data() {
return backend_data_;
}
private:
friend class Processor;
void OnHit(ThreadDebugInfo* thread_info, uint64_t host_pc) {
hit_callback_(this, thread_info, host_pc);
}
// Suspends the breakpoint until it is resumed with Resume.
// This preserves the user enabled state.
// Assumes the caller holds the global lock.
void Suspend() {
++suspend_count_;
if (installed_) {
Uninstall();
}
}
// Resumes a previously-suspended breakpoint, reinstalling it if required.
// Assumes the caller holds the global lock.
void Resume() {
--suspend_count_;
if (!suspend_count_ && enabled_) {
Install();
}
}
private:
Processor* processor_ = nullptr;
void Install();
void Uninstall();
// True if patched into code.
bool installed_ = false;
// True if user enabled.
bool enabled_ = true;
// Depth of suspends (must be 0 to be installed). Defaults to suspended so
// that it's never installed unless the debugger knows about it.
int suspend_count_ = 1;
AddressType address_type_;
uint64_t address_ = 0;
HitCallback hit_callback_;
// Opaque backend data. Don't touch this.
std::vector<std::pair<uint64_t, uint64_t>> backend_data_;
};
} // namespace cpu
} // namespace xe
#endif // XENIA_CPU_BREAKPOINT_H_