Use flags in context structures

This commit is contained in:
Théophile Bastian 2018-06-22 09:12:32 +02:00
parent b6ae4b2115
commit cd9ecafb4f
3 changed files with 92 additions and 28 deletions

View file

@ -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;

View file

@ -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 {
os << "\t\t\t" << "out_ctx.rsp = ";
gen_of_reg(row.cfa);
os << ';' << endl;
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;
}
os << "\t\t\t" << "out_ctx.rbp = ";
gen_of_reg(row.rbp);
os << ';' << endl;
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;
}
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";
// 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)

View file

@ -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;