diff options
author | rsc <devnull@localhost> | 2004-04-19 19:29:25 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2004-04-19 19:29:25 +0000 |
commit | a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46 (patch) | |
tree | 59a0e921597e5aa53e83d487c16727a7bf01547a /src/libmach/dwarfabbrev.c | |
parent | 0e3cc9f456ea49919459bf1164d0c8309a6134fa (diff) | |
download | plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.gz plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.bz2 plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.zip |
libmach
Diffstat (limited to 'src/libmach/dwarfabbrev.c')
-rw-r--r-- | src/libmach/dwarfabbrev.c | 129 |
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); +} + |