Skip to content

Commit 4064586

Browse files
committed
Address missing arch() serialization
Previous work assumed everything as native. That doesn't work when debugging a 32-bit mode application on a 64-bit machine. That means some `SupportedArch` fields needs to be serialized as well, so that if the process was a 32-bit application it gets re-created correctly. This was instantly made visible by the provided test (although it did not test it explicitly).
1 parent 13b9c1e commit 4064586

11 files changed

+91
-51
lines changed

src/CheckpointInfo.cc

+12-10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "ReplayTimeline.h"
44
#include "ScopedFd.h"
55
#include "rr_pcp.capnp.h"
6+
#include "util.h"
67
#include <algorithm>
78
#include <capnp/blob.h>
89
#include <capnp/message.h>
@@ -22,9 +23,10 @@ MarkData::MarkData(const ReplayTimeline::Mark& m)
2223
extra_regs(m.extra_regs()),
2324
return_addresses(m.get_internal()->proto.return_addresses),
2425
singlestep_to_next_mark_no_signal(
25-
m.get_internal()->singlestep_to_next_mark_no_signal) {}
26+
m.get_internal()->singlestep_to_next_mark_no_signal),
27+
arch(m.get_internal()->extra_regs.arch()) {}
2628

27-
MarkData::MarkData(rr::pcp::MarkData::Reader reader, SupportedArch arch,
29+
MarkData::MarkData(rr::pcp::MarkData::Reader reader,
2830
const CPUIDRecords& cpuid_recs)
2931
: time(reader.getTime()),
3032
ticks(reader.getTicks()),
@@ -34,7 +36,8 @@ MarkData::MarkData(rr::pcp::MarkData::Reader reader, SupportedArch arch,
3436
extra_regs(),
3537
return_addresses(),
3638
singlestep_to_next_mark_no_signal(
37-
reader.getSinglestepToNextMarkNoSignal()) {
39+
reader.getSinglestepToNextMarkNoSignal()),
40+
arch(from_trace_arch(reader.getArch())) {
3841
regs.set_arch(arch);
3942
regs.set_from_trace(arch, reader.getRegs().getRaw().begin(),
4043
reader.getRegs().getRaw().size());
@@ -69,8 +72,7 @@ static std::vector<string> checkpoint_directories(const string& trace_dir) {
6972
}
7073

7174
std::vector<CheckpointInfo> get_checkpoint_infos(
72-
const std::string& trace_dir, SupportedArch arch,
73-
const CPUIDRecords& cpuid_recs) {
75+
const std::string& trace_dir, const CPUIDRecords& cpuid_recs) {
7476

7577
std::vector<CheckpointInfo> checkpoints;
7678
for (auto checkpoint_dir : checkpoint_directories(trace_dir)) {
@@ -81,8 +83,8 @@ std::vector<CheckpointInfo> get_checkpoint_infos(
8183
}
8284
capnp::PackedFdMessageReader reader(fd);
8385
auto checkpointsInfoReader = reader.getRoot<pcp::CheckpointInfo>();
84-
auto info = CheckpointInfo{ checkpoint_dir, checkpointsInfoReader, arch,
85-
cpuid_recs };
86+
auto info =
87+
CheckpointInfo{ checkpoint_dir, checkpointsInfoReader, cpuid_recs };
8688
checkpoints.push_back(info);
8789
}
8890

@@ -138,6 +140,7 @@ bool CheckpointInfo::serialize(ReplaySession& session) {
138140
builder.setTicksAtEventStart(mark_data.ticks_at_event_start);
139141
builder.setSinglestepToNextMarkNoSignal(
140142
mark_data.singlestep_to_next_mark_no_signal);
143+
builder.setArch(to_trace_arch(mark_data.arch));
141144
};
142145

143146
if (is_explicit()) {
@@ -220,18 +223,17 @@ CheckpointInfo::CheckpointInfo(const Checkpoint& non_explicit_cp,
220223

221224
CheckpointInfo::CheckpointInfo(std::string metadata_file,
222225
rr::pcp::CheckpointInfo::Reader reader,
223-
SupportedArch arch,
224226
const CPUIDRecords& cpuid_recs)
225227
: capnp_directory(std::move(metadata_file)),
226228
unique_id(reader.getId()),
227229
where(data_to_str(reader.getWhere())),
228230
next_serial(reader.getNextSerial()),
229231
clone_data(reader.isExplicit() ? reader.getExplicit()
230232
: reader.getNonExplicit().getCloneMark(),
231-
arch, cpuid_recs),
233+
cpuid_recs),
232234
non_explicit_mark_data(
233235
reader.isNonExplicit()
234-
? new MarkData{ reader.getNonExplicit().getCheckpointMark(), arch,
236+
? new MarkData{ reader.getNonExplicit().getCheckpointMark(),
235237
cpuid_recs }
236238
: nullptr),
237239
stats() {

src/CheckpointInfo.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "GdbServerConnection.h"
66
#include "ReplayTimeline.h"
77
#include "ReturnAddressList.h"
8+
#include "kernel_abi.h"
89
#include "rr_pcp.capnp.h"
910
#include "util.h"
1011
#include <dirent.h>
@@ -31,8 +32,7 @@ struct MarkData {
3132
// Constructor when serializing
3233
MarkData(const ReplayTimeline::Mark& m);
3334
// Constructor when de-serializing
34-
MarkData(rr::pcp::MarkData::Reader reader, SupportedArch arch,
35-
const CPUIDRecords& cpuid_recs);
35+
MarkData(rr::pcp::MarkData::Reader reader, const CPUIDRecords& cpuid_recs);
3636

3737
FrameTime time;
3838
Ticks ticks;
@@ -42,6 +42,7 @@ struct MarkData {
4242
ExtraRegisters extra_regs;
4343
ReturnAddressList return_addresses;
4444
bool singlestep_to_next_mark_no_signal;
45+
SupportedArch arch;
4546
};
4647

4748
class CheckpointInfo {
@@ -66,7 +67,7 @@ class CheckpointInfo {
6667
const ReplayTimeline::Mark& mark_with_checkpoint);
6768
// When deserializing from capnproto stream
6869
CheckpointInfo(std::string metadata_file,
69-
rr::pcp::CheckpointInfo::Reader reader, SupportedArch arch,
70+
rr::pcp::CheckpointInfo::Reader reader,
7071
const CPUIDRecords& cpuid_recs);
7172

7273
bool serialize(ReplaySession& session);
@@ -116,7 +117,6 @@ std::string checkpoints_index_file(const std::string& trace_dir);
116117
* order by event time.
117118
*/
118119
std::vector<CheckpointInfo> get_checkpoint_infos(
119-
const std::string& trace_dir, SupportedArch arch,
120-
const CPUIDRecords& cpuid_recs);
120+
const std::string& trace_dir, const CPUIDRecords& cpuid_recs);
121121

122122
} // namespace rr

src/PersistentCheckpointing.cc

+21-14
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "TraceFrame.h"
2525
#include "TraceStream.h"
2626
#include "VirtualPerfCounterMonitor.h"
27+
#include "kernel_abi.h"
2728
#include "log.h"
2829
#include "replay_syscall.h"
2930
#include "rr_pcp.capnp.h"
@@ -165,7 +166,7 @@ static void write_map(const WriteVmConfig& cfg,
165166
<< map.map.size();
166167

167168
auto bytes_read = 0ull;
168-
while(static_cast<size_t>(bytes_read) < map.map.size()) {
169+
while (static_cast<size_t>(bytes_read) < map.map.size()) {
169170
const auto current_read = cfg.pread(bytes_read, map.map);
170171
if (current_read == -1)
171172
FILE_OP_FATAL(file) << " couldn't read contents of " << map.map.str();
@@ -309,20 +310,17 @@ void map_private_anonymous(AutoRemoteSyscalls& remote,
309310
}
310311

311312
Task::CapturedState reconstitute_captured_state(
312-
ReplaySession& s, pcp::CapturedState::Reader reader) {
313+
SupportedArch arch, const std::vector<CPUIDRecord>& cpuid_records,
314+
pcp::CapturedState::Reader reader) {
313315
Task::CapturedState res;
314316
res.ticks = reader.getTicks();
315-
{
316-
auto register_raw = reader.getRegs().getRaw();
317-
res.regs = Registers{ s.arch() };
318-
res.regs.set_from_trace(s.arch(), register_raw.begin(),
319-
register_raw.size());
320-
}
321-
{
322-
auto raw = reader.getExtraRegs().getRaw();
323-
set_extra_regs_from_raw(s.arch(), s.trace_reader().cpuid_records(), raw,
324-
res.extra_regs);
325-
}
317+
auto register_raw = reader.getRegs().getRaw();
318+
res.regs = Registers{ arch };
319+
res.regs.restore_from_persistent_checkpoint(arch, register_raw.begin(),
320+
register_raw.size());
321+
322+
auto raw = reader.getExtraRegs().getRaw();
323+
set_extra_regs_from_raw(arch, cpuid_records, raw, res.extra_regs);
326324

327325
res.prname = data_to_str(reader.getPrname());
328326
res.fdtable_identity = reader.getFdtableIdentity();
@@ -380,6 +378,13 @@ void init_scratch_memory(ReplayTask* t, const KernelMapping& km) {
380378
}
381379
}
382380

381+
kj::Array<capnp::byte> prepare_user_desc(const X86Arch::user_desc& desc) {
382+
kj::Array<capnp::byte> data =
383+
kj::heapArray<capnp::byte>(sizeof(X86Arch::user_desc));
384+
memcpy(data.begin(), &desc, sizeof(X86Arch::user_desc)); // Copy raw bytes
385+
return data;
386+
}
387+
383388
void write_capture_state(pcp::CapturedState::Builder& sb,
384389
const Task::CapturedState& state) {
385390
sb.setTicks(state.ticks);
@@ -421,7 +426,9 @@ void write_capture_state(pcp::CapturedState::Builder& sb,
421426
auto thread_areas = sb.initThreadAreas(state.thread_areas.size());
422427
auto i = 0;
423428
for (const auto& ta : state.thread_areas) {
424-
thread_areas[i++] = capnp::Data::Builder{ (std::uint8_t*)&ta, sizeof(ta) };
429+
thread_areas.set(
430+
i++, kj::ArrayPtr<const capnp::byte>(
431+
reinterpret_cast<const capnp::byte*>(&ta), sizeof(ta)));
425432
}
426433
}
427434

src/PersistentCheckpointing.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "AddressSpace.h"
44
#include "CheckpointInfo.h"
5+
#include "kernel_abi.h"
56
#include "log.h"
67
#include "rr_pcp.capnp.h"
78
#include <capnp/blob.h>
@@ -57,7 +58,8 @@ void write_monitor(rr::pcp::FileMonitor::Builder& builder, int fd,
5758
* Restores Task::CapturedState from capnproto data.
5859
*/
5960
Task::CapturedState reconstitute_captured_state(
60-
ReplaySession& s, pcp::CapturedState::Reader reader);
61+
SupportedArch arch, const std::vector<CPUIDRecord>& cpuid_records,
62+
pcp::CapturedState::Reader reader);
6163

6264
void map_private_anonymous(AutoRemoteSyscalls& remote, const KernelMapping& km);
6365

src/Registers.cc

+20
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "ReplayTask.h"
1212
#include "core.h"
13+
#include "kernel_abi.h"
1314
#include "log.h"
1415

1516
using namespace std;
@@ -625,6 +626,25 @@ void Registers::set_from_ptrace_for_arch(SupportedArch a, const void* data,
625626
memcpy(&u.x86regs, data, sizeof(u.x86regs));
626627
}
627628

629+
void Registers::restore_from_persistent_checkpoint(SupportedArch arch,
630+
const void* data,
631+
size_t size) {
632+
switch (arch) {
633+
case x86:
634+
DEBUG_ASSERT(sizeof(u.x86regs) == size);
635+
memcpy(&u.x86regs, data, size);
636+
break;
637+
case x86_64:
638+
DEBUG_ASSERT(sizeof(u.x64regs) == size);
639+
memcpy(&u.x64regs, data, size);
640+
break;
641+
case aarch64:
642+
DEBUG_ASSERT(sizeof(u.x64regs) == size);
643+
memcpy(&u.arm64regs, data, size);
644+
break;
645+
}
646+
}
647+
628648
void Registers::set_from_trace(SupportedArch a, const void* data,
629649
size_t size) {
630650
if (is_x86ish(a)) {

src/Registers.h

+3
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ class Registers {
124124
void set_from_trace(SupportedArch arch, const void* data,
125125
size_t size);
126126

127+
void restore_from_persistent_checkpoint(SupportedArch arch, const void* data,
128+
size_t size);
129+
127130
#define ARCH_SWITCH_CASE(rettype, x86case, x64case, arm64case) \
128131
(([=](void) -> rettype { \
129132
switch (arch()) { \

src/ReplaySession.cc

+8-7
Original file line numberDiff line numberDiff line change
@@ -2260,6 +2260,7 @@ void ReplaySession::serialize_checkpoint(
22602260
auto addr_space_clone = addr_space_builders[i];
22612261
addr_space_clone.setAuxv(kj::ArrayPtr<const capnp::byte>{
22622262
leader->vm()->saved_auxv().data(), leader->vm()->saved_auxv().size() });
2263+
addr_space_clone.setArch(to_trace_arch(as.clone_leader->arch()));
22632264
auto cls = addr_space_clone.initCloneLeaderState();
22642265
write_capture_state(cls, as.clone_leader_state);
22652266
auto pspace = addr_space_builders[i].initProcessSpace();
@@ -2334,8 +2335,9 @@ void ReplaySession::load_checkpoint(const CheckpointInfo& cp_info) {
23342335
const auto proc_space = as.getProcessSpace();
23352336
const auto cleader_captured_state = as.getCloneLeaderState();
23362337

2338+
SupportedArch address_space_arch = from_trace_arch(as.getArch());
23372339
leader->is_stopped_ = true;
2338-
leader->os_exec_stub(arch());
2340+
leader->os_exec_stub(address_space_arch);
23392341
std::string exe_name = data_to_str(proc_space.getExe());
23402342
std::string original_exe_name = data_to_str(proc_space.getOriginalExe());
23412343
leader->post_exec(original_exe_name);
@@ -2465,9 +2467,9 @@ void ReplaySession::load_checkpoint(const CheckpointInfo& cp_info) {
24652467
leader->vm()->restore_auxv(leader, std::move(auxv));
24662468
syscall(SYS_rrcall_reload_auxv, leader->tid);
24672469
std::vector<Task::CapturedState> member_states;
2468-
24692470
for (const auto& member_state : as.getMemberState()) {
2470-
member_states.push_back(reconstitute_captured_state(*this, member_state));
2471+
member_states.push_back(reconstitute_captured_state(
2472+
address_space_arch, trace_in.cpuid_records(), member_state));
24712473
}
24722474

24732475
CapturedMemory captured_memory;
@@ -2478,9 +2480,8 @@ void ReplaySession::load_checkpoint(const CheckpointInfo& cp_info) {
24782480
captured_memory.push_back(
24792481
std::make_pair(captured_mem.getStartAddress(), std::move(mem)));
24802482
}
2481-
2482-
Task::CapturedState cloneLeaderCaptureState =
2483-
reconstitute_captured_state(*this, as.getCloneLeaderState());
2483+
Task::CapturedState cloneLeaderCaptureState = reconstitute_captured_state(
2484+
address_space_arch, trace_in.cpuid_records(), as.getCloneLeaderState());
24842485
auto fd_table_key = cloneLeaderCaptureState.fdtable_identity;
24852486
leader->preload_globals = cloneLeaderCaptureState.preload_globals;
24862487
partial_init_addr_spaces.push_back(CloneCompletion::AddressSpaceClone{
@@ -2574,7 +2575,7 @@ void ReplaySession::load_checkpoint(const CheckpointInfo& cp_info) {
25742575

25752576
std::vector<CheckpointInfo> ReplaySession::get_persistent_checkpoints() {
25762577
return rr::get_checkpoint_infos(resolve_trace_name(trace_reader().dir()),
2577-
arch(), trace_reader().cpuid_records());
2578+
trace_reader().cpuid_records());
25782579
}
25792580

25802581
void ReplaySession::restore_session_info(const CheckpointInfo& cp) {

src/TraceStream.cc

-14
Original file line numberDiff line numberDiff line change
@@ -162,20 +162,6 @@ static trace::CpuTriState to_tristate(bool value) {
162162
return value ? trace::CpuTriState::KNOWN_TRUE : trace::CpuTriState::KNOWN_FALSE;
163163
}
164164

165-
static SupportedArch from_trace_arch(trace::Arch arch) {
166-
switch (arch) {
167-
case trace::Arch::X86:
168-
return x86;
169-
case trace::Arch::X8664:
170-
return x86_64;
171-
case trace::Arch::AARCH64:
172-
return aarch64;
173-
default:
174-
FATAL() << "Unknown arch";
175-
return x86;
176-
}
177-
}
178-
179165
static trace::SignalDisposition to_trace_disposition(
180166
SignalResolvedDisposition disposition) {
181167
switch (disposition) {

src/rr_pcp.capnp

+4
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ struct AddressSpaceClone {
141141
memberState @2 :List(CapturedState);
142142
capturedMemory @3 :List(CapturedMemory);
143143
auxv @4 :Data;
144+
# We need to know how to reconstitute the Register/ExtraRegister's in CapturedState
145+
arch @5 :Arch;
144146
}
145147

146148
struct CloneCompletionInfo {
@@ -161,6 +163,8 @@ struct MarkData {
161163
returnAddresses @5 :List(RemotePtr);
162164
extraRegs @6: ExtraRegisters;
163165
singlestepToNextMarkNoSignal @7 :Bool;
166+
# The arch required to configure regs and extraRegs with the peristed data
167+
arch @8 :Arch;
164168
}
165169

166170

src/util.cc

+14
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,20 @@ std::string default_rr_trace_dir() {
27342734
return cached_dir;
27352735
}
27362736

2737+
SupportedArch from_trace_arch(trace::Arch arch) {
2738+
switch (arch) {
2739+
case trace::Arch::X86:
2740+
return x86;
2741+
case trace::Arch::X8664:
2742+
return x86_64;
2743+
case trace::Arch::AARCH64:
2744+
return aarch64;
2745+
default:
2746+
FATAL() << "Unknown arch";
2747+
return x86;
2748+
}
2749+
}
2750+
27372751
trace::Arch to_trace_arch(SupportedArch arch) {
27382752
switch (arch) {
27392753
case x86:

src/util.h

+1
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,7 @@ void set_extra_regs_from_raw(SupportedArch arch,
722722
capnp::Data::Reader extra_regs_to_raw(const ExtraRegisters&);
723723

724724
trace::Arch to_trace_arch(SupportedArch arch);
725+
SupportedArch from_trace_arch(trace::Arch arch);
725726

726727
/** Convert rr's capnp string representation into std::string. */
727728
std::string data_to_str(const kj::ArrayPtr<const capnp::byte>& data);

0 commit comments

Comments
 (0)