Newer
Older
// @HEADER_COMPONENT libehp
// @HEADER_LANG C++
// @HEADER_BEGIN
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
#ifndef ehp_priv_hpp
#define ehp_priv_hpp
#include <iostream>
#include <iomanip>
#include <fstream>
#include <limits>
#include <stdlib.h>
#include <string.h>
#include <map>
#include <algorithm>
#include <memory>
#include <functional>
#include <stdexcept>
template <int ptrsize>
{
public:
template <class T>
static bool read_type(T &value, uint64_t &position, const uint8_t* const data, const uint64_t max, const bool is_be);
static bool read_type_with_encoding (
const uint8_t encoding, T &value,
const uint8_t* const data,

Jason Hiser
committed
const uint64_t max,
const uint64_t section_start_addr,
const bool is_be
);
const uint8_t* const data,

Jason Hiser
committed
const uint64_t max);
// see https://en.wikipedia.org/wiki/LEB128
static bool read_uleb128
const uint8_t* const data,
const uint64_t max
// see https://en.wikipedia.org/wiki/LEB128
static bool read_sleb128 (
int64_t &result,
const uint8_t* const data,
const uint64_t max
static bool read_length(
uint64_t &act_length,
const uint8_t* const data,
const uint64_t max,
};
template <int ptrsize>
class eh_program_insn_t : public EHProgramInstruction_t
{
public:
eh_program_insn_t() ;

Jason Hiser
committed
eh_program_insn_t(const string &s) ;
tuple<string, int64_t, int64_t> decode() const;
uint64_t getSize() const { return program_bytes.size(); }
void push_byte(uint8_t c) ;
static void print_uleb_operand(
const uint8_t* const data,

Jason Hiser
committed
const uint64_t max) ;
static void print_sleb_operand(
const uint8_t* const data,

Jason Hiser
committed
const uint64_t max) ;
bool parse_insn(
uint8_t opcode,
const uint8_t* const data,
bool isRestoreState() const ;
bool isRememberState() const ;
bool advance(uint64_t &cur_addr, uint64_t CAF) const ;

Jason Hiser
committed
const vector<uint8_t>& getBytes() const ;
vector<uint8_t>& getBytes() ;

Jason Hiser
committed
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 EHProgram_t
{
public:
void push_insn(const eh_program_insn_t<ptrsize> &i);
void print(const uint64_t start_addr, const int64_t caf) const;
const uint64_t& program_start_position,
const uint8_t* const data,
const uint64_t &max_program_pos,
const bool is_be
);

Jason Hiser
committed
virtual const EHProgramInstructionVector_t* getInstructions() const ;
vector<eh_program_insn_t <ptrsize> >& getInstructionsInternal() ;
const vector<eh_program_insn_t <ptrsize> >& getInstructionsInternal() const ;

Jason Hiser
committed
vector<eh_program_insn_t <ptrsize> > instructions;
mutable EHProgramInstructionVector_t instructions_cache;
};
template <int ptrsize>
bool operator<(const eh_program_t<ptrsize>& a, const eh_program_t<ptrsize>& b);
template <int ptrsize>
class cie_contents_t : public CIEContents_t, private 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;
uint64_t return_address_register_column;
uint64_t augmentation_data_length;
uint64_t personality_pointer_position;
uint64_t personality_pointer_size;
eh_program_t<ptrsize> eh_pgm;
public:
cie_contents_t() ;
const eh_program_t<ptrsize>& getProgram() const ;
uint64_t getPosition() const { return cie_position; }
uint64_t getLength() const { return length; }
int64_t getDAF() const ;
uint8_t getPersonalityEncoding() const { return personality_encoding; }
uint64_t getPersonalityPointerPosition() const { return personality_pointer_position; };
uint64_t getPersonalityPointerSize() const { return personality_pointer_size; };
uint64_t getReturnRegister() const ;

Jason Hiser
committed
string getAugmentation() const ;
uint8_t getLSDAEncoding() const ;
uint8_t getFDEEncoding() const ;
const uint8_t* const data,

Jason Hiser
committed
const uint64_t max,
};
template <int ptrsize>
class lsda_call_site_action_t : public LSDACallSiteAction_t, private eh_frame_util_t<ptrsize>
{
private:
int64_t action;
public:
lsda_call_site_action_t() ;
bool parse_lcsa(uint64_t &pos, const uint8_t* const data, const uint64_t max, bool &end, const bool is_be);
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: public LSDATypeTableEntry_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 index,
const uint8_t* const data,
const uint64_t max,
);
void print() const;
};
template <int ptrsize>
class lsda_call_site_t : public LSDACallSite_t, private eh_frame_util_t<ptrsize>
{
private:
uint64_t call_site_offset;
uint64_t call_site_addr;
uint64_t call_site_addr_position;
uint64_t call_site_length;
uint64_t call_site_end_addr;
uint64_t call_site_end_addr_position;
uint64_t landing_pad_offset;
uint64_t landing_pad_addr;
uint64_t landing_pad_addr_position;
uint64_t landing_pad_addr_end_position;
uint64_t action;
uint64_t action_table_offset;
uint64_t action_table_addr;

Jason Hiser
committed
vector<lsda_call_site_action_t <ptrsize> > action_table;
mutable LSDACallSiteActionVector_t action_table_cache;
public:
lsda_call_site_t() ;

Jason Hiser
committed
const LSDACallSiteActionVector_t* getActionTable() const;
const vector<lsda_call_site_action_t <ptrsize> >& getActionTableInternal() const { return action_table; }
vector<lsda_call_site_action_t <ptrsize> >& getActionTableInternal() { return action_table; }
uint64_t getCallSiteAddress() const { return call_site_addr ; }
uint64_t getCallSiteAddressPosition() const { return call_site_addr_position; }
uint64_t getCallSiteEndAddress() const { return call_site_end_addr ; }
uint64_t getCallSiteEndAddressPosition() const { return call_site_end_addr_position; }
uint64_t getLandingPadAddress() const { return landing_pad_addr ; }
uint64_t getLandingPadAddressPosition() const { return landing_pad_addr_position; }
uint64_t getLandingPadAddressEndPosition() const { return landing_pad_addr_end_position; }
bool parse_lcs(
const uint64_t action_table_start_addr,
const uint64_t cs_table_start_addr,
const uint8_t cs_table_encoding,
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,
const bool is_be
);
void print() const;
};
// short hand for a vector of call sites

