blob: 0c1d33abe4e9edbf833ac6410bafcdcd8d8bc62a [file] [log] [blame]
#pragma once
#include <stdint.h>
#include <string.h>
#include <torch/csrc/profiler/unwind/dwarf_enums.h>
#include <torch/csrc/profiler/unwind/unwind_error.h>
struct Lexer {
Lexer(void* data, void* base = nullptr)
: next_((const char*)data), base_((int64_t)base) {}
template <typename T>
T read() {
T result;
memcpy(&result, next_, sizeof(T));
next_ += sizeof(T);
return result;
}
// SLEB/ULEB code adapted from LLVM equivalents
int64_t readSLEB128() {
int64_t Value = 0;
unsigned Shift = 0;
uint8_t Byte;
do {
Byte = read<uint8_t>();
uint64_t Slice = Byte & 0x7f;
if ((Shift >= 64 && Slice != (Value < 0 ? 0x7f : 0x00)) ||
(Shift == 63 && Slice != 0 && Slice != 0x7f)) {
throw UnwindError("sleb128 too big for int64");
}
Value |= Slice << Shift;
Shift += 7;
} while (Byte >= 128);
// Sign extend negative numbers if needed.
if (Shift < 64 && (Byte & 0x40)) {
Value |= (-1ULL) << Shift;
}
return Value;
}
uint64_t readULEB128() {
uint64_t Value = 0;
unsigned Shift = 0;
uint8_t p;
do {
p = read<uint8_t>();
uint64_t Slice = p & 0x7f;
if ((Shift >= 64 && Slice != 0) || Slice << Shift >> Shift != Slice) {
throw UnwindError("uleb128 too big for uint64");
}
Value += Slice << Shift;
Shift += 7;
} while (p >= 128);
return Value;
}
const char* readCString() {
auto result = next_;
next_ += strlen(next_) + 1;
return result;
}
int64_t readEncoded(uint8_t enc) {
int64_t r = 0;
switch (enc & (~DW_EH_PE_indirect & 0xF0)) {
case DW_EH_PE_absptr:
break;
case DW_EH_PE_pcrel:
r = (int64_t)next_;
break;
case DW_EH_PE_datarel:
r = base_;
break;
default:
throw UnwindError("unknown encoding");
}
return r + readEncodedValue(enc);
}
int64_t readEncodedOr(uint8_t enc, int64_t orelse) {
if (enc == DW_EH_PE_omit) {
return orelse;
}
return readEncoded(enc);
}
int64_t read4or8Length() {
int64_t length = read<uint32_t>();
if (length == 0xFFFFFFFF) {
length = read<int64_t>();
}
return length;
}
void* loc() const {
return (void*)next_;
}
Lexer& skip(int64_t bytes) {
next_ += bytes;
return *this;
}
int64_t readEncodedValue(uint8_t enc) {
switch (enc & 0xF) {
case DW_EH_PE_udata2:
return read<uint16_t>();
case DW_EH_PE_sdata2:
return read<int16_t>();
case DW_EH_PE_udata4:
return read<uint32_t>();
case DW_EH_PE_sdata4:
return read<int32_t>();
case DW_EH_PE_udata8:
return read<uint64_t>();
case DW_EH_PE_sdata8:
return read<int64_t>();
case DW_EH_PE_uleb128:
return readULEB128();
case DW_EH_PE_sleb128:
return readSLEB128();
default:
throw UnwindError("not implemented");
}
}
private:
const char* next_;
int64_t base_;
};