eh_elf generator: now also producing global switch

This commit is contained in:
Théophile Bastian 2018-04-30 13:23:48 +02:00
parent 601fb2fcd0
commit 4b327c7c56
8 changed files with 137 additions and 27 deletions

View file

@ -1,5 +1,6 @@
#include "CodeGenerator.hpp"
#include "gen_context_struct.hpp"
#include "settings.hpp"
using namespace std;
@ -23,42 +24,71 @@ void CodeGenerator::gen_of_dwarf() {
os << CONTEXT_STRUCT_STR << '\n'
<< PRELUDE << '\n' << endl;
vector<LookupEntry> lookup_entries;
switch(settings::switch_generation_policy) {
case settings::SGP_SwitchPerFunc:
{
vector<LookupEntry> lookup_entries;
// A function per FDE
for(const auto& fde: dwarf.fde_list) {
LookupEntry cur_entry;
cur_entry.name = naming_scheme(fde);
cur_entry.beg = fde.beg_ip;
cur_entry.end = fde.end_ip;
lookup_entries.push_back(cur_entry);
// A function per FDE
for(const auto& fde: dwarf.fde_list) {
LookupEntry cur_entry;
cur_entry.name = naming_scheme(fde);
cur_entry.beg = fde.beg_ip;
cur_entry.end = fde.end_ip;
lookup_entries.push_back(cur_entry);
gen_of_fde(fde);
os << endl;
gen_function_of_fde(fde);
os << endl;
}
gen_lookup(lookup_entries);
break;
}
case settings::SGP_GlobalSwitch:
{
gen_unwind_func_header("_eh_elf");
for(const auto& fde: dwarf.fde_list) {
gen_switchpart_of_fde(fde);
}
gen_unwind_func_footer();
break;
}
}
gen_lookup(lookup_entries);
}
void CodeGenerator::gen_of_fde(const SimpleDwarf::Fde& fde) {
void CodeGenerator::gen_unwind_func_header(const std::string& name) {
os << "unwind_context_t "
<< naming_scheme(fde)
<< name
<< "(unwind_context_t ctx, uintptr_t pc) {\n"
<< "\tunwind_context_t out_ctx;\n"
<< "\tswitch(pc) {" << endl;
}
void CodeGenerator::gen_unwind_func_footer() {
os << "\t\tdefault: assert(0);\n"
<< "\t}\n"
<< "}" << endl;
}
void CodeGenerator::gen_function_of_fde(const SimpleDwarf::Fde& fde) {
gen_unwind_func_header(naming_scheme(fde));
gen_switchpart_of_fde(fde);
gen_unwind_func_footer();
}
void CodeGenerator::gen_switchpart_of_fde(const SimpleDwarf::Fde& fde) {
os << "\t\t/********** FDE: 0x" << std::hex << fde.fde_offset
<< ", PC = 0x" << fde.beg_ip << std::dec << " */" << std::endl;
for(size_t fde_row_id=0; fde_row_id < fde.rows.size(); ++fde_row_id)
{
uintptr_t up_bound = fde.end_ip;
uintptr_t up_bound = fde.end_ip - 1;
if(fde_row_id != fde.rows.size() - 1)
up_bound = fde.rows[fde_row_id + 1].ip - 1;
gen_of_row(fde.rows[fde_row_id], up_bound);
}
os << "\t\tdefault: assert(0);\n"
<< "\t}\n"
<< "}" << endl;
}
void CodeGenerator::gen_of_row(

View file

@ -31,7 +31,10 @@ class CodeGenerator {
};
void gen_of_dwarf();
void gen_of_fde(const SimpleDwarf::Fde& fde);
void gen_unwind_func_header(const std::string& name);
void gen_unwind_func_footer();
void gen_function_of_fde(const SimpleDwarf::Fde& fde);
void gen_switchpart_of_fde(const SimpleDwarf::Fde& fde);
void gen_of_row(
const SimpleDwarf::DwRow& row,
uintptr_t row_end);

View file

@ -28,6 +28,7 @@ SimpleDwarf DwarfReader::read() const {
SimpleDwarf::Fde DwarfReader::read_fde(const core::Fde& fde) const {
SimpleDwarf::Fde output;
output.fde_offset = fde.get_fde_offset();
output.beg_ip = fde.get_low_pc();
output.end_ip = fde.get_low_pc() + fde.get_func_length();

View file

@ -4,7 +4,7 @@ CXXFLAGS=$(CXXLOCS) -Wall -Wextra -std=c++14 -O2 -g
CXXLIBS=-lelf -ldwarf -ldwarfpp -lsrk31c++ -lc++fileno
TARGET=dwarf-assembly
OBJS=DwarfReader.o SimpleDwarf.o CodeGenerator.o main.o
OBJS=DwarfReader.o SimpleDwarf.o CodeGenerator.o settings.o main.o
###############################################################################

View file

@ -50,6 +50,7 @@ struct SimpleDwarf {
};
struct Fde {
uintptr_t fde_offset; ///< This FDE's offset in the original DWARF
uintptr_t beg_ip, ///< This FDE's start instruction pointer
end_ip; ///< This FDE's end instruction pointer
std::vector<DwRow> rows; ///< Dwarf rows for this FDE

View file

@ -8,17 +8,72 @@
#include "DwarfReader.hpp"
#include "CodeGenerator.hpp"
#include "settings.hpp"
using namespace std;
struct MainOptions {
std::string elf_path;
};
int main(int argc, char** argv) {
if(argc < 2) {
cerr << "Error: missing input file. Usage:" << endl
<< argv[0] << " path/to/binary.elf" << endl;
exit(1);
MainOptions options_parse(int argc, char** argv) {
MainOptions out;
bool seen_switch_gen_policy = false;
bool print_helptext = false;
int exit_status = -1;
for(int option_pos = 1; option_pos < argc; ++option_pos) {
std::string option(argv[option_pos]);
if(option.find("-") != 0) { // This is not an option argument
out.elf_path = option;
}
else if(option == "--help") {
print_helptext = true;
exit_status = 0;
}
else if(option == "--switch-per-func") {
seen_switch_gen_policy = true;
settings::switch_generation_policy =
settings::SGP_SwitchPerFunc;
}
else if(option == "--global-switch") {
seen_switch_gen_policy = true;
settings::switch_generation_policy =
settings::SGP_GlobalSwitch;
}
}
SimpleDwarf parsed_dwarf = DwarfReader(argv[1]).read();
if(!seen_switch_gen_policy) {
cerr << "Error: please use either --switch-per-func or "
<< "--global-switch." << endl;
print_helptext = true;
exit_status = 1;
}
if(out.elf_path.empty()) {
cerr << "Error: missing input file." << endl;
print_helptext = true;
exit_status = 1;
}
if(print_helptext) {
cerr << "Usage: "
<< argv[0]
<< " [--switch-per-func | --global-switch] elf_path"
<< endl;
}
if(exit_status >= 0)
exit(exit_status);
return out;
}
int main(int argc, char** argv) {
MainOptions opts = options_parse(argc, argv);
SimpleDwarf parsed_dwarf = DwarfReader(opts.elf_path).read();
CodeGenerator code_gen(
parsed_dwarf,

5
src/settings.cpp Normal file
View file

@ -0,0 +1,5 @@
#include "settings.hpp"
namespace settings {
SwitchGenerationPolicy switch_generation_policy = SGP_SwitchPerFunc;
}

15
src/settings.hpp Normal file
View file

@ -0,0 +1,15 @@
/** This compile unit holds a few global variables controlling the code
* generator's settings. These variables are used program-wide.
*/
#pragma once
namespace settings {
/// Controls how the eh_elf switches are generated
enum SwitchGenerationPolicy {
SGP_SwitchPerFunc, ///< One switch per function, plus a lookup function
SGP_GlobalSwitch ///< One big switch per ELF file
};
extern SwitchGenerationPolicy switch_generation_policy;
}