Jason Hiser
committed
template <int ptrsize> using call_site_table_t = vector<lsda_call_site_t <ptrsize> > ;
template <int ptrsize> using lsda_type_table_t = vector<lsda_type_table_entry_t <ptrsize> > ;
template <int ptrsize>
class lsda_t : public 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;
uint64_t type_table_addr_location;
uint8_t cs_table_encoding;
uint64_t cs_table_start_offset;
uint64_t cs_table_start_addr;
uint64_t cs_table_start_addr_location;
uint64_t cs_table_length;
uint64_t cs_table_end_addr;
uint64_t action_table_start_addr;

Jason Hiser
committed
call_site_table_t<ptrsize> call_site_table;

Jason Hiser
committed
// this is a vector of pointers into the call site table.
// and is the thing we return when getCallSites is called.
// this is marked as mutable so we can cache it between calls.
mutable CallSiteVector_t call_site_table_cache ;
lsda_type_table_t<ptrsize> type_table;

Jason Hiser
committed
// this is a vector of pointers into the type_table
// and is the thing we return when getTypeTable is called.
// this is marked as mutable so we can cache it between calls.
mutable TypeTableVector_t type_table_cache ;

Jason Hiser
committed
lsda_t();

Jason Hiser
committed
uint8_t getTTEncoding() const ;
const ScoopReplacement_t* gcc_except_scoop_data,
const uint64_t fde_region_start,
const bool is_be
uint64_t getLandingPadBaseAddress() const { return landing_pad_base_addr; }
const CallSiteVector_t* getCallSites() const ;
uint64_t getCallSiteTableAddress() const { return cs_table_start_addr; }
uint64_t getCallSiteTableAddressLocation() const { return cs_table_start_addr_location; }
uint64_t getCallSiteTableLength() const { return cs_table_length; }
uint8_t getCallSiteTableEncoding() const { return cs_table_encoding; }
const call_site_table_t<ptrsize> getCallSitesInternal() const { return call_site_table;}
const TypeTableVector_t* getTypeTable() const ;
uint64_t getTypeTableAddress() const { return type_table_addr; }
uint64_t getTypeTableAddressLocation() const { return type_table_addr_location; }
uint8_t getTypeTableEncoding() const { return type_table_encoding; }
};
template <int ptrsize>
class fde_contents_t : public FDEContents_t, eh_frame_util_t<ptrsize>
uint64_t fde_position;
uint64_t cie_position;
uint64_t fde_start_addr;
uint64_t fde_end_addr;
uint64_t fde_range_len;
uint64_t lsda_addr;
uint64_t fde_start_addr_position;
uint64_t fde_end_addr_position;
uint64_t fde_end_addr_size;
uint64_t fde_lsda_addr_position;
uint64_t fde_lsda_addr_size;
lsda_t<ptrsize> lsda;
eh_program_t<ptrsize> eh_pgm;
cie_contents_t<ptrsize> cie_info;
public:
fde_contents_t() ;
fde_contents_t(const uint64_t start_addr, const uint64_t end_addr)
:
fde_start_addr(start_addr),
fde_end_addr(end_addr)
{}
uint64_t getPosition() const { return fde_position; }
uint64_t getLength() const { return length; }
uint64_t getStartAddress() const { return fde_start_addr; }
uint64_t getEndAddress() const {return fde_end_addr; }
uint64_t getFDEStartAddress() const { return fde_start_addr; }
uint64_t getFDEEndAddress() const {return fde_end_addr; }
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* getLSDA() const { return &lsda; }
const lsda_t<ptrsize>& getLSDAInternal() const { return lsda; }
uint64_t getLSDAAddress() const { return lsda_addr; }
uint64_t getStartAddressPosition() const { return fde_start_addr_position; }
uint64_t getEndAddressPosition() const { return fde_end_addr_position; }
uint64_t getEndAddressSize() const { return fde_end_addr_size; }
uint64_t getLSDAAddressPosition() const { return fde_lsda_addr_position; }
uint64_t getLSDAAddressSize() const { return fde_lsda_addr_size; }
const uint64_t &fde_position,
const uint64_t &cie_position,
const uint8_t* const data,
const ScoopReplacement_t *gcc_except_scoop,
const bool is_be);
void print() const;
};
template <int ptrsize>
bool operator<(const fde_contents_t<ptrsize>& a, const fde_contents_t<ptrsize>& b) { return a.getFDEEndAddress()-1 < b.getFDEStartAddress(); }
template <int ptrsize>
class split_eh_frame_impl_t : public EHFrameParser_t
unique_ptr<ScoopReplacement_t> eh_frame_scoop;
unique_ptr<ScoopReplacement_t> eh_frame_hdr_scoop;
unique_ptr<ScoopReplacement_t> gcc_except_table_scoop;

