Use flags in context structures
This commit is contained in:
parent
b6ae4b2115
commit
cd9ecafb4f
3 changed files with 92 additions and 28 deletions
|
@ -1,6 +1,15 @@
|
|||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
UNWF_RIP=0,
|
||||
UNWF_RSP=1,
|
||||
UNWF_RBP=2,
|
||||
|
||||
UNWF_ERROR=7
|
||||
} unwind_flags_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t flags;
|
||||
uintptr_t rip, rsp, rbp;
|
||||
} unwind_context_t;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "CodeGenerator.hpp"
|
||||
#include "gen_context_struct.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "../shared/context_struct.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
@ -28,16 +29,6 @@ CodeGenerator::CodeGenerator(
|
|||
}
|
||||
}
|
||||
|
||||
static std::string undefined_register() {
|
||||
static std::string val = "";
|
||||
if(val.empty()) {
|
||||
std::ostringstream oss;
|
||||
oss << std::numeric_limits<uintptr_t>::max() << "ull";
|
||||
val = oss.str();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
void CodeGenerator::generate() {
|
||||
gen_of_dwarf();
|
||||
}
|
||||
|
@ -90,12 +81,33 @@ void CodeGenerator::gen_unwind_func_header(const std::string& name) {
|
|||
<< "\tswitch(pc) {" << endl;
|
||||
}
|
||||
|
||||
struct UnwFlags {
|
||||
UnwFlags():
|
||||
error(false), rip(false), rsp(false), rbp(false) {}
|
||||
|
||||
bool error, rip, rsp, rbp;
|
||||
|
||||
uint8_t to_uint8() const {
|
||||
uint8_t out = 0;
|
||||
if(rip)
|
||||
out |= (1 << UNWF_RIP);
|
||||
if(rsp)
|
||||
out |= (1 << UNWF_RSP);
|
||||
if(rbp)
|
||||
out |= (1 << UNWF_RBP);
|
||||
if(error)
|
||||
out |= (1 << UNWF_ERROR);
|
||||
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
void CodeGenerator::gen_unwind_func_footer() {
|
||||
UnwFlags flags;
|
||||
flags.error = true;
|
||||
os << "\t\tdefault:\n"
|
||||
<< "\t\t\tout_ctx.rsp = " << undefined_register() << ";\n"
|
||||
<< "\t\t\tout_ctx.rbp = " << undefined_register() << ";\n"
|
||||
<< "\t\t\tout_ctx.rip = " << undefined_register() << ";\n"
|
||||
<< "\t\t\treturn out_ctx;"
|
||||
<< "\t\t\tout_ctx.flags = " << (int) flags.to_uint8() << "u;\n"
|
||||
<< "\t\t\treturn out_ctx;\n"
|
||||
<< "\t}\n"
|
||||
<< "}" << endl;
|
||||
}
|
||||
|
@ -126,26 +138,51 @@ void CodeGenerator::gen_of_row(
|
|||
uintptr_t row_end)
|
||||
{
|
||||
gen_case(row.ip, row_end);
|
||||
UnwFlags flags;
|
||||
|
||||
|
||||
try {
|
||||
if(!check_reg_valid(row.ra)) {
|
||||
// RA might be undefined (last frame), but if it is defined and we
|
||||
// don't implement it (eg. EXPR), it is an error
|
||||
flags.error = true;
|
||||
goto write_flags;
|
||||
}
|
||||
|
||||
if(check_reg_valid(row.cfa)) {
|
||||
flags.rsp = true;
|
||||
os << "\t\t\t" << "out_ctx.rsp = ";
|
||||
gen_of_reg(row.cfa);
|
||||
os << ';' << endl;
|
||||
}
|
||||
else { // rsp is required (CFA)
|
||||
flags.error = true;
|
||||
goto write_flags;
|
||||
}
|
||||
|
||||
if(check_reg_defined(row.rbp)) {
|
||||
flags.rbp = true;
|
||||
os << "\t\t\t" << "out_ctx.rbp = ";
|
||||
gen_of_reg(row.rbp);
|
||||
os << ';' << endl;
|
||||
}
|
||||
|
||||
if(check_reg_defined(row.ra)) {
|
||||
flags.rip = true;
|
||||
os << "\t\t\t" << "out_ctx.rip = ";
|
||||
gen_of_reg(row.ra);
|
||||
os << ';' << endl;
|
||||
} catch(const UnhandledRegister& exn) {
|
||||
os << ";\n"
|
||||
<< "\t\t\tout_ctx.rip = " << undefined_register() << ";\n"
|
||||
<< "\t\t\tout_ctx.rsp = " << undefined_register() << ";\n"
|
||||
<< "\t\t\tout_ctx.rbp = " << undefined_register() << ";\n";
|
||||
}
|
||||
|
||||
} catch(const UnhandledRegister& exn) {
|
||||
// This should not happen, since we check_reg_*, but heh.
|
||||
flags.error = true;
|
||||
os << ";\n";
|
||||
}
|
||||
|
||||
write_flags:
|
||||
os << "\t\t\tout_ctx.flags = " << (int)flags.to_uint8() << "u;" << endl;
|
||||
|
||||
os << "\t\t\treturn " << "out_ctx" << ";" << endl;
|
||||
}
|
||||
|
||||
|
@ -188,10 +225,25 @@ static const char* ctx_of_dw_name(SimpleDwarf::MachineRegister reg) {
|
|||
return "";
|
||||
}
|
||||
|
||||
bool CodeGenerator::check_reg_defined(const SimpleDwarf::DwRegister& reg) {
|
||||
switch(reg.type) {
|
||||
case SimpleDwarf::DwRegister::REG_UNDEFINED:
|
||||
case SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool CodeGenerator::check_reg_valid(const SimpleDwarf::DwRegister& reg) {
|
||||
return reg.type != SimpleDwarf::DwRegister::REG_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void CodeGenerator::gen_of_reg(const SimpleDwarf::DwRegister& reg) {
|
||||
switch(reg.type) {
|
||||
case SimpleDwarf::DwRegister::REG_UNDEFINED:
|
||||
os << undefined_register();
|
||||
// This function is not supposed to be called on an undefined
|
||||
// register
|
||||
throw UnhandledRegister();
|
||||
break;
|
||||
case SimpleDwarf::DwRegister::REG_REGISTER:
|
||||
os << ctx_of_dw_name(reg.reg)
|
||||
|
|
|
@ -48,6 +48,9 @@ class CodeGenerator {
|
|||
|
||||
void gen_lookup(const std::vector<LookupEntry>& entries);
|
||||
|
||||
bool check_reg_defined(const SimpleDwarf::DwRegister& reg);
|
||||
bool check_reg_valid(const SimpleDwarf::DwRegister& reg);
|
||||
|
||||
private:
|
||||
SimpleDwarf dwarf;
|
||||
std::ostream& os;
|
||||
|
|
Loading…
Reference in a new issue