blob: 7683327fc4a4cecdd4a5859203459272d9a8f097 [file] [edit]
#ifndef RR_REMOTE_CODE_PTR_H_
#define RR_REMOTE_CODE_PTR_H_
#include <cstddef>
#include <iostream>
#include "kernel_abi.h"
namespace rr {
/*
* A pointer to code in the tracee address space. Convertible to a
* remote_ptr<void>.
*/
class remote_code_ptr {
public:
remote_code_ptr() : ptr(0) {}
remote_code_ptr(uintptr_t ptr) : ptr(ptr) {}
remote_code_ptr(std::nullptr_t) : ptr(0) {}
bool operator==(const remote_code_ptr& other) const {
return ptr == other.ptr;
}
bool operator!=(const remote_code_ptr& other) const {
return ptr != other.ptr;
}
bool operator<=(const remote_code_ptr& other) const {
return ptr <= other.ptr;
}
bool operator>=(const remote_code_ptr& other) const {
return ptr >= other.ptr;
}
bool operator<(const remote_code_ptr& other) const { return ptr < other.ptr; }
bool operator>(const remote_code_ptr& other) const { return ptr > other.ptr; }
// XXXkhuey this will have to get smarter once we have ARM.
remote_code_ptr operator+(intptr_t delta) const {
return remote_code_ptr(ptr + delta);
}
remote_code_ptr operator-(intptr_t delta) const {
return remote_code_ptr(ptr - delta);
}
intptr_t operator-(remote_code_ptr other) const { return ptr - other.ptr; }
remote_code_ptr decrement_by_syscall_insn_length(SupportedArch arch) const {
return remote_code_ptr(ptr - rr::syscall_instruction_length(arch));
}
remote_code_ptr increment_by_syscall_insn_length(SupportedArch arch) const {
return remote_code_ptr(ptr + rr::syscall_instruction_length(arch));
}
remote_code_ptr undo_executed_bkpt(SupportedArch arch) {
switch (arch) {
case x86:
case x86_64:
return decrement_by_bkpt_insn_length_private(arch);
case aarch64:
// On aarch64 executed breakpoint instructions do not increment the pc
return *this;
default:
DEBUG_ASSERT(0 && "Unknown architecture");
__builtin_unreachable();
}
}
remote_code_ptr advance_past_executed_bkpt(SupportedArch arch) {
switch (arch) {
case x86:
case x86_64:
return *this;
case aarch64:
// On aarch64 executed breakpoint instructions do not increment the pc
return increment_by_bkpt_insn_length(arch);
default:
DEBUG_ASSERT(0 && "Unknown architecture");
__builtin_unreachable();
}
}
remote_code_ptr increment_by_bkpt_insn_length(SupportedArch arch) const {
return remote_code_ptr(ptr + rr::bkpt_instruction_length(arch));
}
remote_code_ptr increment_by_movrm_insn_length(SupportedArch arch) const {
return remote_code_ptr(ptr + rr::movrm_instruction_length(arch));
}
remote_code_ptr decrement_by_vsyscall_entry_length(SupportedArch arch) const {
return remote_code_ptr(ptr - rr::vsyscall_entry_length(arch));
}
template <typename T> remote_ptr<T> to_data_ptr() const {
return remote_ptr<T>(to_data_ptr_value());
}
// Return the pointer in a form suitable for storing in a register. Only
// intended for use by Registers and the operator <<
uintptr_t register_value() const { return ptr; }
bool is_null() const { return !ptr; }
explicit operator bool() const { return ptr != 0; }
private:
// Private to avoid accidentally using this instead of undo_executed_bkpt.
// You probably want that one.
remote_code_ptr decrement_by_bkpt_insn_length_private(SupportedArch arch) const {
return remote_code_ptr(ptr - rr::bkpt_instruction_length(arch));
}
// Return the integer value for this pointer viewed as a data pointer.
// A no-op on Intel architectures, will mask off the thumb bit on ARM.
uintptr_t to_data_ptr_value() const { return ptr; }
uintptr_t ptr;
};
std::ostream& operator<<(std::ostream& stream, remote_code_ptr p);
} // namespace rr
namespace std {
template <> struct hash<rr::remote_code_ptr> {
size_t operator()(const rr::remote_code_ptr& ptr) const {
return hash<uintptr_t>()(ptr.register_value());
}
};
} // namespace std
#endif // RR_REMOTE_CODE_PTR_H_