Skip to content

Commit

Permalink
Check microarch for compatibility when replaying a transported trace …
Browse files Browse the repository at this point in the history
…and CPUID faulting is not available

Resolves #2122
  • Loading branch information
rocallahan committed Oct 31, 2017
1 parent 33fdbb2 commit 244151f
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/PerfCounters.cc
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ static CpuMicroarch get_cpu_microarch() {
}

auto cpuid_data = cpuid(CPUID_GETFEATURES, 0);
unsigned int cpu_type = (cpuid_data.eax & 0xF0FF0);
unsigned int cpu_type = cpuid_data.eax & 0xF0FF0;
unsigned int ext_family = (cpuid_data.eax >> 20) & 0xff;
switch (cpu_type) {
case 0x006F0:
Expand Down
24 changes: 9 additions & 15 deletions src/ReplaySession.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,14 @@ ReplaySession::ReplaySession(const std::string& dir)
advance_to_next_trace_frame();

if (trace_in.uses_cpuid_faulting() && !has_cpuid_faulting()) {
FATAL() << "Trace was recorded with CPUID faulting enabled, but this\n"
<< "system does not support CPUID faulting";
CLEAN_FATAL()
<< "Trace was recorded with CPUID faulting enabled, but this\n"
"system does not support CPUID faulting.";
}
if (!has_cpuid_faulting() && !cpuid_compatible(trace_in.cpuid_records())) {
CLEAN_FATAL()
<< "Trace was recorded on a machine with different CPUID values\n"
"and CPUID faulting is not enabled; replay will not work.";
}
if (has_cpuid_faulting() && trace_in.bound_to_cpu() >= 0) {
// The recorded trace was bound to a CPU, but we have CPUID faulting so
Expand Down Expand Up @@ -303,18 +309,6 @@ static void perform_interrupted_syscall(ReplayTask* t) {
remote.regs().set_syscall_result(ret);
}

static const CPUIDRecord* find_cpuid_record(
const Registers& r, const vector<CPUIDRecord>& records) {
uint32_t eax = r.ax();
uint32_t ecx = r.cx();
for (const auto& rec : records) {
if (rec.eax_in == eax && (rec.ecx_in == ecx || rec.ecx_in == UINT32_MAX)) {
return &rec;
}
}
return nullptr;
}

bool ReplaySession::handle_unrecorded_cpuid_fault(
ReplayTask* t, const StepConstraints& constraints) {
if (t->stop_sig() != SIGSEGV || !has_cpuid_faulting() ||
Expand All @@ -328,7 +322,7 @@ bool ReplaySession::handle_unrecorded_cpuid_fault(

const vector<CPUIDRecord>& records = trace_in.cpuid_records();
Registers r = t->regs();
const CPUIDRecord* rec = find_cpuid_record(r, records);
const CPUIDRecord* rec = find_cpuid_record(records, r.ax(), r.cx());
ASSERT(t, rec) << "Can't find CPUID record for request AX=" << HEX(r.ax())
<< " CX=" << HEX(r.cx());
r.set_cpuid_output(rec->out.eax, rec->out.ebx, rec->out.ecx, rec->out.edx);
Expand Down
25 changes: 25 additions & 0 deletions src/util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,31 @@ bool cpuid_faulting_works() {
return cpuid_faulting_ok;
}

const CPUIDRecord* find_cpuid_record(const vector<CPUIDRecord>& records,
uint32_t eax, uint32_t ecx) {
for (const auto& rec : records) {
if (rec.eax_in == eax && (rec.ecx_in == ecx || rec.ecx_in == UINT32_MAX)) {
return &rec;
}
}
return nullptr;
}

bool cpuid_compatible(const vector<CPUIDRecord>& trace_records) {
// We could compare all CPUID records but that might be fragile (it's hard to
// be sure the values don't change in ways applications don't care about).
// Let's just check the microarch for now.
auto cpuid_data = cpuid(CPUID_GETFEATURES, 0);
unsigned int cpu_type = cpuid_data.eax & 0xF0FF0;
auto trace_cpuid_data =
find_cpuid_record(trace_records, CPUID_GETFEATURES, 0);
if (!trace_cpuid_data) {
FATAL() << "GETFEATURES missing???";
}
unsigned int trace_cpu_type = trace_cpuid_data->out.eax & 0xF0FF0;
return cpu_type == trace_cpu_type;
}

template <typename Arch>
static CloneParameters extract_clone_parameters_arch(const Registers& regs) {
CloneParameters result;
Expand Down
20 changes: 20 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ struct CPUIDData {
};
CPUIDData cpuid(uint32_t code, uint32_t subrequest);

/**
* Return all CPUID values supported by this CPU.
*/
struct CPUIDRecord {
uint32_t eax_in;
// UINT32_MAX means ECX not relevant
Expand All @@ -179,8 +182,25 @@ struct CPUIDRecord {
};
std::vector<CPUIDRecord> all_cpuid_records();

/**
* Returns true if CPUID faulting is supported by the kernel and hardware and
* is actually working.
*/
bool cpuid_faulting_works();

/**
* Locate a CPUID record for the give parameters, or return nullptr if there
* isn't one.
*/
const CPUIDRecord* find_cpuid_record(const std::vector<CPUIDRecord>& records,
uint32_t eax, uint32_t ecx);

/**
* Return true if the trace's CPUID values are "compatible enough" with our
* CPU's CPUID values.
*/
bool cpuid_compatible(const std::vector<CPUIDRecord>& trace_records);

struct CloneParameters {
remote_ptr<void> stack;
remote_ptr<int> ptid;
Expand Down

0 comments on commit 244151f

Please sign in to comment.