blob: 503d51492ae6dc694bdd624d9b35c8797978a267 [file] [log] [blame]
/*
* 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);
}