Reconcile debugger and save state stuff into a single implementation.

Fixes #497 and fixes #496.
Still rough edges, but at least less duplication.
This commit is contained in:
Ben Vanik
2016-01-18 11:48:21 -08:00
parent ca135eb0e7
commit 6777ce6668
51 changed files with 1687 additions and 2250 deletions

View File

@@ -17,22 +17,61 @@ namespace cpu {
class Breakpoint {
public:
Breakpoint(Processor* processor,
std::function<void(uint32_t, uint64_t)> hit_callback);
Breakpoint(Processor* processor, uint32_t address,
std::function<void(uint32_t, uint64_t)> hit_callback);
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();
uint32_t address() const { return address_; }
void set_address(uint32_t address) {
assert_false(installed_);
address_ = address;
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_);
}
bool installed() const { return installed_; }
bool Install();
bool Uninstall();
void Hit(uint64_t host_pc) { hit_callback_(address_, host_pc); }
// 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 {
@@ -42,12 +81,50 @@ class Breakpoint {
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;
uint32_t address_ = 0;
std::function<void(uint32_t, uint64_t)> hit_callback_;
// 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_;