Skip to content

Commit 7c381ca

Browse files
committedJul 18, 2017
Refactor lib.hpp and lib.cpp into smaller units. Move the libdwarf includes out of private/, albeit for incidental reasons.
1 parent 624b567 commit 7c381ca

25 files changed

+6761
-6477
lines changed
 

‎Makefile.am

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ dwarfpp_private_includedir = $(includedir)/dwarfpp/private
1616
dwarfpp_private_include_HEADERS = include/dwarfpp/private/libdwarf-handles.hpp include/dwarfpp/private/libdwarf.hpp
1717

1818
lib_LTLIBRARIES = src/libdwarfpp.la
19-
src_libdwarfpp_la_SOURCES = src/expr.cpp src/lib.cpp src/attr.cpp src/frame.cpp src/regs.cpp src/spec.cpp src/util.cpp
19+
src_libdwarfpp_la_SOURCES = src/libdwarf.cpp src/libdwarf-handles.cpp src/libdwarf-data.cpp src/expr.cpp src/lib.cpp src/attr.cpp src/frame.cpp src/regs.cpp src/spec.cpp src/util.cpp src/root.cpp src/abstract.cpp src/iter.cpp src/dies.cpp
2020
src_libdwarfpp_la_LIBADD = $(LIBSRK31CXX_LIBS) $(LIBCXXFILENO_LIBS) -lsupc++
2121

2222
INC_PP = include/dwarfpp

‎examples/subseq.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
#include <dwarfpp/attr.hpp>
55
#include <srk31/selective_iterator.hpp>
66

7-
using std::cout;
7+
using std::cout;
8+
using std::cerr;
89
using std::endl;
910
using namespace dwarf;
1011
using dwarf::core::iterator_sibs;

‎include/dwarfpp/abstract-inl.hpp

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#ifndef DWARFPP_ABSTRACT_INL_HPP_
2+
#define DWARFPP_ABSTRACT_INL_HPP_
3+
4+
#include <iostream>
5+
#include <utility>
6+
7+
#include "abstract.hpp"
8+
#include "root.hpp"
9+
#include "iter.hpp"
10+
#include "dies.hpp"
11+
12+
namespace dwarf
13+
{
14+
using std::string;
15+
16+
namespace core
17+
{
18+
inline spec& in_memory_abstract_die::get_spec(root_die& r) const
19+
{ return r.cu_pos(m_cu_offset).spec_here(); }
20+
21+
inline basic_die *factory::make_payload(abstract_die&& h, root_die& r)
22+
{
23+
Die d(std::move(dynamic_cast<Die&&>(h)));
24+
if (d.tag_here() == DW_TAG_compile_unit) return make_cu_payload(std::move(d), r);
25+
else return make_non_cu_payload(std::move(d), r);
26+
}
27+
}
28+
}
29+
30+
#endif

‎include/dwarfpp/abstract.hpp

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// abstract_die and factory
2+
#ifndef DWARFPP_ABSTRACT_HPP_
3+
#define DWARFPP_ABSTRACT_HPP_
4+
5+
#include "util.hpp"
6+
#include "spec.hpp"
7+
#include "opt.hpp"
8+
#include "attr.hpp"
9+
10+
#include "libdwarf.hpp"
11+
12+
namespace dwarf
13+
{
14+
using std::string;
15+
16+
namespace core
17+
{
18+
using namespace dwarf::lib;
19+
#ifndef NO_TLS
20+
extern __thread Dwarf_Error current_dwarf_error;
21+
#else
22+
#warning "No TLS, so DWARF error reporting is not thread-safe."
23+
extern Dwarf_Error current_dwarf_error;
24+
#endif
25+
// forward declarations
26+
struct root_die;
27+
struct iterator_base;
28+
struct dwarf_current_factory_t;
29+
struct basic_die;
30+
struct compile_unit_die;
31+
using dwarf::spec::opt;
32+
using dwarf::spec::spec;
33+
using dwarf::spec::DEFAULT_DWARF_SPEC; // FIXME: ... or get rid of spec:: namespace?
34+
35+
/* This is a small interface designed to be implementable over both
36+
* libdwarf Dwarf_Die handles and whatever other representation we
37+
* choose. */
38+
struct abstract_die
39+
{
40+
// basically the "libdwarf methods" on core::Die...
41+
// ... but note that we can change the interface a little, e.g. see get_name()
42+
// ... to make it more generic but perhaps a little less efficient
43+
44+
virtual Dwarf_Off get_offset() const = 0;
45+
virtual Dwarf_Half get_tag() const = 0;
46+
virtual opt<string> get_name() const = 0;
47+
// we can't do this because
48+
// - it fixes string deletion behaviour to libdwarf-style,
49+
// - it creates a circular dependency with the contents of libdwarf-handles.hpp
50+
//virtual unique_ptr<const char, string_deleter> get_raw_name() const = 0;
51+
virtual Dwarf_Off get_enclosing_cu_offset() const = 0;
52+
virtual bool has_attr(Dwarf_Half attr) const = 0;
53+
inline bool has_attribute(Dwarf_Half attr) const { return has_attr(attr); }
54+
virtual encap::attribute_map copy_attrs() const = 0;
55+
/* HMM. Can we make this non-virtual?
56+
* Just move the code from Die (and get rid of that method)? */
57+
virtual spec& get_spec(root_die& r) const = 0;
58+
string summary() const;
59+
};
60+
61+
/* the in-memory version, for synthetic (non-library-backed) DIEs. */
62+
struct in_memory_abstract_die: public virtual abstract_die
63+
{
64+
root_die *p_root;
65+
Dwarf_Off m_offset;
66+
Dwarf_Off m_cu_offset;
67+
Dwarf_Half m_tag;
68+
encap::attribute_map m_attrs;
69+
70+
Dwarf_Off get_offset() const { return m_offset; }
71+
Dwarf_Half get_tag() const { return m_tag; }
72+
opt<string> get_name() const
73+
{ return has_attr(DW_AT_name) ? m_attrs.find(DW_AT_name)->second.get_string() : opt<string>(); }
74+
Dwarf_Off get_enclosing_cu_offset() const
75+
{ return m_cu_offset; }
76+
bool has_attr(Dwarf_Half attr) const
77+
{ return m_attrs.find(attr) != m_attrs.end(); }
78+
encap::attribute_map copy_attrs() const
79+
{ return m_attrs; }
80+
encap::attribute_map& attrs()
81+
{ return m_attrs; }
82+
inline spec& get_spec(root_die& r) const;
83+
root_die& get_root() const
84+
{ return *p_root; }
85+
86+
in_memory_abstract_die(root_die& r, Dwarf_Off offset, Dwarf_Off cu_offset, Dwarf_Half tag)
87+
: p_root(&r), m_offset(offset), m_cu_offset(cu_offset), m_tag(tag)
88+
{}
89+
};
90+
91+
// now we can define factory
92+
struct factory
93+
{
94+
/* This mess is caused by spec bootstrapping. We have to construct
95+
* the CU payload to read its spec info, so this doesn't work in
96+
* the case of CUs. All factories behave the same for CUs,
97+
* calling the make_cu_payload method. */
98+
protected:
99+
virtual basic_die *make_non_cu_payload(abstract_die&& h, root_die& r) = 0;
100+
compile_unit_die *make_cu_payload(abstract_die&& , root_die& r);
101+
compile_unit_die *make_new_cu(root_die& r, std::function<compile_unit_die*()> constructor);
102+
public:
103+
inline basic_die *make_payload(abstract_die&& h, root_die& r);
104+
basic_die *make_new(const iterator_base& parent, Dwarf_Half tag);
105+
106+
static inline factory& for_spec(dwarf::spec::spec& def);
107+
virtual basic_die *dummy_for_tag(Dwarf_Half tag) = 0;
108+
};
109+
struct dwarf_current_factory_t : public factory
110+
{
111+
basic_die *make_non_cu_payload(abstract_die&& h, root_die& r);
112+
basic_die *dummy_for_tag(Dwarf_Half tag);
113+
};
114+
extern dwarf_current_factory_t dwarf_current_factory;
115+
inline factory& factory::for_spec(dwarf::spec::abstract_def& def)
116+
{
117+
if (&def == &dwarf::spec::dwarf_current) return dwarf_current_factory;
118+
assert(false); // FIXME support more specs
119+
}
120+
struct in_memory_abstract_die;
121+
}
122+
}
123+
124+
#endif

