599 lines
12 KiB
C++
599 lines
12 KiB
C++
|
|
#include "rust_internal.h"
|
|
|
|
bool
|
|
rust_crate_reader::mem_reader::is_ok()
|
|
{
|
|
return ok;
|
|
}
|
|
|
|
bool
|
|
rust_crate_reader::mem_reader::at_end()
|
|
{
|
|
return pos == mem.lim;
|
|
}
|
|
|
|
void
|
|
rust_crate_reader::mem_reader::fail()
|
|
{
|
|
ok = false;
|
|
}
|
|
|
|
void
|
|
rust_crate_reader::mem_reader::reset()
|
|
{
|
|
pos = mem.base;
|
|
ok = true;
|
|
}
|
|
|
|
rust_crate_reader::mem_reader::mem_reader(rust_crate::mem_area &m)
|
|
: mem(m),
|
|
ok(true),
|
|
pos(m.base)
|
|
{}
|
|
|
|
size_t
|
|
rust_crate_reader::mem_reader::tell_abs()
|
|
{
|
|
return pos;
|
|
}
|
|
|
|
size_t
|
|
rust_crate_reader::mem_reader::tell_off()
|
|
{
|
|
return pos - mem.base;
|
|
}
|
|
|
|
void
|
|
rust_crate_reader::mem_reader::seek_abs(uintptr_t p)
|
|
{
|
|
if (!ok || p < mem.base || p >= mem.lim)
|
|
ok = false;
|
|
else
|
|
pos = p;
|
|
}
|
|
|
|
void
|
|
rust_crate_reader::mem_reader::seek_off(uintptr_t p)
|
|
{
|
|
seek_abs(p + mem.base);
|
|
}
|
|
|
|
|
|
bool
|
|
rust_crate_reader::mem_reader::adv_zstr(size_t sz)
|
|
{
|
|
sz = 0;
|
|
while (ok) {
|
|
char c;
|
|
get(c);
|
|
++sz;
|
|
if (c == '\0')
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
rust_crate_reader::mem_reader::get_zstr(char const *&c, size_t &sz)
|
|
{
|
|
if (!ok)
|
|
return false;
|
|
c = (char const *)(pos);
|
|
return adv_zstr(sz);
|
|
}
|
|
|
|
void
|
|
rust_crate_reader::mem_reader::adv(size_t amt)
|
|
{
|
|
if (pos < mem.base
|
|
|| pos >= mem.lim
|
|
|| pos + amt > mem.lim)
|
|
ok = false;
|
|
if (!ok)
|
|
return;
|
|
// mem.dom->log(rust_log::MEM, "adv %d bytes", amt);
|
|
pos += amt;
|
|
ok &= !at_end();
|
|
I(mem.dom, at_end() || (mem.base <= pos && pos < mem.lim));
|
|
}
|
|
|
|
|
|
rust_crate_reader::abbrev::abbrev(rust_dom *dom,
|
|
uintptr_t body_off,
|
|
size_t body_sz,
|
|
uintptr_t tag,
|
|
uint8_t has_children) :
|
|
dom(dom),
|
|
body_off(body_off),
|
|
tag(tag),
|
|
has_children(has_children),
|
|
idx(0)
|
|
{}
|
|
|
|
|
|
rust_crate_reader::abbrev_reader::abbrev_reader
|
|
(rust_crate::mem_area &abbrev_mem)
|
|
: mem_reader(abbrev_mem),
|
|
abbrevs(abbrev_mem.dom)
|
|
{
|
|
rust_dom *dom = mem.dom;
|
|
while (is_ok() && !at_end()) {
|
|
|
|
// dom->log(rust_log::DWARF, "reading new abbrev at 0x%" PRIxPTR,
|
|
// tell_off());
|
|
|
|
uintptr_t idx, tag;
|
|
uint8_t has_children;
|
|
get_uleb(idx);
|
|
get_uleb(tag);
|
|
get(has_children);
|
|
|
|
uintptr_t attr, form;
|
|
size_t body_off = tell_off();
|
|
while (is_ok() && step_attr_form_pair(attr, form));
|
|
|
|
// dom->log(rust_log::DWARF,
|
|
// "finished scanning attr/form pairs, pos=0x%"
|
|
// PRIxPTR ", lim=0x%" PRIxPTR ", is_ok=%d, at_end=%d",
|
|
// pos, mem.lim, is_ok(), at_end());
|
|
|
|
if (is_ok() || at_end()) {
|
|
dom->log(rust_log::DWARF, "read abbrev: %" PRIdPTR, idx);
|
|
I(dom, idx = abbrevs.length() + 1);
|
|
abbrevs.push(new (dom) abbrev(dom, body_off,
|
|
tell_off() - body_off,
|
|
tag, has_children));
|
|
}
|
|
}
|
|
}
|
|
|
|
rust_crate_reader::abbrev *
|
|
rust_crate_reader::abbrev_reader::get_abbrev(size_t i) {
|
|
i -= 1;
|
|
if (i < abbrevs.length())
|
|
return abbrevs[i];
|
|
return NULL;
|
|
}
|
|
|
|
bool
|
|
rust_crate_reader::abbrev_reader::step_attr_form_pair(uintptr_t &attr,
|
|
uintptr_t &form)
|
|
{
|
|
attr = 0;
|
|
form = 0;
|
|
// mem.dom->log(rust_log::DWARF, "reading attr/form pair at 0x%" PRIxPTR,
|
|
// tell_off());
|
|
get_uleb(attr);
|
|
get_uleb(form);
|
|
// mem.dom->log(rust_log::DWARF, "attr 0x%" PRIxPTR ", form 0x%" PRIxPTR,
|
|
// attr, form);
|
|
return ! (attr == 0 && form == 0);
|
|
}
|
|
rust_crate_reader::abbrev_reader::~abbrev_reader() {
|
|
while (abbrevs.length()) {
|
|
delete abbrevs.pop();
|
|
}
|
|
}
|
|
|
|
|
|
bool
|
|
rust_crate_reader::attr::is_numeric() const
|
|
{
|
|
switch (form) {
|
|
case DW_FORM_ref_addr:
|
|
case DW_FORM_addr:
|
|
case DW_FORM_data4:
|
|
case DW_FORM_data1:
|
|
case DW_FORM_flag:
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
rust_crate_reader::attr::is_string() const
|
|
{
|
|
return form == DW_FORM_string;
|
|
}
|
|
|
|
size_t
|
|
rust_crate_reader::attr::get_ssz(rust_dom *dom) const
|
|
{
|
|
I(dom, is_string());
|
|
return val.str.sz;
|
|
}
|
|
|
|
char const *
|
|
rust_crate_reader::attr::get_str(rust_dom *dom) const
|
|
{
|
|
I(dom, is_string());
|
|
return val.str.s;
|
|
}
|
|
|
|
uintptr_t
|
|
rust_crate_reader::attr::get_num(rust_dom *dom) const
|
|
{
|
|
I(dom, is_numeric());
|
|
return val.num;
|
|
}
|
|
|
|
bool
|
|
rust_crate_reader::attr::is_unknown() const {
|
|
return !(is_numeric() || is_string());
|
|
}
|
|
|
|
rust_crate_reader::rdr_sess::rdr_sess(die_reader *rdr) : rdr(rdr)
|
|
{
|
|
I(rdr->mem.dom, !rdr->in_use);
|
|
rdr->in_use = true;
|
|
}
|
|
|
|
rust_crate_reader::rdr_sess::~rdr_sess()
|
|
{
|
|
rdr->in_use = false;
|
|
}
|
|
|
|
rust_crate_reader::die::die(die_reader *rdr, uintptr_t off)
|
|
: rdr(rdr),
|
|
off(off),
|
|
using_rdr(false)
|
|
{
|
|
rust_dom *dom = rdr->mem.dom;
|
|
rdr_sess use(rdr);
|
|
|
|
rdr->reset();
|
|
rdr->seek_off(off);
|
|
if (!rdr->is_ok()) {
|
|
ab = NULL;
|
|
return;
|
|
}
|
|
size_t ab_idx;
|
|
rdr->get_uleb(ab_idx);
|
|
if (!ab_idx) {
|
|
ab = NULL;
|
|
dom->log(rust_log::DWARF, "DIE <0x%" PRIxPTR "> (null)", off);
|
|
dom->get_log().outdent();
|
|
} else {
|
|
ab = rdr->abbrevs.get_abbrev(ab_idx);
|
|
if (!ab) {
|
|
dom->log(rust_log::DWARF, " bad abbrev number: 0x%"
|
|
PRIxPTR, ab_idx);
|
|
rdr->fail();
|
|
} else {
|
|
dom->log(rust_log::DWARF, "DIE <0x%" PRIxPTR "> abbrev 0x%"
|
|
PRIxPTR, off, ab_idx);
|
|
dom->log(rust_log::DWARF, " tag 0x%x, has children: %d",
|
|
ab->tag, ab->has_children);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool
|
|
rust_crate_reader::die::is_null() const
|
|
{
|
|
return ab == NULL;
|
|
}
|
|
|
|
bool
|
|
rust_crate_reader::die::has_children() const
|
|
{
|
|
return (!is_null()) && ab->has_children;
|
|
}
|
|
|
|
dw_tag
|
|
rust_crate_reader::die::tag() const
|
|
{
|
|
if (is_null())
|
|
return (dw_tag) (-1);
|
|
return (dw_tag) ab->tag;
|
|
}
|
|
|
|
bool
|
|
rust_crate_reader::die::start_attrs() const
|
|
{
|
|
if (is_null())
|
|
return false;
|
|
rdr->reset();
|
|
rdr->seek_off(off + 1);
|
|
rdr->abbrevs.reset();
|
|
rdr->abbrevs.seek_off(ab->body_off);
|
|
return rdr->is_ok();
|
|
}
|
|
|
|
bool
|
|
rust_crate_reader::die::step_attr(attr &a) const
|
|
{
|
|
uintptr_t ai, fi;
|
|
if (rdr->abbrevs.step_attr_form_pair(ai, fi) && rdr->is_ok()) {
|
|
a.at = (dw_at)ai;
|
|
a.form = (dw_form)fi;
|
|
|
|
uint32_t u32;
|
|
uint8_t u8;
|
|
|
|
switch (a.form) {
|
|
case DW_FORM_string:
|
|
return rdr->get_zstr(a.val.str.s, a.val.str.sz);
|
|
break;
|
|
|
|
case DW_FORM_ref_addr:
|
|
I(rdr->mem.dom, sizeof(uintptr_t) == 4);
|
|
case DW_FORM_addr:
|
|
case DW_FORM_data4:
|
|
rdr->get(u32);
|
|
a.val.num = (uintptr_t)u32;
|
|
return rdr->is_ok() || rdr->at_end();
|
|
break;
|
|
|
|
case DW_FORM_data1:
|
|
case DW_FORM_flag:
|
|
rdr->get(u8);
|
|
a.val.num = u8;
|
|
return rdr->is_ok() || rdr->at_end();
|
|
break;
|
|
|
|
case DW_FORM_block1:
|
|
rdr->get(u8);
|
|
rdr->adv(u8);
|
|
return rdr->is_ok() || rdr->at_end();
|
|
break;
|
|
|
|
case DW_FORM_block4:
|
|
rdr->get(u32);
|
|
rdr->adv(u32);
|
|
return rdr->is_ok() || rdr->at_end();
|
|
break;
|
|
|
|
case DW_FORM_udata:
|
|
rdr->get_uleb(u32);
|
|
return rdr->is_ok() || rdr->at_end();
|
|
break;
|
|
|
|
default:
|
|
rdr->mem.dom->log(rust_log::DWARF, " unknown dwarf form: 0x%"
|
|
PRIxPTR, a.form);
|
|
rdr->fail();
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
rust_crate_reader::die::find_str_attr(dw_at at, char const *&c)
|
|
{
|
|
rdr_sess use(rdr);
|
|
if (is_null())
|
|
return false;
|
|
if (start_attrs()) {
|
|
attr a;
|
|
while (step_attr(a)) {
|
|
if (a.at == at && a.is_string()) {
|
|
c = a.get_str(rdr->mem.dom);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
rust_crate_reader::die::find_num_attr(dw_at at, uintptr_t &n)
|
|
{
|
|
rdr_sess use(rdr);
|
|
if (is_null())
|
|
return false;
|
|
if (start_attrs()) {
|
|
attr a;
|
|
while (step_attr(a)) {
|
|
if (a.at == at && a.is_numeric()) {
|
|
n = a.get_num(rdr->mem.dom);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
rust_crate_reader::die::is_transparent()
|
|
{
|
|
// "semantically transparent" DIEs are those with
|
|
// children that serve to structure the tree but have
|
|
// tags that don't reflect anything in the rust-module
|
|
// name hierarchy.
|
|
switch (tag()) {
|
|
case DW_TAG_compile_unit:
|
|
case DW_TAG_lexical_block:
|
|
return (has_children());
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
rust_crate_reader::die::find_child_by_name(char const *c,
|
|
die &child,
|
|
bool exact)
|
|
{
|
|
rust_dom *dom = rdr->mem.dom;
|
|
I(dom, has_children());
|
|
I(dom, !is_null());
|
|
|
|
for (die ch = next(); !ch.is_null(); ch = ch.next_sibling()) {
|
|
char const *ac;
|
|
if (!exact && ch.is_transparent()) {
|
|
if (ch.find_child_by_name(c, child, exact)) {
|
|
return true;
|
|
}
|
|
}
|
|
else if (ch.find_str_attr(DW_AT_name, ac)) {
|
|
if (strcmp(ac, c) == 0) {
|
|
child = ch;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
rust_crate_reader::die::find_child_by_tag(dw_tag tag, die &child)
|
|
{
|
|
rust_dom *dom = rdr->mem.dom;
|
|
I(dom, has_children());
|
|
I(dom, !is_null());
|
|
|
|
for (child = next(); !child.is_null();
|
|
child = child.next_sibling()) {
|
|
if (child.tag() == tag)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
rust_crate_reader::die
|
|
rust_crate_reader::die::next() const
|
|
{
|
|
rust_dom *dom = rdr->mem.dom;
|
|
|
|
if (is_null()) {
|
|
rdr->seek_off(off + 1);
|
|
return die(rdr, rdr->tell_off());
|
|
}
|
|
|
|
{
|
|
rdr_sess use(rdr);
|
|
if (start_attrs()) {
|
|
attr a;
|
|
while (step_attr(a)) {
|
|
I(dom, !(a.is_numeric() && a.is_string()));
|
|
if (a.is_numeric())
|
|
dom->log(rust_log::DWARF, " attr num: 0x%"
|
|
PRIxPTR, a.get_num(dom));
|
|
else if (a.is_string())
|
|
dom->log(rust_log::DWARF, " attr str: %s",
|
|
a.get_str(dom));
|
|
else
|
|
dom->log(rust_log::DWARF, " attr ??:");
|
|
}
|
|
}
|
|
if (has_children())
|
|
dom->get_log().indent();
|
|
}
|
|
return die(rdr, rdr->tell_off());
|
|
}
|
|
|
|
rust_crate_reader::die
|
|
rust_crate_reader::die::next_sibling() const
|
|
{
|
|
// FIXME: use DW_AT_sibling, when present.
|
|
if (has_children()) {
|
|
// rdr->mem.dom->log(rust_log::DWARF, "+++ children of die 0x%"
|
|
// PRIxPTR, off);
|
|
die child = next();
|
|
while (!child.is_null())
|
|
child = child.next_sibling();
|
|
// rdr->mem.dom->log(rust_log::DWARF, "--- children of die 0x%"
|
|
// PRIxPTR, off);
|
|
return child.next();
|
|
} else {
|
|
return next();
|
|
}
|
|
}
|
|
|
|
|
|
rust_crate_reader::die
|
|
rust_crate_reader::die_reader::first_die()
|
|
{
|
|
reset();
|
|
seek_off(cu_base
|
|
+ sizeof(dwarf_vers)
|
|
+ sizeof(cu_abbrev_off)
|
|
+ sizeof(sizeof_addr));
|
|
return die(this, tell_off());
|
|
}
|
|
|
|
void
|
|
rust_crate_reader::die_reader::dump()
|
|
{
|
|
rust_dom *dom = mem.dom;
|
|
die d = first_die();
|
|
while (!d.is_null())
|
|
d = d.next_sibling();
|
|
I(dom, d.is_null());
|
|
I(dom, d.off == mem.lim - mem.base);
|
|
}
|
|
|
|
|
|
rust_crate_reader::die_reader::die_reader(rust_crate::mem_area &die_mem,
|
|
abbrev_reader &abbrevs)
|
|
: mem_reader(die_mem),
|
|
abbrevs(abbrevs),
|
|
cu_unit_length(0),
|
|
cu_base(0),
|
|
dwarf_vers(0),
|
|
cu_abbrev_off(0),
|
|
sizeof_addr(0),
|
|
in_use(false)
|
|
{
|
|
rust_dom *dom = mem.dom;
|
|
|
|
rdr_sess use(this);
|
|
|
|
get(cu_unit_length);
|
|
cu_base = tell_off();
|
|
|
|
get(dwarf_vers);
|
|
get(cu_abbrev_off);
|
|
get(sizeof_addr);
|
|
|
|
if (is_ok()) {
|
|
dom->log(rust_log::DWARF, "new root CU at 0x%" PRIxPTR, die_mem.base);
|
|
dom->log(rust_log::DWARF, "CU unit length: %" PRId32, cu_unit_length);
|
|
dom->log(rust_log::DWARF, "dwarf version: %" PRId16, dwarf_vers);
|
|
dom->log(rust_log::DWARF, "CU abbrev off: %" PRId32, cu_abbrev_off);
|
|
dom->log(rust_log::DWARF, "size of address: %" PRId8, sizeof_addr);
|
|
I(dom, sizeof_addr == sizeof(uintptr_t));
|
|
I(dom, dwarf_vers >= 2);
|
|
I(dom, cu_base + cu_unit_length == die_mem.lim - die_mem.base);
|
|
} else {
|
|
dom->log(rust_log::DWARF, "failed to read root CU header");
|
|
}
|
|
}
|
|
|
|
rust_crate_reader::die_reader::~die_reader() {
|
|
}
|
|
|
|
|
|
rust_crate_reader::rust_crate_reader(rust_dom *dom,
|
|
rust_crate const *crate)
|
|
: dom(dom),
|
|
crate(crate),
|
|
abbrev_mem(crate->get_debug_abbrev(dom)),
|
|
abbrevs(abbrev_mem),
|
|
die_mem(crate->get_debug_info(dom)),
|
|
dies(die_mem, abbrevs)
|
|
{
|
|
dom->log(rust_log::MEM, "crate_reader on crate: 0x%" PRIxPTR, this);
|
|
dom->log(rust_log::MEM, "debug_abbrev: 0x%" PRIxPTR, abbrev_mem.base);
|
|
dom->log(rust_log::MEM, "debug_info: 0x%" PRIxPTR, die_mem.base);
|
|
// For now, perform diagnostics only.
|
|
dies.dump();
|
|
}
|
|
|
|
|
|
//
|
|
// Local Variables:
|
|
// mode: C++
|
|
// fill-column: 78;
|
|
// indent-tabs-mode: nil
|
|
// c-basic-offset: 4
|
|
// buffer-file-coding-system: utf-8-unix
|
|
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
|
// End:
|