diff --git a/.gitattributes b/.gitattributes index cdf835e7b6c97828826f46d48f5a9beea15d034b..744bbaafd5658922f472f44e7c0f644c9be9cbbd 100644 --- a/.gitattributes +++ b/.gitattributes @@ -280,6 +280,7 @@ libIRDB/test/create_variant.cpp -text libIRDB/test/create_variantir.cpp -text libIRDB/test/drop_variant.cpp -text libIRDB/test/dwarf2.h -text +libIRDB/test/eh_frame.hpp -text libIRDB/test/fill_in_cfg.cpp -text libIRDB/test/fill_in_indtargs.cpp -text libIRDB/test/fill_in_indtargs.hpp -text diff --git a/libIRDB/src/core/eh.cpp b/libIRDB/src/core/eh.cpp index 036b94eda4d9ed4f968369d9a64b390dbeba45a5..0b39d6da51f7a190de2929c5f64311857c9cc246 100644 --- a/libIRDB/src/core/eh.cpp +++ b/libIRDB/src/core/eh.cpp @@ -32,12 +32,11 @@ using namespace std; bool libIRDB::operator<(const EhProgram_t&a, const EhProgram_t&b) { - return tie(a.cie_program,a.fde_program,a.code_alignment_factor,a.data_alignment_factor,a.return_register, a.ptrsize) + return tie(a.cie_program,a.fde_program,a.code_alignment_factor,a.data_alignment_factor,a.return_register, a.ptrsize, a.GetRelocations()) < - tie(b.cie_program,b.fde_program,b.code_alignment_factor,b.data_alignment_factor,b.return_register, b.ptrsize); + tie(b.cie_program,b.fde_program,b.code_alignment_factor,b.data_alignment_factor,b.return_register, b.ptrsize, b.GetRelocations()); } - namespace std { template<> diff --git a/libIRDB/test/SConscript b/libIRDB/test/SConscript index 9575e20c3f62add5566e3d8a06bc0e178641e4c8..01ec9b4d8a6a9beae1f355560841cbe3c4b1d1b3 100644 --- a/libIRDB/test/SConscript +++ b/libIRDB/test/SConscript @@ -32,13 +32,17 @@ if 'build_tools' not in myenv or myenv['build_tools'] is None or int(myenv['buil install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) Default(install) + pgm=myenv.Program("fill_in_cfg.exe", Split("split_eh_frame.cpp fill_in_cfg.cpp"), LIBPATH=LIBPATH, LIBS=LIBS) + install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) + Default(install) + pgm=myenv.Program("fix_calls.exe", ehframe+Split("fix_calls.cpp"), LIBPATH=LIBPATH, LIBS=LIBS) install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) Default(install) # most programs go to $sectrans/bin pgms='''print_variant list_programs create_variant create_variantir read_variantir clone - drop_variant generate_spri fill_in_cfg unfix_calls + drop_variant generate_spri unfix_calls find_strings build_callgraph build_preds rename_function pin_address mark_functions_safe ''' for i in Split(pgms): diff --git a/libIRDB/test/eh_frame.hpp b/libIRDB/test/eh_frame.hpp new file mode 100644 index 0000000000000000000000000000000000000000..81d23c53cb06e4e34ecde6d1786d445668c4e73d --- /dev/null +++ b/libIRDB/test/eh_frame.hpp @@ -0,0 +1,393 @@ +#ifndef eh_frame_hpp +#define eh_frame_hpp + +#include <libIRDB-core.hpp> +#include <iostream> +#include <iomanip> +#include <fstream> +#include <limits> +#include <stdlib.h> +#include <string.h> +#include <map> +#include <assert.h> +#include <elf.h> +#include <algorithm> +#include <memory> + +#include <exeio.h> +#include "beaengine/BeaEngine.h" +#include "dwarf2.h" + + + + +typedef std::map<libIRDB::virtual_offset_t, libIRDB::Instruction_t*> OffsetMap_t; + +template <int ptrsize> +class eh_frame_util_t +{ + public: + template <class T> + static bool read_type(T &value, unsigned int &position, const uint8_t* const data, const int max); + template <class T> + static bool read_type_with_encoding + (const uint8_t encoding, T &value, + unsigned int &position, + const uint8_t* const data, + const int max, + const uint64_t section_start_addr ); + + static bool read_string + (std::string &s, + unsigned int & position, + const uint8_t* const data, + const int max); + + + // see https://en.wikipedia.org/wiki/LEB128 + static bool read_uleb128 + ( uint64_t &result, + uint32_t& position, + const uint8_t* const data, + const uint32_t max); + + // see https://en.wikipedia.org/wiki/LEB128 + static bool read_sleb128 ( + int64_t &result, + uint32_t & position, + const uint8_t* const data, + const uint32_t max); + + static bool read_length( + uint64_t &act_length, + unsigned int &position, + const uint8_t* const data, + const uint32_t max); +}; + +template <int ptrsize> +class eh_program_insn_t +{ + public: + + eh_program_insn_t() ; + eh_program_insn_t(const std::string &s) ; + + void print(uint64_t &pc, int64_t caf=1) const; + + void push_byte(uint8_t c) ; + + static void print_uleb_operand( + uint32_t pos, + const uint8_t* const data, + const uint32_t max) ; + + static void print_sleb_operand( + uint32_t pos, + const uint8_t* const data, + const uint32_t max) ; + + bool parse_insn( + uint8_t opcode, + uint32_t& pos, + const uint8_t* const data, + const uint32_t &max); + + bool isNop() const ; + bool isRestoreState() const ; + bool isRememberState() const ; + + bool Advance(uint64_t &cur_addr, uint64_t CAF) const ; + + const std::vector<uint8_t>& GetBytes() const ; + std::vector<uint8_t>& GetBytes() ; + + private: + + std::vector<uint8_t> program_bytes; +}; + +template <int ptrsize> +bool operator<(const eh_program_insn_t<ptrsize>& a, const eh_program_insn_t<ptrsize>& b); + +template <int ptrsize> +class eh_program_t +{ + public: + void push_insn(const eh_program_insn_t<ptrsize> &i); + + void print(const uint64_t start_addr=0) const; + + bool parse_program( + const uint32_t& program_start_position, + const uint8_t* const data, + const uint32_t &max_program_pos); + const std::vector<eh_program_insn_t <ptrsize> >& GetInstructions() const ; + std::vector<eh_program_insn_t <ptrsize> >& GetInstructions() ; + private: + std::vector<eh_program_insn_t <ptrsize> > instructions; +}; + +template <int ptrsize> +bool operator<(const eh_program_t<ptrsize>& a, const eh_program_t<ptrsize>& b); + +template <int ptrsize> +class cie_contents_t : eh_frame_util_t<ptrsize> +{ + private: + uint64_t cie_position; + uint64_t length; + uint8_t cie_id; + uint8_t cie_version; + std::string augmentation; + uint64_t code_alignment_factor; + int64_t data_alignment_factor; + uint64_t return_address_register_column; + uint64_t augmentation_data_length; + uint8_t personality_encoding; + uint64_t personality; + uint8_t lsda_encoding; + uint8_t fde_encoding; + eh_program_t<ptrsize> eh_pgm; + + public: + + cie_contents_t() ; + + const eh_program_t<ptrsize>& GetProgram() const ; + uint64_t GetCAF() const ; + int64_t GetDAF() const ; + uint64_t GetPersonality() const ; + uint64_t GetReturnRegister() const ; + + std::string GetAugmentation() const ; + uint8_t GetLSDAEncoding() const ; + uint8_t GetFDEEncoding() const ; + + bool parse_cie( + const uint32_t &cie_position, + const uint8_t* const data, + const uint32_t max, + const uint64_t eh_addr); + void print() const ; + void build_ir(libIRDB::Instruction_t* insn) const; +}; + +template <int ptrsize> +class lsda_call_site_action_t : private eh_frame_util_t<ptrsize> +{ + private: + int64_t action; + + public: + lsda_call_site_action_t() ; + int64_t GetAction() const ; + + bool parse_lcsa(uint32_t& pos, const uint8_t* const data, const uint64_t max, bool &end); + void print() const; +}; + +template <int ptrsize> +bool operator< (const lsda_call_site_action_t <ptrsize> &lhs, const lsda_call_site_action_t <ptrsize> &rhs); + +template <int ptrsize> +class lsda_type_table_entry_t: private eh_frame_util_t<ptrsize> +{ + private: + uint64_t pointer_to_typeinfo; + uint64_t tt_encoding; + uint64_t tt_encoding_size; + + public: + lsda_type_table_entry_t() ; + + uint64_t GetTypeInfoPointer() const ; + uint64_t GetEncoding() const ; + uint64_t GetTTEncodingSize() const ; + + bool parse( + const uint64_t p_tt_encoding, + const uint64_t tt_pos, + const uint64_t index, + const uint8_t* const data, + const uint64_t max, + const uint64_t data_addr + ); + + void print() const; + +}; + +template <int ptrsize> +class lsda_call_site_t : private eh_frame_util_t<ptrsize> +{ + private: + uint64_t call_site_offset; + uint64_t call_site_addr; + uint64_t call_site_length; + uint64_t call_site_end_addr; + uint64_t landing_pad_offset; + uint64_t landing_pad_addr; + uint64_t action; + uint64_t action_table_offset; + uint64_t action_table_addr; + + std::vector<lsda_call_site_action_t <ptrsize> > action_table; + + public: + lsda_call_site_t() ; + + int64_t GetMaxTypeTableIndex() const; + + uint64_t GetLandingPadAddress() const { return landing_pad_addr ; } + + + bool parse_lcs( + const uint64_t action_table_start_addr, + const uint64_t cs_table_start_addr, + const uint8_t cs_table_encoding, + uint32_t &pos, + const uint8_t* const data, + const uint64_t max, /* call site table max */ + const uint64_t data_addr, + const uint64_t landing_pad_base_addr, + const uint64_t gcc_except_table_max); + + void print() const; + + bool appliesTo(const libIRDB::Instruction_t* insn) const; + + void build_ir(libIRDB::Instruction_t* insn, const std::vector<lsda_type_table_entry_t <ptrsize> > &type_table, const uint8_t& tt_encoding, const OffsetMap_t& om, libIRDB::FileIR_t* firp) const; +}; + + +// short hand for a vector of call sites +template <int ptrsize> using call_site_table_t = std::vector<lsda_call_site_t <ptrsize> > ; + +template <int ptrsize> +class lsda_t : private eh_frame_util_t<ptrsize> +{ + private: + uint8_t landing_pad_base_encoding; + uint64_t landing_pad_base_addr; // often ommitted. when ommitted, filled in from FDE region start. + uint8_t type_table_encoding; + uint64_t type_table_offset; + uint64_t type_table_addr; + uint8_t cs_table_encoding; + uint64_t cs_table_start_offset; + uint64_t cs_table_start_addr; + uint64_t cs_table_length; + uint64_t cs_table_end_addr; + uint64_t action_table_start_addr; + call_site_table_t <ptrsize> call_site_table; + std::vector<lsda_type_table_entry_t <ptrsize> > type_table; + + public: + + uint8_t GetTTEncoding() const ; + + lsda_t() ; + + bool parse_lsda(const uint64_t lsda_addr, const libIRDB::DataScoop_t* gcc_except_scoop, const uint64_t fde_region_start); + void print() const; + void build_ir(libIRDB::Instruction_t* insn, const OffsetMap_t& om, libIRDB::FileIR_t* firp) const; + + const call_site_table_t<ptrsize> GetCallSites() const { return call_site_table;} + +}; + + + +template <int ptrsize> +class fde_contents_t : eh_frame_util_t<ptrsize> +{ + uint32_t fde_position; + uint32_t cie_position; + uint64_t length; + uint8_t id; + uint64_t fde_start_addr; + uint64_t fde_end_addr; + uint64_t fde_range_len; + uint64_t lsda_addr; + + + lsda_t<ptrsize> lsda; + eh_program_t<ptrsize> eh_pgm; + cie_contents_t<ptrsize> cie_info; + + public: + fde_contents_t() ; + + bool appliesTo(const libIRDB::Instruction_t* insn) const; + + uint64_t GetFDEStartAddress() const ; + + const cie_contents_t<ptrsize>& GetCIE() const ; + cie_contents_t<ptrsize>& GetCIE() ; + + const eh_program_t<ptrsize>& GetProgram() const ; + eh_program_t<ptrsize>& GetProgram() ; + + const lsda_t<ptrsize>& GetLSDA() const { return lsda; } + + bool parse_fde( + const uint32_t &fde_position, + const uint32_t &cie_position, + const uint8_t* const data, + const uint64_t max, + const uint64_t eh_addr, + const libIRDB::DataScoop_t* gcc_except_scoop); + + void print() const; + + void build_ir(libIRDB::Instruction_t* insn, const OffsetMap_t &om, libIRDB::FileIR_t* firp) const; + +}; + +class split_eh_frame_t +{ + public: + + virtual bool parse()=0; + virtual void build_ir() const =0; + virtual void print() const=0; + virtual libIRDB::Instruction_t* find_lp(libIRDB::Instruction_t*) const =0; + + static std::unique_ptr<split_eh_frame_t> factory(libIRDB::FileIR_t *firp); + +}; + +template <int ptrsize> +class split_eh_frame_impl_t : public split_eh_frame_t +{ + private: + + libIRDB::FileIR_t* firp; + libIRDB::DataScoop_t* eh_frame_scoop; + libIRDB::DataScoop_t* eh_frame_hdr_scoop; + libIRDB::DataScoop_t* gcc_except_table_scoop; + OffsetMap_t offset_to_insn_map; + std::vector<cie_contents_t <ptrsize> > cies; + std::vector<fde_contents_t <ptrsize> > fdes; + + + bool init_offset_map(); + + bool iterate_fdes(); + + public: + + split_eh_frame_impl_t(libIRDB::FileIR_t* p_firp); + + bool parse(); + + void print() const; + + void build_ir() const; + + libIRDB::Instruction_t* find_lp(libIRDB::Instruction_t*) const ; +}; + +void split_eh_frame(libIRDB::FileIR_t* firp); + +#endif diff --git a/libIRDB/test/fill_in_cfg.cpp b/libIRDB/test/fill_in_cfg.cpp index d27abadc1468a1a93bd1c5fac40bbbe3f2f5d5db..a6263a9e45d8021feefa6071599a09695afde9e0 100644 --- a/libIRDB/test/fill_in_cfg.cpp +++ b/libIRDB/test/fill_in_cfg.cpp @@ -27,13 +27,11 @@ #include <assert.h> #include <sys/mman.h> #include <ctype.h> - #include <exeio.h> #include "elfio/elfio.hpp" #include "elfio/elfio_dump.hpp" - - #include "beaengine/BeaEngine.h" +#include "eh_frame.hpp" int odd_target_count=0; int bad_target_count=0; @@ -555,6 +553,61 @@ void fill_in_scoops(FileIR_t *firp) } +void fill_in_landing_pads(FileIR_t *firp) +{ + const auto eh_frame_rep_ptr = split_eh_frame_t::factory(firp); + eh_frame_rep_ptr->parse(); + eh_frame_rep_ptr->print(); + cout<<"Completed eh-frame parsing"<<endl; + + map<Function_t*,set<Instruction_t*> > insns_to_add_to_funcs; + + for_each(firp->GetInstructions().begin(), firp->GetInstructions().end(), [&](Instruction_t* t) + { + if(t->GetFunction()==NULL) + return; + auto lp=eh_frame_rep_ptr->find_lp(t); + if(lp && lp->GetFunction()==NULL) + insns_to_add_to_funcs[t->GetFunction()].insert(lp); + }); + + + for_each(insns_to_add_to_funcs.begin(), insns_to_add_to_funcs.end(), [&](pair<Function_t* const,set<Instruction_t*> > & p) + { + auto & func=p.first; + auto insns=p.second; /* copy */ + auto insn_count=0; + + while(insns.size()>0 ) + { + auto it=insns.begin(); + auto insn=*it; + insns.erase(it); + + assert(insn); + if(insn->GetFunction()!=NULL) + continue; + + auto lp=eh_frame_rep_ptr->find_lp(insn); + if(lp && lp->GetFunction()==NULL) + insns.insert(lp); + + insn->SetFunction(func); + cout<<" Adding "<<insn->GetBaseID()<<":"<<insn->getDisassembly()<<"@"<<hex<<insn->GetAddress()->GetVirtualOffset()<<dec<<endl; + insn_count++; + + + auto target=insn->GetTarget(); + auto fallthru=insn->GetFallthrough(); + + if(target) insns.insert(target); + if(fallthru) insns.insert(fallthru); + } + cout<<"Found LP outside of function "<<func->GetName()<<" added "<<insn_count<<" instructions"<<endl; + }); + +} + main(int argc, char* argv[]) { @@ -606,6 +659,7 @@ main(int argc, char* argv[]) fill_in_cfg(firp); fill_in_scoops(firp); + fill_in_landing_pads(firp); // write the DB back and commit our changes firp->WriteToDB(); diff --git a/libIRDB/test/split_eh_frame.cpp b/libIRDB/test/split_eh_frame.cpp index a60b44c0c8abf19f1c4356e27e8de2243f8f36a6..8b86fa8dfa9c72ce7766d18fd65fd2ca4c157c55 100644 --- a/libIRDB/test/split_eh_frame.cpp +++ b/libIRDB/test/split_eh_frame.cpp @@ -15,793 +15,803 @@ #include "beaengine/BeaEngine.h" #include "dwarf2.h" - +#include "eh_frame.hpp" using namespace std; using namespace EXEIO; using namespace libIRDB; -typedef map<virtual_offset_t, Instruction_t*> OffsetMap_t; template <int ptrsize> -class eh_frame_util_t +template <class T> +bool eh_frame_util_t<ptrsize>::read_type(T &value, unsigned int &position, const uint8_t* const data, const int max) { - public: - template <class T> - static bool read_type(T &value, unsigned int &position, const uint8_t* const data, const int max) - { - if(position + sizeof(T) > max) return true; + if(position + sizeof(T) > max) return true; - - // typecast to the right type - auto ptr=(const T*)&data[position]; + + // typecast to the right type + auto ptr=(const T*)&data[position]; - // set output parameters - position+=sizeof(T); - value=*ptr; + // set output parameters + position+=sizeof(T); + value=*ptr; - return false; - - } - template <class T> - static bool read_type_with_encoding - (const uint8_t encoding, T &value, - unsigned int &position, - const uint8_t* const data, - const int max, - const uint64_t section_start_addr ) + return false; + +} +template <int ptrsize> +template <class T> +bool eh_frame_util_t<ptrsize>::read_type_with_encoding + (const uint8_t encoding, T &value, + unsigned int &position, + const uint8_t* const data, + const int max, + const uint64_t section_start_addr ) +{ + auto orig_position=position; + auto encoding_lower8=encoding&0xf; + auto encoding_upper8=encoding&0xf0; + value=0; + switch(encoding_lower8) { - auto orig_position=position; - auto encoding_lower8=encoding&0xf; - auto encoding_upper8=encoding&0xf0; - value=0; - switch(encoding_lower8) - { - case DW_EH_PE_omit : - return true; + case DW_EH_PE_omit : + return true; - case DW_EH_PE_uleb128: - { - auto newval=uint64_t(0); - if(eh_frame_util_t<ptrsize>::read_uleb128(newval,position,data,max)) - return true; - value=newval; - break; - } - case DW_EH_PE_sleb128: - { - auto newval=int64_t(0); - if(eh_frame_util_t<ptrsize>::read_sleb128(newval,position,data,max)) - return true; - value=newval; - break; - } - case DW_EH_PE_udata2 : - { - auto newval=uint16_t(0); - if(eh_frame_util_t<ptrsize>::read_type(newval,position,data,max)) - return true; - value=newval; - break; - } - case DW_EH_PE_udata4 : - { - auto newval=uint32_t(0); - if(eh_frame_util_t<ptrsize>::read_type(newval,position,data,max)) - return true; - value=newval; - break; - } - case DW_EH_PE_udata8 : - { - auto newval=uint64_t(0); - if(eh_frame_util_t<ptrsize>::read_type(newval,position,data,max)) - return true; - value=newval; - break; - } - case DW_EH_PE_absptr: - { - if(ptrsize==8) - { - if(eh_frame_util_t<ptrsize>::read_type_with_encoding(DW_EH_PE_udata8, value, position, data, max, section_start_addr)) - return true; - break; - } - else if(ptrsize==4) - { - if(eh_frame_util_t<ptrsize>::read_type_with_encoding(DW_EH_PE_udata4, value, position, data, max, section_start_addr)) - return true; - break; - } - assert(0); - - } - case DW_EH_PE_sdata2 : - { - auto newval=int16_t(0); - if(eh_frame_util_t<ptrsize>::read_type(newval,position,data,max)) - return true; - value=newval; - break; - } - case DW_EH_PE_sdata4 : + case DW_EH_PE_uleb128: + { + auto newval=uint64_t(0); + if(eh_frame_util_t<ptrsize>::read_uleb128(newval,position,data,max)) + return true; + value=newval; + break; + } + case DW_EH_PE_sleb128: + { + auto newval=int64_t(0); + if(eh_frame_util_t<ptrsize>::read_sleb128(newval,position,data,max)) + return true; + value=newval; + break; + } + case DW_EH_PE_udata2 : + { + auto newval=uint16_t(0); + if(eh_frame_util_t<ptrsize>::read_type(newval,position,data,max)) + return true; + value=newval; + break; + } + case DW_EH_PE_udata4 : + { + auto newval=uint32_t(0); + if(eh_frame_util_t<ptrsize>::read_type(newval,position,data,max)) + return true; + value=newval; + break; + } + case DW_EH_PE_udata8 : + { + auto newval=uint64_t(0); + if(eh_frame_util_t<ptrsize>::read_type(newval,position,data,max)) + return true; + value=newval; + break; + } + case DW_EH_PE_absptr: + { + if(ptrsize==8) { - auto newval=int32_t(0); - if(eh_frame_util_t<ptrsize>::read_type(newval,position,data,max)) + if(eh_frame_util_t<ptrsize>::read_type_with_encoding(DW_EH_PE_udata8, value, position, data, max, section_start_addr)) return true; - value=newval; break; } - case DW_EH_PE_sdata8 : + else if(ptrsize==4) { - auto newval=int64_t(0); - if(read_type(newval,position,data,max)) + if(eh_frame_util_t<ptrsize>::read_type_with_encoding(DW_EH_PE_udata4, value, position, data, max, section_start_addr)) return true; - value=newval; break; } - - case DW_EH_PE_signed : - default: - assert(0); - }; - - switch(encoding_upper8) + assert(0); + + } + case DW_EH_PE_sdata2 : { - case DW_EH_PE_absptr: - break; - case DW_EH_PE_pcrel : - value+=section_start_addr+orig_position; - break; - case DW_EH_PE_textrel: - case DW_EH_PE_datarel: - case DW_EH_PE_funcrel: - case DW_EH_PE_aligned: - case DW_EH_PE_indirect: - default: - assert(0); + auto newval=int16_t(0); + if(eh_frame_util_t<ptrsize>::read_type(newval,position,data,max)) return true; + value=newval; + break; } - return false; - } - - static bool read_string - (string &s, - unsigned int & position, - const uint8_t* const data, - const int max) - { - while(data[position]!='\0' && position < max) + case DW_EH_PE_sdata4 : { - s+=data[position]; - position++; + auto newval=int32_t(0); + if(eh_frame_util_t<ptrsize>::read_type(newval,position,data,max)) + return true; + value=newval; + break; } + case DW_EH_PE_sdata8 : + { + auto newval=int64_t(0); + if(read_type(newval,position,data,max)) + return true; + value=newval; + break; + } + + case DW_EH_PE_signed : + default: + assert(0); + }; + switch(encoding_upper8) + { + case DW_EH_PE_absptr: + break; + case DW_EH_PE_pcrel : + value+=section_start_addr+orig_position; + break; + case DW_EH_PE_textrel: + case DW_EH_PE_datarel: + case DW_EH_PE_funcrel: + case DW_EH_PE_aligned: + case DW_EH_PE_indirect: + default: + assert(0); + return true; + } + return false; +} + +template <int ptrsize> +bool eh_frame_util_t<ptrsize>::read_string + (string &s, + unsigned int & position, + const uint8_t* const data, + const int max) +{ + while(data[position]!='\0' && position < max) + { + s+=data[position]; position++; - return (position>max); } + position++; + return (position>max); +} + - // see https://en.wikipedia.org/wiki/LEB128 - static bool read_uleb128 - ( uint64_t &result, - uint32_t& position, - const uint8_t* const data, - const uint32_t max) +// see https://en.wikipedia.org/wiki/LEB128 +template <int ptrsize> +bool eh_frame_util_t<ptrsize>::read_uleb128 + ( uint64_t &result, + uint32_t& position, + const uint8_t* const data, + const uint32_t max) +{ + result = 0; + auto shift = 0; + while( position < max ) { - result = 0; - auto shift = 0; - while( position < max ) - { - auto byte = data[position]; - position++; - result |= ( ( byte & 0x7f ) << shift); - if ( ( byte & 0x80) == 0) - break; - shift += 7; - } - return ( position > max ); - + auto byte = data[position]; + position++; + result |= ( ( byte & 0x7f ) << shift); + if ( ( byte & 0x80) == 0) + break; + shift += 7; } - // see https://en.wikipedia.org/wiki/LEB128 - static bool read_sleb128 ( - int64_t &result, - uint32_t & position, - const uint8_t* const data, - const uint32_t max) - { - result = 0; - auto shift = 0; - auto size = 64; // number of bits in signed integer; - auto byte=uint8_t(0); - do - { - byte = data [position]; - position++; - result |= ((byte & 0x7f)<< shift); - shift += 7; - } while( (byte & 0x80) != 0); - - /* sign bit of byte is second high order bit (0x40) */ - if ((shift < size) && ( (byte & 0x40) !=0 /* sign bit of byte is set */)) - /* sign extend */ - result |= - (1 << shift); - return ( position > max ); + return ( position > max ); - } - - static bool read_length( - uint64_t &act_length, - unsigned int &position, - const uint8_t* const data, - const uint32_t max) +} +// see https://en.wikipedia.org/wiki/LEB128 +template <int ptrsize> +bool eh_frame_util_t<ptrsize>::read_sleb128 ( + int64_t &result, + uint32_t & position, + const uint8_t* const data, + const uint32_t max) +{ + result = 0; + auto shift = 0; + auto size = 64; // number of bits in signed integer; + auto byte=uint8_t(0); + do { - auto eh_frame_scoop_data=data; - auto length=uint32_t(0); - auto length_64bit=uint64_t(0); - if(read_type(length,position, eh_frame_scoop_data, max)) - return true; + byte = data [position]; + position++; + result |= ((byte & 0x7f)<< shift); + shift += 7; + } while( (byte & 0x80) != 0); - if(length==0xffffffff) - { - if(read_type(length_64bit,position, eh_frame_scoop_data, max)) - return true; - act_length=length_64bit; - } - else - act_length=length; + /* sign bit of byte is second high order bit (0x40) */ + if ((shift < size) && ( (byte & 0x40) !=0 /* sign bit of byte is set */)) + /* sign extend */ + result |= - (1 << shift); + return ( position > max ); - return false; - } -}; +} template <int ptrsize> -class eh_program_insn_t +bool eh_frame_util_t<ptrsize>::read_length( + uint64_t &act_length, + unsigned int &position, + const uint8_t* const data, + const uint32_t max) { - public: - - eh_program_insn_t() { } - eh_program_insn_t(const string &s) - : program_bytes(s.begin(), next(s.begin(), s.size())) - { } + auto eh_frame_scoop_data=data; + auto length=uint32_t(0); + auto length_64bit=uint64_t(0); + if(read_type(length,position, eh_frame_scoop_data, max)) + return true; - void print(uint64_t &pc, int64_t caf=1) const + if(length==0xffffffff) { - // make sure uint8_t is an unsigned char. - static_assert(std::is_same<unsigned char, uint8_t>::value, "uint8_t is not unsigned char"); + if(read_type(length_64bit,position, eh_frame_scoop_data, max)) + return true; + act_length=length_64bit; + } + else + act_length=length; + + return false; +} + +template <int ptrsize> +eh_program_insn_t<ptrsize>::eh_program_insn_t() { } + +template <int ptrsize> +eh_program_insn_t<ptrsize>::eh_program_insn_t(const string &s) + : program_bytes(s.begin(), next(s.begin(), s.size())) +{ } - auto data=program_bytes.data(); - auto opcode=program_bytes[0]; - auto opcode_upper2=(uint8_t)(opcode >> 6); - auto opcode_lower6=(uint8_t)(opcode & (0x3f)); - auto pos=uint32_t(1); - auto max=program_bytes.size(); +template <int ptrsize> +void eh_program_insn_t<ptrsize>::print(uint64_t &pc, int64_t caf) const +{ + // make sure uint8_t is an unsigned char. + static_assert(std::is_same<unsigned char, uint8_t>::value, "uint8_t is not unsigned char"); + + auto data=program_bytes.data(); + auto opcode=program_bytes[0]; + auto opcode_upper2=(uint8_t)(opcode >> 6); + auto opcode_lower6=(uint8_t)(opcode & (0x3f)); + auto pos=uint32_t(1); + auto max=program_bytes.size(); - switch(opcode_upper2) + switch(opcode_upper2) + { + case 1: { - case 1: - { - // case DW_CFA_advance_loc: - pc+=(opcode_lower6*caf); - cout<<" cfa_advance_loc "<<dec<<+opcode_lower6<<" to "<<hex<<pc<<endl; - break; - } - case 2: - { - uint64_t uleb=0; - if(eh_frame_util_t<ptrsize>::read_uleb128(uleb, pos, data, max)) - return; - // case DW_CFA_offset: - cout<<" cfa_offset "<<dec<<uleb<<endl; - break; - } - case 3: - { - // case DW_CFA_restore (register #): - cout<<" cfa_restore"<<endl; - break; - } - case 0: + // case DW_CFA_advance_loc: + pc+=(opcode_lower6*caf); + cout<<" cfa_advance_loc "<<dec<<+opcode_lower6<<" to "<<hex<<pc<<endl; + break; + } + case 2: + { + uint64_t uleb=0; + if(eh_frame_util_t<ptrsize>::read_uleb128(uleb, pos, data, max)) + return; + // case DW_CFA_offset: + cout<<" cfa_offset "<<dec<<uleb<<endl; + break; + } + case 3: + { + // case DW_CFA_restore (register #): + cout<<" cfa_restore"<<endl; + break; + } + case 0: + { + switch(opcode_lower6) { - switch(opcode_lower6) - { - - case DW_CFA_nop: - cout<<" nop" <<endl; - break; - case DW_CFA_remember_state: - cout<<" remember_state" <<endl; - break; - case DW_CFA_restore_state: - cout<<" restore_state" <<endl; - break; - - // takes single uleb128 - case DW_CFA_undefined: - cout<<" undefined" ; - print_uleb_operand(pos,data,max); - cout<<endl; - break; - case DW_CFA_same_value: - cout<<" same_value "; - print_uleb_operand(pos,data,max); - cout<<endl; - break; - case DW_CFA_restore_extended: - cout<<" restore_extended "; - print_uleb_operand(pos,data,max); - cout<<endl; - break; - case DW_CFA_def_cfa_register: - cout<<" def_cfa_register "; - print_uleb_operand(pos,data,max); - cout<<endl; - break; - case DW_CFA_GNU_args_size: - cout<<" GNU_arg_size "; - print_uleb_operand(pos,data,max); - cout<<endl; - break; - case DW_CFA_def_cfa_offset: - cout<<" def_cfa_offset "; - print_uleb_operand(pos,data,max); - cout<<endl; - break; - - case DW_CFA_set_loc: - { - auto arg=uintptr_t(0xDEADBEEF); - switch(ptrsize) - { - case 4: - arg=*(uint32_t*)data[pos]; break; - case 8: - arg=*(uint64_t*)data[pos]; break; - } - cout<<" set_loc "<<hex<<arg<<endl; - break; - } - case DW_CFA_advance_loc1: - { - auto loc=*(uint8_t*)(&data[pos]); - pc+=(loc*caf); - cout<<" advance_loc1 "<<+loc<<" to " <<pc << endl; - break; - } + case DW_CFA_nop: + cout<<" nop" <<endl; + break; + case DW_CFA_remember_state: + cout<<" remember_state" <<endl; + break; + case DW_CFA_restore_state: + cout<<" restore_state" <<endl; + break; - case DW_CFA_advance_loc2: - { - auto loc=*(uint16_t*)(&data[pos]); - pc+=(loc*caf); - cout<<" advance_loc2 "<<+loc<<" to " <<pc << endl; - break; - } + // takes single uleb128 + case DW_CFA_undefined: + cout<<" undefined" ; + print_uleb_operand(pos,data,max); + cout<<endl; + break; + + case DW_CFA_same_value: + cout<<" same_value "; + print_uleb_operand(pos,data,max); + cout<<endl; + break; + case DW_CFA_restore_extended: + cout<<" restore_extended "; + print_uleb_operand(pos,data,max); + cout<<endl; + break; + case DW_CFA_def_cfa_register: + cout<<" def_cfa_register "; + print_uleb_operand(pos,data,max); + cout<<endl; + break; + case DW_CFA_GNU_args_size: + cout<<" GNU_arg_size "; + print_uleb_operand(pos,data,max); + cout<<endl; + break; + case DW_CFA_def_cfa_offset: + cout<<" def_cfa_offset "; + print_uleb_operand(pos,data,max); + cout<<endl; + break; - case DW_CFA_advance_loc4: - { - auto loc=*(uint32_t*)(&data[pos]); - pc+=(loc*caf); - cout<<" advance_loc4 "<<+loc<<" to " <<pc << endl; - break; - } - case DW_CFA_offset_extended: - cout<<" offset_extended "; - print_uleb_operand(pos,data,max); - print_uleb_operand(pos,data,max); - cout<<endl; - break; - case DW_CFA_register: - cout<<" register "; - print_uleb_operand(pos,data,max); - print_uleb_operand(pos,data,max); - cout<<endl; - break; - case DW_CFA_def_cfa: - cout<<" def_cfa "; - print_uleb_operand(pos,data,max); - print_uleb_operand(pos,data,max); - cout<<endl; - break; - case DW_CFA_def_cfa_sf: - cout<<" def_cfa_sf "; - print_uleb_operand(pos,data,max); - print_sleb_operand(pos,data,max); - cout<<endl; - break; - - case DW_CFA_def_cfa_expression: - { - auto uleb=uint64_t(0); - if(eh_frame_util_t<ptrsize>::read_uleb128(uleb, pos, data, max)) - return ; - cout<<" def_cfa_expression "<<dec<<uleb<<endl; - pos+=uleb; // doing this old school for now, as we aren't printing the expression. - break; - } - case DW_CFA_expression: - { - auto uleb1=uint64_t(0); - auto uleb2=uint64_t(0); - if(eh_frame_util_t<ptrsize>::read_uleb128(uleb1, pos, data, max)) - return ; - if(eh_frame_util_t<ptrsize>::read_uleb128(uleb2, pos, data, max)) - return ; - cout<<" expression "<<dec<<uleb1<<" "<<uleb2<<endl; - pos+=uleb2; - break; - } - case DW_CFA_val_expression: - { - auto uleb1=uint64_t(0); - auto uleb2=uint64_t(0); - if(eh_frame_util_t<ptrsize>::read_uleb128(uleb1, pos, data, max)) - return ; - if(eh_frame_util_t<ptrsize>::read_uleb128(uleb2, pos, data, max)) - return ; - cout<<" val_expression "<<dec<<uleb1<<" "<<uleb2<<endl; - pos+=uleb2; - break; - } - case DW_CFA_def_cfa_offset_sf: - { - auto leb=int64_t(0); - if(eh_frame_util_t<ptrsize>::read_sleb128(leb, pos, data, max)) - return ; - cout<<" def_cfa_offset_sf "<<dec<<leb; - break; - } - case DW_CFA_offset_extended_sf: + case DW_CFA_set_loc: + { + auto arg=uintptr_t(0xDEADBEEF); + switch(ptrsize) { - auto uleb1=uint64_t(0); - auto sleb2=int64_t(0); - if(eh_frame_util_t<ptrsize>::read_uleb128(uleb1, pos, data, max)) - return ; - if(eh_frame_util_t<ptrsize>::read_sleb128(sleb2, pos, data, max)) - return ; - cout<<" offset_extended_sf "<<dec<<uleb1<<" "<<sleb2<<endl; - break; + case 4: + arg=*(uint32_t*)data[pos]; break; + case 8: + arg=*(uint64_t*)data[pos]; break; } + cout<<" set_loc "<<hex<<arg<<endl; + break; + } + case DW_CFA_advance_loc1: + { + auto loc=*(uint8_t*)(&data[pos]); + pc+=(loc*caf); + cout<<" advance_loc1 "<<+loc<<" to " <<pc << endl; + break; + } + case DW_CFA_advance_loc2: + { + auto loc=*(uint16_t*)(&data[pos]); + pc+=(loc*caf); + cout<<" advance_loc2 "<<+loc<<" to " <<pc << endl; + break; + } - /* SGI/MIPS specific */ - case DW_CFA_MIPS_advance_loc8: + case DW_CFA_advance_loc4: + { + auto loc=*(uint32_t*)(&data[pos]); + pc+=(loc*caf); + cout<<" advance_loc4 "<<+loc<<" to " <<pc << endl; + break; + } + case DW_CFA_offset_extended: + cout<<" offset_extended "; + print_uleb_operand(pos,data,max); + print_uleb_operand(pos,data,max); + cout<<endl; + break; + case DW_CFA_register: + cout<<" register "; + print_uleb_operand(pos,data,max); + print_uleb_operand(pos,data,max); + cout<<endl; + break; + case DW_CFA_def_cfa: + cout<<" def_cfa "; + print_uleb_operand(pos,data,max); + print_uleb_operand(pos,data,max); + cout<<endl; + break; + case DW_CFA_def_cfa_sf: + cout<<" def_cfa_sf "; + print_uleb_operand(pos,data,max); + print_sleb_operand(pos,data,max); + cout<<endl; + break; - /* GNU extensions */ - case DW_CFA_GNU_window_save: - case DW_CFA_GNU_negative_offset_extended: - default: - cout<<"Unhandled opcode cannot print. opcode="<<opcode<<endl; + case DW_CFA_def_cfa_expression: + { + auto uleb=uint64_t(0); + if(eh_frame_util_t<ptrsize>::read_uleb128(uleb, pos, data, max)) + return ; + cout<<" def_cfa_expression "<<dec<<uleb<<endl; + pos+=uleb; // doing this old school for now, as we aren't printing the expression. + break; } - break; + case DW_CFA_expression: + { + auto uleb1=uint64_t(0); + auto uleb2=uint64_t(0); + if(eh_frame_util_t<ptrsize>::read_uleb128(uleb1, pos, data, max)) + return ; + if(eh_frame_util_t<ptrsize>::read_uleb128(uleb2, pos, data, max)) + return ; + cout<<" expression "<<dec<<uleb1<<" "<<uleb2<<endl; + pos+=uleb2; + break; + } + case DW_CFA_val_expression: + { + auto uleb1=uint64_t(0); + auto uleb2=uint64_t(0); + if(eh_frame_util_t<ptrsize>::read_uleb128(uleb1, pos, data, max)) + return ; + if(eh_frame_util_t<ptrsize>::read_uleb128(uleb2, pos, data, max)) + return ; + cout<<" val_expression "<<dec<<uleb1<<" "<<uleb2<<endl; + pos+=uleb2; + break; + } + case DW_CFA_def_cfa_offset_sf: + { + auto leb=int64_t(0); + if(eh_frame_util_t<ptrsize>::read_sleb128(leb, pos, data, max)) + return ; + cout<<" def_cfa_offset_sf "<<dec<<leb; + break; + } + case DW_CFA_offset_extended_sf: + { + auto uleb1=uint64_t(0); + auto sleb2=int64_t(0); + if(eh_frame_util_t<ptrsize>::read_uleb128(uleb1, pos, data, max)) + return ; + if(eh_frame_util_t<ptrsize>::read_sleb128(sleb2, pos, data, max)) + return ; + cout<<" offset_extended_sf "<<dec<<uleb1<<" "<<sleb2<<endl; + break; + } + + + /* SGI/MIPS specific */ + case DW_CFA_MIPS_advance_loc8: + + /* GNU extensions */ + case DW_CFA_GNU_window_save: + case DW_CFA_GNU_negative_offset_extended: + default: + cout<<"Unhandled opcode cannot print. opcode="<<opcode<<endl; } + break; } - } - void push_byte(uint8_t c) { program_bytes.push_back(c); } +} - static void print_uleb_operand( - uint32_t pos, - const uint8_t* const data, - const uint32_t max) - { - auto uleb=uint64_t(0xdeadbeef); - eh_frame_util_t<ptrsize>::read_uleb128(uleb, pos, data, max); - cout<<" "<<dec<<uleb; - } +template <int ptrsize> +void eh_program_insn_t<ptrsize>::push_byte(uint8_t c) { program_bytes.push_back(c); } - static void print_sleb_operand( - uint32_t pos, - const uint8_t* const data, - const uint32_t max) - { - auto leb=int64_t(0xdeadbeef); - eh_frame_util_t<ptrsize>::read_sleb128(leb, pos, data, max); - cout<<" "<<dec<<leb; - } +template <int ptrsize> +void eh_program_insn_t<ptrsize>::print_uleb_operand( + uint32_t pos, + const uint8_t* const data, + const uint32_t max) +{ + auto uleb=uint64_t(0xdeadbeef); + eh_frame_util_t<ptrsize>::read_uleb128(uleb, pos, data, max); + cout<<" "<<dec<<uleb; +} - bool parse_insn( - uint8_t opcode, - uint32_t& pos, - const uint8_t* const data, - const uint32_t &max) - { - auto &eh_insn = *this; - auto insn_start=pos-1; - auto opcode_upper2=(uint8_t)(opcode >> 6); - auto opcode_lower6=(uint8_t)(opcode & (0x3f)); +template <int ptrsize> +void eh_program_insn_t<ptrsize>::print_sleb_operand( + uint32_t pos, + const uint8_t* const data, + const uint32_t max) +{ + auto leb=int64_t(0xdeadbeef); + eh_frame_util_t<ptrsize>::read_sleb128(leb, pos, data, max); + cout<<" "<<dec<<leb; +} + +template <int ptrsize> +bool eh_program_insn_t<ptrsize>::parse_insn( + uint8_t opcode, + uint32_t& pos, + const uint8_t* const data, + const uint32_t &max) +{ + auto &eh_insn = *this; + auto insn_start=pos-1; + auto opcode_upper2=(uint8_t)(opcode >> 6); + auto opcode_lower6=(uint8_t)(opcode & (0x3f)); - // calculate the end of the instruction, which is inherently per-opcode - switch(opcode_upper2) + // calculate the end of the instruction, which is inherently per-opcode + switch(opcode_upper2) + { + case 1: { - case 1: - { - // case DW_CFA_advance_loc: - break; - } - case 2: - { - auto uleb=uint64_t(0); - if(eh_frame_util_t<ptrsize>::read_uleb128(uleb, pos, data, max)) - return true; - // case DW_CFA_offset: - break; - } - case 3: - { - // case DW_CFA_offset: - break; - } - case 0: + // case DW_CFA_advance_loc: + break; + } + case 2: + { + auto uleb=uint64_t(0); + if(eh_frame_util_t<ptrsize>::read_uleb128(uleb, pos, data, max)) + return true; + // case DW_CFA_offset: + break; + } + case 3: + { + // case DW_CFA_offset: + break; + } + case 0: + { + switch(opcode_lower6) { - switch(opcode_lower6) + + case DW_CFA_nop: + case DW_CFA_remember_state: + case DW_CFA_restore_state: + break; + + // takes single uleb128 + case DW_CFA_undefined: + case DW_CFA_same_value: + case DW_CFA_restore_extended: + case DW_CFA_def_cfa_register: + case DW_CFA_GNU_args_size: + case DW_CFA_def_cfa_offset: { - - case DW_CFA_nop: - case DW_CFA_remember_state: - case DW_CFA_restore_state: - break; - - // takes single uleb128 - case DW_CFA_undefined: - case DW_CFA_same_value: - case DW_CFA_restore_extended: - case DW_CFA_def_cfa_register: - case DW_CFA_GNU_args_size: - case DW_CFA_def_cfa_offset: - { - auto uleb=uint64_t(0); - if(eh_frame_util_t<ptrsize>::read_uleb128(uleb, pos, data, max)) - return true; - break; - } + auto uleb=uint64_t(0); + if(eh_frame_util_t<ptrsize>::read_uleb128(uleb, pos, data, max)) + return true; + break; + } - case DW_CFA_set_loc: - pos+=ptrsize; - break; + case DW_CFA_set_loc: + pos+=ptrsize; + break; - case DW_CFA_advance_loc1: - pos+=1; - break; + case DW_CFA_advance_loc1: + pos+=1; + break; - case DW_CFA_advance_loc2: - pos+=2; - break; + case DW_CFA_advance_loc2: + pos+=2; + break; - case DW_CFA_advance_loc4: - pos+=4; - break; + case DW_CFA_advance_loc4: + pos+=4; + break; - case DW_CFA_offset_extended: - case DW_CFA_register: - case DW_CFA_def_cfa: - { - auto uleb1=uint64_t(1); - auto uleb2=uint64_t(0); - if(eh_frame_util_t<ptrsize>::read_uleb128(uleb1, pos, data, max)) - return true; - if(eh_frame_util_t<ptrsize>::read_uleb128(uleb2, pos, data, max)) - return true; - break; - } - case DW_CFA_def_cfa_sf: - { - auto leb1=uint64_t(0); - auto leb2=int64_t(0); - if(eh_frame_util_t<ptrsize>::read_uleb128(leb1, pos, data, max)) - return true; - if(eh_frame_util_t<ptrsize>::read_sleb128(leb2, pos, data, max)) - return true; - break; - } + case DW_CFA_offset_extended: + case DW_CFA_register: + case DW_CFA_def_cfa: + { + auto uleb1=uint64_t(1); + auto uleb2=uint64_t(0); + if(eh_frame_util_t<ptrsize>::read_uleb128(uleb1, pos, data, max)) + return true; + if(eh_frame_util_t<ptrsize>::read_uleb128(uleb2, pos, data, max)) + return true; + break; + } + case DW_CFA_def_cfa_sf: + { + auto leb1=uint64_t(0); + auto leb2=int64_t(0); + if(eh_frame_util_t<ptrsize>::read_uleb128(leb1, pos, data, max)) + return true; + if(eh_frame_util_t<ptrsize>::read_sleb128(leb2, pos, data, max)) + return true; + break; + } - case DW_CFA_def_cfa_expression: - { - auto uleb=uint64_t(0); - if(eh_frame_util_t<ptrsize>::read_uleb128(uleb, pos, data, max)) - return true; - pos+=uleb; - break; - } - case DW_CFA_expression: - case DW_CFA_val_expression: - { - auto uleb1=uint64_t(0); - auto uleb2=uint64_t(0); - if(eh_frame_util_t<ptrsize>::read_uleb128(uleb1, pos, data, max)) - return true; - if(eh_frame_util_t<ptrsize>::read_uleb128(uleb2, pos, data, max)) - return true; - pos+=uleb2; - break; - } - case DW_CFA_def_cfa_offset_sf: - { - auto leb=int64_t(0); - if(eh_frame_util_t<ptrsize>::read_sleb128(leb, pos, data, max)) - return true; - break; - } - case DW_CFA_offset_extended_sf: - { - auto uleb1=uint64_t(0); - auto sleb2=int64_t(0); - if(eh_frame_util_t<ptrsize>::read_uleb128(uleb1, pos, data, max)) - return true; - if(eh_frame_util_t<ptrsize>::read_sleb128(sleb2, pos, data, max)) - return true; - break; - } - /* Dwarf 2.1 */ - case DW_CFA_val_offset: - case DW_CFA_val_offset_sf: + case DW_CFA_def_cfa_expression: + { + auto uleb=uint64_t(0); + if(eh_frame_util_t<ptrsize>::read_uleb128(uleb, pos, data, max)) + return true; + pos+=uleb; + break; + } + case DW_CFA_expression: + case DW_CFA_val_expression: + { + auto uleb1=uint64_t(0); + auto uleb2=uint64_t(0); + if(eh_frame_util_t<ptrsize>::read_uleb128(uleb1, pos, data, max)) + return true; + if(eh_frame_util_t<ptrsize>::read_uleb128(uleb2, pos, data, max)) + return true; + pos+=uleb2; + break; + } + case DW_CFA_def_cfa_offset_sf: + { + auto leb=int64_t(0); + if(eh_frame_util_t<ptrsize>::read_sleb128(leb, pos, data, max)) + return true; + break; + } + case DW_CFA_offset_extended_sf: + { + auto uleb1=uint64_t(0); + auto sleb2=int64_t(0); + if(eh_frame_util_t<ptrsize>::read_uleb128(uleb1, pos, data, max)) + return true; + if(eh_frame_util_t<ptrsize>::read_sleb128(sleb2, pos, data, max)) + return true; + break; + } + /* Dwarf 2.1 */ + case DW_CFA_val_offset: + case DW_CFA_val_offset_sf: - /* SGI/MIPS specific */ - case DW_CFA_MIPS_advance_loc8: + /* SGI/MIPS specific */ + case DW_CFA_MIPS_advance_loc8: - /* GNU extensions */ - case DW_CFA_GNU_window_save: - case DW_CFA_GNU_negative_offset_extended: - default: - // Unhandled opcode cannot xform this eh-frame - cout<<"No decoder for opcode "<<+opcode<<endl; - return true; - } - break; + /* GNU extensions */ + case DW_CFA_GNU_window_save: + case DW_CFA_GNU_negative_offset_extended: + default: + // Unhandled opcode cannot xform this eh-frame + cout<<"No decoder for opcode "<<+opcode<<endl; + return true; } - default: - cout<<"No decoder for opcode "<<+opcode<<endl; - return true; + break; } - - // insert bytes into the instruction. - auto insn_end=pos; - for_each( &data[insn_start], &data[insn_end], [&](const uint8_t c) - { - eh_insn.push_byte(c); - }); - return false; + default: + cout<<"No decoder for opcode "<<+opcode<<endl; + return true; } - bool isNop() const + // insert bytes into the instruction. + auto insn_end=pos; + for_each( &data[insn_start], &data[insn_end], [&](const uint8_t c) { - const auto data=program_bytes.data(); - const auto opcode=program_bytes[0]; - const auto opcode_upper2=(uint8_t)(opcode >> 6); - const auto opcode_lower6=(uint8_t)(opcode & (0x3f)); - switch(opcode_upper2) + eh_insn.push_byte(c); + }); + return false; +} + +template <int ptrsize> +bool eh_program_insn_t<ptrsize>::isNop() const +{ + const auto data=program_bytes.data(); + const auto opcode=program_bytes[0]; + const auto opcode_upper2=(uint8_t)(opcode >> 6); + const auto opcode_lower6=(uint8_t)(opcode & (0x3f)); + switch(opcode_upper2) + { + case 0: { - case 0: + switch(opcode_lower6) { - switch(opcode_lower6) - { - - case DW_CFA_nop: - return true; - } + + case DW_CFA_nop: + return true; } } - return false; } - bool isRestoreState() const + return false; +} + +template <int ptrsize> +bool eh_program_insn_t<ptrsize>::isRestoreState() const +{ + const auto data=program_bytes.data(); + const auto opcode=program_bytes[0]; + const auto opcode_upper2=(uint8_t)(opcode >> 6); + const auto opcode_lower6=(uint8_t)(opcode & (0x3f)); + switch(opcode_upper2) { - const auto data=program_bytes.data(); - const auto opcode=program_bytes[0]; - const auto opcode_upper2=(uint8_t)(opcode >> 6); - const auto opcode_lower6=(uint8_t)(opcode & (0x3f)); - switch(opcode_upper2) + case 0: { - case 0: + switch(opcode_lower6) { - switch(opcode_lower6) - { - case DW_CFA_restore_state: - return true; - } + case DW_CFA_restore_state: + return true; } } - return false; } - bool isRememberState() const + return false; +} + +template <int ptrsize> +bool eh_program_insn_t<ptrsize>::isRememberState() const +{ + const auto data=program_bytes.data(); + const auto opcode=program_bytes[0]; + const auto opcode_upper2=(uint8_t)(opcode >> 6); + const auto opcode_lower6=(uint8_t)(opcode & (0x3f)); + switch(opcode_upper2) { - const auto data=program_bytes.data(); - const auto opcode=program_bytes[0]; - const auto opcode_upper2=(uint8_t)(opcode >> 6); - const auto opcode_lower6=(uint8_t)(opcode & (0x3f)); - switch(opcode_upper2) + case 0: { - case 0: + switch(opcode_lower6) { - switch(opcode_lower6) - { - case DW_CFA_remember_state: - return true; - } + case DW_CFA_remember_state: + return true; } } - return false; } + return false; +} - bool Advance(uint64_t &cur_addr, uint64_t CAF) const - { - // make sure uint8_t is an unsigned char. - static_assert(std::is_same<unsigned char, uint8_t>::value, "uint8_t is not unsigned char"); - - auto data=program_bytes.data(); - auto opcode=program_bytes[0]; - auto opcode_upper2=(uint8_t)(opcode >> 6); - auto opcode_lower6=(uint8_t)(opcode & (0x3f)); - auto pos=uint32_t(1); - auto max=program_bytes.size(); - - switch(opcode_upper2) +template <int ptrsize> +bool eh_program_insn_t<ptrsize>::Advance(uint64_t &cur_addr, uint64_t CAF) const +{ + // make sure uint8_t is an unsigned char. + static_assert(std::is_same<unsigned char, uint8_t>::value, "uint8_t is not unsigned char"); + + auto data=program_bytes.data(); + auto opcode=program_bytes[0]; + auto opcode_upper2=(uint8_t)(opcode >> 6); + auto opcode_lower6=(uint8_t)(opcode & (0x3f)); + auto pos=uint32_t(1); + auto max=program_bytes.size(); + + switch(opcode_upper2) + { + case 1: { - case 1: - { - // case DW_CFA_advance_loc: - cur_addr+=(opcode_lower6*CAF); - return true; - } - case 0: + // case DW_CFA_advance_loc: + cur_addr+=(opcode_lower6*CAF); + return true; + } + case 0: + { + switch(opcode_lower6) { - switch(opcode_lower6) + case DW_CFA_set_loc: { - case DW_CFA_set_loc: - { - assert(0); -/* - auto arg=uintptr_t(0xDEADBEEF); - switch(ptrsize) - { - case 4: - arg=*(uint32_t*)data[pos]; break; - case 8: - arg=*(uint64_t*)data[pos]; break; - } - cout<<" set_loc "<<hex<<arg<<endl; - break; -*/ - return true; - } - case DW_CFA_advance_loc1: - { - auto loc=*(uint8_t*)(&data[pos]); - cur_addr+=(loc*CAF); - return true; - } - - case DW_CFA_advance_loc2: - { - auto loc=*(uint16_t*)(&data[pos]); - cur_addr+=(loc*CAF); - return true; - } - - case DW_CFA_advance_loc4: + assert(0); +/* + auto arg=uintptr_t(0xDEADBEEF); + switch(ptrsize) { - auto loc=*(uint32_t*)(&data[pos]); - cur_addr+=(loc*CAF); - return true; + case 4: + arg=*(uint32_t*)data[pos]; break; + case 8: + arg=*(uint64_t*)data[pos]; break; } + cout<<" set_loc "<<hex<<arg<<endl; + break; +*/ + return true; + } + case DW_CFA_advance_loc1: + { + auto loc=*(uint8_t*)(&data[pos]); + cur_addr+=(loc*CAF); + return true; + } + + case DW_CFA_advance_loc2: + { + auto loc=*(uint16_t*)(&data[pos]); + cur_addr+=(loc*CAF); + return true; + } + + case DW_CFA_advance_loc4: + { + auto loc=*(uint32_t*)(&data[pos]); + cur_addr+=(loc*CAF); + return true; } } } - return false; } + return false; +} + +template <int ptrsize> +const vector<uint8_t>& eh_program_insn_t<ptrsize>::GetBytes() const { return program_bytes; } + +template <int ptrsize> +vector<uint8_t>& eh_program_insn_t<ptrsize>::GetBytes() { return program_bytes; } - const vector<uint8_t>& GetBytes() const { return program_bytes; } - vector<uint8_t>& GetBytes() { return program_bytes; } - private: - vector<uint8_t> program_bytes; -}; template <int ptrsize> bool operator<(const eh_program_insn_t<ptrsize>& a, const eh_program_insn_t<ptrsize>& b) @@ -810,53 +820,53 @@ bool operator<(const eh_program_insn_t<ptrsize>& a, const eh_program_insn_t<ptrs } template <int ptrsize> -class eh_program_t +void eh_program_t<ptrsize>::push_insn(const eh_program_insn_t<ptrsize> &i) { instructions.push_back(i); } + +template <int ptrsize> +void eh_program_t<ptrsize>::print(const uint64_t start_addr) const { - public: - void push_insn(const eh_program_insn_t<ptrsize> &i) { instructions.push_back(i); } + auto pc=start_addr; + cout << " Program: " << endl ; + for_each(instructions.begin(), instructions.end(), [&](const eh_program_insn_t<ptrsize>& i) + { + i.print(pc); + }); +} - void print(const uint64_t start_addr=0) const +template <int ptrsize> +bool eh_program_t<ptrsize>::parse_program( + const uint32_t& program_start_position, + const uint8_t* const data, + const uint32_t &max_program_pos) +{ + eh_program_t &eh_pgm=*this; + auto max=max_program_pos; + auto pos=program_start_position; + while(pos < max_program_pos) { - auto pc=start_addr; - cout << " Program: " << endl ; - for_each(instructions.begin(), instructions.end(), [&](const eh_program_insn_t<ptrsize>& i) - { - i.print(pc); - }); - } + auto opcode=uint8_t(0); + if(eh_frame_util_t<ptrsize>::read_type(opcode,pos,data,max)) + return true; + eh_program_insn_t<ptrsize> eh_insn; + if(eh_insn.parse_insn(opcode,pos,data,max)) + return true; - bool parse_program( - const uint32_t& program_start_position, - const uint8_t* const data, - const uint32_t &max_program_pos) - { - eh_program_t &eh_pgm=*this; - auto max=max_program_pos; - auto pos=program_start_position; - while(pos < max_program_pos) - { - auto opcode=uint8_t(0); - if(eh_frame_util_t<ptrsize>::read_type(opcode,pos,data,max)) - return true; - eh_program_insn_t<ptrsize> eh_insn; - if(eh_insn.parse_insn(opcode,pos,data,max)) - return true; + eh_pgm.push_insn(eh_insn); + + + } - eh_pgm.push_insn(eh_insn); + auto program_end_position=pos; - - } + //cout<<endl; + return false; +} - auto program_end_position=pos; +template <int ptrsize> +const vector<eh_program_insn_t <ptrsize> >& eh_program_t<ptrsize>::GetInstructions() const { return instructions; } - //cout<<endl; - return false; - } - const vector<eh_program_insn_t <ptrsize> >& GetInstructions() const { return instructions; } - vector<eh_program_insn_t <ptrsize> >& GetInstructions() { return instructions; } - private: - vector<eh_program_insn_t <ptrsize> > instructions; -}; +template <int ptrsize> +vector<eh_program_insn_t <ptrsize> >& eh_program_t<ptrsize>::GetInstructions() { return instructions; } template <int ptrsize> bool operator<(const eh_program_t<ptrsize>& a, const eh_program_t<ptrsize>& b) @@ -865,230 +875,230 @@ bool operator<(const eh_program_t<ptrsize>& a, const eh_program_t<ptrsize>& b) } template <int ptrsize> -class cie_contents_t : eh_frame_util_t<ptrsize> -{ - private: - uint64_t cie_position; - uint64_t length; - uint8_t cie_id; - uint8_t cie_version; - string augmentation; - uint64_t code_alignment_factor; - int64_t data_alignment_factor; - uint64_t return_address_register_column; - uint64_t augmentation_data_length; - uint8_t personality_encoding; - uint64_t personality; - uint8_t lsda_encoding; - uint8_t fde_encoding; - eh_program_t<ptrsize> eh_pgm; - - public: - - cie_contents_t() : - cie_position(0), - length(0), - cie_id(0), - cie_version(0), - code_alignment_factor(0), - data_alignment_factor(0), - return_address_register_column(0), - augmentation_data_length(0), - personality_encoding(0), - personality(0), - lsda_encoding(0), - fde_encoding(0) - {} - - const eh_program_t<ptrsize>& GetProgram() const { return eh_pgm; } - uint64_t GetCAF() const { return code_alignment_factor; } - int64_t GetDAF() const { return data_alignment_factor; } - uint64_t GetPersonality() const { return personality; } - uint64_t GetReturnRegister() const { return return_address_register_column; } - - string GetAugmentation() const { return augmentation; } - uint8_t GetLSDAEncoding() const { return lsda_encoding;} - uint8_t GetFDEEncoding() const { return fde_encoding;} - - bool parse_cie( - const uint32_t &cie_position, - const uint8_t* const data, - const uint32_t max, - const uint64_t eh_addr) - { - auto &c=*this; - const auto eh_frame_scoop_data= data; - auto position=cie_position; - auto length= uint64_t(0); +cie_contents_t<ptrsize>::cie_contents_t() : + cie_position(0), + length(0), + cie_id(0), + cie_version(0), + code_alignment_factor(0), + data_alignment_factor(0), + return_address_register_column(0), + augmentation_data_length(0), + personality_encoding(0), + personality(0), + lsda_encoding(0), + fde_encoding(0) +{} - if(this->read_length(length, position, eh_frame_scoop_data, max)) - return true; - auto end_pos=position+length; +template <int ptrsize> +const eh_program_t<ptrsize>& cie_contents_t<ptrsize>::GetProgram() const { return eh_pgm; } - auto cie_id=uint32_t(0); - if(this->read_type(cie_id, position, eh_frame_scoop_data, max)) - return true; +template <int ptrsize> +uint64_t cie_contents_t<ptrsize>::GetCAF() const { return code_alignment_factor; } - auto cie_version=uint8_t(0); - if(this->read_type(cie_version, position, eh_frame_scoop_data, max)) - return true; +template <int ptrsize> +int64_t cie_contents_t<ptrsize>::GetDAF() const { return data_alignment_factor; } - if(cie_version==1) - { } // OK - else if(cie_version==3) - { } // OK - else - // Err. - return true; +template <int ptrsize> +uint64_t cie_contents_t<ptrsize>::GetPersonality() const { return personality; } - auto augmentation=string(); - if(this->read_string(augmentation, position, eh_frame_scoop_data, max)) - return true; +template <int ptrsize> +uint64_t cie_contents_t<ptrsize>::GetReturnRegister() const { return return_address_register_column; } - auto code_alignment_factor=uint64_t(0); - if(this->read_uleb128(code_alignment_factor, position, eh_frame_scoop_data, max)) - return true; - - auto data_alignment_factor=int64_t(0); - if(this->read_sleb128(data_alignment_factor, position, eh_frame_scoop_data, max)) - return true; - // type depends on version info. can always promote to 64 bits. - auto return_address_register_column=uint64_t(0); - if(cie_version==1) - { - auto return_address_register_column_8=uint8_t(0); - if(this->read_type(return_address_register_column_8, position, eh_frame_scoop_data, max)) - return true; - return_address_register_column=return_address_register_column_8; - } - else if(cie_version==3) - { - auto return_address_register_column_64=uint64_t(0); - if(this->read_uleb128(return_address_register_column_64, position, eh_frame_scoop_data, max)) - return true; - return_address_register_column=return_address_register_column_64; - } - else - assert(0); +template <int ptrsize> +string cie_contents_t<ptrsize>::GetAugmentation() const { return augmentation; } - auto augmentation_data_length=uint64_t(0); - if(augmentation.find("z") != string::npos) - { - if(this->read_uleb128(augmentation_data_length, position, eh_frame_scoop_data, max)) - return true; - } - auto personality_encoding=uint8_t(DW_EH_PE_omit); - auto personality=uint64_t(0); - if(augmentation.find("P") != string::npos) - { - if(this->read_type(personality_encoding, position, eh_frame_scoop_data, max)) - return true; +template <int ptrsize> +uint8_t cie_contents_t<ptrsize>::GetLSDAEncoding() const { return lsda_encoding;} - // indirect is OK as a personality encoding, but we don't need to go that far. - // we just need to record what's in the CIE, regardless of whether it's the actual - // personality routine or it's the pointer to the personality routine. - auto personality_encoding_sans_indirect = personality_encoding&(~DW_EH_PE_indirect); - if(this->read_type_with_encoding(personality_encoding_sans_indirect, personality, position, eh_frame_scoop_data, max, eh_addr)) - return true; - } +template <int ptrsize> +uint8_t cie_contents_t<ptrsize>::GetFDEEncoding() const { return fde_encoding;} - auto lsda_encoding=uint8_t(DW_EH_PE_omit); - if(augmentation.find("L") != string::npos) - { - if(this->read_type(lsda_encoding, position, eh_frame_scoop_data, max)) - return true; - } - auto fde_encoding=uint8_t(DW_EH_PE_omit); - if(augmentation.find("R") != string::npos) - { - if(this->read_type(fde_encoding, position, eh_frame_scoop_data, max)) - return true; - } - if(eh_pgm.parse_program(position, eh_frame_scoop_data, end_pos)) + +template <int ptrsize> +bool cie_contents_t<ptrsize>::parse_cie( + const uint32_t &cie_position, + const uint8_t* const data, + const uint32_t max, + const uint64_t eh_addr) +{ + auto &c=*this; + const auto eh_frame_scoop_data= data; + auto position=cie_position; + auto length= uint64_t(0); + + if(this->read_length(length, position, eh_frame_scoop_data, max)) + return true; + + auto end_pos=position+length; + + auto cie_id=uint32_t(0); + if(this->read_type(cie_id, position, eh_frame_scoop_data, max)) + return true; + + auto cie_version=uint8_t(0); + if(this->read_type(cie_version, position, eh_frame_scoop_data, max)) + return true; + + if(cie_version==1) + { } // OK + else if(cie_version==3) + { } // OK + else + // Err. + return true; + + auto augmentation=string(); + if(this->read_string(augmentation, position, eh_frame_scoop_data, max)) + return true; + + auto code_alignment_factor=uint64_t(0); + if(this->read_uleb128(code_alignment_factor, position, eh_frame_scoop_data, max)) + return true; + + auto data_alignment_factor=int64_t(0); + if(this->read_sleb128(data_alignment_factor, position, eh_frame_scoop_data, max)) + return true; + + // type depends on version info. can always promote to 64 bits. + auto return_address_register_column=uint64_t(0); + if(cie_version==1) + { + auto return_address_register_column_8=uint8_t(0); + if(this->read_type(return_address_register_column_8, position, eh_frame_scoop_data, max)) + return true; + return_address_register_column=return_address_register_column_8; + } + else if(cie_version==3) + { + auto return_address_register_column_64=uint64_t(0); + if(this->read_uleb128(return_address_register_column_64, position, eh_frame_scoop_data, max)) return true; + return_address_register_column=return_address_register_column_64; + } + else + assert(0); + auto augmentation_data_length=uint64_t(0); + if(augmentation.find("z") != string::npos) + { + if(this->read_uleb128(augmentation_data_length, position, eh_frame_scoop_data, max)) + return true; + } + auto personality_encoding=uint8_t(DW_EH_PE_omit); + auto personality=uint64_t(0); + if(augmentation.find("P") != string::npos) + { + if(this->read_type(personality_encoding, position, eh_frame_scoop_data, max)) + return true; - c.cie_position=cie_position; - c.cie_id=cie_id; - c.cie_version=cie_version; - c.augmentation=augmentation; - c.code_alignment_factor=code_alignment_factor; - c.data_alignment_factor=data_alignment_factor; - c.return_address_register_column=return_address_register_column; - c.augmentation_data_length=augmentation_data_length; - c.personality_encoding=personality_encoding; - c.personality=personality; - c.lsda_encoding=lsda_encoding; - c.fde_encoding=fde_encoding; - - // all OK - return false; + // indirect is OK as a personality encoding, but we don't need to go that far. + // we just need to record what's in the CIE, regardless of whether it's the actual + // personality routine or it's the pointer to the personality routine. + auto personality_encoding_sans_indirect = personality_encoding&(~DW_EH_PE_indirect); + if(this->read_type_with_encoding(personality_encoding_sans_indirect, personality, position, eh_frame_scoop_data, max, eh_addr)) + return true; } - void print() const + + auto lsda_encoding=uint8_t(DW_EH_PE_omit); + if(augmentation.find("L") != string::npos) { - cout << "["<<setw(6)<<hex<<cie_position<<"] CIE length="<<dec<<length<<endl; - cout << " CIE_id: " << +cie_id << endl; - cout << " version: " << +cie_version << endl; - cout << " augmentation: \"" << augmentation << "\"" << endl; - cout << " code_alignment_factor: " << code_alignment_factor << endl; - cout << " data_alignment_factor: " << dec << data_alignment_factor << endl; - cout << " return_address_register: " << dec << return_address_register_column << endl; - cout << " Augmentation data: " << endl ; - cout << " aug data len: " << hex << +augmentation_data_length << endl; - cout << " personality_encoding: " << hex << +personality_encoding << endl; - cout << " personality: " << hex << +personality << endl; - cout << " lsda_encoding: " << hex << +lsda_encoding << endl; - cout << " fde_encoding: " << hex << +fde_encoding << endl; - cout << " Program: " << endl ; - eh_pgm.print(); - + if(this->read_type(lsda_encoding, position, eh_frame_scoop_data, max)) + return true; } - void build_ir(Instruction_t* insn) const + auto fde_encoding=uint8_t(DW_EH_PE_omit); + if(augmentation.find("R") != string::npos) { - // nothing to do? built up one level. - //eh_pgm.print(); + if(this->read_type(fde_encoding, position, eh_frame_scoop_data, max)) + return true; } -}; + if(eh_pgm.parse_program(position, eh_frame_scoop_data, end_pos)) + return true; + + + c.cie_position=cie_position; + c.cie_id=cie_id; + c.cie_version=cie_version; + c.augmentation=augmentation; + c.code_alignment_factor=code_alignment_factor; + c.data_alignment_factor=data_alignment_factor; + c.return_address_register_column=return_address_register_column; + c.augmentation_data_length=augmentation_data_length; + c.personality_encoding=personality_encoding; + c.personality=personality; + c.lsda_encoding=lsda_encoding; + c.fde_encoding=fde_encoding; + + // all OK + return false; +} template <int ptrsize> -class lsda_call_site_action_t : private eh_frame_util_t<ptrsize> +void cie_contents_t<ptrsize>::print() const { - private: - int64_t action; + cout << "["<<setw(6)<<hex<<cie_position<<"] CIE length="<<dec<<length<<endl; + cout << " CIE_id: " << +cie_id << endl; + cout << " version: " << +cie_version << endl; + cout << " augmentation: \"" << augmentation << "\"" << endl; + cout << " code_alignment_factor: " << code_alignment_factor << endl; + cout << " data_alignment_factor: " << dec << data_alignment_factor << endl; + cout << " return_address_register: " << dec << return_address_register_column << endl; + cout << " Augmentation data: " << endl ; + cout << " aug data len: " << hex << +augmentation_data_length << endl; + cout << " personality_encoding: " << hex << +personality_encoding << endl; + cout << " personality: " << hex << +personality << endl; + cout << " lsda_encoding: " << hex << +lsda_encoding << endl; + cout << " fde_encoding: " << hex << +fde_encoding << endl; + cout << " Program: " << endl ; + eh_pgm.print(); + +} - public: - lsda_call_site_action_t() : - action(0) - {} +template <int ptrsize> +void cie_contents_t<ptrsize>::build_ir(Instruction_t* insn) const +{ + // nothing to do? built up one level. + //eh_pgm.print(); +} - int64_t GetAction() const { return action;} +template <int ptrsize> +lsda_call_site_action_t<ptrsize>::lsda_call_site_action_t() : + action(0) +{} - bool parse_lcsa(uint32_t& pos, const uint8_t* const data, const uint64_t max, bool &end) - { - end=false; - if(this->read_sleb128(action, pos, data, max)) - return true; - assert(action>=0); +template <int ptrsize> +int64_t lsda_call_site_action_t<ptrsize>::GetAction() const { return action;} - auto next_action=pos; - auto next_pos_offset=int64_t(0); - if(this->read_sleb128(next_pos_offset, pos, data, max)) - return true; - - if(next_pos_offset==0) - end=true; - else - pos=next_action+next_pos_offset; - return false; - } - void print() const - { - cout<<" "<<action<<endl; - } -}; + +template <int ptrsize> +bool lsda_call_site_action_t<ptrsize>::parse_lcsa(uint32_t& pos, const uint8_t* const data, const uint64_t max, bool &end) +{ + end=false; + if(this->read_sleb128(action, pos, data, max)) + return true; + + assert(action>=0); + + auto next_action=pos; + auto next_pos_offset=int64_t(0); + if(this->read_sleb128(next_pos_offset, pos, data, max)) + return true; + + if(next_pos_offset==0) + end=true; + else + pos=next_action+next_pos_offset; + return false; +} + +template <int ptrsize> +void lsda_call_site_action_t<ptrsize>::print() const +{ + cout<<" "<<action<<endl; +} template <int ptrsize> bool operator< (const lsda_call_site_action_t <ptrsize> &lhs, const lsda_call_site_action_t <ptrsize> &rhs) @@ -1097,940 +1107,938 @@ bool operator< (const lsda_call_site_action_t <ptrsize> &lhs, const lsda_call_si } template <int ptrsize> -class lsda_type_table_entry_t: private eh_frame_util_t<ptrsize> -{ - private: - uint64_t pointer_to_typeinfo; - uint64_t tt_encoding; - uint64_t tt_encoding_size; - - public: - lsda_type_table_entry_t() : - pointer_to_typeinfo(0), tt_encoding(0) - {} - - uint64_t GetTypeInfoPointer() const { return pointer_to_typeinfo; } - uint64_t GetEncoding() const { return tt_encoding; } - uint64_t GetTTEncodingSize() const { return tt_encoding_size; } - - bool parse( - const uint64_t p_tt_encoding, - const uint64_t tt_pos, - const uint64_t index, - const uint8_t* const data, - const uint64_t max, - const uint64_t data_addr - ) - { - tt_encoding=p_tt_encoding; - const auto tt_encoding_sans_indirect = tt_encoding&(~DW_EH_PE_indirect); - const auto tt_encoding_sans_indir_sans_pcrel = tt_encoding_sans_indirect & (~DW_EH_PE_pcrel); - const auto has_pcrel = (tt_encoding & DW_EH_PE_pcrel) == DW_EH_PE_pcrel; - switch(tt_encoding & 0xf) // get just the size field - { - case DW_EH_PE_udata4: - case DW_EH_PE_sdata4: - tt_encoding_size=4; - break; - default: - assert(0); - } - const auto orig_act_pos=uint32_t(tt_pos+(-index*tt_encoding_size)); - auto act_pos=uint32_t(tt_pos+(-index*tt_encoding_size)); - if(this->read_type_with_encoding(tt_encoding_sans_indir_sans_pcrel, pointer_to_typeinfo, act_pos, data, max, data_addr)) - return true; +lsda_type_table_entry_t<ptrsize>::lsda_type_table_entry_t() : + pointer_to_typeinfo(0), tt_encoding(0) +{} - // check if there's a 0 in the field - if(pointer_to_typeinfo != 0 && has_pcrel) - pointer_to_typeinfo += orig_act_pos + data_addr; - return false; - } +template <int ptrsize> +uint64_t lsda_type_table_entry_t<ptrsize>::GetTypeInfoPointer() const { return pointer_to_typeinfo; } - void print() const - { - cout<<" pointer_to_typeinfo: 0x"<<hex<<pointer_to_typeinfo<<endl; - } +template <int ptrsize> +uint64_t lsda_type_table_entry_t<ptrsize>::GetEncoding() const { return tt_encoding; } + +template <int ptrsize> +uint64_t lsda_type_table_entry_t<ptrsize>::GetTTEncodingSize() const { return tt_encoding_size; } - -}; template <int ptrsize> -class lsda_call_site_t : private eh_frame_util_t<ptrsize> +bool lsda_type_table_entry_t<ptrsize>::parse( + const uint64_t p_tt_encoding, + const uint64_t tt_pos, + const uint64_t index, + const uint8_t* const data, + const uint64_t max, + const uint64_t data_addr + ) { - private: - uint64_t call_site_offset; - uint64_t call_site_addr; - uint64_t call_site_length; - uint64_t call_site_end_addr; - uint64_t landing_pad_offset; - uint64_t landing_pad_addr; - uint64_t action; - uint64_t action_table_offset; - uint64_t action_table_addr; - - vector<lsda_call_site_action_t <ptrsize> > action_table; - - public: - lsda_call_site_t() : - call_site_offset(0), - call_site_addr(0), - call_site_length(0), - call_site_end_addr(0), - landing_pad_offset(0), - landing_pad_addr(0), - action(0), - action_table_offset(0), - action_table_addr(0) - {} - - int64_t GetMaxTypeTableIndex() const + tt_encoding=p_tt_encoding; + const auto tt_encoding_sans_indirect = tt_encoding&(~DW_EH_PE_indirect); + const auto tt_encoding_sans_indir_sans_pcrel = tt_encoding_sans_indirect & (~DW_EH_PE_pcrel); + const auto has_pcrel = (tt_encoding & DW_EH_PE_pcrel) == DW_EH_PE_pcrel; + switch(tt_encoding & 0xf) // get just the size field { - if(action_table.size()==0) - return 0; - return max_element(action_table.begin(), action_table.end())->GetAction(); + case DW_EH_PE_udata4: + case DW_EH_PE_sdata4: + tt_encoding_size=4; + break; + default: + assert(0); } - + const auto orig_act_pos=uint32_t(tt_pos+(-index*tt_encoding_size)); + auto act_pos=uint32_t(tt_pos+(-index*tt_encoding_size)); + if(this->read_type_with_encoding(tt_encoding_sans_indir_sans_pcrel, pointer_to_typeinfo, act_pos, data, max, data_addr)) + return true; - bool parse_lcs( - const uint64_t action_table_start_addr, - const uint64_t cs_table_start_addr, - const uint8_t cs_table_encoding, - uint32_t &pos, - const uint8_t* const data, - const uint64_t max, /* call site table max */ - const uint64_t data_addr, - const uint64_t landing_pad_base_addr, - const uint64_t gcc_except_table_max) - { - - if(this->read_type_with_encoding(cs_table_encoding, call_site_offset, pos, data, max, data_addr)) - return true; - call_site_addr=landing_pad_base_addr+call_site_offset; - if(this->read_type_with_encoding(cs_table_encoding, call_site_length, pos, data, max, data_addr)) - return true; - call_site_end_addr=call_site_addr+call_site_length; - if(this->read_type_with_encoding(cs_table_encoding, landing_pad_offset, pos, data, max, data_addr)) - return true; + // check if there's a 0 in the field + if(pointer_to_typeinfo != 0 && has_pcrel) + pointer_to_typeinfo += orig_act_pos + data_addr; - // calc the actual addr. - if(landing_pad_offset == 0) - landing_pad_addr=0; - else - landing_pad_addr=landing_pad_base_addr+landing_pad_offset; + return false; +} - if(this->read_uleb128(action, pos, data, max)) - return true; - if(action == 0) - { /* no action table -- means no cleanup is needed, just unwinding. */ } - else if( action > 0 ) - { - action_table_offset=action-1; - action_table_addr=action_table_start_addr+action-1; +template <int ptrsize> +void lsda_type_table_entry_t<ptrsize>::print() const +{ + cout<<" pointer_to_typeinfo: 0x"<<hex<<pointer_to_typeinfo<<endl; +} - // parse action tables - bool end=false; - auto act_table_pos=uint32_t(action_table_addr-data_addr); - while(!end) - { - lsda_call_site_action_t<ptrsize> lcsa; - if(lcsa.parse_lcsa(act_table_pos, data, gcc_except_table_max, end)) - return true; - action_table.push_back(lcsa); - - } - } - else if( action < 0 ) - { - assert(0); // a negative value in "action" indicates a negative type filter. - // this indicates a null-terminated list of types in the type table. - // as there's no example of this, assert for now. - } - else - { - assert(0); // how is this possible? - } + + + +template <int ptrsize> +lsda_call_site_t<ptrsize>::lsda_call_site_t() : + call_site_offset(0), + call_site_addr(0), + call_site_length(0), + call_site_end_addr(0), + landing_pad_offset(0), + landing_pad_addr(0), + action(0), + action_table_offset(0), + action_table_addr(0) +{} + + +template <int ptrsize> +int64_t lsda_call_site_t<ptrsize>::GetMaxTypeTableIndex() const +{ + if(action_table.size()==0) + return 0; + return max_element(action_table.begin(), action_table.end())->GetAction(); +} + + + +template <int ptrsize> +bool lsda_call_site_t<ptrsize>::parse_lcs( + const uint64_t action_table_start_addr, + const uint64_t cs_table_start_addr, + const uint8_t cs_table_encoding, + uint32_t &pos, + const uint8_t* const data, + const uint64_t max, /* call site table max */ + const uint64_t data_addr, + const uint64_t landing_pad_base_addr, + const uint64_t gcc_except_table_max) +{ - return false; - } + if(this->read_type_with_encoding(cs_table_encoding, call_site_offset, pos, data, max, data_addr)) + return true; + call_site_addr=landing_pad_base_addr+call_site_offset; + if(this->read_type_with_encoding(cs_table_encoding, call_site_length, pos, data, max, data_addr)) + return true; + call_site_end_addr=call_site_addr+call_site_length; + if(this->read_type_with_encoding(cs_table_encoding, landing_pad_offset, pos, data, max, data_addr)) + return true; + + // calc the actual addr. + if(landing_pad_offset == 0) + landing_pad_addr=0; + else + landing_pad_addr=landing_pad_base_addr+landing_pad_offset; + + if(this->read_uleb128(action, pos, data, max)) + return true; - void print() const + if(action == 0) + { /* no action table -- means no cleanup is needed, just unwinding. */ } + else if( action > 0 ) { - cout<<" CS Offset : 0x"<<hex<<call_site_offset<<endl; - cout<<" CS len : 0x"<<hex<<call_site_length<<endl; - cout<<" landing pad off. : 0x"<<hex<<landing_pad_offset<<endl; - cout<<" action (1+addr) : 0x"<<hex<<action<<endl; - cout<<" ---interpreted---"<<endl; - cout<<" CS Addr : 0x"<<hex<<call_site_addr<<endl; - cout<<" CS End Addr : 0x"<<hex<<call_site_end_addr<<endl; - cout<<" landing pad addr : 0x"<<hex<<landing_pad_addr<<endl; - cout<<" act-tab off : 0x"<<hex<<action_table_offset<<endl; - cout<<" act-tab addr : 0x"<<hex<<action_table_addr<<endl; - cout<<" act-tab : "<<endl; - for_each(action_table.begin(), action_table.end(), [&](const lsda_call_site_action_t<ptrsize>& p) + action_table_offset=action-1; + action_table_addr=action_table_start_addr+action-1; + + // parse action tables + bool end=false; + auto act_table_pos=uint32_t(action_table_addr-data_addr); + while(!end) { - p.print(); - }); + lsda_call_site_action_t<ptrsize> lcsa; + if(lcsa.parse_lcsa(act_table_pos, data, gcc_except_table_max, end)) + return true; + action_table.push_back(lcsa); + + } } - - bool appliesTo(const Instruction_t* insn) const + else if( action < 0 ) { - assert(insn && insn->GetAddress()); - auto insn_addr=insn->GetAddress()->GetVirtualOffset(); - - return ( call_site_addr <=insn_addr && insn_addr<call_site_end_addr ); + assert(0); // a negative value in "action" indicates a negative type filter. + // this indicates a null-terminated list of types in the type table. + // as there's no example of this, assert for now. } + else + { + assert(0); // how is this possible? + } + + return false; +} + - void build_ir(Instruction_t* insn, const vector<lsda_type_table_entry_t <ptrsize> > &type_table, const uint8_t& tt_encoding, const OffsetMap_t& om, FileIR_t* firp) const +template <int ptrsize> +void lsda_call_site_t<ptrsize>::print() const +{ + cout<<" CS Offset : 0x"<<hex<<call_site_offset<<endl; + cout<<" CS len : 0x"<<hex<<call_site_length<<endl; + cout<<" landing pad off. : 0x"<<hex<<landing_pad_offset<<endl; + cout<<" action (1+addr) : 0x"<<hex<<action<<endl; + cout<<" ---interpreted---"<<endl; + cout<<" CS Addr : 0x"<<hex<<call_site_addr<<endl; + cout<<" CS End Addr : 0x"<<hex<<call_site_end_addr<<endl; + cout<<" landing pad addr : 0x"<<hex<<landing_pad_addr<<endl; + cout<<" act-tab off : 0x"<<hex<<action_table_offset<<endl; + cout<<" act-tab addr : 0x"<<hex<<action_table_addr<<endl; + cout<<" act-tab : "<<endl; + for_each(action_table.begin(), action_table.end(), [&](const lsda_call_site_action_t<ptrsize>& p) { - assert(appliesTo(insn)); + p.print(); + }); +} - // find landing pad instruction. - auto lp_insn=(Instruction_t*)NULL; - auto lp_it=om.find(landing_pad_addr); - if(lp_it!=om.end()) - lp_insn=lp_it->second; - // create the callsite. - auto new_ehcs = new EhCallSite_t(BaseObj_t::NOT_IN_DATABASE, tt_encoding, lp_insn); - firp->GetAllEhCallSites().insert(new_ehcs); - insn->SetEhCallSite(new_ehcs); +template <int ptrsize> +bool lsda_call_site_t<ptrsize>::appliesTo(const Instruction_t* insn) const +{ + assert(insn && insn->GetAddress()); + auto insn_addr=insn->GetAddress()->GetVirtualOffset(); - cout<<"landing pad addr : 0x"<<hex<<landing_pad_addr<<endl; - if(action_table.size() == 0 ) - { - new_ehcs->SetHasCleanup(); - cout<<"Destructors to call, but no exceptions to catch"<<endl; - } - else + return ( call_site_addr <=insn_addr && insn_addr<call_site_end_addr ); +} + + +template <int ptrsize> +void lsda_call_site_t<ptrsize>::build_ir(Instruction_t* insn, const vector<lsda_type_table_entry_t <ptrsize> > &type_table, const uint8_t& tt_encoding, const OffsetMap_t& om, FileIR_t* firp) const +{ + assert(appliesTo(insn)); + + // find landing pad instruction. + auto lp_insn=(Instruction_t*)NULL; + auto lp_it=om.find(landing_pad_addr); + if(lp_it!=om.end()) + lp_insn=lp_it->second; + + // create the callsite. + auto new_ehcs = new EhCallSite_t(BaseObj_t::NOT_IN_DATABASE, tt_encoding, lp_insn); + firp->GetAllEhCallSites().insert(new_ehcs); + insn->SetEhCallSite(new_ehcs); + + cout<<"landing pad addr : 0x"<<hex<<landing_pad_addr<<endl; + if(action_table.size() == 0 ) + { + new_ehcs->SetHasCleanup(); + cout<<"Destructors to call, but no exceptions to catch"<<endl; + } + else + { + for_each(action_table.begin(), action_table.end(), [&](const lsda_call_site_action_t<ptrsize>& p) { - for_each(action_table.begin(), action_table.end(), [&](const lsda_call_site_action_t<ptrsize>& p) + const auto action=p.GetAction(); + new_ehcs->GetTTOrderVector().push_back(action); + if(action==0) { - const auto action=p.GetAction(); - new_ehcs->GetTTOrderVector().push_back(action); - if(action==0) - { - // NO! This means that the type table has a 0, which means catch all. - // an action table entry of 0 means that it has a cleanup, but not a catch all. - //auto newreloc=new Relocation_t(BaseObj_t::NOT_IN_DATABASE, 0, "type_table_entry", NULL, 0); - //new_ehcs->GetRelocations().insert(newreloc); - //firp->GetRelocations().insert(newreloc); - new_ehcs->SetHasCleanup(); - cout<<"Cleanup only (no catches) ."<<endl; - } - else if(action>0) - { - const auto index=action - 1; - //cout<<"Catch for type: "; - // the type table reveral was done during parsing, type table is right-side-up now. - //type_table.at(index).print(); - auto wrt=(DataScoop_t*)NULL; - assert(index<type_table.size()); - if(type_table.at(index).GetTypeInfoPointer()!=0) - { - wrt=firp->FindScoop(type_table.at(index).GetTypeInfoPointer()); - assert(wrt); - } - const auto offset=index*type_table.at(index).GetTTEncodingSize(); - auto addend=0; - if(wrt!=NULL) - addend=type_table.at(index).GetTypeInfoPointer()-wrt->GetStart()->GetVirtualOffset(); - auto newreloc=new Relocation_t(BaseObj_t::NOT_IN_DATABASE, offset, "type_table_entry", wrt, addend); - new_ehcs->GetRelocations().insert(newreloc); - firp->GetRelocations().insert(newreloc); - - if(wrt==NULL) - cout<<"Catch all in type table"<<endl; - else - cout<<"Catch for type at "<<wrt->GetName()<<"+0x"<<hex<<addend<<"."<<endl; - } - else if(action<0) + // NO! This means that the type table has a 0, which means catch all. + // an action table entry of 0 means that it has a cleanup, but not a catch all. + //auto newreloc=new Relocation_t(BaseObj_t::NOT_IN_DATABASE, 0, "type_table_entry", NULL, 0); + //new_ehcs->GetRelocations().insert(newreloc); + //firp->GetRelocations().insert(newreloc); + new_ehcs->SetHasCleanup(); + cout<<"Cleanup only (no catches) ."<<endl; + } + else if(action>0) + { + const auto index=action - 1; + //cout<<"Catch for type: "; + // the type table reveral was done during parsing, type table is right-side-up now. + //type_table.at(index).print(); + auto wrt=(DataScoop_t*)NULL; + assert(index<type_table.size()); + if(type_table.at(index).GetTypeInfoPointer()!=0) { - assert(0); // see note in parse_lcs about actions < 0. + wrt=firp->FindScoop(type_table.at(index).GetTypeInfoPointer()); + assert(wrt); } + const auto offset=index*type_table.at(index).GetTTEncodingSize(); + auto addend=0; + if(wrt!=NULL) + addend=type_table.at(index).GetTypeInfoPointer()-wrt->GetStart()->GetVirtualOffset(); + auto newreloc=new Relocation_t(BaseObj_t::NOT_IN_DATABASE, offset, "type_table_entry", wrt, addend); + new_ehcs->GetRelocations().insert(newreloc); + firp->GetRelocations().insert(newreloc); + + if(wrt==NULL) + cout<<"Catch all in type table"<<endl; else - { - cout<<"What? :"<< action <<endl; - exit(1); - } - }); - } + cout<<"Catch for type at "<<wrt->GetName()<<"+0x"<<hex<<addend<<"."<<endl; + } + else if(action<0) + { + assert(0); // see note in parse_lcs about actions < 0. + } + else + { + cout<<"What? :"<< action <<endl; + exit(1); + } + }); } -}; +} + template <int ptrsize> -class lsda_t : private eh_frame_util_t<ptrsize> +uint8_t lsda_t<ptrsize>::GetTTEncoding() const { return type_table_encoding; } + +template <int ptrsize> +lsda_t<ptrsize>::lsda_t() : + landing_pad_base_encoding(0), + landing_pad_base_addr(0), + type_table_encoding(0), + type_table_offset(0), + type_table_addr(0), + cs_table_encoding(0), + cs_table_start_offset(0), + cs_table_start_addr(0), + cs_table_length(0), + cs_table_end_addr(0), + action_table_start_addr(0) +{} + +template <int ptrsize> +bool lsda_t<ptrsize>::parse_lsda(const uint64_t lsda_addr, const DataScoop_t* gcc_except_scoop, const uint64_t fde_region_start) { - private: - uint8_t landing_pad_base_encoding; - uint64_t landing_pad_base_addr; // often ommitted. when ommitted, filled in from FDE region start. - uint8_t type_table_encoding; - uint64_t type_table_offset; - uint64_t type_table_addr; - uint8_t cs_table_encoding; - uint64_t cs_table_start_offset; - uint64_t cs_table_start_addr; - uint64_t cs_table_length; - uint64_t cs_table_end_addr; - uint64_t action_table_start_addr; - vector<lsda_call_site_t <ptrsize> > call_site_table; - vector<lsda_type_table_entry_t <ptrsize> > type_table; - - public: - - uint8_t GetTTEncoding() const { return type_table_encoding; } - - lsda_t() : - landing_pad_base_encoding(0), - landing_pad_base_addr(0), - type_table_encoding(0), - type_table_offset(0), - type_table_addr(0), - cs_table_encoding(0), - cs_table_start_offset(0), - cs_table_start_addr(0), - cs_table_length(0), - cs_table_end_addr(0), - action_table_start_addr(0) - {} - - bool parse_lsda(const uint64_t lsda_addr, const DataScoop_t* gcc_except_scoop, const uint64_t fde_region_start) + // make sure there's a coop and that we're in the range. + if(!gcc_except_scoop) + return true; + if(lsda_addr<gcc_except_scoop->GetStart()->GetVirtualOffset()) + return true; + if(lsda_addr>=gcc_except_scoop->GetEnd()->GetVirtualOffset()) + return true; + + const auto data=(const uint8_t* const)gcc_except_scoop->GetContents().data(); + const auto data_addr=gcc_except_scoop->GetStart()->GetVirtualOffset(); + const auto max=gcc_except_scoop->GetContents().size(); + auto pos=uint32_t(lsda_addr-data_addr); + auto start_pos=pos; + + if(this->read_type(landing_pad_base_encoding, pos, data, max)) + return true; + if(landing_pad_base_encoding!=DW_EH_PE_omit) { - // make sure there's a coop and that we're in the range. - if(!gcc_except_scoop) - return true; - if(lsda_addr<gcc_except_scoop->GetStart()->GetVirtualOffset()) - return true; - if(lsda_addr>=gcc_except_scoop->GetEnd()->GetVirtualOffset()) + if(this->read_type_with_encoding(landing_pad_base_encoding,landing_pad_base_addr, pos, data, max, data_addr)) return true; + } + else + landing_pad_base_addr=fde_region_start; - const auto data=(const uint8_t* const)gcc_except_scoop->GetContents().data(); - const auto data_addr=gcc_except_scoop->GetStart()->GetVirtualOffset(); - const auto max=gcc_except_scoop->GetContents().size(); - auto pos=uint32_t(lsda_addr-data_addr); - auto start_pos=pos; + if(this->read_type(type_table_encoding, pos, data, max)) + return true; - if(this->read_type(landing_pad_base_encoding, pos, data, max)) + auto type_table_pos=0; + if(type_table_encoding!=DW_EH_PE_omit) + { + if(this->read_uleb128(type_table_offset, pos, data, max)) return true; - if(landing_pad_base_encoding!=DW_EH_PE_omit) - { - if(this->read_type_with_encoding(landing_pad_base_encoding,landing_pad_base_addr, pos, data, max, data_addr)) - return true; - } - else - landing_pad_base_addr=fde_region_start; + type_table_addr=lsda_addr+type_table_offset+(pos-start_pos); + type_table_pos=pos+type_table_offset; + } + else + type_table_addr=0; - if(this->read_type(type_table_encoding, pos, data, max)) - return true; + if(this->read_type(cs_table_encoding, pos, data, max)) + return true; - auto type_table_pos=0; - if(type_table_encoding!=DW_EH_PE_omit) - { - if(this->read_uleb128(type_table_offset, pos, data, max)) - return true; - type_table_addr=lsda_addr+type_table_offset+(pos-start_pos); - type_table_pos=pos+type_table_offset; - } - else - type_table_addr=0; + if(this->read_uleb128(cs_table_length, pos, data, max)) + return true; - if(this->read_type(cs_table_encoding, pos, data, max)) - return true; + auto cs_table_end=pos+cs_table_length; + auto cs_table_start_pos=pos; + cs_table_start_offset=pos; + cs_table_start_addr=lsda_addr+pos-start_pos; + cs_table_end_addr=cs_table_start_addr+cs_table_length; - if(this->read_uleb128(cs_table_length, pos, data, max)) + // action table comes immediately after the call site table. + action_table_start_addr=cs_table_start_addr+cs_table_length; + auto max_tt_entry=uint64_t(0); + while(1) + { + lsda_call_site_t<ptrsize> lcs; + if(lcs.parse_lcs(action_table_start_addr, + cs_table_start_addr,cs_table_encoding, pos, data, cs_table_end, data_addr, landing_pad_base_addr, max)) + { return true; + } - auto cs_table_end=pos+cs_table_length; - auto cs_table_start_pos=pos; - cs_table_start_offset=pos; - cs_table_start_addr=lsda_addr+pos-start_pos; - cs_table_end_addr=cs_table_start_addr+cs_table_length; + call_site_table.push_back(lcs); + max_tt_entry=std::max(max_tt_entry, (uint64_t)lcs.GetMaxTypeTableIndex()); + + if(pos>=cs_table_end) + break; + } - // action table comes immediately after the call site table. - action_table_start_addr=cs_table_start_addr+cs_table_length; - auto max_tt_entry=uint64_t(0); - while(1) + if(type_table_encoding!=DW_EH_PE_omit) + { + // 1-based indexing because of odd backwards indexing of type table. + for(int i=1;i<=max_tt_entry;i++) { - lsda_call_site_t<ptrsize> lcs; - if(lcs.parse_lcs(action_table_start_addr, - cs_table_start_addr,cs_table_encoding, pos, data, cs_table_end, data_addr, landing_pad_base_addr, max)) - { + lsda_type_table_entry_t <ptrsize> ltte; + if(ltte.parse(type_table_encoding, type_table_pos, i, data, max, data_addr )) return true; - } - - call_site_table.push_back(lcs); - max_tt_entry=std::max(max_tt_entry, (uint64_t)lcs.GetMaxTypeTableIndex()); - - if(pos>=cs_table_end) - break; + type_table.push_back(ltte); } + } - if(type_table_encoding!=DW_EH_PE_omit) - { - // 1-based indexing because of odd backwards indexing of type table. - for(int i=1;i<=max_tt_entry;i++) - { - lsda_type_table_entry_t <ptrsize> ltte; - if(ltte.parse(type_table_encoding, type_table_pos, i, data, max, data_addr )) - return true; - type_table.push_back(ltte); - } - } + return false; +} - return false; - } - void print() const +template <int ptrsize> +void lsda_t<ptrsize>::print() const +{ + cout<<" LSDA:"<<endl; + cout<<" LP base encoding : 0x"<<hex<<+landing_pad_base_encoding<<endl; + cout<<" LP base addr : 0x"<<hex<<+landing_pad_base_addr<<endl; + cout<<" TypeTable encoding : 0x"<<hex<<+type_table_encoding<<endl; + cout<<" TypeTable offset : 0x"<<hex<<type_table_offset<<endl; + cout<<" TypeTable addr : 0x"<<hex<<+type_table_addr<<endl; + cout<<" CS tab encoding : 0x"<<hex<<+cs_table_encoding<<endl; + cout<<" CS tab addr : 0x"<<hex<<+cs_table_start_addr<<endl; + cout<<" CS tab offset : 0x"<<hex<<+cs_table_start_offset<<endl; + cout<<" CS tab length : 0x"<<hex<<+cs_table_length<<endl; + cout<<" CS tab end addr : 0x"<<hex<<+cs_table_end_addr<<endl; + cout<<" Act tab start_addr : 0x"<<hex<<+action_table_start_addr<<endl; + cout<<" CS tab :"<<endl; + int i=0; + for_each(call_site_table.begin(), call_site_table.end(), [&](const lsda_call_site_t<ptrsize>& p) { - cout<<" LSDA:"<<endl; - cout<<" LP base encoding : 0x"<<hex<<+landing_pad_base_encoding<<endl; - cout<<" LP base addr : 0x"<<hex<<+landing_pad_base_addr<<endl; - cout<<" TypeTable encoding : 0x"<<hex<<+type_table_encoding<<endl; - cout<<" TypeTable offset : 0x"<<hex<<type_table_offset<<endl; - cout<<" TypeTable addr : 0x"<<hex<<+type_table_addr<<endl; - cout<<" CS tab encoding : 0x"<<hex<<+cs_table_encoding<<endl; - cout<<" CS tab addr : 0x"<<hex<<+cs_table_start_addr<<endl; - cout<<" CS tab offset : 0x"<<hex<<+cs_table_start_offset<<endl; - cout<<" CS tab length : 0x"<<hex<<+cs_table_length<<endl; - cout<<" CS tab end addr : 0x"<<hex<<+cs_table_end_addr<<endl; - cout<<" Act tab start_addr : 0x"<<hex<<+action_table_start_addr<<endl; - cout<<" CS tab :"<<endl; - int i=0; - for_each(call_site_table.begin(), call_site_table.end(), [&](const lsda_call_site_t<ptrsize>& p) - { - cout<<" [ "<<hex<<i++<<"] call site table entry "<<endl; - p.print(); - }); - i=0; - for_each(type_table.begin(), type_table.end(), [&](const lsda_type_table_entry_t<ptrsize>& p) - { - cout<<" [ "<<hex<<i++<<"] Type table entry "<<endl; - p.print(); - }); - } - void build_ir(Instruction_t* insn, const OffsetMap_t& om, FileIR_t* firp) const + cout<<" [ "<<hex<<i++<<"] call site table entry "<<endl; + p.print(); + }); + i=0; + for_each(type_table.begin(), type_table.end(), [&](const lsda_type_table_entry_t<ptrsize>& p) { - auto cs_it=find_if(call_site_table.begin(), call_site_table.end(), [&](const lsda_call_site_t<ptrsize>& p) - { - return p.appliesTo(insn); - }); + cout<<" [ "<<hex<<i++<<"] Type table entry "<<endl; + p.print(); + }); +} - if(cs_it!= call_site_table.end()) - { - cs_it->build_ir(insn, type_table, GetTTEncoding(), om, firp); - } - else - { - // no call site table entry for this instruction. - } +template <int ptrsize> +void lsda_t<ptrsize>::build_ir(Instruction_t* insn, const OffsetMap_t& om, FileIR_t* firp) const +{ + auto cs_it=find_if(call_site_table.begin(), call_site_table.end(), [&](const lsda_call_site_t<ptrsize>& p) + { + return p.appliesTo(insn); + }); + + if(cs_it!= call_site_table.end()) + { + cs_it->build_ir(insn, type_table, GetTTEncoding(), om, firp); + } + else + { + // no call site table entry for this instruction. } -}; +} + + +template <int ptrsize> +fde_contents_t<ptrsize>::fde_contents_t() : + fde_position(0), + cie_position(0), + length(0), + id(0), + fde_start_addr(0), + fde_end_addr(0), + fde_range_len(0), + lsda_addr(0) +{} template <int ptrsize> -class fde_contents_t : eh_frame_util_t<ptrsize> +bool fde_contents_t<ptrsize>::appliesTo(const Instruction_t* insn) const { - uint32_t fde_position; - uint32_t cie_position; - uint64_t length; - uint8_t id; - uint64_t fde_start_addr; - uint64_t fde_end_addr; - uint64_t fde_range_len; - uint64_t lsda_addr; - - - lsda_t<ptrsize> lsda; - eh_program_t<ptrsize> eh_pgm; - cie_contents_t<ptrsize> cie_info; - - public: - fde_contents_t() : - fde_position(0), - cie_position(0), - length(0), - id(0), - fde_start_addr(0), - fde_end_addr(0), - fde_range_len(0), - lsda_addr(0) - {} - - - bool appliesTo(const Instruction_t* insn) const - { - assert(insn && insn->GetAddress()); - auto insn_addr=insn->GetAddress()->GetVirtualOffset(); + assert(insn && insn->GetAddress()); + auto insn_addr=insn->GetAddress()->GetVirtualOffset(); - return ( fde_start_addr<=insn_addr && insn_addr<fde_end_addr ); - } + return ( fde_start_addr<=insn_addr && insn_addr<fde_end_addr ); +} - uint64_t GetFDEStartAddress() const { return fde_start_addr; } +template <int ptrsize> +uint64_t fde_contents_t<ptrsize>::GetFDEStartAddress() const { return fde_start_addr; } - const cie_contents_t<ptrsize>& GetCIE() const { return cie_info; } - cie_contents_t<ptrsize>& GetCIE() { return cie_info; } +template <int ptrsize> +const cie_contents_t<ptrsize>& fde_contents_t<ptrsize>::GetCIE() const { return cie_info; } - const eh_program_t<ptrsize>& GetProgram() const { return eh_pgm; } - eh_program_t<ptrsize>& GetProgram() { return eh_pgm; } +template <int ptrsize> +cie_contents_t<ptrsize>& fde_contents_t<ptrsize>::GetCIE() { return cie_info; } - bool parse_fde( - const uint32_t &fde_position, - const uint32_t &cie_position, - const uint8_t* const data, - const uint64_t max, - const uint64_t eh_addr, - const DataScoop_t* gcc_except_scoop) - { - auto &c=*this; - const auto eh_frame_scoop_data=data; +template <int ptrsize> +const eh_program_t<ptrsize>& fde_contents_t<ptrsize>::GetProgram() const { return eh_pgm; } - if(cie_info.parse_cie(cie_position, data, max, eh_addr)) - return true; +template <int ptrsize> +eh_program_t<ptrsize>& fde_contents_t<ptrsize>::GetProgram() { return eh_pgm; } - auto pos=fde_position; - auto length=uint64_t(0); - if(this->read_length(length, pos, eh_frame_scoop_data, max)) - return true; +template <int ptrsize> +bool fde_contents_t<ptrsize>::parse_fde( + const uint32_t &fde_position, + const uint32_t &cie_position, + const uint8_t* const data, + const uint64_t max, + const uint64_t eh_addr, + const DataScoop_t* gcc_except_scoop) +{ + auto &c=*this; + const auto eh_frame_scoop_data=data; - - auto end_pos=pos+length; - auto end_length_position=pos; + if(cie_info.parse_cie(cie_position, data, max, eh_addr)) + return true; - auto cie_id=uint32_t(0); - if(this->read_type(cie_id, pos, eh_frame_scoop_data, max)) - return true; + auto pos=fde_position; + auto length=uint64_t(0); + if(this->read_length(length, pos, eh_frame_scoop_data, max)) + return true; - auto fde_start_addr=uint64_t(0); - if(this->read_type_with_encoding(c.GetCIE().GetFDEEncoding(),fde_start_addr, pos, eh_frame_scoop_data, max, eh_addr)) - return true; - auto fde_range_len=uint64_t(0); - if(this->read_type_with_encoding(c.GetCIE().GetFDEEncoding() & 0xf /* drop pc-rel bits */,fde_range_len, pos, eh_frame_scoop_data, max, eh_addr)) - return true; + auto end_pos=pos+length; + auto end_length_position=pos; - auto fde_end_addr=fde_start_addr+fde_range_len; + auto cie_id=uint32_t(0); + if(this->read_type(cie_id, pos, eh_frame_scoop_data, max)) + return true; - auto augmentation_data_length=uint64_t(0); - if(c.GetCIE().GetAugmentation().find("z") != string::npos) - { - if(this->read_uleb128(augmentation_data_length, pos, eh_frame_scoop_data, max)) - return true; - } - auto lsda_addr=uint64_t(0); - if(c.GetCIE().GetLSDAEncoding()!= DW_EH_PE_omit) - { - if(this->read_type_with_encoding(c.GetCIE().GetLSDAEncoding(), lsda_addr, pos, eh_frame_scoop_data, max, eh_addr)) - return true; - if(c.lsda.parse_lsda(lsda_addr,gcc_except_scoop, fde_start_addr)) - return true; - } + auto fde_start_addr=uint64_t(0); + if(this->read_type_with_encoding(c.GetCIE().GetFDEEncoding(),fde_start_addr, pos, eh_frame_scoop_data, max, eh_addr)) + return true; - if(c.eh_pgm.parse_program(pos, eh_frame_scoop_data, end_pos)) - return true; + auto fde_range_len=uint64_t(0); + if(this->read_type_with_encoding(c.GetCIE().GetFDEEncoding() & 0xf /* drop pc-rel bits */,fde_range_len, pos, eh_frame_scoop_data, max, eh_addr)) + return true; - c.fde_position=fde_position; - c.cie_position=cie_position; - c.length=length; - c.id=id; - c.fde_start_addr=fde_start_addr; - c.fde_end_addr=fde_end_addr; - c.fde_range_len=fde_range_len; - c.lsda_addr=lsda_addr; + auto fde_end_addr=fde_start_addr+fde_range_len; - return false; + auto augmentation_data_length=uint64_t(0); + if(c.GetCIE().GetAugmentation().find("z") != string::npos) + { + if(this->read_uleb128(augmentation_data_length, pos, eh_frame_scoop_data, max)) + return true; } - - void print() const + auto lsda_addr=uint64_t(0); + if(c.GetCIE().GetLSDAEncoding()!= DW_EH_PE_omit) { - - cout << "["<<setw(6)<<hex<<fde_position<<"] FDE length="<<dec<<length; - cout <<" cie=["<<setw(6)<<hex<<cie_position<<"]"<<endl; - cout<<" FDE len addr: "<<dec<<length<<endl; - cout<<" FDE Start addr: "<<hex<<fde_start_addr<<endl; - cout<<" FDE End addr: "<<hex<<fde_end_addr<<endl; - cout<<" FDE len: "<<dec<<fde_range_len<<endl; - cout<<" FDE LSDA: "<<hex<<lsda_addr<<endl; - eh_pgm.print(fde_start_addr); - if(GetCIE().GetLSDAEncoding()!= DW_EH_PE_omit) - lsda.print(); - else - cout<<" No LSDA for this FDE."<<endl; + if(this->read_type_with_encoding(c.GetCIE().GetLSDAEncoding(), lsda_addr, pos, eh_frame_scoop_data, max, eh_addr)) + return true; + if(c.lsda.parse_lsda(lsda_addr,gcc_except_scoop, fde_start_addr)) + return true; } - void build_ir(Instruction_t* insn, const OffsetMap_t &om, FileIR_t* firp) const - { - // assert this is the right FDE. - assert( fde_start_addr<= insn->GetAddress()->GetVirtualOffset() && insn->GetAddress()->GetVirtualOffset() <= fde_end_addr); + if(c.eh_pgm.parse_program(pos, eh_frame_scoop_data, end_pos)) + return true; - //eh_pgm.print(fde_start_addr); - if(lsda_addr!=0) - lsda.build_ir(insn,om,firp); - } + c.fde_position=fde_position; + c.cie_position=cie_position; + c.length=length; + c.id=id; + c.fde_start_addr=fde_start_addr; + c.fde_end_addr=fde_end_addr; + c.fde_range_len=fde_range_len; + c.lsda_addr=lsda_addr; -}; + return false; +} -class split_eh_frame_t +template <int ptrsize> +void fde_contents_t<ptrsize>::print() const { - public: - virtual bool parse()=0; - virtual void build_ir() const =0; -}; + cout << "["<<setw(6)<<hex<<fde_position<<"] FDE length="<<dec<<length; + cout <<" cie=["<<setw(6)<<hex<<cie_position<<"]"<<endl; + cout<<" FDE len addr: "<<dec<<length<<endl; + cout<<" FDE Start addr: "<<hex<<fde_start_addr<<endl; + cout<<" FDE End addr: "<<hex<<fde_end_addr<<endl; + cout<<" FDE len: "<<dec<<fde_range_len<<endl; + cout<<" FDE LSDA: "<<hex<<lsda_addr<<endl; + eh_pgm.print(fde_start_addr); + if(GetCIE().GetLSDAEncoding()!= DW_EH_PE_omit) + lsda.print(); + else + cout<<" No LSDA for this FDE."<<endl; +} template <int ptrsize> -class split_eh_frame_impl_t : public split_eh_frame_t +void fde_contents_t<ptrsize>::build_ir(Instruction_t* insn, const OffsetMap_t &om, FileIR_t* firp) const { - private: + // assert this is the right FDE. + assert( fde_start_addr<= insn->GetAddress()->GetVirtualOffset() && insn->GetAddress()->GetVirtualOffset() <= fde_end_addr); + + //eh_pgm.print(fde_start_addr); + if(lsda_addr!=0) + lsda.build_ir(insn,om,firp); +} - FileIR_t* firp; - DataScoop_t* eh_frame_scoop; - DataScoop_t* eh_frame_hdr_scoop; - DataScoop_t* gcc_except_table_scoop; - OffsetMap_t offset_to_insn_map; - vector<cie_contents_t <ptrsize> > cies; - vector<fde_contents_t <ptrsize> > fdes; - bool init_offset_map() - { - for_each(firp->GetInstructions().begin(), firp->GetInstructions().end(), [&](Instruction_t* i) - { - offset_to_insn_map[i->GetAddress()->GetVirtualOffset()]=i; - }); - return false; - } - bool iterate_fdes() +template <int ptrsize> +bool split_eh_frame_impl_t<ptrsize>::init_offset_map() +{ + for_each(firp->GetInstructions().begin(), firp->GetInstructions().end(), [&](Instruction_t* i) { - auto eh_frame_scoop_data=(const uint8_t* const)eh_frame_scoop->GetContents().c_str(); - auto data=eh_frame_scoop_data; - auto eh_addr= eh_frame_scoop->GetStart()->GetVirtualOffset(); - auto max=eh_frame_scoop->GetContents().size(); - auto position=uint32_t(0); + offset_to_insn_map[i->GetAddress()->GetVirtualOffset()]=i; + }); + return false; +} - //cout << "----------------------------------------"<<endl; - while(1) - { - auto old_position=position; - auto act_length=uint64_t(0); - if(eh_frame_util_t<ptrsize>::read_length(act_length, position, eh_frame_scoop_data, max)) - break; +template <int ptrsize> +bool split_eh_frame_impl_t<ptrsize>::iterate_fdes() +{ + auto eh_frame_scoop_data=(const uint8_t* const)eh_frame_scoop->GetContents().c_str(); + auto data=eh_frame_scoop_data; + auto eh_addr= eh_frame_scoop->GetStart()->GetVirtualOffset(); + auto max=eh_frame_scoop->GetContents().size(); + auto position=uint32_t(0); + + //cout << "----------------------------------------"<<endl; + while(1) + { + auto old_position=position; + auto act_length=uint64_t(0); - auto next_position=position + act_length; - auto cie_offset=uint32_t(0); - auto cie_offset_position=position; + if(eh_frame_util_t<ptrsize>::read_length(act_length, position, eh_frame_scoop_data, max)) + break; - if(eh_frame_util_t<ptrsize>::read_type(cie_offset,position, eh_frame_scoop_data, max)) - break; + auto next_position=position + act_length; + auto cie_offset=uint32_t(0); + auto cie_offset_position=position; - //cout << " [ " << setw(6) << hex << old_position << "] " ; - if(act_length==0) - { - //cout << "Zero terminator " << endl; - break; - } - else if(cie_offset==0) - { - //cout << "CIE length="<< dec << act_length << endl; - cie_contents_t<ptrsize> c; - if(c.parse_cie(old_position, data, max, eh_addr)) - return true; - cies.push_back(c); - } - else - { - fde_contents_t<ptrsize> f; - auto cie_position = cie_offset_position - cie_offset; - //cout << "FDE length="<< dec << act_length << " cie=[" << setw(6) << hex << cie_position << "]" << endl; - if(f.parse_fde(old_position, cie_position, data, max, eh_addr, gcc_except_table_scoop)) - return true; - fdes.push_back(f); - } - //cout << "----------------------------------------"<<endl; - + if(eh_frame_util_t<ptrsize>::read_type(cie_offset,position, eh_frame_scoop_data, max)) + break; - // next CIE/FDE - assert(position<=next_position); // so we don't accidentally over-read a CIE/FDE - position=next_position; + //cout << " [ " << setw(6) << hex << old_position << "] " ; + if(act_length==0) + { + //cout << "Zero terminator " << endl; + break; + } + else if(cie_offset==0) + { + //cout << "CIE length="<< dec << act_length << endl; + cie_contents_t<ptrsize> c; + if(c.parse_cie(old_position, data, max, eh_addr)) + return true; + cies.push_back(c); + } + else + { + fde_contents_t<ptrsize> f; + auto cie_position = cie_offset_position - cie_offset; + //cout << "FDE length="<< dec << act_length << " cie=[" << setw(6) << hex << cie_position << "]" << endl; + if(f.parse_fde(old_position, cie_position, data, max, eh_addr, gcc_except_table_scoop)) + return true; + fdes.push_back(f); } - return false; + //cout << "----------------------------------------"<<endl; + + + // next CIE/FDE + assert(position<=next_position); // so we don't accidentally over-read a CIE/FDE + position=next_position; } + return false; +} - public: - split_eh_frame_impl_t(FileIR_t* p_firp) - : firp(p_firp), - eh_frame_scoop(NULL), - eh_frame_hdr_scoop(NULL), - gcc_except_table_scoop(NULL) - { - assert(firp!=NULL); +template <int ptrsize> +split_eh_frame_impl_t<ptrsize>::split_eh_frame_impl_t(FileIR_t* p_firp) + : firp(p_firp), + eh_frame_scoop(NULL), + eh_frame_hdr_scoop(NULL), + gcc_except_table_scoop(NULL) +{ + assert(firp!=NULL); - // function to find a scoop by name. - auto lookup_scoop_by_name=[&](const string &name) -> DataScoop_t* + // function to find a scoop by name. + auto lookup_scoop_by_name=[&](const string &name) -> DataScoop_t* + { + auto scoop_it=find_if(firp->GetDataScoops().begin(), firp->GetDataScoops().end(), [name](DataScoop_t* scoop) { - auto scoop_it=find_if(firp->GetDataScoops().begin(), firp->GetDataScoops().end(), [name](DataScoop_t* scoop) - { - return scoop->GetName()==name; - }); + return scoop->GetName()==name; + }); - if(scoop_it!=firp->GetDataScoops().end()) - return *scoop_it; - return NULL; - }; + if(scoop_it!=firp->GetDataScoops().end()) + return *scoop_it; + return NULL; + }; - eh_frame_scoop=lookup_scoop_by_name(".eh_frame"); - eh_frame_hdr_scoop=lookup_scoop_by_name(".eh_frame_hdr"); - gcc_except_table_scoop=lookup_scoop_by_name(".gcc_except_table"); + eh_frame_scoop=lookup_scoop_by_name(".eh_frame"); + eh_frame_hdr_scoop=lookup_scoop_by_name(".eh_frame_hdr"); + gcc_except_table_scoop=lookup_scoop_by_name(".gcc_except_table"); - } +} - bool parse() - { - if(eh_frame_scoop==NULL) - return true; // no frame info in this binary +template <int ptrsize> +bool split_eh_frame_impl_t<ptrsize>::parse() +{ + if(eh_frame_scoop==NULL) + return true; // no frame info in this binary - if(init_offset_map()) - return true; - if(iterate_fdes()) - return true; + if(init_offset_map()) + return true; - return false; - } + if(iterate_fdes()) + return true; + + return false; +} - void print() const - { - for_each(cies.begin(), cies.end(), [&](const cie_contents_t<ptrsize> &p) - { - p.print(); - }); - for_each(fdes.begin(), fdes.end(), [&](const fde_contents_t<ptrsize> &p) - { - p.print(); - }); - } - void build_ir() const +template <int ptrsize> +void split_eh_frame_impl_t<ptrsize>::print() const +{ + for_each(cies.begin(), cies.end(), [&](const cie_contents_t<ptrsize> &p) { - typedef pair<EhProgram_t*,uint64_t> whole_pgm_t; + p.print(); + }); + for_each(fdes.begin(), fdes.end(), [&](const fde_contents_t<ptrsize> &p) + { + p.print(); + }); +} - auto reusedpgms=size_t(0); - struct EhProgramComparator_t { + +template <int ptrsize> +void split_eh_frame_impl_t<ptrsize>::build_ir() const +{ + typedef pair<EhProgram_t*,uint64_t> whole_pgm_t; + + auto reusedpgms=size_t(0); + struct EhProgramComparator_t { // bool operator() (const EhProgram_t* a, const EhProgram_t* b) { return *a < *b; } - bool operator() (const whole_pgm_t& a, const whole_pgm_t& b) - { return tie(*a.first, a.second) < tie(*b.first,b.second); } - }; + bool operator() (const whole_pgm_t& a, const whole_pgm_t& b) + { return tie(*a.first, a.second) < tie(*b.first,b.second); } + }; - // this is used to avoid adding duplicate entries to the program's IR, it allows a lookup by value - // instead of the IR's set which allows duplicates. - auto eh_program_cache = set<whole_pgm_t, EhProgramComparator_t>(); + // this is used to avoid adding duplicate entries to the program's IR, it allows a lookup by value + // instead of the IR's set which allows duplicates. + auto eh_program_cache = set<whole_pgm_t, EhProgramComparator_t>(); - // find the right cie and fde, and build the IR from those for this instruction. - auto build_ir_insn=[&](Instruction_t* insn) -> void + // find the right cie and fde, and build the IR from those for this instruction. + auto build_ir_insn=[&](Instruction_t* insn) -> void + { + auto fie_it=find_if(fdes.begin(), fdes.end(), [&](const fde_contents_t<ptrsize> &p) { - auto fie_it=find_if(fdes.begin(), fdes.end(), [&](const fde_contents_t<ptrsize> &p) - { - return p.appliesTo(insn); - }); + return p.appliesTo(insn); + }); - if(fie_it!=fdes.end()) - { + if(fie_it!=fdes.end()) + { - if(getenv("EHIR_VERBOSE")!=NULL) - { - cout<<hex<<insn->GetAddress()->GetVirtualOffset()<<":" - <<insn->GetBaseID()<<":"<<insn->getDisassembly()<<" -> "<<endl; - //fie_it->GetCIE().print(); - fie_it->print(); - } + if(getenv("EHIR_VERBOSE")!=NULL) + { + cout<<hex<<insn->GetAddress()->GetVirtualOffset()<<":" + <<insn->GetBaseID()<<":"<<insn->getDisassembly()<<" -> "<<endl; + //fie_it->GetCIE().print(); + fie_it->print(); + } - const auto fde_addr=fie_it->GetFDEStartAddress(); - const auto caf=fie_it->GetCIE().GetCAF(); - const auto daf=fie_it->GetCIE().GetDAF(); - const auto return_reg=fie_it->GetCIE().GetReturnRegister(); - const auto personality=fie_it->GetCIE().GetPersonality(); - const auto insn_addr=insn->GetAddress()->GetVirtualOffset(); + const auto fde_addr=fie_it->GetFDEStartAddress(); + const auto caf=fie_it->GetCIE().GetCAF(); + const auto daf=fie_it->GetCIE().GetDAF(); + const auto return_reg=fie_it->GetCIE().GetReturnRegister(); + const auto personality=fie_it->GetCIE().GetPersonality(); + const auto insn_addr=insn->GetAddress()->GetVirtualOffset(); - auto import_pgm = [&](EhProgramListing_t& out_pgm, const eh_program_t<ptrsize> in_pgm) -> void + auto import_pgm = [&](EhProgramListing_t& out_pgm, const eh_program_t<ptrsize> in_pgm) -> void + { + auto cur_addr=fde_addr; + for(const auto & insn : in_pgm.GetInstructions()) { - auto cur_addr=fde_addr; - for(const auto & insn : in_pgm.GetInstructions()) + if(insn.Advance(cur_addr, caf)) + { + if(cur_addr > insn_addr) + break; + } + else if(insn.isNop()) { - if(insn.Advance(cur_addr, caf)) - { - if(cur_addr > insn_addr) - break; - } - else if(insn.isNop()) - { - // skip nops - } - else if(insn.isRestoreState()) + // skip nops + } + else if(insn.isRestoreState()) + { + // if a restore state happens, pop back out any instructions until + // we find the corresponding remember_state + while(1) { - // if a restore state happens, pop back out any instructions until - // we find the corresponding remember_state - while(1) + if(out_pgm.size()==0) { - if(out_pgm.size()==0) - { - // unmatched remember state - cerr<<"Error in CIE/FDE program: unmatched restore_state command"<<endl; - break; - } - const auto back_str=out_pgm.back(); - out_pgm.pop_back(); - const auto back_insn=eh_program_insn_t<ptrsize>(back_str); - if(back_insn.isRememberState()) - break; + // unmatched remember state + cerr<<"Error in CIE/FDE program: unmatched restore_state command"<<endl; + break; } + const auto back_str=out_pgm.back(); + out_pgm.pop_back(); + const auto back_insn=eh_program_insn_t<ptrsize>(back_str); + if(back_insn.isRememberState()) + break; } - else - { - string to_push(insn.GetBytes().begin(),insn.GetBytes().end()); - out_pgm.push_back(to_push); - } - } - if(getenv("EHIR_VERBOSE")!=NULL) + else { - cout<<"\tPgm has insn_count="<<out_pgm.size()<<endl; + string to_push(insn.GetBytes().begin(),insn.GetBytes().end()); + out_pgm.push_back(to_push); } - }; - - // build an eh program on the stack; - - auto ehpgm=EhProgram_t(BaseObj_t::NOT_IN_DATABASE,caf,daf,return_reg, ptrsize); - import_pgm(ehpgm.GetCIEProgram(), fie_it->GetCIE().GetProgram()); - import_pgm(ehpgm.GetFDEProgram(), fie_it->GetProgram()); - + } if(getenv("EHIR_VERBOSE")!=NULL) - ehpgm.print(); - // see if we've already built this one. - auto ehpgm_it = eh_program_cache.find(whole_pgm_t(&ehpgm, personality)) ; - if(ehpgm_it != eh_program_cache.end()) { - // yes, use the cached program. - insn->SetEhProgram(ehpgm_it->first); - if(getenv("EHIR_VERBOSE")!=NULL) - cout<<"Re-using existing Program!"<<endl; - reusedpgms++; + cout<<"\tPgm has insn_count="<<out_pgm.size()<<endl; } - else /* doesn't yet exist! */ - { - - if(getenv("EHIR_VERBOSE")!=NULL) - cout<<"Allocating new Program!"<<endl; - - // allocate a new pgm in the heap so we can give it to the IR. - auto newehpgm=new EhProgram_t(ehpgm); // copy constructor - assert(newehpgm); - firp->GetAllEhPrograms().insert(newehpgm); - - // allocate a relocation for the personality and give it to the IR. - auto personality_scoop=firp->FindScoop(personality); - auto personality_insn_it=offset_to_insn_map.find(personality); - auto personality_insn=personality_insn_it==offset_to_insn_map.end() ? (Instruction_t*)NULL : personality_insn_it->second; - auto personality_obj = personality_scoop ? (BaseObj_t*)personality_scoop : (BaseObj_t*)personality_insn; - auto addend= personality_scoop ? personality - personality_scoop->GetStart()->GetVirtualOffset() : 0; - auto newreloc=new Relocation_t(BaseObj_t::NOT_IN_DATABASE, 0, "personality", personality_obj, addend); - assert(personality==0 || personality_obj!=NULL); - assert(newreloc); - - if(personality_obj==NULL) - cout<<"Null personality obj: 0x"<<hex<<personality<<endl; - else if(personality_scoop) - cout<<"Found personality scoop: 0x"<<hex<<personality<<" -> " - <<personality_scoop->GetName()<<"+0x"<<hex<<addend<<endl; - else if(personality_insn) - cout<<"Found personality insn: 0x"<<hex<<personality<<" -> " - <<personality_insn->GetBaseID()<<":"<<personality_insn->getDisassembly()<<endl; - else - assert(0); + }; - newehpgm->GetRelocations().insert(newreloc); - firp->GetRelocations().insert(newreloc); + // build an eh program on the stack; + auto ehpgm=EhProgram_t(BaseObj_t::NOT_IN_DATABASE,caf,daf,return_reg, ptrsize); + import_pgm(ehpgm.GetCIEProgram(), fie_it->GetCIE().GetProgram()); + import_pgm(ehpgm.GetFDEProgram(), fie_it->GetProgram()); - // record for this insn - insn->SetEhProgram(newehpgm); - // update cache. - eh_program_cache.insert(whole_pgm_t(newehpgm,personality)); - } - - // build the IR from the FDE. - fie_it->GetCIE().build_ir(insn); - fie_it->build_ir(insn, offset_to_insn_map,firp); - } - else + if(getenv("EHIR_VERBOSE")!=NULL) + ehpgm.print(); + // see if we've already built this one. + auto ehpgm_it = eh_program_cache.find(whole_pgm_t(&ehpgm, personality)) ; + if(ehpgm_it != eh_program_cache.end()) { + // yes, use the cached program. + insn->SetEhProgram(ehpgm_it->first); if(getenv("EHIR_VERBOSE")!=NULL) - { - cout<<hex<<insn->GetAddress()->GetVirtualOffset()<<":" - <<insn->GetBaseID()<<":"<<insn->getDisassembly()<<" has no FDE "<<endl; - } + cout<<"Re-using existing Program!"<<endl; + reusedpgms++; } - - }; + else /* doesn't yet exist! */ + { + + if(getenv("EHIR_VERBOSE")!=NULL) + cout<<"Allocating new Program!"<<endl; + + // allocate a new pgm in the heap so we can give it to the IR. + auto newehpgm=new EhProgram_t(ehpgm); // copy constructor + assert(newehpgm); + firp->GetAllEhPrograms().insert(newehpgm); + + // allocate a relocation for the personality and give it to the IR. + auto personality_scoop=firp->FindScoop(personality); + auto personality_insn_it=offset_to_insn_map.find(personality); + auto personality_insn=personality_insn_it==offset_to_insn_map.end() ? (Instruction_t*)NULL : personality_insn_it->second; + auto personality_obj = personality_scoop ? (BaseObj_t*)personality_scoop : (BaseObj_t*)personality_insn; + auto addend= personality_scoop ? personality - personality_scoop->GetStart()->GetVirtualOffset() : 0; + auto newreloc=new Relocation_t(BaseObj_t::NOT_IN_DATABASE, 0, "personality", personality_obj, addend); + assert(personality==0 || personality_obj!=NULL); + assert(newreloc); + + if(personality_obj==NULL) + cout<<"Null personality obj: 0x"<<hex<<personality<<endl; + else if(personality_scoop) + cout<<"Found personality scoop: 0x"<<hex<<personality<<" -> " + <<personality_scoop->GetName()<<"+0x"<<hex<<addend<<endl; + else if(personality_insn) + cout<<"Found personality insn: 0x"<<hex<<personality<<" -> " + <<personality_insn->GetBaseID()<<":"<<personality_insn->getDisassembly()<<endl; + else + assert(0); + newehpgm->GetRelocations().insert(newreloc); + firp->GetRelocations().insert(newreloc); - auto remove_reloc=[&](Relocation_t* r) -> void - { - firp->GetRelocations().erase(r); - delete r; - }; - auto remove_address=[&](AddressID_t* a) -> void - { - firp->GetAddresses().erase(a); - for(auto &r : a->GetRelocations()) remove_reloc(r); - for(auto &r : firp->GetRelocations()) assert(r->GetWRT() != a); - delete a; - }; - - auto remove_scoop=[&] (DataScoop_t* s) -> void - { - if(s==NULL) - return; - firp->GetDataScoops().erase(s); - remove_address(s->GetStart()); - remove_address(s->GetEnd()); - for(auto &r : s->GetRelocations()) remove_reloc(r); - for(auto &r : firp->GetRelocations()) assert(r->GetWRT() != s); - delete s; - }; - - for(Instruction_t* i : firp->GetInstructions()) + // record for this insn + insn->SetEhProgram(newehpgm); + + // update cache. + eh_program_cache.insert(whole_pgm_t(newehpgm,personality)); + } + + // build the IR from the FDE. + fie_it->GetCIE().build_ir(insn); + fie_it->build_ir(insn, offset_to_insn_map,firp); + } + else { - build_ir_insn(i); + if(getenv("EHIR_VERBOSE")!=NULL) + { + cout<<hex<<insn->GetAddress()->GetVirtualOffset()<<":" + <<insn->GetBaseID()<<":"<<insn->getDisassembly()<<" has no FDE "<<endl; + } } + + }; - cout<<"#ATTRIBUTE total_eh_programs_created="<<dec<<firp->GetAllEhPrograms().size()<<endl; - cout<<"#ATTRIBUTE total_eh_programs_reused="<<dec<<reusedpgms<<endl; - cout<<"#ATTRIBUTE total_eh_programs="<<dec<<firp->GetAllEhPrograms().size()+reusedpgms<<endl; + auto remove_reloc=[&](Relocation_t* r) -> void + { + firp->GetRelocations().erase(r); + delete r; + }; - // will put back in a min, removing for commit - remove_scoop(eh_frame_scoop); - remove_scoop(eh_frame_hdr_scoop); - remove_scoop(gcc_except_table_scoop); - + auto remove_address=[&](AddressID_t* a) -> void + { + firp->GetAddresses().erase(a); + for(auto &r : a->GetRelocations()) remove_reloc(r); + for(auto &r : firp->GetRelocations()) assert(r->GetWRT() != a); + delete a; + }; + + auto remove_scoop=[&] (DataScoop_t* s) -> void + { + if(s==NULL) + return; + firp->GetDataScoops().erase(s); + remove_address(s->GetStart()); + remove_address(s->GetEnd()); + for(auto &r : s->GetRelocations()) remove_reloc(r); + for(auto &r : firp->GetRelocations()) assert(r->GetWRT() != s); + delete s; + }; + + for(Instruction_t* i : firp->GetInstructions()) + { + build_ir_insn(i); } -}; + + cout<<"#ATTRIBUTE total_eh_programs_created="<<dec<<firp->GetAllEhPrograms().size()<<endl; + cout<<"#ATTRIBUTE total_eh_programs_reused="<<dec<<reusedpgms<<endl; + cout<<"#ATTRIBUTE total_eh_programs="<<dec<<firp->GetAllEhPrograms().size()+reusedpgms<<endl; + + remove_scoop(eh_frame_scoop); + remove_scoop(eh_frame_hdr_scoop); + remove_scoop(gcc_except_table_scoop); + +} + +template <int ptrsize> +libIRDB::Instruction_t* split_eh_frame_impl_t<ptrsize>::find_lp(libIRDB::Instruction_t* i) const +{ + const auto fde_it=find_if(fdes.begin(), fdes.end(), [&](const fde_contents_t <ptrsize>& fde) + { return fde.appliesTo(i); }); + + if(fde_it==fdes.end()) + return NULL; + + const auto &the_fde=*fde_it; + const auto &the_lsda=the_fde.GetLSDA(); + const auto &cstab = the_lsda.GetCallSites(); + + const auto cstab_it=find_if(cstab.begin(), cstab.end(), [&](const lsda_call_site_t <ptrsize>& cs) + { return cs.appliesTo(i); }); + + if(cstab_it==cstab.end()) + return NULL; + + const auto &the_cstab_entry=*cstab_it; + const auto lp_addr= the_cstab_entry.GetLandingPadAddress(); + + const auto om_it=offset_to_insn_map.find(lp_addr); + + if(om_it==offset_to_insn_map.end()) + return NULL; + + auto lp=om_it->second; + return lp; +} + + +unique_ptr<split_eh_frame_t> split_eh_frame_t::factory(FileIR_t *firp) +{ + if( firp->GetArchitectureBitWidth()==64) + return unique_ptr<split_eh_frame_t>(new split_eh_frame_impl_t<8>(firp)); + else + return unique_ptr<split_eh_frame_t>(new split_eh_frame_impl_t<4>(firp)); + +} void split_eh_frame(FileIR_t* firp) { auto found_err=false; //auto eh_frame_splitter=(unique_ptr<split_eh_frame_t>)NULL; - auto eh_frame_splitter=unique_ptr<split_eh_frame_t>((nullptr_t)NULL); - if( firp->GetArchitectureBitWidth()==64) - eh_frame_splitter.reset(new split_eh_frame_impl_t<8>(firp)); - else - eh_frame_splitter.reset(new split_eh_frame_impl_t<4>(firp)); + const auto eh_frame_splitter=split_eh_frame_t::factory(firp); found_err=eh_frame_splitter->parse(); eh_frame_splitter->build_ir();