diff options
Diffstat (limited to 'src/rt/rust_crate_reader.cpp')
| -rw-r--r-- | src/rt/rust_crate_reader.cpp | 578 |
1 files changed, 578 insertions, 0 deletions
diff --git a/src/rt/rust_crate_reader.cpp b/src/rt/rust_crate_reader.cpp new file mode 100644 index 00000000000..3c36729ff26 --- /dev/null +++ b/src/rt/rust_crate_reader.cpp @@ -0,0 +1,578 @@ + +#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()) { + + // 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); + } else { + ab = rdr->abbrevs.get_abbrev(ab_idx); + 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; + + 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 ??:"); + } + } + } + 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: |