‎include/dwarfpp/attr.hpp

+2-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* dwarfpp: C++ binding for a useful subset of libdwarf, plus extra goodies.
22
*
3-
* attr.hpp: transparently-allocated, mutable representations
3+
* attr.hpp: transparently-allocated, mutable representations
44
* of libdwarf-like structures.
55
*
66
* Copyright (c) 2010--17, Stephen Kell.
@@ -13,20 +13,13 @@
1313
#include <vector>
1414

1515
#include "spec.hpp"
16-
#include "private/libdwarf.hpp" /* includes libdwarf.h, Error, No_entry, some fwddecls */
17-
#include "expr.hpp"
16+
#include "libdwarf.hpp" /* includes libdwarf.h, Error, No_entry, some fwddecls */
1817

1918
#include <boost/optional.hpp>
2019
#include <srk31/util.hpp> /* for forward_constructors */
2120

2221
namespace dwarf
2322
{
24-
namespace lib
25-
{
26-
bool operator==(const Dwarf_Ranges& e1, const Dwarf_Ranges& e2);
27-
bool operator!=(const Dwarf_Ranges& e1, const Dwarf_Ranges& e2);
28-
std::ostream& operator<<(std::ostream& s, const Dwarf_Ranges& e);
29-
}
3023
namespace core
3124
{
3225
// libdwarf handle stuff -- FIXME: avoid depending where possible
@@ -43,7 +36,6 @@ namespace dwarf
4336
}
4437
namespace encap
4538
{
46-
using namespace dwarf::expr;
4739
using namespace dwarf::lib;
4840
class rangelist;
4941
class loclist;

‎include/dwarfpp/dies-inl.hpp

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#ifndef DWARFPP_DIES_INL_HPP_
2+
#define DWARFPP_DIES_INL_HPP_
3+
4+
#include <iostream>
5+
#include <utility>
6+
#include <libgen.h> /* FIXME: use a C++-y way to do dirname() */
7+
8+
#include "dies.hpp"
9+
10+
namespace dwarf
11+
{
12+
using std::string;
13+
14+
namespace core
15+
{
16+
inline iterator_base
17+
with_named_children_die::named_child(const std::string& name) const
18+
{
19+
/* The default implementation just asks the root. Since we've somehow
20+
* been called via the payload, we have the added inefficiency of
21+
* searching for ourselves first. This shouldn't happen, though
22+
* I'm not sure if we explicitly avoid it. Warn. */
23+
debug(2) << "Warning: inefficient usage of with_named_children_die::named_child" << endl;
24+
25+
/* NOTE: the idea about payloads knowing about their children is
26+
* already dodgy because it breaks our "no knowledge of structure"
27+
* property. We can likely work around this by requiring that named_child
28+
* implementations call back to the root if they fail, i.e. that the root
29+
* is allowed to know about structure which the child doesn't.
30+
* Or we could call into the root to "validate" our view, somehow,
31+
* to support the case where a given root "hides" some DIEs.
32+
* This might be a method
33+
*
34+
* iterator_base
35+
* root_die::check_named_child(const iterator_base& found, const std::string& name)
36+
*
37+
* which calls around into find_named_child if the check fails.
38+
*
39+
* i.e. the root_die has a final say, but the payload itself "hints"
40+
* at the likely answer. So the payload can avoid find_named_child's
41+
* linear search in the common case, but fall back to it in weird
42+
* scenarios (deletions).
43+
*/
44+
root_die& r = get_root();
45+
Dwarf_Off off = get_offset();
46+
auto start_iter = r.find(off);
47+
return r.find_named_child(start_iter, name);
48+
}
49+
50+
inline opt<std::string> compile_unit_die::source_file_fq_pathname(unsigned o) const
51+
{
52+
string filepath = source_file_name(o);
53+
opt<string> maybe_dir = this->get_comp_dir();
54+
if (filepath.length() > 0 && filepath.at(0) == '/') return opt<string>(filepath);
55+
else if (!maybe_dir) return opt<string>();
56+
else
57+
{
58+
// we want to do
59+
// return dir + "/" + path;
60+
// BUT "path" can contain "../".
61+
string ourdir = *maybe_dir;
62+
string ourpath = filepath;
63+
while (boost::starts_with(ourpath, "../"))
64+
{
65+
char *buf = strdup(ourdir.c_str());
66+
ourdir = dirname(buf); /* modifies buf! */
67+
free(buf);
68+
ourpath = ourpath.substr(3);
69+
}
70+
71+
return opt<string>(ourdir + "/" + ourpath);
72+
}
73+
}
74+
75+
/* FIXME: these use libdwarf-specific StringList -- how to abstract this?
76+
* Add to abstract_die? Move to root_die? As a private interface on root_die
77+
* with which compile_unit_die is friendly? */
78+
inline std::string compile_unit_die::source_file_name(unsigned o) const
79+
{
80+
StringList names(d);
81+
//if (!names) throw Error(current_dwarf_error, 0);
82+
/* Source file numbers in DWARF are indexed starting from 1.
83+
* Source file zero means "no source file".
84+
* However, our array filesbuf is indexed beginning zero! */
85+
assert(o <= names.get_len()); // FIXME: how to report error? ("throw No_entry();"?)
86+
return names[o - 1];
87+
}
88+
89+
inline unsigned compile_unit_die::source_file_count() const
90+
{
91+
// FIXME: cache some stuff
92+
StringList names(d);
93+
return names.get_len();
94+
}
95+
}
96+
}
97+
98+
#endif

‎include/dwarfpp/dies.hpp

+610
Large diffs are not rendered by default.

‎include/dwarfpp/expr.hpp

+5-15
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@
55
* Copyright (c) 2010--17, Stephen Kell.
66
*/
77

8-
#ifndef __DWARFPP_EXPR_HPP
9-
#define __DWARFPP_EXPR_HPP
8+
#ifndef DWARFPP_EXPR_HPP_
9+
#define DWARFPP_EXPR_HPP_
1010

1111
#include <vector>
1212
#include <stack>
1313
#include <boost/icl/interval_map.hpp>
1414
#include <strings.h> // for bzero
1515
#include "spec.hpp"
16-
#include "private/libdwarf.hpp"
16+
#include "libdwarf.hpp"
17+
#include "libdwarf-handles.hpp"
18+
#include "abstract.hpp"
1719
#include "opt.hpp"
1820

1921
namespace dwarf
@@ -24,18 +26,6 @@ namespace dwarf
2426
using std::vector;
2527
using std::string;
2628

27-
namespace lib
28-
{
29-
bool operator==(const Dwarf_Loc& e1, const Dwarf_Loc& e2);
30-
bool operator!=(const Dwarf_Loc& e1, const Dwarf_Loc& e2);
31-
bool operator<(const lib::Dwarf_Loc& arg1, const lib::Dwarf_Loc& arg2);
32-
std::ostream& operator<<(std::ostream& s, const Dwarf_Loc /* a.k.a. expr_instr */ & e);
33-
std::ostream& operator<<(std::ostream& s, const Dwarf_Locdesc& ld);
34-
bool operator==(const Dwarf_Ranges& e1, const Dwarf_Ranges& e2);
35-
bool operator!=(const Dwarf_Ranges& e1, const Dwarf_Ranges& e2);
36-
std::ostream& operator<<(std::ostream& s, const Dwarf_Ranges& e);
37-
}
38-
3929
namespace expr
4030
{
4131
class evaluator;

‎include/dwarfpp/iter-inl.hpp

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#ifndef DWARFPP_ITER_INL_HPP_
2+
#define DWARFPP_ITER_INL_HPP_
3+
4+
#include <iostream>
5+
#include <utility>
6+
7+
#include "iter.hpp"
8+
#include "dies.hpp"
9+
10+
namespace dwarf
11+
{
12+
using std::string;
13+
using std::endl;
14+
15+
namespace core
16+
{
17+
inline spec& iterator_base::spec_here() const
18+
{
19+
if (tag_here() == DW_TAG_compile_unit)
20+
{
21+
// we only ask CUs for their spec after payload construction
22+
assert(state == WITH_PAYLOAD);
23+
auto p_cu = dynamic_pointer_cast<compile_unit_die>(cur_payload);
24+
assert(p_cu);
25+
switch(p_cu->version_stamp)
26+
{
27+
case 2: return ::dwarf::spec::dwarf_current; // HACK: we don't model old DWARFs for now
28+
case 4: return ::dwarf::spec::dwarf_current;
29+
default:
30+
debug() << "Warning: saw unexpected DWARF version stamp "
31+
<< p_cu->version_stamp << endl;
32+
return ::dwarf::spec::dwarf_current;
33+
}
34+
}
35+
else return get_handle().get_spec(*p_root);
36+
}
37+
38+
inline iterator_df<compile_unit_die>
39+
iterator_base::enclosing_cu() const
40+
{ return get_root().pos(enclosing_cu_offset_here(), 1, opt<Dwarf_Off>(0UL)); }
41+
inline sequence< iterator_sibs<> >
42+
iterator_base::children_here()
43+
{
44+
return std::make_pair<iterator_sibs<>, iterator_sibs<> >(
45+
p_root->first_child(*this),
46+
iterator_base::END
47+
);
48+
}
49+
inline sequence< iterator_sibs<> >
50+
iterator_base::children_here() const
51+
{ return const_cast<iterator_base*>(this)->children(); }
52+
// synonyms
53+
inline sequence< iterator_sibs<> >
54+
iterator_base::children() { return children_here(); }
55+
inline sequence< iterator_sibs<> >
56+
iterator_base::children() const { return children_here(); }
57+
}
58+
}
59+
60+
#endif

‎include/dwarfpp/iter.hpp

+838
Large diffs are not rendered by default.

‎include/dwarfpp/lib.hpp

+11-2,804
Large diffs are not rendered by default.

‎include/dwarfpp/private/libdwarf-handles.hpp ‎include/dwarfpp/libdwarf-handles.hpp

+50-16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,33 @@
1+
/* dwarfpp: C++ binding for a useful subset of libdwarf, plus extra goodies.
2+
*
3+
* libdwarf-handles.hpp: basic C++ wrapping of libdwarf C API (info section).
4+
*
5+
* Copyright (c) 2008--17, Stephen Kell.
6+
*/
7+
8+
#ifndef DWARFPP_PRIVATE_LIBDWARF_HANDLES_HPP_
9+
#define DWARFPP_PRIVATE_LIBDWARF_HANDLES_HPP_
10+
11+
#include "dwarfpp/libdwarf.hpp"
12+
#include "dwarfpp/abstract.hpp"
13+
14+
#include <iostream>
15+
#include <utility>
16+
#include <functional>
17+
#include <vector>
18+
19+
namespace dwarf
20+
{
21+
namespace core
22+
{
23+
using std::unique_ptr;
24+
using std::vector;
25+
using std::pair;
26+
using namespace dwarf::lib;
27+
/* Forward-declare what we assume from libdwarfpp. */
28+
struct root_die;
29+
struct iterator_base;
30+
struct abstract_die;
131

232
/* FIXME: clean up Errors properly. It's complicated. A Dwarf_Error is a handle
333
* that needs to be dwarf_dealloc'd, but there are two exceptions:
@@ -51,7 +81,7 @@
5181
DW_DLA_STRING);
5282
} else assert(!arg);
5383
}
54-
};
84+
};
5585
typedef struct Dwarf_Die_s* Dwarf_Die;
5686
struct Die : /*private*/ virtual abstract_die // remind me: why is this private?
5787
{
@@ -79,31 +109,31 @@
79109

80110
// to avoid making exception handling compulsory,
81111
// we provide static "maybe" constructor functions (defined in lib.hpp)...
82-
static inline handle_type
112+
static handle_type
83113
try_construct(root_die& r, const iterator_base& die); /* siblingof */
84-
static inline handle_type
114+
static handle_type
85115
try_construct(root_die& r); /* siblingof with null die */
86-
static inline handle_type
116+
static handle_type
87117
try_construct(const iterator_base& die); /* child */
88-
static inline handle_type
118+
static handle_type
89119
try_construct(root_die& r, Dwarf_Off off); /* offdie */
90120

91121
// ... and an "upgrade" constructor that is guaranteed not to fail
92-
inline Die(handle_type h);
122+
Die(handle_type h) : handle(std::move(h)) {}
93123

94124
// ... and a "nullptr" constructor
95-
inline Die(std::nullptr_t n, root_die *p_r) : handle(nullptr, deleter(nullptr, *p_r)) {}
125+
Die(std::nullptr_t n, root_die *p_r) : handle(nullptr, deleter(nullptr, *p_r)) {}
96126

97127
// ... then the "normal" constructors, that throw exceptions on failure
98-
inline Die(root_die& r, const iterator_base& die); /* siblingof */
99-
inline explicit Die(root_die& r); /* siblingof in the root case */
100-
inline explicit Die(const iterator_base& die); /* child */
101-
inline explicit Die(root_die& r, Dwarf_Off off); /* offdie */
128+
Die(root_die& r, const iterator_base& die); /* siblingof */
129+
explicit Die(root_die& r); /* siblingof in the root case */
130+
explicit Die(const iterator_base& die); /* child */
131+
Die(root_die& r, Dwarf_Off off); /* offdie */
102132

103133
// move constructor
104-
inline Die(Die&& d) : handle(std::move(d.handle)) {}
134+
Die(Die&& d) : handle(std::move(d.handle)) {}
105135
// move assignment
106-
inline Die& operator=(Die&& d) { handle = std::move(d.handle); return *this; }
136+
Die& operator=(Die&& d) { handle = std::move(d.handle); return *this; }
107137

108138
raw_handle_type raw_handle() { return handle.get(); }
109139
raw_handle_type raw_handle() const { return handle.get(); }
@@ -115,7 +145,7 @@
115145
Dwarf_Off enclosing_cu_offset_here() const;
116146
bool has_attr_here(Dwarf_Half attr) const;
117147
bool has_attribute_here(Dwarf_Half attr) const { return has_attr_here(attr); }
118-
inline spec& spec_here() const;
148+
spec& spec_here() const;
119149

120150
// for convenience, this one is public -- basic_die's subclasses call it
121151
// (whereas the rest of our abstract_die implementation is private)
@@ -680,7 +710,7 @@
680710
{
681711
debug() << "Warning: libdwarf didn't understand DWARF expression in " //DIE 0x"
682712
<< std::hex /*<< a.d.get_offset() << ", */ << "attribute " << DEFAULT_DWARF_SPEC.attr_lookup(a.attr_here()) << std::dec
683-
<< endl;
713+
<< std::endl;
684714
return handle_type(nullptr, deleter(a.get_dbg()));
685715
}
686716
assert(listlen == 1);
@@ -700,7 +730,7 @@
700730
if (ret != DW_DLV_OK)
701731
{
702732
debug() << "Warning: libdwarf didn't understand DWARF expression from caller."
703-
<< endl;
733+
<< std::endl;
704734
return handle_type(nullptr, deleter(dbg));
705735
}
706736
assert(listlen == 1);
@@ -837,3 +867,7 @@
837867
// inlines we couldn't define earlier -- declared in private/libdwarf-handles.hpp
838868
inline encap::attribute_map Die::copy_attrs() const
839869
{ return encap::attribute_map(AttributeList(*this), *this, get_constructing_root()); }
870+
871+
}
872+
}
873+
#endif

‎include/dwarfpp/private/libdwarf.hpp ‎include/dwarfpp/libdwarf.hpp

+13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef DWARFPP_LIBDWARF_HPP_
22
#define DWARFPP_LIBDWARF_HPP_
33

4+
#include <iostream>
45
#include <libelf.h>
56

67
namespace dwarf
@@ -34,6 +35,18 @@ namespace dwarf
3435
No_entry() {}
3536
};
3637
void default_error_handler(Dwarf_Error error, Dwarf_Ptr errarg);
38+
39+
bool operator==(const Dwarf_Ranges& e1, const Dwarf_Ranges& e2);
40+
bool operator!=(const Dwarf_Ranges& e1, const Dwarf_Ranges& e2);
41+
std::ostream& operator<<(std::ostream& s, const Dwarf_Ranges& e);
42+
bool operator==(const Dwarf_Loc& e1, const Dwarf_Loc& e2);
43+
bool operator!=(const Dwarf_Loc& e1, const Dwarf_Loc& e2);
44+
bool operator<(const lib::Dwarf_Loc& arg1, const lib::Dwarf_Loc& arg2);
45+
std::ostream& operator<<(std::ostream& s, const Dwarf_Loc /* a.k.a. expr_instr */ & e);
46+
std::ostream& operator<<(std::ostream& s, const Dwarf_Locdesc& ld);
47+
bool operator==(const Dwarf_Ranges& e1, const Dwarf_Ranges& e2);
48+
bool operator!=(const Dwarf_Ranges& e1, const Dwarf_Ranges& e2);
49+
std::ostream& operator<<(std::ostream& s, const Dwarf_Ranges& e);
3750
}
3851
}
3952

‎include/dwarfpp/root-inl.hpp

+448
Large diffs are not rendered by default.

‎include/dwarfpp/root.hpp

+608
Large diffs are not rendered by default.

‎src/abstract.cpp

+196
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
#include "dwarfpp/abstract.hpp"
2+
#include "dwarfpp/abstract-inl.hpp"
3+
#include "dwarfpp/libdwarf-handles.hpp"
4+
#include "dwarfpp/root.hpp"
5+
#include "dwarfpp/root-inl.hpp"
6+
#include "dwarfpp/iter.hpp"
7+
#include "dwarfpp/iter-inl.hpp"
8+
#include "dwarfpp/dies.hpp"
9+
#include "dwarfpp/dies-inl.hpp"
10+
11+
#include <sstream>
12+
13+
namespace dwarf
14+
{
15+
namespace core
16+
{
17+
string abstract_die::summary() const
18+
{
19+
std::ostringstream s;
20+
s << "At 0x" << std::hex << get_offset() << std::dec
21+
<< ", tag " << dwarf::spec::DEFAULT_DWARF_SPEC.tag_lookup(get_tag());
22+
return s.str();
23+
}
24+
dwarf_current_factory_t dwarf_current_factory;
25+
basic_die *dwarf_current_factory_t::make_non_cu_payload(abstract_die&& h, root_die& r)
26+
{
27+
basic_die *p;
28+
Die d(std::move(dynamic_cast<Die&&>(h)));
29+
assert(d.tag_here() != DW_TAG_compile_unit);
30+
switch (d.tag_here())
31+
{
32+
#define factory_case(name, ...) \
33+
case DW_TAG_ ## name: p = new name ## _die(d.spec_here(), std::move(d.handle)); break; // FIXME: not "basic_die"...
34+
#include "dwarf-current-factory.h"
35+
#undef factory_case
36+
default: p = new basic_die(d.spec_here(), std::move(d.handle)); break;
37+
}
38+
return p;
39+
}
40+
41+
compile_unit_die *factory::make_cu_payload(abstract_die&& h, root_die& r)
42+
{
43+
// Key point: we're not allowed to call Die::spec_here() for this handle.
44+
// We could write libdwarf-level code to grab the version stamp and
45+
// so on... for now, just construct the thing.
46+
Die d(std::move(dynamic_cast<Die&&>(h)));
47+
Dwarf_Off off = d.offset_here();
48+
auto p = new compile_unit_die(dwarf::spec::dwarf_current, std::move(d.handle));
49+
/* fill in the CU fields -- this code would be shared by all
50+
* factories, so we put it here (but HMM, if our factories were
51+
* a delegation chain, we could just put it in the root). */
52+
53+
bool ret = r.set_cu_context(off);
54+
assert(ret);
55+
56+
p->cu_header_length = *r.last_seen_cu_header_length;
57+
p->version_stamp = *r.last_seen_version_stamp;
58+
p->abbrev_offset = *r.last_seen_abbrev_offset;
59+
p->address_size = *r.last_seen_address_size;
60+
p->offset_size = *r.last_seen_offset_size;
61+
p->extension_size = *r.last_seen_extension_size;
62+
p->next_cu_header = *r.last_seen_next_cu_header;
63+
64+
return p;
65+
}
66+
67+
// like make_cu_payload, but we're called by the root_die to make a whole fresh CU
68+
// FIXME: this
69+
compile_unit_die *factory::make_new_cu(root_die& r, std::function<compile_unit_die*()> constructor)
70+
{
71+
auto p = constructor();
72+
//new compile_unit_die(dwarf::spec::dwarf_current, Die::handle_type(nullptr, nullptr));
73+
// FIXME FIXME FIXME FIXME FIXME FIXME FIXME
74+
p->cu_header_length = 1;
75+
p->version_stamp = 2;
76+
p->abbrev_offset = 0;
77+
p->address_size = sizeof (void*);
78+
p->offset_size = sizeof (void*);
79+
p->extension_size = sizeof (void*);
80+
p->next_cu_header = 0;
81+
82+
// NOTE: the DIE we just created does not even have an offset
83+
// until it is added to the sticky set of the containing root DIE
84+
85+
return p;
86+
}
87+
88+
basic_die *factory::make_new(const iterator_base& parent, Dwarf_Half tag)
89+
{
90+
root_die& r = parent.root();
91+
// declare all the in-memory structs as local classes (for now)
92+
#define factory_case(name, ...) \
93+
struct in_memory_ ## name ## _die : public in_memory_abstract_die, \
94+
public name ## _die \
95+
{ \
96+
in_memory_ ## name ## _die(const iterator_base& parent) \
97+
: \
98+
/* initialize basic_die directly, since it's a virtual base */ \
99+
basic_die(parent.depth() >= 1 ? parent.spec_here() : DEFAULT_DWARF_SPEC, \
100+
parent.root()), \
101+
in_memory_abstract_die(parent.root(), \
102+
parent.is_root_position() ? \
103+
parent.root().fresh_cu_offset() \
104+
: parent.root().fresh_offset_under(/*parent.root().enclosing_cu(parent)*/parent), \
105+
parent.is_root_position() ? 0 : parent.enclosing_cu_offset_here(), \
106+
DW_TAG_ ## name), \
107+
name ## _die(parent.depth() >= 1 ? parent.spec_here() : DEFAULT_DWARF_SPEC) \
108+
{ \
109+
if (parent.is_root_position()) m_cu_offset = m_offset; \
110+
parent.root().live_dies.insert( \
111+
make_pair(this->in_memory_abstract_die::get_offset(), this) \
112+
); \
113+
} \
114+
root_die& get_root() const \
115+
{ return *p_root; } \
116+
/* We also (morally redundantly) override all the abstract_die methods
117+
* to call the in_memory_abstract_die versions, in order to
118+
* provide a unique final overrider. */ \
119+
Dwarf_Off get_offset() const \
120+
{ return this->in_memory_abstract_die::get_offset(); } \
121+
Dwarf_Half get_tag() const \
122+
{ return this->in_memory_abstract_die::get_tag(); } \
123+
opt<string> get_name() const \
124+
{ return this->in_memory_abstract_die::get_name(); } \
125+
Dwarf_Off get_enclosing_cu_offset() const \
126+
{ return this->in_memory_abstract_die::get_enclosing_cu_offset(); } \
127+
bool has_attr(Dwarf_Half attr) const \
128+
{ return this->in_memory_abstract_die::has_attr(attr); } \
129+
encap::attribute_map copy_attrs() const \
130+
{ return this->in_memory_abstract_die::copy_attrs(); } \
131+
inline spec& get_spec(root_die& r) const \
132+
{ return this->in_memory_abstract_die::get_spec(r); } \
133+
/* also override the wider attribute API from basic_die */ \
134+
/* get all attrs in one go */ \
135+
virtual encap::attribute_map all_attrs() const \
136+
{ return copy_attrs(); } \
137+
/* get a single attr */ \
138+
virtual encap::attribute_value attr(Dwarf_Half a) const \
139+
{ if (has_attr(a)) return m_attrs.find(a)->second; else assert(false); } \
140+
/* get all attrs in one go, seeing through abstract_origin / specification links */ \
141+
/* -- this one should work already: virtual encap::attribute_map find_all_attrs() const; */ \
142+
/* get a single attr, seeing through abstract_origin / specification links */ \
143+
/* -- this one should work already: virtual encap::attribute_value find_attr(Dwarf_Half a) const; */ \
144+
};
145+
#include "dwarf-current-factory.h"
146+
#undef factory_case
147+
148+
if (tag == DW_TAG_compile_unit)
149+
{
150+
return make_new_cu(r, [parent](){ return new in_memory_compile_unit_die(parent); });
151+
}
152+
153+
//Dwarf_Off parent_off = parent.offset_here();
154+
//Dwarf_Off new_off = /*parent.is_root_position() ? r.fresh_cu_offset() : */ r.fresh_offset_under(r.enclosing_cu(parent));
155+
//Dwarf_Off cu_off = /*(tag == DW_TAG_compile_unit) ? new_off : */ parent.enclosing_cu_offset_here();
156+
157+
basic_die *ret = nullptr;
158+
switch (tag)
159+
{
160+
#define factory_case(name, ...) \
161+
case DW_TAG_ ## name: \
162+
ret = new in_memory_ ## name ## _die(parent); break;
163+
#include "dwarf-current-factory.h"
164+
default: return nullptr;
165+
}
166+
#undef factory_case
167+
return ret;
168+
169+
if (parent.depth() == 1)
170+
{
171+
auto it = r.pos(ret->get_offset(), parent.depth() + 1);
172+
if (it.global_name_here())
173+
{
174+
r.visible_named_grandchildren_cache.insert(make_pair(*it.global_name_here(), ret->get_offset()));
175+
}
176+
}
177+
}
178+
179+
basic_die *dwarf_current_factory_t::dummy_for_tag(Dwarf_Half tag)
180+
{
181+
static basic_die dummy_basic(dwarf::spec::dwarf_current);
182+
#define factory_case(name, ...) \
183+
static name ## _die dummy_ ## name(dwarf::spec::dwarf_current);
184+
#include "dwarf-current-factory.h"
185+
#undef factory_case
186+
switch (tag)
187+
{
188+
#define factory_case(name, ...) \
189+
case DW_TAG_ ## name: return &dummy_ ## name;
190+
#include "dwarf-current-factory.h"
191+
#undef factory_case
192+
default: return &dummy_basic;
193+
}
194+
}
195+
}
196+
}

‎src/attr.cpp

-33
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,6 @@ using std::endl;
88

99
namespace dwarf
1010
{
11-
namespace lib
12-
{
13-
bool operator==(const Dwarf_Ranges& e1, const Dwarf_Ranges& e2)
14-
{
15-
return e1.dwr_addr1 == e2.dwr_addr1
16-
&& e1.dwr_addr2 == e2.dwr_addr2
17-
&& e1.dwr_type == e2.dwr_type;
18-
}
19-
bool operator!=(const Dwarf_Ranges& e1, const Dwarf_Ranges& e2)
20-
{
21-
return !(e1 == e2);
22-
}
23-
std::ostream& operator<<(std::ostream& s, const Dwarf_Ranges& rl)
24-
{
25-
switch (rl.dwr_type)
26-
{
27-
case DW_RANGES_ENTRY:
28-
s << "[0x" << std::hex << rl.dwr_addr1
29-
<< ", 0x" << std::hex << rl.dwr_addr2 << ")";
30-
break;
31-
case DW_RANGES_ADDRESS_SELECTION:
32-
assert(rl.dwr_addr1 == 0xffffffff || rl.dwr_addr1 == 0xffffffffffffffffULL);
33-
s << "set base 0x" << std::hex << rl.dwr_addr2;
34-
break;
35-
case DW_RANGES_END:
36-
assert(rl.dwr_addr1 == 0 && rl.dwr_addr2 == 0);
37-
s << "end";
38-
break;
39-
default: assert(false); break;
40-
}
41-
return s;
42-
}
43-
}
4411
namespace encap
4512
{
4613
void attribute_value::print_raw(std::ostream& s) const

‎src/dies.cpp

+2,334
Large diffs are not rendered by default.

‎src/expr.cpp

+2-61
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
#include <set>
1111
#include <srk31/endian.hpp>
1212

13-
#include "lib.hpp"
13+
#include "abstract.hpp"
14+
#include "abstract-inl.hpp"
1415
#include "expr.hpp"
1516

1617
using std::map;
@@ -23,66 +24,6 @@ using dwarf::spec::opt;
2324

2425
namespace dwarf
2526
{
26-
namespace lib
27-
{
28-
std::ostream& operator<<(std::ostream& s, const Dwarf_Locdesc& ld)
29-
{
30-
s << dwarf::encap::loc_expr(ld);
31-
return s;
32-
}
33-
std::ostream& operator<<(std::ostream& s, const Dwarf_Loc& l)
34-
{
35-
// HACK: we can't infer the DWARF standard from the Dwarf_Loc we've been passed,
36-
// so use the default.
37-
s << "0x" << std::hex << l.lr_offset << std::dec
38-
<< ": " << dwarf::spec::DEFAULT_DWARF_SPEC.op_lookup(l.lr_atom);
39-
std::ostringstream buf;
40-
std::string to_append;
41-
42-
switch (dwarf::spec::DEFAULT_DWARF_SPEC.op_operand_count(l.lr_atom))
43-
{
44-
case 2:
45-
buf << ", " << dwarf::encap::attribute_value(
46-
l.lr_number2,
47-
dwarf::spec::DEFAULT_DWARF_SPEC.op_operand_form_list(l.lr_atom)[1]
48-
);
49-
to_append += buf.str();
50-
case 1:
51-
buf.clear();
52-
buf << "(" << dwarf::encap::attribute_value(
53-
l.lr_number,
54-
dwarf::spec::DEFAULT_DWARF_SPEC.op_operand_form_list(l.lr_atom)[0]
55-
);
56-
to_append.insert(0, buf.str());
57-
to_append += ")";
58-
case 0:
59-
s << to_append;
60-
break;
61-
default: s << "(unexpected number of operands) ";
62-
}
63-
s << ";";
64-
return s;
65-
}
66-
bool operator<(const Dwarf_Loc& arg1, const Dwarf_Loc& arg2)
67-
{
68-
return arg1.lr_atom < arg2.lr_atom
69-
|| (arg1.lr_atom == arg2.lr_atom && arg1.lr_number < arg2.lr_number)
70-
|| (arg1.lr_atom == arg2.lr_atom && arg1.lr_number == arg2.lr_number && arg1.lr_number2 < arg2.lr_number2)
71-
|| (arg1.lr_atom == arg2.lr_atom && arg1.lr_number == arg2.lr_number && arg1.lr_number2 == arg2.lr_number2 &&
72-
arg1.lr_offset < arg2.lr_offset);
73-
}
74-
bool operator==(const Dwarf_Loc& e1, const Dwarf_Loc& e2)
75-
{
76-
return e1.lr_atom == e2.lr_atom
77-
&& e1.lr_number == e2.lr_number
78-
&& e1.lr_number2 == e2.lr_number2
79-
&& e1.lr_offset == e2.lr_offset;
80-
}
81-
bool operator!=(const Dwarf_Loc& e1, const Dwarf_Loc& e2)
82-
{
83-
return !(e1 == e2);
84-
}
85-
}
8627
namespace expr
8728
{
8829
using namespace dwarf::lib;

‎src/iter.cpp

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#include "dwarfpp/abstract.hpp"
2+
#include "dwarfpp/abstract-inl.hpp"
3+
#include "dwarfpp/root.hpp"
4+
#include "dwarfpp/root-inl.hpp"
5+
#include "dwarfpp/iter.hpp"
6+
#include "dwarfpp/iter-inl.hpp"
7+
#include "dwarfpp/dies.hpp"
8+
#include "dwarfpp/dies-inl.hpp"
9+
10+
#include <iostream>
11+
#include <utility>
12+
13+
namespace dwarf
14+
{
15+
using std::endl;
16+
using std::dynamic_pointer_cast;
17+
18+
namespace core
19+
{
20+
/* printing of iterator_bases -- *avoid* dereferencing, for speed */
21+
void iterator_base::print(std::ostream& s, unsigned indent_level /* = 0 */) const
22+
{
23+
if (!is_real_die_position())
24+
{
25+
s << "(no DIE)";
26+
}
27+
else
28+
{
29+
for (unsigned u = 0; u < indent_level; ++u) s << "\t";
30+
s << "DIE, offset 0x" << std::hex << offset_here() << std::dec
31+
<< ", tag " << spec_here().tag_lookup(tag_here());
32+
if (name_here()) s << ", name \"" << *name_here() << "\"";
33+
else s << ", no name";
34+
}
35+
}
36+
void iterator_base::print_with_attrs(std::ostream& s, unsigned indent_level /* = 0 */) const
37+
{
38+
if (!is_real_die_position())
39+
{
40+
s << "(no DIE)" << endl;
41+
}
42+
else
43+
{
44+
for (unsigned u = 0; u < indent_level; ++u) s << "\t";
45+
s << "DIE, offset 0x" << std::hex << offset_here() << std::dec
46+
<< ", tag " << spec_here().tag_lookup(tag_here())
47+
<< ", attributes: ";
48+
//srk31::indenting_ostream is(s);
49+
//is.inc_level();
50+
s << endl;
51+
auto m = copy_attrs();
52+
m.print(s, indent_level + 1);
53+
//is << endl << copy_attrs();
54+
//is.dec_level();
55+
}
56+
}
57+
std::ostream& operator<<(std::ostream& s, const iterator_base& i)
58+
{
59+
i.print(s);
60+
return s;
61+
}
62+
iterator_base
63+
iterator_base::named_child(const string& name) const
64+
{
65+
if (state == WITH_PAYLOAD)
66+
{
67+
/* This means we *can* ask the payload. What will the
68+
* payload do by default? Call the root, of course.
69+
* (But some payloads might be smarter.) */
70+
auto p_with = dynamic_pointer_cast<with_named_children_die>(cur_payload);
71+
if (p_with)
72+
{
73+
return p_with->named_child(name);
74+
}
75+
}
76+
return p_root->find_named_child(*this, name);
77+
}
78+
Dwarf_Off iterator_base::offset_here() const
79+
{
80+
if (!is_real_die_position()) { assert(is_root_position()); return 0; }
81+
return get_handle().get_offset();
82+
}
83+
Dwarf_Half iterator_base::tag_here() const
84+
{
85+
if (!is_real_die_position()) return 0;
86+
return get_handle().get_tag();
87+
}
88+
//std::unique_ptr<const char, string_deleter>
89+
opt<string>
90+
iterator_base::name_here() const
91+
{
92+
if (!is_real_die_position()) return opt<string>();
93+
return get_handle().get_name();
94+
}
95+
opt<string>
96+
iterator_base::global_name_here() const
97+
{
98+
auto maybe_name = name_here();
99+
if (maybe_name &&
100+
(!has_attr_here(DW_AT_visibility)
101+
|| attr(DW_AT_visibility).get_unsigned()
102+
!= DW_VIS_local)) return maybe_name;
103+
else return opt<string>();
104+
}
105+
bool iterator_base::has_attr_here(Dwarf_Half attr) const
106+
{
107+
if (!is_real_die_position()) return false;
108+
return get_handle().has_attr(attr);
109+
}
110+
iterator_base iterator_base::nearest_enclosing(Dwarf_Half tag) const
111+
{
112+
if (tag == DW_TAG_compile_unit)
113+
{
114+
Dwarf_Off cu_off = enclosing_cu_offset_here();
115+
return p_root->cu_pos(cu_off);
116+
}
117+
else
118+
{
119+
auto cur = *this; // copies!
120+
while (cur.is_real_die_position() && cur.tag_here() != tag)
121+
{
122+
if (!p_root->move_to_parent(cur)) return END;
123+
}
124+
if (!cur.is_real_die_position()) return END;
125+
else return cur;
126+
}
127+
}
128+
// Dwarf_Off iterator_base::enclosing_cu_offset_here() const
129+
// {
130+
// return get_handle().enclosing_cu_offset_here();
131+
// }
132+
133+
iterator_base iterator_base::parent() const
134+
{
135+
return p_root->parent(*this);
136+
}
137+
138+
const iterator_base iterator_base::END;
139+
}
140+
}

‎src/lib.cpp

-3,536
Large diffs are not rendered by default.

‎src/libdwarf-data.cpp

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// all the operator overloads etc. that we define on libdwarf data
2+
3+
#include "dwarfpp/libdwarf.hpp"
4+
#include "dwarfpp/abstract.hpp"
5+
#include "dwarfpp/abstract-inl.hpp"
6+
#include "dwarfpp/attr.hpp"
7+
#include "dwarfpp/expr.hpp"
8+
9+
#include <sstream>
10+
11+
namespace dwarf
12+
{
13+
namespace lib
14+
{
15+
bool operator==(const Dwarf_Ranges& e1, const Dwarf_Ranges& e2)
16+
{
17+
return e1.dwr_addr1 == e2.dwr_addr1
18+
&& e1.dwr_addr2 == e2.dwr_addr2
19+
&& e1.dwr_type == e2.dwr_type;
20+
}
21+
bool operator!=(const Dwarf_Ranges& e1, const Dwarf_Ranges& e2)
22+
{
23+
return !(e1 == e2);
24+
}
25+
std::ostream& operator<<(std::ostream& s, const Dwarf_Ranges& rl)
26+
{
27+
switch (rl.dwr_type)
28+
{
29+
case DW_RANGES_ENTRY:
30+
s << "[0x" << std::hex << rl.dwr_addr1
31+
<< ", 0x" << std::hex << rl.dwr_addr2 << ")";
32+
break;
33+
case DW_RANGES_ADDRESS_SELECTION:
34+
assert(rl.dwr_addr1 == 0xffffffff || rl.dwr_addr1 == 0xffffffffffffffffULL);
35+
s << "set base 0x" << std::hex << rl.dwr_addr2;
36+
break;
37+
case DW_RANGES_END:
38+
assert(rl.dwr_addr1 == 0 && rl.dwr_addr2 == 0);
39+
s << "end";
40+
break;
41+
default: assert(false); break;
42+
}
43+
return s;
44+
}
45+
std::ostream& operator<<(std::ostream& s, const Dwarf_Locdesc& ld)
46+
{
47+
s << dwarf::encap::loc_expr(ld);
48+
return s;
49+
}
50+
std::ostream& operator<<(std::ostream& s, const Dwarf_Loc& l)
51+
{
52+
// HACK: we can't infer the DWARF standard from the Dwarf_Loc we've been passed,
53+
// so use the default.
54+
s << "0x" << std::hex << l.lr_offset << std::dec
55+
<< ": " << dwarf::spec::DEFAULT_DWARF_SPEC.op_lookup(l.lr_atom);
56+
std::ostringstream buf;
57+
std::string to_append;
58+
59+
switch (dwarf::spec::DEFAULT_DWARF_SPEC.op_operand_count(l.lr_atom))
60+
{
61+
case 2:
62+
buf << ", " << dwarf::encap::attribute_value(
63+
l.lr_number2,
64+
dwarf::spec::DEFAULT_DWARF_SPEC.op_operand_form_list(l.lr_atom)[1]
65+
);
66+
to_append += buf.str();
67+
case 1:
68+
buf.clear();
69+
buf << "(" << dwarf::encap::attribute_value(
70+
l.lr_number,
71+
dwarf::spec::DEFAULT_DWARF_SPEC.op_operand_form_list(l.lr_atom)[0]
72+
);
73+
to_append.insert(0, buf.str());
74+
to_append += ")";
75+
case 0:
76+
s << to_append;
77+
break;
78+
default: s << "(unexpected number of operands) ";
79+
}
80+
s << ";";
81+
return s;
82+
}
83+
bool operator<(const Dwarf_Loc& arg1, const Dwarf_Loc& arg2)
84+
{
85+
return arg1.lr_atom < arg2.lr_atom
86+
|| (arg1.lr_atom == arg2.lr_atom && arg1.lr_number < arg2.lr_number)
87+
|| (arg1.lr_atom == arg2.lr_atom && arg1.lr_number == arg2.lr_number && arg1.lr_number2 < arg2.lr_number2)
88+
|| (arg1.lr_atom == arg2.lr_atom && arg1.lr_number == arg2.lr_number && arg1.lr_number2 == arg2.lr_number2 &&
89+
arg1.lr_offset < arg2.lr_offset);
90+
}
91+
bool operator==(const Dwarf_Loc& e1, const Dwarf_Loc& e2)
92+
{
93+
return e1.lr_atom == e2.lr_atom
94+
&& e1.lr_number == e2.lr_number
95+
&& e1.lr_number2 == e2.lr_number2
96+
&& e1.lr_offset == e2.lr_offset;
97+
}
98+
bool operator!=(const Dwarf_Loc& e1, const Dwarf_Loc& e2)
99+
{
100+
return !(e1 == e2);
101+
}
102+
}
103+
}

‎src/libdwarf-handles.cpp

+259
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
// de-inlined versions of all the libdwarf-specific handle methods
2+
// remember the goal here: to allow easy rebasing of the library
3+
// (with a bit of #ifdef'ing)
4+
// ... onto DWARF libraries that aren't libdwarf.
5+
// ... consider libdw1, LLVM stuff, etc..
6+
7+
#include "dwarfpp/abstract.hpp"
8+
#include "dwarfpp/abstract-inl.hpp"
9+
#include "dwarfpp/libdwarf-handles.hpp"
10+
#include "dwarfpp/root.hpp"
11+
#include "dwarfpp/root-inl.hpp"
12+
#include "dwarfpp/iter.hpp"
13+
#include "dwarfpp/iter-inl.hpp"
14+
#include "dwarfpp/dies.hpp"
15+
#include "dwarfpp/dies-inl.hpp"
16+
17+
namespace dwarf
18+
{
19+
namespace core
20+
{
21+
Die::handle_type
22+
Die::try_construct(root_die& r, const iterator_base& it) /* siblingof */
23+
{
24+
raw_handle_type returned;
25+
if (!dynamic_cast<Die *>(&it.get_handle())) return handle_type(nullptr, deleter(nullptr, r));
26+
int ret = dwarf_siblingof(r.dbg.handle.get(), dynamic_cast<Die&>(it.get_handle()).handle.get(),
27+
&returned, &current_dwarf_error);
28+
if (ret == DW_DLV_OK) return handle_type(returned, deleter(r.dbg.handle.get(), r));
29+
else return handle_type(nullptr, deleter(nullptr, r));
30+
}
31+
Die::handle_type
32+
Die::try_construct(root_die& r) /* siblingof in "first DIE of current CU" case */
33+
{
34+
raw_handle_type returned;
35+
if (!r.dbg.handle) return handle_type(nullptr, deleter(nullptr, r));
36+
int ret = dwarf_siblingof(r.dbg.handle.get(), nullptr, &returned, &current_dwarf_error);
37+
if (ret == DW_DLV_OK) return handle_type(returned, deleter(r.dbg.handle.get(), r));
38+
else return handle_type(nullptr, deleter(nullptr, r));
39+
}
40+
Die::handle_type
41+
Die::try_construct(const iterator_base& it) /* child */
42+
{
43+
raw_handle_type returned;
44+
root_die& r = it.get_root();
45+
if (!dynamic_cast<Die *>(&it.get_handle())) return handle_type(nullptr, deleter(nullptr, r));
46+
int ret = dwarf_child(dynamic_cast<Die&>(it.get_handle()).handle.get(), &returned, &current_dwarf_error);
47+
if (ret == DW_DLV_OK) return handle_type(returned, deleter(it.get_root().dbg.handle.get(), r));
48+
else return handle_type(nullptr, deleter(nullptr, r));
49+
}
50+
Die::handle_type
51+
Die::try_construct(root_die& r, Dwarf_Off off) /* offdie */
52+
{
53+
raw_handle_type returned;
54+
if (!r.dbg.handle) return handle_type(nullptr, deleter(nullptr, r));
55+
int ret = dwarf_offdie(r.dbg.handle.get(), off, &returned, &current_dwarf_error);
56+
if (ret == DW_DLV_OK) return handle_type(returned, deleter(r.dbg.handle.get(), r));
57+
else return handle_type(nullptr, deleter(nullptr, r));
58+
}
59+
60+
/* FIXME: just build iterators directly?
61+
* Or at least move the cache logic out of here and into the
62+
* iterator constructors. Then also eliminate the
63+
* try_construct stuff and just do it in the Die constructors.
64+
* We use try_construct in root_die::pos, but we should use a
65+
* constructor on iterator_base.
66+
* We use try_construct in iterator_base's copy constructor,
67+
* but we should just define a copy constructor for Die.
68+
* Also see how much we use attrs_here() / attributes_here(). */
69+
70+
Die::Die(root_die& r, const iterator_base& it) /* siblingof */
71+
: handle(try_construct(r, it))
72+
{
73+
if (!this->handle) throw Error(current_dwarf_error, 0);
74+
// also update the parent cache and sibling cache.
75+
// 1. "it"'s parent is our parent; what is "it"'s parent?
76+
Dwarf_Off off = this->offset_here();
77+
opt<Dwarf_Off> it_parent_off;
78+
if (it.fast_deref() && it.fast_deref()->cached_parent_off) it_parent_off = it.fast_deref()->cached_parent_off;
79+
else
80+
{
81+
auto found = r.parent_of.find(it.offset_here());
82+
if (found != r.parent_of.end()) it_parent_off = opt<Dwarf_Off>(found->second);
83+
}
84+
if (it_parent_off)
85+
{
86+
// parent of the sibling is the same as parent of "it"
87+
r.parent_of[off] = *it_parent_off;
88+
// no payload yet; FIXME we should really store this in the iterator
89+
// so that when we create payload we can populate its cache right away
90+
} else debug() << "Warning: parent cache did not know 0x" << std::hex << it.offset_here() << std::dec << std::endl;
91+
92+
// 2. we are the next sibling of "it"
93+
r.next_sibling_of[it.offset_here()] = off;
94+
if (it.fast_deref()) it.fast_deref()->cached_next_sibling_off = opt<Dwarf_Off>(off);
95+
}
96+
Die::Die(root_die& r) /* siblingof in "first die of CU" case */
97+
: handle(try_construct(r))
98+
{
99+
if (!this->handle) throw Error(current_dwarf_error, 0);
100+
// update parent cache
101+
Dwarf_Off off = this->offset_here();
102+
r.parent_of[off] = 0UL; // FIXME: looks wrong
103+
// the *caller* updates first_child_of, next_sibling_of
104+
}
105+
Die::Die(root_die& r, Dwarf_Off off) /* offdie */
106+
: handle(try_construct(r, off))
107+
{
108+
if (!this->handle) throw Error(current_dwarf_error, 0);
109+
// NOTE: we don't know our parent -- can't update parent cache
110+
}
111+
Die::Die(const iterator_base& it) /* child */
112+
: handle(try_construct(it))
113+
{
114+
root_die& r = it.get_root();
115+
if (!this->handle) throw Error(current_dwarf_error, 0);
116+
Dwarf_Off off = this->offset_here();
117+
r.parent_of[off] = it.offset_here();
118+
// first_child_of, next_sibling_of
119+
r.first_child_of[it.offset_here()] = off;
120+
}
121+
122+
spec& Die::spec_here() const
123+
{
124+
// HACK: avoid creating any payload for now, for speed-testing
125+
return ::dwarf::spec::dwarf_current;
126+
127+
/* NOTE: subtlety concerning payload construction. To make the
128+
* payload, we need the factory, meaning we need the spec.
129+
* BUT to read the spec, we need the CU payload!
130+
* Escape this by ensuring that root_die::make_payload, in the CU case,
131+
* uses the default factory. In turn, we ensure that all factories,
132+
* for the CU case, behave the same. I have refactored
133+
* the factory base class so that only non-CU DIEs get the make_payload
134+
* call. */
135+
136+
// this spec_here() is only used from the factory, and not
137+
// used in the CU case because the factory handles that specially
138+
assert(tag_here() != DW_TAG_compile_unit);
139+
140+
Dwarf_Off cu_offset = enclosing_cu_offset_here();
141+
// this should be sticky, hence fast to find
142+
return get_constructing_root().pos(cu_offset, 1, opt<Dwarf_Off>(0UL)).spec_here();
143+
144+
// {
145+
// return
146+
// if (state == HANDLE_ONLY)
147+
// {
148+
// p_root->make_payload(*this);
149+
// }
150+
// assert(cur_payload && state == WITH_PAYLOAD);
151+
// auto p_cu = dynamic_pointer_cast<compile_unit_die>(cur_payload);
152+
// assert(p_cu);
153+
// switch(p_cu->version_stamp)
154+
// {
155+
// case 2: return ::dwarf::spec::dwarf_current;
156+
// default: assert(false);
157+
// }
158+
// }
159+
// else
160+
// {
161+
// // NO! CUs now lie about their spec
162+
// // return nearest_enclosing(DW_TAG_compile_unit).spec_here();
163+
164+
}
165+
Debug::Debug(int fd)
166+
{
167+
Dwarf_Debug returned;
168+
int ret = dwarf_init(fd, DW_DLC_READ, exception_error_handler,
169+
nullptr, &returned, &current_dwarf_error);
170+
assert(ret == DW_DLV_OK);
171+
this->handle = handle_type(returned);
172+
}
173+
174+
Debug::Debug(Elf *elf)
175+
{
176+
Dwarf_Debug returned;
177+
int ret = dwarf_elf_init(reinterpret_cast<dwarf::lib::Elf_opaque_in_libdwarf*>(elf),
178+
DW_DLC_READ, exception_error_handler,
179+
nullptr, &returned, &current_dwarf_error);
180+
assert(ret == DW_DLV_OK);
181+
this->handle = handle_type(returned);
182+
}
183+
184+
void
185+
Debug::deleter::operator()(raw_handle_type arg) const
186+
{
187+
dwarf_finish(arg, &current_dwarf_error);
188+
}
189+
190+
std::ostream& operator<<(std::ostream& s, const AttributeList& attrs)
191+
{
192+
for (int i = 0; i < attrs.get_len(); ++i)
193+
{
194+
s << dwarf::spec::DEFAULT_DWARF_SPEC.attr_lookup(attrs[i].attr_here());
195+
encap::attribute_value v(attrs[i], attrs.d, attrs.d.get_constructing_root());
196+
s << ": " << v << std::endl;
197+
}
198+
return s;
199+
}
200+
Dwarf_Off Die::offset_here() const
201+
{
202+
Dwarf_Off off;
203+
int ret = dwarf_dieoffset(raw_handle(), &off, &current_dwarf_error);
204+
assert(ret == DW_DLV_OK);
205+
return off;
206+
}
207+
Dwarf_Half Die::tag_here() const
208+
{
209+
Dwarf_Half tag;
210+
int ret = dwarf_tag(handle.get(), &tag, &current_dwarf_error);
211+
assert(ret == DW_DLV_OK);
212+
return tag;
213+
}
214+
std::unique_ptr<const char, string_deleter>
215+
Die::name_here() const
216+
{
217+
char *str;
218+
int ret = dwarf_diename(raw_handle(), &str, &current_dwarf_error);
219+
if (ret == DW_DLV_NO_ENTRY) return nullptr;
220+
if (ret == DW_DLV_OK) return unique_ptr<const char, string_deleter>(
221+
str, string_deleter(get_dbg()));
222+
assert(false);
223+
}
224+
bool Die::has_attr_here(Dwarf_Half attr) const
225+
{
226+
Dwarf_Bool returned;
227+
int ret = dwarf_hasattr(raw_handle(), attr, &returned, &current_dwarf_error);
228+
assert(ret == DW_DLV_OK);
229+
return returned;
230+
}
231+
// for nearest_enclosing(DW_TAG_compile_unit), libdwarf supplies a call:
232+
// dwarf_CU_dieoffset_given_die -- gives you the CU of a DIE
233+
Dwarf_Off Die::enclosing_cu_offset_here() const
234+
{
235+
Dwarf_Off cu_offset;
236+
int ret = dwarf_CU_dieoffset_given_die(raw_handle(),
237+
&cu_offset, &current_dwarf_error);
238+
if (ret == DW_DLV_OK) return cu_offset;
239+
else assert(false);
240+
}
241+
242+
Dwarf_Half Attribute::attr_here() const
243+
{
244+
Dwarf_Half attr;
245+
int ret = dwarf_whatattr(handle.get(), &attr, &current_dwarf_error);
246+
assert(ret == DW_DLV_OK);
247+
return attr;
248+
}
249+
250+
Dwarf_Half Attribute::form_here() const
251+
{
252+
Dwarf_Half form;
253+
int ret = dwarf_whatform(handle.get(), &form, &current_dwarf_error);
254+
assert(ret == DW_DLV_OK);
255+
return form;
256+
}
257+
258+
}
259+
}

‎src/libdwarf.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include "dwarfpp/libdwarf.hpp"
2+
#include "dwarfpp/util.hpp"
3+
4+
namespace dwarf
5+
{
6+
namespace core
7+
{
8+
using namespace dwarf::lib;
9+
10+
#ifndef NO_TLS
11+
__thread Dwarf_Error current_dwarf_error;
12+
#else
13+
Dwarf_Error current_dwarf_error;
14+
#endif
15+
16+
void exception_error_handler(Dwarf_Error error, Dwarf_Ptr errarg)
17+
{
18+
throw Error(error, errarg); // FIXME: saner non-copying interface?
19+
}
20+
}
21+
namespace lib
22+
{
23+
void default_error_handler(Dwarf_Error e, Dwarf_Ptr errarg)
24+
{
25+
//fprintf(stderr, "DWARF error!\n"); /* this is the C version */
26+
/* NOTE: when called by a libdwarf function,
27+
* errarg is always the Dwarf_Debug concerned with the error */
28+
core::debug() << "libdwarf error!" << std::endl;
29+
throw Error(e, errarg); /* Whoever catches this should also dwarf_dealloc the Dwarf_Error_s. */
30+
}
31+
} // end namespace lib
32+
}

‎src/root.cpp

+795
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.