1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
|
#pragma once
#include <torch/csrc/profiler/unwind/action.h>
#include <torch/csrc/profiler/unwind/unwind_error.h>
#include <cstdint>
#include <limits>
namespace torch::unwind {
struct UnwindState {
int64_t rip, rbp, rsp;
};
struct Unwinder {
Unwinder(Action rsp, Action rip, Action rbp)
: kind_(rip.kind == A_UNDEFINED ? END : STANDARD),
reg_(rsp.reg),
off_(rsp.data),
rip_off_(rip.data),
rbp_off_(
rbp.kind == A_UNDEFINED ? std::numeric_limits<int64_t>::max()
: rbp.data),
deref_(rsp.kind == A_REG_PLUS_DATA_DEREF) {
check(rsp.reg == D_RSP || rsp.reg == D_RBP);
check(rip.kind == A_UNDEFINED || rip.kind == A_LOAD_CFA_OFFSET);
if (rsp.kind == A_REG_PLUS_DATA) {
check(rbp.kind == A_LOAD_CFA_OFFSET || rbp.kind == A_UNDEFINED);
} else if (rsp.kind == A_REG_PLUS_DATA_DEREF) {
if (rbp.kind == A_REG_PLUS_DATA_DEREF) {
check(rbp.reg == rsp.reg);
rbp_off_ -= rsp.data;
} else {
check(rbp.kind == A_UNDEFINED);
}
} else {
check(false);
}
}
void check(bool cond) {
if (!cond) {
throw UnwindError("Unwinding actions do not follow supported patterns");
}
}
bool terminator() const {
return kind_ != STANDARD;
}
bool isUnknown() const {
return kind_ == UNKNOWN;
}
// unwinder representing some pattern unsupported in
// current implementation
static Unwinder unknown() {
return Unwinder();
}
UnwindState run(const UnwindState& cur) const {
UnwindState r = cur;
r.rsp = (reg_ == D_RSP ? cur.rsp : cur.rbp) + off_;
r.rbp = rbp_off_ == std::numeric_limits<int64_t>::max()
? cur.rbp
// NOLINTNEXTLINE(performance-no-int-to-ptr)
: *(int64_t*)(r.rsp + rbp_off_);
if (deref_) {
// NOLINTNEXTLINE(performance-no-int-to-ptr)
r.rsp = *(int64_t*)r.rsp;
}
// NOLINTNEXTLINE(performance-no-int-to-ptr)
r.rip = *(int64_t*)(r.rsp + rip_off_);
return r;
}
private:
Unwinder() : kind_(UNKNOWN), reg_(0), off_(0), rip_off_(0), rbp_off_(0) {}
enum Kind { STANDARD, END, UNKNOWN } kind_;
uint32_t reg_;
int64_t off_;
int64_t rip_off_;
int64_t rbp_off_;
bool deref_{false};
};
} // namespace torch::unwind
|