Skip to content

Commit

Permalink
Move extra_regs to ReplayTask, use extra_regs_fallible in more places.
Browse files Browse the repository at this point in the history
Fixes #3725
  • Loading branch information
khuey committed Apr 18, 2024
1 parent b8ed44a commit b9117dd
Show file tree
Hide file tree
Showing 14 changed files with 133 additions and 93 deletions.
4 changes: 2 additions & 2 deletions src/BreakpointCondition.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

namespace rr {

class Task;
class ReplayTask;

class BreakpointCondition {
public:
virtual ~BreakpointCondition() {}
virtual bool evaluate(Task* t) const = 0;
virtual bool evaluate(ReplayTask* t) const = 0;
};

} // namespace rr
Expand Down
2 changes: 1 addition & 1 deletion src/GdbCommand.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ static SimpleGdbCommand elapsed_time(
});

static SimpleGdbCommand when(
"when", "Print the numer of the last completely replayed rr event.",
"when", "Print the number of the last completely replayed rr event.",
[](GdbServer&, Task* t, const vector<string>&) {
if (!t->session().is_replaying()) {
return GdbCommandHandler::cmd_end_diversion();
Expand Down
14 changes: 7 additions & 7 deletions src/GdbServer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ static bool set_reg(Task* target, const GdbRegisterValue& reg) {
return true;
}

ExtraRegisters extra_regs = target->extra_regs();
ExtraRegisters extra_regs = *target->extra_regs_fallible();

This comment has been minimized.

Copy link
@rocallahan

rocallahan Apr 18, 2024

Collaborator

Wouldn't it be better to just call extra_regs() as before and get an ASSERT failure if the task is dead, instead of crashing with a null deref or worse here?

This comment has been minimized.

Copy link
@khuey

khuey Apr 18, 2024

Author Collaborator

That's not possible anymore since I moved extra_regs() to ReplayTask but I added code to do that logic manually.

if (extra_regs.write_register(reg.name, reg.value, reg.size)) {
target->set_extra_regs(extra_regs);
return true;
Expand Down Expand Up @@ -166,10 +166,10 @@ static WatchType watchpoint_type(GdbRequestType req) {
}

static void maybe_singlestep_for_event(Task* t, GdbRequest* req) {
if (!t->session().is_replaying()) {
ReplayTask* rt = ReplayTask::cast_or_null(t);
if (!rt) {
return;
}
auto rt = static_cast<ReplayTask*>(t);
if (trace_instructions_up_to_event(
rt->session().current_trace_frame().time())) {
fputs("Stepping: ", stderr);
Expand Down Expand Up @@ -218,7 +218,7 @@ class GdbBreakpointCondition : public BreakpointCondition {
expressions.push_back(GdbServerExpression(b.data(), b.size()));
}
}
virtual bool evaluate(Task* t) const override {
virtual bool evaluate(ReplayTask* t) const override {
for (auto& e : expressions) {
GdbServerExpression::Value v;
// Break if evaluation fails or the result is nonzero
Expand Down Expand Up @@ -638,12 +638,12 @@ void GdbServer::dispatch_debugger_request(Session& session,
}
case DREQ_GET_REG: {
GdbRegisterValue reg =
get_reg(target->regs(), target->extra_regs(), req.reg().name);
get_reg(target->regs(), *target->extra_regs_fallible(), req.reg().name);
dbg->reply_get_reg(reg);
return;
}
case DREQ_GET_REGS: {
dispatch_regs_request(target->regs(), target->extra_regs());
dispatch_regs_request(target->regs(), *target->extra_regs_fallible());
return;
}
case DREQ_SET_REG: {
Expand Down Expand Up @@ -768,7 +768,7 @@ void GdbServer::dispatch_debugger_request(Session& session,
}
SavedRegisters& regs = saved_register_states[state_index];
regs.regs = target->regs();
regs.extra_regs = target->extra_regs();
regs.extra_regs = *target->extra_regs_fallible();
dbg->reply_save_register_state(true, state_index);
return;
}
Expand Down
4 changes: 2 additions & 2 deletions src/GdbServerExpression.cc
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ struct ExpressionState {
push(stack[stack.size() - 1 - offset].i);
}

void step(Task* t) {
void step(ReplayTask* t) {
DEBUG_ASSERT(!error);
BinaryOperands operands;
switch (fetch<uint8_t>()) {
Expand Down Expand Up @@ -424,7 +424,7 @@ GdbServerExpression::GdbServerExpression(const uint8_t* data, size_t size) {
}
#endif

bool GdbServerExpression::evaluate(Task* t, Value* result) const {
bool GdbServerExpression::evaluate(ReplayTask* t, Value* result) const {
if (bytecode_variants.empty()) {
return false;
}
Expand Down
4 changes: 2 additions & 2 deletions src/GdbServerExpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace rr {

class Task;
class ReplayTask;

/**
* gdb has a simple bytecode language for writing expressions to be evaluated
Expand All @@ -31,7 +31,7 @@ class GdbServerExpression {
* If evaluation succeeds, store the final result in *result and return true.
* Otherwise return false.
*/
bool evaluate(Task* t, Value* result) const;
bool evaluate(ReplayTask* t, Value* result) const;

private:
/**
Expand Down
8 changes: 5 additions & 3 deletions src/RecordSession.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1649,9 +1649,11 @@ static bool inject_handled_signal(RecordTask* t) {
// to 4.7 or thereabouts ptrace can still return stale values. Fix that here.
// This also sets bit 0 of the XINUSE register to 1 to avoid issues where it
// get set to 1 nondeterministically.
ExtraRegisters e = t->extra_regs();
e.reset();
t->set_extra_regs(e);
if (auto e_ptr = t->extra_regs_fallible()) {
ExtraRegisters e = *e_ptr;
e.reset();
t->set_extra_regs(e);
}

return true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/RecordTask.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2018,7 +2018,7 @@ void RecordTask::record_event(Event ev, FlushSyscallbuf flush,
registers = &regs();
}
if (ev.record_extra_regs()) {
extra_registers = &extra_regs();
extra_registers = extra_regs_fallible();
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/ReplayCommand.cc
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ static void serve_replay_no_debugger(const string& trace_dir,
replay_session->trace_reader().time() >= flags.singlestep_to_event) {
cmd = RUN_SINGLESTEP;
fputs("Stepping from: ", stderr);
Task* t = replay_session->current_task();
ReplayTask* t = ReplayTask::cast_or_null(replay_session->current_task());
t->regs().print_register_file_compact(stderr);
fputc(' ', stderr);
t->extra_regs().print_register_file_compact(stderr);
Expand Down
14 changes: 14 additions & 0 deletions src/ReplayTask.cc
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,20 @@ void ReplayTask::set_real_tid_and_update_serial(pid_t tid) {
serial = session().next_task_serial();
}

/* static */ ReplayTask* ReplayTask::cast_or_null(Task* t) {

This comment has been minimized.

Copy link
@rocallahan

rocallahan Apr 18, 2024

Collaborator

Elsewhere we call this as_replay().

This comment has been minimized.

Copy link
@khuey

khuey Apr 18, 2024

Author Collaborator

Did that.

if (t->session().is_replaying() || t->session().is_diversion()) {
return static_cast<ReplayTask*>(t);
}
return nullptr;
}

const ExtraRegisters& ReplayTask::extra_regs() {
if (!extra_regs_fallible()) {
ASSERT(this, false) << "Can't find task for infallible extra_regs";
}
return extra_registers;
}

bool ReplayTask::post_vm_clone(CloneReason reason, int flags, Task* origin) {
if (Task::post_vm_clone(reason, flags, origin) &&
reason == TRACEE_CLONE &&
Expand Down
5 changes: 5 additions & 0 deletions src/ReplayTask.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ class ReplayTask final : public Task {
*/
void set_real_tid_and_update_serial(pid_t tid);

/** Return the extra registers of this. Asserts if the task died. */
const ExtraRegisters& extra_regs();

void note_sched_in_syscallbuf_syscall_hook() {
seen_sched_in_syscallbuf_syscall_hook = true;
}
Expand All @@ -86,6 +89,8 @@ class ReplayTask final : public Task {
return name_;
}

static ReplayTask* cast_or_null(Task* t);

private:
template <typename Arch> void init_buffers_arch();

Expand Down
10 changes: 6 additions & 4 deletions src/RerunCommand.cc
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ static uint64_t seg_reg(const Registers& regs, uint8_t index) {
}
}

static void print_regs(Task* t, FrameTime event, uint64_t instruction_count,
static void print_regs(ReplayTask* t, FrameTime event, uint64_t instruction_count,
const RerunFlags& flags, const vector<TraceField>& fields, FILE* out) {
if (fields.empty()) {
return;
Expand Down Expand Up @@ -587,7 +587,7 @@ static const uint64_t sentinel_ret_address = 9;
static void run_diversion_function(ReplaySession& replay, Task* task,
const RerunFlags& flags) {
DiversionSession::shr_ptr diversion_session = replay.clone_diversion();
Task* t = diversion_session->find_task(task->tuid());
ReplayTask* t = ReplayTask::cast_or_null(diversion_session->find_task(task->tuid()));
Registers regs = t->regs();
// align stack
auto sp = remote_ptr<uint64_t>(regs.sp().as_int() & ~uintptr_t(0xf)) - 1;
Expand Down Expand Up @@ -669,7 +669,8 @@ static int rerun(const string& trace_dir, const RerunFlags& flags, CommandForChe
while (replay_session->trace_reader().time() < flags.trace_end) {
RunCommand cmd = RUN_CONTINUE;

Task* old_task = replay_session->current_task();
auto old_task_p = replay_session->current_task();
ReplayTask* old_task = old_task_p ? ReplayTask::cast_or_null(old_task_p) : nullptr;
auto old_task_tuid = old_task ? old_task->tuid() : TaskUid();
remote_code_ptr old_ip = old_task ? old_task->ip() : remote_code_ptr();
FrameTime before_time = replay_session->trace_reader().time();
Expand Down Expand Up @@ -702,7 +703,8 @@ static int rerun(const string& trace_dir, const RerunFlags& flags, CommandForChe
if (cmd != RUN_CONTINUE) {
// The old_task may have exited (and been deallocated) in the `replay_session->replay_step(cmd)` above.
// So we need to try and obtain it from the session again to make sure it still exists.
Task* old_task = old_task_tuid.tid() ? replay_session->find_task(old_task_tuid) : nullptr;
Task* old_task_p = old_task_tuid.tid() ? replay_session->find_task(old_task_tuid) : nullptr;
ReplayTask* old_task = old_task_p ? ReplayTask::cast_or_null(old_task_p) : nullptr;
remote_code_ptr after_ip = old_task ? old_task->ip() : remote_code_ptr();
DEBUG_ASSERT(after_time >= before_time && after_time <= before_time + 1);

Expand Down
83 changes: 42 additions & 41 deletions src/Task.cc
Original file line number Diff line number Diff line change
Expand Up @@ -544,17 +544,21 @@ static void ptrace_syscall_exit_legacy_arch(Task* t, Task* tracee, const Registe
case Arch::PTRACE_SETFPREGS: {
auto data = t->read_mem(
remote_ptr<typename Arch::user_fpregs_struct>(regs.arg4()));
auto r = tracee->extra_regs();
r.set_user_fpregs_struct(t, Arch::arch(), &data, sizeof(data));
tracee->set_extra_regs(r);
if (auto r_ptr = tracee->extra_regs_fallible()) {
ExtraRegisters r = *r_ptr;
r.set_user_fpregs_struct(t, Arch::arch(), &data, sizeof(data));
tracee->set_extra_regs(r);
}
break;
}
case Arch::PTRACE_SETFPXREGS: {
auto data =
t->read_mem(remote_ptr<X86Arch::user_fpxregs_struct>(regs.arg4()));
auto r = tracee->extra_regs();
r.set_user_fpxregs_struct(t, data);
tracee->set_extra_regs(r);
if (auto r_ptr = tracee->extra_regs_fallible()) {
ExtraRegisters r = *r_ptr;
r.set_user_fpxregs_struct(t, data);
tracee->set_extra_regs(r);
}
break;
}
case Arch::PTRACE_POKEUSR: {
Expand Down Expand Up @@ -749,10 +753,12 @@ void Task::on_syscall_exit_arch(int syscallno, const Registers& regs) {
case NT_PRFPREG: {
auto set = ptrace_get_regs_set<Arch>(
this, regs, user_fpregs_struct_size(tracee->arch()));
ExtraRegisters r = tracee->extra_regs();
r.set_user_fpregs_struct(this, tracee->arch(), set.data(),
set.size());
tracee->set_extra_regs(r);
if (auto r_ptr = tracee->extra_regs_fallible()) {
ExtraRegisters r = *r_ptr;
r.set_user_fpregs_struct(this, tracee->arch(), set.data(),
set.size());
tracee->set_extra_regs(r);
}
break;
}
case NT_ARM_SYSTEM_CALL: {
Expand All @@ -777,29 +783,31 @@ void Task::on_syscall_exit_arch(int syscallno, const Registers& regs) {
break;
}
case NT_X86_XSTATE: {
switch (tracee->extra_regs().format()) {
case ExtraRegisters::XSAVE: {
XSaveLayout layout;
ReplaySession* replay = session().as_replay();
if (replay) {
layout = xsave_layout_from_trace(
replay->trace_reader().cpuid_records());
} else {
layout = xsave_native_layout();
if (auto extra_regs = tracee->extra_regs_fallible()) {
switch (extra_regs->format()) {
case ExtraRegisters::XSAVE: {
XSaveLayout layout;
ReplaySession* replay = session().as_replay();
if (replay) {
layout = xsave_layout_from_trace(
replay->trace_reader().cpuid_records());
} else {
layout = xsave_native_layout();
}
auto set = ptrace_get_regs_set<Arch>(this, regs, layout.full_size);
ExtraRegisters r;
bool ok =
r.set_to_raw_data(tracee->arch(), ExtraRegisters::XSAVE,
set.data(), set.size(), layout);
ASSERT(this, ok) << "Invalid XSAVE data";
tracee->set_extra_regs(r);
break;
}
auto set = ptrace_get_regs_set<Arch>(this, regs, layout.full_size);
ExtraRegisters r;
bool ok =
r.set_to_raw_data(tracee->arch(), ExtraRegisters::XSAVE,
set.data(), set.size(), layout);
ASSERT(this, ok) << "Invalid XSAVE data";
tracee->set_extra_regs(r);
break;
default:
ASSERT(this, false) << "Unknown ExtraRegisters format; "
"Should have been caught during "
"prepare_ptrace";
}
default:
ASSERT(this, false) << "Unknown ExtraRegisters format; "
"Should have been caught during "
"prepare_ptrace";
}
break;
}
Expand Down Expand Up @@ -1043,7 +1051,7 @@ void Task::post_exec(const string& exe_file) {

extra_registers = ExtraRegisters(registers.arch());
extra_registers_known = false;
ExtraRegisters e = extra_regs();
ExtraRegisters e = *extra_regs_fallible();
e.reset();
set_extra_regs(e);

Expand Down Expand Up @@ -1174,13 +1182,6 @@ const ExtraRegisters* Task::extra_regs_fallible() {
return &extra_registers;
}

const ExtraRegisters& Task::extra_regs() {
if (!extra_regs_fallible()) {
ASSERT(this, false) << "Can't find task for infallible extra_regs";
}
return extra_registers;
}

#if defined(__i386__) || defined(__x86_64__)
static ssize_t dr_user_word_offset(size_t i) {
DEBUG_ASSERT(i < NUM_X86_DEBUG_REGS);
Expand Down Expand Up @@ -2152,7 +2153,7 @@ static bool simulate_transient_error(Task* t) {
static FrameTime simulate_error_at_event_ = simulate_error_at_event();

if (simulated_error || !t->session().is_replaying() ||
static_cast<ReplayTask*>(t)->session().trace_stream()->time() < simulate_error_at_event_) {
ReplayTask::cast_or_null(t)->session().trace_stream()->time() < simulate_error_at_event_) {
return false;
}
simulated_error = true;
Expand Down Expand Up @@ -2716,7 +2717,7 @@ Task::CapturedState Task::capture_state() {
state.serial = serial;
state.tguid = thread_group()->tguid();
state.regs = regs();
state.extra_regs = extra_regs();
state.extra_regs = *extra_regs_fallible();
state.prname = name();
if (arch() == aarch64) {
bool ok = read_aarch64_tls_register(&state.tls_register);
Expand Down
3 changes: 0 additions & 3 deletions src/Task.h
Original file line number Diff line number Diff line change
Expand Up @@ -504,9 +504,6 @@ class Task {
/** Return the current regs of this. */
const Registers& regs() const;

/** Return the extra registers of this. Asserts if the task died. */
const ExtraRegisters& extra_regs();

/** Return the extra registers of this, or null if the task died. */
const ExtraRegisters* extra_regs_fallible();

Expand Down
Loading

0 comments on commit b9117dd

Please sign in to comment.