Jason Hiser
committed
vector<cie_contents_t <ptrsize> > cies;
mutable CIEVector_t cies_cache;
set<fde_contents_t <ptrsize> > fdes;
mutable FDEVector_t fdes_cache;
split_eh_frame_impl_t
(
const ScoopReplacement_t &eh_frame,
const ScoopReplacement_t &eh_frame_hdr,
const ScoopReplacement_t &gcc_except_table
)
:
eh_frame_scoop(new ScoopReplacement_t(eh_frame)),
eh_frame_hdr_scoop(new ScoopReplacement_t(eh_frame_hdr)),
gcc_except_table_scoop(new ScoopReplacement_t(gcc_except_table))
{
}
bool parse_arm(const bool is_be);

Jason Hiser
committed
virtual const FDEVector_t* getFDEs() const;
virtual const CIEVector_t* getCIEs() const;
virtual const FDEContents_t* findFDE(uint64_t addr) const;
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
// overrides for arm-specific classes.
/*
template <int ptrsize>
class arm_lsda_t : public lsda_t<ptrsize>
{
private:
public:
arm_lsda_t() : lsda_t<ptrsize>() {}
bool parse_lsda(const uint64_t lsda_addr,
const ScoopReplacement_t* exidx_scoop,
const uint64_t fde_region_start,
const bool is_be
);
void print() const { lsda_t::print(); }
};
*/
template <int ptrsize>
class arm_cie_contents_t : public CIEContents_t, private eh_frame_util_t<ptrsize>
{
private:
uint64_t personality;
// there's not really a CIE on arm mode, so there's no pgm.
// but we declare one so people cna inspect that it's empty.
const eh_program_t<ptrsize> pgm;
const eh_program_t<ptrsize>& getProgram() const { return pgm; }
uint64_t getPosition() const { throw std::runtime_error( " not implemented"); }
uint64_t getLength() const { throw std::runtime_error( " not implemented"); }
uint64_t getCAF() const { return 4; }
int64_t getDAF() const { return 4; }
uint8_t getPersonalityEncoding() const { return 0; }
uint64_t getPersonality() const { return personality; }
uint64_t getPersonalityPointerPosition() const { throw std::runtime_error( " not implemented"); }
uint64_t getPersonalityPointerSize() const { throw std::runtime_error( " not implemented"); }
uint64_t getReturnRegister() const { return 0; }
string getAugmentation() const { throw std::runtime_error( " not implemented"); }
uint8_t getLSDAEncoding() const { throw std::runtime_error( " not implemented"); }
uint8_t getFDEEncoding() const { throw std::runtime_error( " not implemented"); }
virtual void print(const uint64_t startAddr) const
{
cout << "personality=" << hex << personality << endl;
}
void setPersonality(uint64_t pers) { personality=pers; }
};
template <int ptrsize>
class arm_eh_program_insn_t : public EHProgramInstruction_t
{
public:
arm_eh_program_insn_t() ;
arm_eh_program_insn_t(const vector<uint8_t> &v)
program_bytes(begin(v),end(v))
{
}
virtual ~arm_eh_program_insn_t() {}
virtual void print(uint64_t &pc, int64_t caf=1) const ;
virtual tuple<string, int64_t, int64_t> decode() const { throw std::runtime_error("not implemented"); }
virtual uint64_t getSize() const { return program_bytes.size(); }
virtual bool isNop() const { return false; }
virtual bool isDefCFAOffset() const { return false; }
virtual bool isRestoreState() const { return false; }
virtual bool isRememberState() const { return false; }
virtual const EHProgramInstructionByteVector_t& getBytes() const { return program_bytes; }
virtual bool advance(uint64_t &cur_addr, uint64_t CAF) const { return false; /* no advance operations for arm */ }
private:
vector<uint8_t> program_bytes;
};
template <int ptrsize>
class arm_eh_program_t : public EHProgram_t
{
public:
arm_eh_program_t(const vector<uint8_t>& unwind_pgm={});
virtual const EHProgramInstructionVector_t* getInstructions() const;
vector<arm_eh_program_insn_t <ptrsize> >& getInstructionsInternal() { return instructions; }
const vector<eh_program_insn_t <ptrsize> >& getInstructionsInternal() const { return instructions; }
void print(const uint64_t start_addr, const int64_t caf) const;
private:
vector<arm_eh_program_insn_t <ptrsize> > instructions;
mutable EHProgramInstructionVector_t instructions_cache;
};
template <int ptrsize>
class arm_fde_contents_t : public FDEContents_t, eh_frame_util_t<ptrsize>
{
uint64_t fde_start_addr=0;
uint64_t fde_end_addr=0;
uint64_t fde_lsda_addr=0;
uint32_t can_unwind=false;
lsda_t<ptrsize> lsda;
arm_cie_contents_t<ptrsize> cie;
public:
arm_fde_contents_t( uint64_t fde_start,uint64_t lsda_addr,bool p_can_unwind) :
fde_start_addr(fde_start),
fde_lsda_addr(lsda_addr),
can_unwind(p_can_unwind)
{}
arm_fde_contents_t(const uint64_t start_addr, const uint64_t end_addr)
:
fde_start_addr(start_addr),
fde_end_addr(end_addr)
{}
virtual uint64_t getPosition() const { throw std::runtime_error( " not implemented"); }
virtual uint64_t getLength() const { return fde_end_addr-fde_start_addr+1; }
virtual uint64_t getStartAddress() const { return fde_start_addr; }
virtual uint64_t getEndAddress() const { return fde_end_addr; }
virtual uint64_t getFDEStartAddress() const { return fde_start_addr; }
virtual uint64_t getFDEEndAddress() const {return fde_end_addr; }
virtual const CIEContents_t& getCIE() const { return cie; }
virtual const EHProgram_t& getProgram() const { return eh_pgm; }
virtual const LSDA_t* getLSDA() const { return &lsda; }
virtual uint64_t getLSDAAddress() const { return fde_lsda_addr; }
virtual uint64_t getStartAddressPosition() const { throw std::runtime_error(" not implemented"); }
virtual uint64_t getEndAddressPosition() const { throw std::runtime_error(" not implemented"); }
virtual uint64_t getEndAddressSize() const { throw std::runtime_error(" not implemented"); }
virtual uint64_t getLSDAAddressPosition() const { throw std::runtime_error(" not implemented"); }
virtual uint64_t getLSDAAddressSize() const { throw std::runtime_error(" not implemented"); }
virtual void print() const ;
void setEndAddress(uint64_t end) { fde_end_addr = end; }
bool getCanUnwind() const { return can_unwind; }
void setPersonality(uint64_t pers) { cie.setPersonality(pers); }
void setProgram(const arm_eh_program_t<ptrsize>& pgm) { eh_pgm=pgm; }
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
bool parse_lsda(const uint64_t lsda_addr,
const ScoopReplacement_t* extab_scoop,
const uint64_t fde_region_start,
const bool is_be
)
{
return lsda.parse_lsda(lsda_addr,extab_scoop,fde_region_start,is_be);
}
};
template <int ptrsize>
bool operator<(const arm_fde_contents_t<ptrsize>& a, const arm_fde_contents_t<ptrsize>& b) { return a.getFDEEndAddress()-1 < b.getFDEStartAddress(); }
template <int ptrsize>
class split_arm_eh_frame_impl_t : public EHFrameParser_t
{
private:
unique_ptr<ScoopReplacement_t> extab_scoop;
unique_ptr<ScoopReplacement_t> exidx_scoop;
unique_ptr<ScoopReplacement_t> lnk_scoop;
set<arm_fde_contents_t <ptrsize> > fdes;
mutable CIEVector_t cies_cache;
mutable FDEVector_t fdes_cache;
vector<uint8_t> parse_arm_eh_pgm(const uint64_t lsda_addr, const ScoopReplacement_t *lsda_scoop, arm_fde_contents_t<ptrsize> &fde, const bool is_be);
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
public:
split_arm_eh_frame_impl_t
(
const ScoopReplacement_t &extab,
const ScoopReplacement_t &exidx,
const ScoopReplacement_t &lnk
)
:
extab_scoop(new ScoopReplacement_t(extab)),
exidx_scoop(new ScoopReplacement_t(exidx)),
lnk_scoop (new ScoopReplacement_t(lnk))
{
}
bool parse(const bool is_be);
void print() const {};
virtual const FDEVector_t* getFDEs() const ;
virtual const CIEVector_t* getCIEs() const ;
virtual const FDEContents_t* findFDE(uint64_t addr) const ;
};