|  | /* | 
|  | * 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]; | 
|  | werrstr("abbrev not found"); | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | DwarfAbbrev* | 
|  | dwarfgetabbrev(Dwarf *d, ulong off, ulong num) | 
|  | { | 
|  | DwarfAbbrev *a; | 
|  | int na; | 
|  |  | 
|  | if((na = loadabbrevs(d, off, &a)) < 0){ | 
|  | werrstr("loadabbrevs: %r"); | 
|  | return nil; | 
|  | } | 
|  | return findabbrev(a, na, num); | 
|  | } | 
|  |  |