173 lines
5.9 KiB
C++
173 lines
5.9 KiB
C++
/* dwarfpp: C++ binding for a useful subset of libdwarf, plus extra goodies.
|
|
*
|
|
* abstract.hpp: base class and factory definitions
|
|
*
|
|
* Copyright (c) 2008--17, Stephen Kell. For licensing information, see the
|
|
* LICENSE file in the root of the libdwarfpp tree.
|
|
*/
|
|
|
|
#ifndef DWARFPP_ABSTRACT_HPP_
|
|
#define DWARFPP_ABSTRACT_HPP_
|
|
|
|
#include "util.hpp"
|
|
#include "spec.hpp"
|
|
#include "opt.hpp"
|
|
#include "attr.hpp"
|
|
|
|
#include "libdwarf.hpp"
|
|
|
|
namespace dwarf
|
|
{
|
|
using std::string;
|
|
|
|
namespace core
|
|
{
|
|
using namespace dwarf::lib;
|
|
#ifndef NO_TLS
|
|
extern __thread Dwarf_Error current_dwarf_error;
|
|
#else
|
|
#warning "No TLS, so DWARF error reporting is not thread-safe."
|
|
extern Dwarf_Error current_dwarf_error;
|
|
#endif
|
|
// forward declarations
|
|
struct root_die;
|
|
struct iterator_base;
|
|
struct dwarf_current_factory_t;
|
|
struct basic_die;
|
|
struct compile_unit_die;
|
|
using dwarf::spec::opt;
|
|
using dwarf::spec::spec;
|
|
using dwarf::spec::DEFAULT_DWARF_SPEC; // FIXME: ... or get rid of spec:: namespace?
|
|
|
|
/* This is a small interface designed to be implementable over both
|
|
* libdwarf Dwarf_Die handles and whatever other representation we
|
|
* choose. */
|
|
struct abstract_die
|
|
{
|
|
// basically the "libdwarf methods" on core::Die...
|
|
// ... but note that we can change the interface a little, e.g. see get_name()
|
|
// ... to make it more generic but perhaps a little less efficient
|
|
|
|
virtual Dwarf_Off get_offset() const = 0;
|
|
virtual Dwarf_Half get_tag() const = 0;
|
|
virtual opt<string> get_name() const = 0;
|
|
// we can't do this because
|
|
// - it fixes string deletion behaviour to libdwarf-style,
|
|
// - it creates a circular dependency with the contents of libdwarf-handles.hpp
|
|
//virtual unique_ptr<const char, string_deleter> get_raw_name() const = 0;
|
|
virtual Dwarf_Off get_enclosing_cu_offset() const = 0;
|
|
virtual bool has_attr(Dwarf_Half attr) const = 0;
|
|
inline bool has_attribute(Dwarf_Half attr) const { return has_attr(attr); }
|
|
virtual encap::attribute_map copy_attrs() const = 0;
|
|
/* HMM. Can we make this non-virtual?
|
|
* Just move the code from Die (and get rid of that method)? */
|
|
virtual spec& get_spec(root_die& r) const = 0;
|
|
string summary() const;
|
|
};
|
|
|
|
/* the in-memory version, for synthetic (non-library-backed) DIEs. */
|
|
struct in_memory_abstract_die: public virtual abstract_die
|
|
{
|
|
root_die *p_root;
|
|
Dwarf_Off m_offset;
|
|
Dwarf_Off m_cu_offset;
|
|
Dwarf_Half m_tag;
|
|
struct attribute_map : public encap::attribute_map
|
|
{
|
|
private:
|
|
in_memory_abstract_die *p_owner;
|
|
public:
|
|
// constructor -- we start empty and belong to an instance of in_memory_abstract_die
|
|
attribute_map(in_memory_abstract_die& d) : p_owner(&d) {}
|
|
// using encap::attribute_map::attribute_map(
|
|
typedef encap::attribute_map super;
|
|
private:
|
|
void update_cache_on_insert(iterator inserted);
|
|
public:
|
|
std::pair<iterator, bool> insert(const value_type& val)
|
|
{
|
|
auto ret = this->super::insert(val);
|
|
auto inserted = ret.second;
|
|
if (inserted) update_cache_on_insert(ret.first);
|
|
return ret;
|
|
}
|
|
std::pair<iterator,bool> insert(value_type&& val) // was template <typename P>
|
|
{
|
|
auto ret = this->super::insert(val);
|
|
auto inserted = ret.second;
|
|
if (inserted) update_cache_on_insert(ret.first);
|
|
return ret;
|
|
}
|
|
iterator
|
|
insert(const_iterator position, const value_type& val)
|
|
{
|
|
unsigned size_before = size();
|
|
auto ret = this->super::insert(position, val);
|
|
if (size() > size_before) update_cache_on_insert(ret);
|
|
return ret;
|
|
}
|
|
iterator
|
|
insert(const_iterator position, value_type&& val) // was template <typename P>
|
|
{
|
|
unsigned size_before = size();
|
|
auto ret = this->super::insert(position, val);
|
|
if (size() > size_before) update_cache_on_insert(ret);
|
|
return ret;
|
|
}
|
|
} m_attrs;
|
|
|
|
Dwarf_Off get_offset() const { return m_offset; }
|
|
Dwarf_Half get_tag() const { return m_tag; }
|
|
opt<string> get_name() const
|
|
{ return has_attr(DW_AT_name) ? m_attrs.find(DW_AT_name)->second.get_string() : opt<string>(); }
|
|
Dwarf_Off get_enclosing_cu_offset() const
|
|
{ return m_cu_offset; }
|
|
bool has_attr(Dwarf_Half attr) const
|
|
{ return m_attrs.find(attr) != m_attrs.end(); }
|
|
encap::attribute_map copy_attrs() const
|
|
{ return m_attrs; }
|
|
encap::attribute_map& attrs()
|
|
{ return m_attrs; }
|
|
inline spec& get_spec(root_die& r) const;
|
|
root_die& get_root() const
|
|
{ return *p_root; }
|
|
|
|
in_memory_abstract_die(root_die& r, Dwarf_Off offset, Dwarf_Off cu_offset, Dwarf_Half tag)
|
|
: p_root(&r), m_offset(offset), m_cu_offset(cu_offset), m_tag(tag), m_attrs(*this)
|
|
{}
|
|
};
|
|
|
|
// now we can define factory
|
|
struct factory
|
|
{
|
|
/* This mess is caused by spec bootstrapping. We have to construct
|
|
* the CU payload to read its spec info, so this doesn't work in
|
|
* the case of CUs. All factories behave the same for CUs,
|
|
* calling the make_cu_payload method. */
|
|
protected:
|
|
virtual basic_die *make_non_cu_payload(abstract_die&& h, root_die& r) = 0;
|
|
compile_unit_die *make_cu_payload(abstract_die&& , root_die& r);
|
|
compile_unit_die *make_new_cu(root_die& r, std::function<compile_unit_die*()> constructor);
|
|
public:
|
|
inline basic_die *make_payload(abstract_die&& h, root_die& r);
|
|
basic_die *make_new(const iterator_base& parent, Dwarf_Half tag);
|
|
|
|
static inline factory& for_spec(dwarf::spec::spec& def);
|
|
virtual basic_die *dummy_for_tag(Dwarf_Half tag) = 0;
|
|
};
|
|
struct dwarf_current_factory_t : public factory
|
|
{
|
|
basic_die *make_non_cu_payload(abstract_die&& h, root_die& r);
|
|
basic_die *dummy_for_tag(Dwarf_Half tag);
|
|
};
|
|
extern dwarf_current_factory_t dwarf_current_factory;
|
|
inline factory& factory::for_spec(dwarf::spec::abstract_def& def)
|
|
{
|
|
if (&def == &dwarf::spec::dwarf_current) return dwarf_current_factory;
|
|
assert(false); // FIXME support more specs
|
|
}
|
|
struct in_memory_abstract_die;
|
|
}
|
|
}
|
|
|
|
#endif
|