about summary refs log tree commit diff
path: root/src/rt/rust_crate_reader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rt/rust_crate_reader.cpp')
-rw-r--r--src/rt/rust_crate_reader.cpp578
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: