aboutsummaryrefslogtreecommitdiff
path: root/src/libmach/dwarfabbrev.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-04-19 19:29:25 +0000
committerrsc <devnull@localhost>2004-04-19 19:29:25 +0000
commita84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46 (patch)
tree59a0e921597e5aa53e83d487c16727a7bf01547a /src/libmach/dwarfabbrev.c
parent0e3cc9f456ea49919459bf1164d0c8309a6134fa (diff)
downloadplan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.gz
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.bz2
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.zip
libmach
Diffstat (limited to 'src/libmach/dwarfabbrev.c')
-rw-r--r--src/libmach/dwarfabbrev.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/libmach/dwarfabbrev.c b/src/libmach/dwarfabbrev.c
new file mode 100644
index 00000000..2db418dd
--- /dev/null
+++ b/src/libmach/dwarfabbrev.c
@@ -0,0 +1,129 @@
+/*
+ * Dwarf abbreviation parsing code.
+ *
+ * The convention here is that calling dwarfgetabbrevs relinquishes
+ * access to any abbrevs returned previously. Will have to add
+ * explicit reference counting if this turns out not to be acceptable.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "elf.h"
+#include "dwarf.h"
+
+static int parseabbrevs(Dwarf*, ulong, DwarfAbbrev*, DwarfAttr*, int*, int*);
+DwarfAbbrev *dwarfgetabbrev(Dwarf*, ulong, ulong);
+
+static int
+loadabbrevs(Dwarf *d, ulong off, DwarfAbbrev **aa)
+{
+ int nattr, nabbrev;
+ DwarfAbbrev *abbrev;
+ DwarfAttr *attr;
+
+ if(d->acache.off == off && d->acache.na){
+ *aa = d->acache.a;
+ return d->acache.na;
+ }
+
+ /* two passes - once to count, then allocate, then a second to copy */
+ if(parseabbrevs(d, off, nil, nil, &nabbrev, &nattr) < 0)
+ return -1;
+
+ abbrev = malloc(nabbrev*sizeof(DwarfAbbrev) + nattr*sizeof(DwarfAttr));
+ attr = (DwarfAttr*)(abbrev+nabbrev);
+
+ if(parseabbrevs(d, off, abbrev, attr, nil, nil) < 0){
+ free(abbrev);
+ return -1;
+ }
+
+ free(d->acache.a);
+ d->acache.a = abbrev;
+ d->acache.na = nabbrev;
+ d->acache.off = off;
+
+ *aa = abbrev;
+ return nabbrev;
+}
+
+static int
+parseabbrevs(Dwarf *d, ulong off, DwarfAbbrev *abbrev, DwarfAttr *attr, int *pnabbrev, int *pnattr)
+{
+ int i, nabbrev, nattr, haskids;
+ ulong num, tag, name, form;
+ DwarfBuf b;
+
+ if(off >= d->abbrev.len){
+ werrstr("bad abbrev section offset 0x%lux >= 0x%lux\n", off, d->abbrev.len);
+ return -1;
+ }
+
+ memset(&b, 0, sizeof b);
+ b.p = d->abbrev.data + off;
+ b.ep = d->abbrev.data + d->abbrev.len;
+
+ nabbrev = 0;
+ nattr = 0;
+ for(;;){
+ if(b.p == nil){
+ werrstr("malformed abbrev data");
+ return -1;
+ }
+ num = dwarfget128(&b);
+ if(num == 0)
+ break;
+ tag = dwarfget128(&b);
+ haskids = dwarfget1(&b);
+ for(i=0;; i++){
+ name = dwarfget128(&b);
+ form = dwarfget128(&b);
+ if(name == 0 && form == 0)
+ break;
+ if(attr){
+ attr[i].name = name;
+ attr[i].form = form;
+ }
+ }
+ if(abbrev){
+ abbrev->num = num;
+ abbrev->tag = tag;
+ abbrev->haskids = haskids;
+ abbrev->attr = attr;
+ abbrev->nattr = i;
+ abbrev++;
+ attr += i;
+ }
+ nabbrev++;
+ nattr += i;
+ }
+ if(pnabbrev)
+ *pnabbrev = nabbrev;
+ if(pnattr)
+ *pnattr = nattr;
+ return 0;
+}
+
+static DwarfAbbrev*
+findabbrev(DwarfAbbrev *a, int na, ulong num)
+{
+ int i;
+
+ for(i=0; i<na; i++)
+ if(a[i].num == num)
+ return &a[i];
+ return nil;
+}
+
+DwarfAbbrev*
+dwarfgetabbrev(Dwarf *d, ulong off, ulong num)
+{
+ DwarfAbbrev *a;
+ int na;
+
+ if((na = loadabbrevs(d, off, &a)) < 0)
+ return nil;
+ return findabbrev(a, na, num);
+}
+