mirror of
https://github.com/reactos/reactos.git
synced 2024-08-22 11:22:59 +00:00
1016 lines
30 KiB
C
1016 lines
30 KiB
C
/*
|
|
* Dwarf info parse and search.
|
|
*/
|
|
|
|
#include <precomp.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
enum
|
|
{
|
|
DwarfAttrSibling = 0x01,
|
|
DwarfAttrLocation = 0x02,
|
|
DwarfAttrName = 0x03,
|
|
DwarfAttrOrdering = 0x09,
|
|
DwarfAttrByteSize = 0x0B,
|
|
DwarfAttrBitOffset = 0x0C,
|
|
DwarfAttrBitSize = 0x0D,
|
|
DwarfAttrStmtList = 0x10,
|
|
DwarfAttrLowpc = 0x11,
|
|
DwarfAttrHighpc = 0x12,
|
|
DwarfAttrLanguage = 0x13,
|
|
DwarfAttrDiscr = 0x15,
|
|
DwarfAttrDiscrValue = 0x16,
|
|
DwarfAttrVisibility = 0x17,
|
|
DwarfAttrImport = 0x18,
|
|
DwarfAttrStringLength = 0x19,
|
|
DwarfAttrCommonRef = 0x1A,
|
|
DwarfAttrCompDir = 0x1B,
|
|
DwarfAttrConstValue = 0x1C,
|
|
DwarfAttrContainingType = 0x1D,
|
|
DwarfAttrDefaultValue = 0x1E,
|
|
DwarfAttrInline = 0x20,
|
|
DwarfAttrIsOptional = 0x21,
|
|
DwarfAttrLowerBound = 0x22,
|
|
DwarfAttrProducer = 0x25,
|
|
DwarfAttrPrototyped = 0x27,
|
|
DwarfAttrReturnAddr = 0x2A,
|
|
DwarfAttrStartScope = 0x2C,
|
|
DwarfAttrStrideSize = 0x2E,
|
|
DwarfAttrUpperBound = 0x2F,
|
|
DwarfAttrAbstractOrigin = 0x31,
|
|
DwarfAttrAccessibility = 0x32,
|
|
DwarfAttrAddrClass = 0x33,
|
|
DwarfAttrArtificial = 0x34,
|
|
DwarfAttrBaseTypes = 0x35,
|
|
DwarfAttrCalling = 0x36,
|
|
DwarfAttrCount = 0x37,
|
|
DwarfAttrDataMemberLoc = 0x38,
|
|
DwarfAttrDeclColumn = 0x39,
|
|
DwarfAttrDeclFile = 0x3A,
|
|
DwarfAttrDeclLine = 0x3B,
|
|
DwarfAttrDeclaration = 0x3C,
|
|
DwarfAttrDiscrList = 0x3D,
|
|
DwarfAttrEncoding = 0x3E,
|
|
DwarfAttrExternal = 0x3F,
|
|
DwarfAttrFrameBase = 0x40,
|
|
DwarfAttrFriend = 0x41,
|
|
DwarfAttrIdentifierCase = 0x42,
|
|
DwarfAttrMacroInfo = 0x43,
|
|
DwarfAttrNamelistItem = 0x44,
|
|
DwarfAttrPriority = 0x45,
|
|
DwarfAttrSegment = 0x46,
|
|
DwarfAttrSpecification = 0x47,
|
|
DwarfAttrStaticLink = 0x48,
|
|
DwarfAttrType = 0x49,
|
|
DwarfAttrUseLocation = 0x4A,
|
|
DwarfAttrVarParam = 0x4B,
|
|
DwarfAttrVirtuality = 0x4C,
|
|
DwarfAttrVtableElemLoc = 0x4D,
|
|
DwarfAttrAllocated = 0x4E,
|
|
DwarfAttrAssociated = 0x4F,
|
|
DwarfAttrDataLocation = 0x50,
|
|
DwarfAttrStride = 0x51,
|
|
DwarfAttrEntrypc = 0x52,
|
|
DwarfAttrUseUTF8 = 0x53,
|
|
DwarfAttrExtension = 0x54,
|
|
DwarfAttrRanges = 0x55,
|
|
DwarfAttrTrampoline = 0x56,
|
|
DwarfAttrCallColumn = 0x57,
|
|
DwarfAttrCallFile = 0x58,
|
|
DwarfAttrCallLine = 0x59,
|
|
DwarfAttrDescription = 0x5A,
|
|
DwarfAttrMax,
|
|
|
|
FormAddr = 0x01,
|
|
FormDwarfBlock2 = 0x03,
|
|
FormDwarfBlock4 = 0x04,
|
|
FormData2 = 0x05,
|
|
FormData4 = 0x06,
|
|
FormData8 = 0x07,
|
|
FormString = 0x08,
|
|
FormDwarfBlock = 0x09,
|
|
FormDwarfBlock1 = 0x0A,
|
|
FormData1 = 0x0B,
|
|
FormFlag = 0x0C,
|
|
FormSdata = 0x0D,
|
|
FormStrp = 0x0E,
|
|
FormUdata = 0x0F,
|
|
FormRefAddr = 0x10,
|
|
FormRef1 = 0x11,
|
|
FormRef2 = 0x12,
|
|
FormRef4 = 0x13,
|
|
FormRef8 = 0x14,
|
|
FormRefUdata = 0x15,
|
|
FormIndirect = 0x16
|
|
};
|
|
|
|
static int parseattrs(Dwarf *d, DwarfBuf*, ulong, ulong, DwarfAbbrev*, DwarfAttrs*);
|
|
static int getulong(DwarfBuf*, int, ulong, ulong*, int*);
|
|
static int getuchar(DwarfBuf*, int, uchar*);
|
|
static int getstring(Dwarf *d, DwarfBuf*, int, char**);
|
|
static int getblock(DwarfBuf*, int, DwarfBlock*);
|
|
static int skipform(Dwarf *d, DwarfBuf*, int);
|
|
|
|
int
|
|
dwarflookupnameinunit(Dwarf *d, ulong unit, char *name, DwarfSym *s)
|
|
{
|
|
DwarfSym compunit = { };
|
|
if(dwarfenumunit(d, unit, &compunit) < 0)
|
|
return -1;
|
|
while(dwarfnextsymat(d, &compunit, s) == 0) {
|
|
werrstr("got %s looking for %s\n", s->attrs.name, name);
|
|
if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
|
|
return 0;
|
|
}
|
|
werrstr("symbol '%s' not found", name);
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
dwarflookupsubname(Dwarf *d, DwarfSym *parent, char *name, DwarfSym *s)
|
|
{
|
|
*s = *parent;
|
|
while(dwarfnextsymat(d, parent, s))
|
|
if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
|
|
return 0;
|
|
werrstr("symbol '%s' not found", name);
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
dwarflookupchildtag(Dwarf *d, DwarfSym *parent, ulong tag, DwarfSym *s)
|
|
{
|
|
int rsym = dwarfnextsymat(d, parent, s);
|
|
while (rsym == 0 && s->attrs.tag != tag) {
|
|
if (s->attrs.haskids) {
|
|
DwarfSym p = *s;
|
|
int csym = dwarflookupchildtag(d, &p, tag, s);
|
|
if (csym == 0) {
|
|
return csym;
|
|
}
|
|
}
|
|
rsym = dwarfnextsym(d, s);
|
|
}
|
|
return rsym;
|
|
}
|
|
|
|
int
|
|
dwarflookuptag(Dwarf *d, ulong unit, ulong tag, DwarfSym *s)
|
|
{
|
|
DwarfSym compunit = { };
|
|
if (dwarfenumunit(d, unit, &compunit) < 0) {
|
|
return -1;
|
|
}
|
|
do {
|
|
if (compunit.attrs.tag == tag) {
|
|
*s = compunit;
|
|
return 0;
|
|
}
|
|
if (dwarflookupchildtag(d, &compunit, tag, s) == 0)
|
|
return 0;
|
|
} while(dwarfnextsym(d, &compunit) == 0);
|
|
werrstr("symbol with tag 0x%lux not found", tag);
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
dwarfseeksym(Dwarf *d, ulong unit, ulong off, DwarfSym *s)
|
|
{
|
|
DwarfSym compunit = { };
|
|
if(dwarfenumunit(d, unit, &compunit) < 0)
|
|
return -1;
|
|
werrstr("dwarfseeksym: unit %x off %x\n", unit, off);
|
|
s->b.d = d;
|
|
s->b.p = d->info.data + unit + off;
|
|
s->b.ep = compunit.b.ep;
|
|
if(dwarfnextsymat(d, &compunit, s) == -1)
|
|
return -1;
|
|
werrstr("dwarfseeksym: unit %x off %x, tag %x", unit, off, s->attrs.tag);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
dwarflookupfn(Dwarf *d, ulong unit, ulong pc, DwarfSym *s)
|
|
{
|
|
DwarfSym compunit = { };
|
|
if(dwarfenumunit(d, unit, &compunit) < 0)
|
|
return -1;
|
|
while(dwarfnextsymat(d, &compunit, s) == 0){
|
|
if(s->attrs.tag != TagSubprogram)
|
|
continue;
|
|
if(s->attrs.lowpc <= pc && pc < s->attrs.highpc)
|
|
return 0;
|
|
}
|
|
werrstr("fn containing pc 0x%lux not found", pc);
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
dwarfenumunit(Dwarf *d, ulong unit, DwarfSym *s)
|
|
{
|
|
int i;
|
|
ulong aoff, len;
|
|
|
|
if(unit >= d->info.len){
|
|
werrstr("dwarf unit address 0x%x >= 0x%x out of range", unit, d->info.len);
|
|
return -1;
|
|
}
|
|
memset(s, 0, sizeof *s);
|
|
memset(&s->b, 0, sizeof s->b);
|
|
|
|
s->b.d = d;
|
|
s->b.p = d->info.data + unit;
|
|
s->b.ep = d->info.data + d->info.len;
|
|
len = dwarfget4(&s->b);
|
|
s->unit = unit;
|
|
s->nextunit = unit + 4 + len;
|
|
s->b.ep = d->info.data + s->nextunit;
|
|
|
|
if(s->b.ep - s->b.p < len){
|
|
badheader:
|
|
werrstr("bad dwarf unit header at unit 0x%lux end %x start %x len %x", unit, s->b.ep - d->info.data, s->b.p - d->info.data, len);
|
|
return -1;
|
|
}
|
|
s->b.ep = s->b.p+len;
|
|
if((i=dwarfget2(&s->b)) > 4)
|
|
goto badheader;
|
|
aoff = dwarfget4(&s->b);
|
|
s->b.addrsize = dwarfget1(&s->b);
|
|
if(d->addrsize == 0)
|
|
d->addrsize = s->b.addrsize;
|
|
if(s->b.p == nil)
|
|
goto badheader;
|
|
|
|
s->aoff = aoff;
|
|
|
|
return dwarfnextsym(d, s);
|
|
}
|
|
|
|
int
|
|
dwarfnextsym(Dwarf *d, DwarfSym *s)
|
|
{
|
|
ulong num;
|
|
DwarfAbbrev *a;
|
|
|
|
werrstr("sym at %x (left %x)\n", s->b.p - d->info.data, s->b.ep - s->b.p);
|
|
|
|
num = dwarfget128(&s->b);
|
|
werrstr("abbrev num %x\n", num);
|
|
s->num = num;
|
|
if(num == 0){
|
|
return -1;
|
|
}
|
|
|
|
a = dwarfgetabbrev(d, s->aoff, num);
|
|
werrstr("a %p\n", a);
|
|
if(a == nil){
|
|
werrstr("getabbrev %x %x for %x", s->aoff, num, s->unit);
|
|
return -1;
|
|
}
|
|
|
|
if(parseattrs(d, &s->b, s->attrs.tag, s->unit, a, &s->attrs) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (s->attrs.haskids) {
|
|
DwarfSym childSkip = { };
|
|
s->childoff = s->b.p - d->info.data;
|
|
werrstr("Set childoff at %x\n", s->childoff);
|
|
int r = dwarfnextsymat(d, s, &childSkip);
|
|
while (r == 0) {
|
|
r = dwarfnextsym(d, &childSkip);
|
|
}
|
|
s->b = childSkip.b;
|
|
} else {
|
|
s->childoff = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
dwarfnextsymat(Dwarf *d, DwarfSym *parent, DwarfSym *child)
|
|
{
|
|
uint sib;
|
|
|
|
if (!parent->attrs.haskids || !parent->childoff)
|
|
return -1;
|
|
|
|
child->unit = parent->unit;
|
|
child->aoff = parent->aoff;
|
|
child->depth = parent->depth + 1;
|
|
if(child->attrs.have.sibling){
|
|
sib = child->attrs.sibling;
|
|
if(sib < d->info.len && d->info.data+sib > child->b.p)
|
|
child->b.p = d->info.data+sib;
|
|
else if (sib >= d->info.len) {
|
|
werrstr("sibling reported as out of bounds %d vs %d", sib, d->info.len);
|
|
return -1;
|
|
} else if (d->info.data+sib+parent->unit < child->b.p) {
|
|
werrstr("subsequent sibling is listed before prev %d vs %d", sib+parent->unit, child->b.p - d->info.data);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// Uninitialized
|
|
if (!child->b.d) {
|
|
child->b = parent->b;
|
|
child->b.p = parent->childoff + parent->b.d->info.data;
|
|
werrstr("Rewound to childoff %x\n", parent->childoff);
|
|
}
|
|
|
|
return dwarfnextsym(d, child);
|
|
}
|
|
|
|
typedef struct Parse Parse;
|
|
struct Parse {
|
|
const char *namestr;
|
|
int name;
|
|
int off;
|
|
int haveoff;
|
|
int type;
|
|
};
|
|
|
|
#define ATTR(x) (#x)+9, x
|
|
#define OFFSET(x) offsetof(DwarfAttrs, x), offsetof(DwarfAttrs, have.x)
|
|
|
|
static Parse plist[] = { /* Font Tab 4 */
|
|
{ ATTR(DwarfAttrAbstractOrigin), OFFSET(abstractorigin), TReference },
|
|
{ ATTR(DwarfAttrAccessibility), OFFSET(accessibility), TConstant },
|
|
{ ATTR(DwarfAttrAddrClass), OFFSET(addrclass), TConstant },
|
|
{ ATTR(DwarfAttrBaseTypes), OFFSET(basetypes), TReference },
|
|
{ ATTR(DwarfAttrBitOffset), OFFSET(bitoffset), TConstant },
|
|
{ ATTR(DwarfAttrBitSize), OFFSET(bitsize), TConstant },
|
|
{ ATTR(DwarfAttrByteSize), OFFSET(bytesize), TConstant },
|
|
{ ATTR(DwarfAttrCalling), OFFSET(calling), TConstant },
|
|
{ ATTR(DwarfAttrCommonRef), OFFSET(commonref), TReference },
|
|
{ ATTR(DwarfAttrCompDir), OFFSET(compdir), TString },
|
|
{ ATTR(DwarfAttrConstValue), OFFSET(constvalue), TString|TConstant|TBlock },
|
|
{ ATTR(DwarfAttrContainingType), OFFSET(containingtype), TReference },
|
|
{ ATTR(DwarfAttrCount), OFFSET(count), TConstant|TReference },
|
|
{ ATTR(DwarfAttrDataMemberLoc), OFFSET(datamemberloc), TBlock|TConstant|TReference },
|
|
{ ATTR(DwarfAttrDeclColumn), OFFSET(declcolumn), TConstant },
|
|
{ ATTR(DwarfAttrDeclFile), OFFSET(declfile), TConstant },
|
|
{ ATTR(DwarfAttrDeclLine), OFFSET(declline), TConstant },
|
|
{ ATTR(DwarfAttrDefaultValue), OFFSET(defaultvalue), TReference },
|
|
{ ATTR(DwarfAttrDiscr), OFFSET(discr), TReference },
|
|
{ ATTR(DwarfAttrDiscrList), OFFSET(discrlist), TBlock },
|
|
{ ATTR(DwarfAttrDiscrValue), OFFSET(discrvalue), TConstant },
|
|
{ ATTR(DwarfAttrEncoding), OFFSET(encoding), TConstant },
|
|
{ ATTR(DwarfAttrFrameBase), OFFSET(framebase), TBlock|TConstant },
|
|
{ ATTR(DwarfAttrFriend), OFFSET(friend), TReference },
|
|
{ ATTR(DwarfAttrHighpc), OFFSET(highpc), TAddress },
|
|
{ ATTR(DwarfAttrEntrypc), OFFSET(entrypc), TAddress },
|
|
{ ATTR(DwarfAttrIdentifierCase), OFFSET(identifiercase), TConstant },
|
|
{ ATTR(DwarfAttrImport), OFFSET(import), TReference },
|
|
{ ATTR(DwarfAttrInline), OFFSET(inlined), TConstant },
|
|
{ ATTR(DwarfAttrArtificial), OFFSET(isartificial), TFlag },
|
|
{ ATTR(DwarfAttrDeclaration), OFFSET(isdeclaration), TFlag },
|
|
{ ATTR(DwarfAttrExternal), OFFSET(isexternal), TFlag },
|
|
{ ATTR(DwarfAttrIsOptional), OFFSET(isoptional), TFlag },
|
|
{ ATTR(DwarfAttrPrototyped), OFFSET(isprototyped), TFlag },
|
|
{ ATTR(DwarfAttrVarParam), OFFSET(isvarparam), TFlag },
|
|
{ ATTR(DwarfAttrLanguage), OFFSET(language), TConstant },
|
|
{ ATTR(DwarfAttrLocation), OFFSET(location), TReference|TBlock },
|
|
{ ATTR(DwarfAttrLowerBound), OFFSET(lowerbound), TConstant|TReference },
|
|
{ ATTR(DwarfAttrLowpc), OFFSET(lowpc), TAddress },
|
|
{ ATTR(DwarfAttrMacroInfo), OFFSET(macroinfo), TConstant },
|
|
{ ATTR(DwarfAttrName), OFFSET(name), TString },
|
|
{ ATTR(DwarfAttrNamelistItem), OFFSET(namelistitem), TBlock },
|
|
{ ATTR(DwarfAttrOrdering), OFFSET(ordering), TConstant },
|
|
{ ATTR(DwarfAttrPriority), OFFSET(priority), TReference },
|
|
{ ATTR(DwarfAttrProducer), OFFSET(producer), TString },
|
|
{ ATTR(DwarfAttrRanges), OFFSET(ranges), TReference },
|
|
{ ATTR(DwarfAttrReturnAddr), OFFSET(returnaddr), TBlock|TConstant },
|
|
{ ATTR(DwarfAttrSegment), OFFSET(segment), TBlock|TConstant },
|
|
{ ATTR(DwarfAttrSibling), OFFSET(sibling), TReference },
|
|
{ ATTR(DwarfAttrSpecification), OFFSET(specification), TReference },
|
|
{ ATTR(DwarfAttrStartScope), OFFSET(startscope), TConstant },
|
|
{ ATTR(DwarfAttrStaticLink), OFFSET(staticlink), TBlock|TConstant },
|
|
{ ATTR(DwarfAttrStmtList), OFFSET(stmtlist), TConstant },
|
|
{ ATTR(DwarfAttrStrideSize), OFFSET(stridesize), TConstant },
|
|
{ ATTR(DwarfAttrStringLength), OFFSET(stringlength), TBlock|TConstant },
|
|
{ ATTR(DwarfAttrType), OFFSET(type), TReference },
|
|
{ ATTR(DwarfAttrUpperBound), OFFSET(upperbound), TConstant|TReference },
|
|
{ ATTR(DwarfAttrUseLocation), OFFSET(uselocation), TBlock|TConstant },
|
|
{ ATTR(DwarfAttrVirtuality), OFFSET(virtuality), TConstant },
|
|
{ ATTR(DwarfAttrVisibility), OFFSET(visibility), TConstant },
|
|
{ ATTR(DwarfAttrVtableElemLoc), OFFSET(vtableelemloc), TBlock|TReference },
|
|
{ }
|
|
};
|
|
|
|
static Parse ptab[DwarfAttrMax];
|
|
|
|
static int
|
|
parseattrs(Dwarf *d, DwarfBuf *b, ulong tag, ulong unit, DwarfAbbrev *a, DwarfAttrs *attrs)
|
|
{
|
|
int i, f, n, got;
|
|
static int nbad;
|
|
void *v;
|
|
|
|
/* initialize ptab first time through for quick access */
|
|
if(ptab[DwarfAttrName].name != DwarfAttrName)
|
|
for(i=0; plist[i].name; i++)
|
|
ptab[plist[i].name] = plist[i];
|
|
|
|
memset(attrs, 0, sizeof *attrs);
|
|
attrs->tag = a->tag;
|
|
attrs->haskids = a->haskids;
|
|
|
|
for(i=0; i<a->nattr; i++){
|
|
n = a->attr[i].name;
|
|
f = a->attr[i].form;
|
|
werrstr("struct: (@%x) n %x f %x (%d %d)\n", b->p - d->info.data, n, f, ptab[n].haveoff, ptab[n].off);
|
|
if(n < 0 || n >= DwarfAttrMax || ptab[n].name==0) {
|
|
if (skipform(d, b, f) < 0) {
|
|
if(++nbad == 1)
|
|
werrstr("dwarf parse attrs: cannot skip form %d", f);
|
|
return -1;
|
|
}
|
|
continue;
|
|
}
|
|
v = (char*)attrs + ptab[n].off;
|
|
got = 0;
|
|
if(f == FormIndirect)
|
|
f = dwarfget128(b);
|
|
if((ptab[n].type&(TConstant|TReference|TAddress))
|
|
&& getulong(b, f, unit, v, &got) >= 0)
|
|
;
|
|
else if((ptab[n].type&TFlag) && getuchar(b, f, v) >= 0)
|
|
got = TFlag;
|
|
else if((ptab[n].type&TString) && getstring(d, b, f, v) >= 0)
|
|
got = TString;
|
|
else if((ptab[n].type&TBlock) && getblock(b, f, v) >= 0) {
|
|
got = TBlock;
|
|
} else {
|
|
werrstr("Skipping form %x\n", f);
|
|
if(skipform(d, b, f) < 0){
|
|
//if(++nbad == 1)
|
|
werrstr("dwarf parse attrs: cannot skip form %d", f);
|
|
return -1;
|
|
}
|
|
}
|
|
#if 0
|
|
if(got == TBlock && (ptab[n].type&TConstant))
|
|
got = constblock(b->d, v, v);
|
|
#endif
|
|
*((uchar*)attrs+ptab[n].haveoff) = got;
|
|
}
|
|
|
|
if (attrs->have.name)
|
|
werrstr("%s: tag %x kids %d (last %x)\n", attrs->name, attrs->tag, attrs->haskids, b->p - b->d->info.data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
getulong(DwarfBuf *b, int form, ulong unit, ulong *u, int *type)
|
|
{
|
|
static int nbad;
|
|
uvlong uv;
|
|
|
|
switch(form){
|
|
default:
|
|
return -1;
|
|
|
|
/* addresses */
|
|
case FormAddr:
|
|
*type = TAddress;
|
|
*u = dwarfgetaddr(b);
|
|
return 0;
|
|
|
|
/* references */
|
|
case FormRefAddr:
|
|
/* absolute ref in .debug_info */
|
|
*type = TReference;
|
|
*u = dwarfgetaddr(b);
|
|
return 0;
|
|
case FormRef1:
|
|
*u = dwarfget1(b);
|
|
goto relativeref;
|
|
case FormRef2:
|
|
*u = dwarfget2(b);
|
|
goto relativeref;
|
|
case FormRef4:
|
|
*u = dwarfget4(b);
|
|
goto relativeref;
|
|
case FormRef8:
|
|
*u = dwarfget8(b);
|
|
goto relativeref;
|
|
case FormRefUdata:
|
|
*u = dwarfget128(b);
|
|
relativeref:
|
|
*u += unit;
|
|
*type = TReference;
|
|
return 0;
|
|
|
|
/* constants */
|
|
case FormData1:
|
|
*u = dwarfget1(b);
|
|
goto constant;
|
|
case FormData2:
|
|
*u = dwarfget2(b);
|
|
goto constant;
|
|
case FormData4:
|
|
*u = dwarfget4(b);
|
|
goto constant;
|
|
case FormData8:
|
|
uv = dwarfget8(b);
|
|
*u = uv;
|
|
if(uv != *u && ++nbad == 1)
|
|
werrstr("dwarf: truncating 64-bit attribute constants");
|
|
goto constant;
|
|
case FormSdata:
|
|
*u = dwarfget128s(b);
|
|
goto constant;
|
|
case FormUdata:
|
|
*u = dwarfget128(b);
|
|
constant:
|
|
*type = TConstant;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int
|
|
getuchar(DwarfBuf *b, int form, uchar *u)
|
|
{
|
|
switch(form){
|
|
default:
|
|
return -1;
|
|
|
|
case FormFlag:
|
|
*u = dwarfget1(b);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int
|
|
getstring(Dwarf *d, DwarfBuf *b, int form, char **s)
|
|
{
|
|
static int nbad;
|
|
ulong u, x;
|
|
|
|
switch(form){
|
|
default:
|
|
return -1;
|
|
|
|
case FormString:
|
|
x = b->p - d->info.data;
|
|
*s = dwarfgetstring(b);
|
|
for (u = 0; (*s)[u]; u++) {
|
|
assert(isprint((*s)[u]));
|
|
}
|
|
return 0;
|
|
|
|
case FormStrp:
|
|
u = dwarfget4(b);
|
|
if(u >= b->d->str.len){
|
|
if(++nbad == 1)
|
|
werrstr("dwarf: bad string pointer 0x%lux in attribute", u);
|
|
/* don't return error - maybe can proceed */
|
|
*s = nil;
|
|
}else
|
|
*s = (char*)b->d->str.data + u;
|
|
return 0;
|
|
|
|
}
|
|
}
|
|
|
|
static int
|
|
getblock(DwarfBuf *b, int form, DwarfBlock *bl)
|
|
{
|
|
ulong n;
|
|
|
|
switch(form){
|
|
default:
|
|
return -1;
|
|
case FormDwarfBlock:
|
|
n = dwarfget128(b);
|
|
goto copyn;
|
|
case FormDwarfBlock1:
|
|
n = dwarfget1(b);
|
|
goto copyn;
|
|
case FormDwarfBlock2:
|
|
n = dwarfget2(b);
|
|
goto copyn;
|
|
case FormDwarfBlock4:
|
|
n = dwarfget4(b);
|
|
copyn:
|
|
bl->data = dwarfgetnref(b, n);
|
|
bl->len = n;
|
|
if(bl->data == nil)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* last resort */
|
|
static int
|
|
skipform(Dwarf *d, DwarfBuf *b, int form)
|
|
{
|
|
int type;
|
|
DwarfVal val;
|
|
|
|
if(getulong(b, form, 0, &val.c, &type) < 0
|
|
&& getuchar(b, form, (uchar*)&val) < 0
|
|
&& getstring(d, b, form, &val.s) < 0
|
|
&& getblock(b, form, &val.b) < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
void stackinit(DwarfStack *stack)
|
|
{
|
|
memset(stack, 0, sizeof(*stack));
|
|
stack->data = stack->storage;
|
|
stack->length = 0; stack->max = sizeof(stack->storage) / sizeof(stack->storage[0]);
|
|
}
|
|
|
|
void stackpush(DwarfStack *stack, ulong value)
|
|
{
|
|
if (stack->length == stack->max) {
|
|
ulong *newstack = malloc(sizeof(ulong)*stack->max*2);
|
|
memcpy(newstack, stack->data, sizeof(ulong)*stack->length);
|
|
if (stack->data != stack->storage)
|
|
free(stack->data);
|
|
stack->data = newstack;
|
|
stack->max *= 2;
|
|
}
|
|
werrstr("stack[%d] = %x", stack->length, value);
|
|
stack->data[stack->length++] = value;
|
|
}
|
|
|
|
ulong stackpop(DwarfStack *stack)
|
|
{
|
|
ASSERT(stack->length > 0);
|
|
ulong val = stack->data[--stack->length];
|
|
werrstr("pop stack[%d] -> %x", stack->length, val);
|
|
return val;
|
|
}
|
|
|
|
void stackfree(DwarfStack *stack)
|
|
{
|
|
if (stack->data != stack->storage)
|
|
free(stack->data);
|
|
}
|
|
|
|
// Returns -1 on failure
|
|
int dwarfgetarg(Dwarf *d, const char *name, DwarfBuf *buf, ulong cfa, PROSSYM_REGISTERS registers, ulong *result)
|
|
{
|
|
int ret = 0;
|
|
DwarfStack stack = { };
|
|
stackinit(&stack);
|
|
stackpush(&stack, cfa);
|
|
while (buf->p < buf->ep) {
|
|
int opcode = dwarfget1(buf);
|
|
werrstr("opcode %x", opcode);
|
|
switch (opcode) {
|
|
case 0:
|
|
buf->p = buf->ep;
|
|
break;
|
|
case OpAddr:
|
|
if (d->addrsize == 4) {
|
|
stackpush(&stack, dwarfget4(buf));
|
|
break;
|
|
} else {
|
|
werrstr("%s: we only support 4 byte addrs", name);
|
|
goto fatal;
|
|
}
|
|
case OpConst1s: {
|
|
signed char c = dwarfget1(buf);
|
|
stackpush(&stack, c);
|
|
} break;
|
|
case OpConst1u:
|
|
stackpush(&stack, dwarfget1(buf));
|
|
break;
|
|
case OpConst2s: {
|
|
signed short s = dwarfget2(buf);
|
|
stackpush(&stack, s);
|
|
} break;
|
|
case OpConst2u:
|
|
stackpush(&stack, dwarfget2(buf));
|
|
break;
|
|
case OpConst4s: {
|
|
signed int i = dwarfget4(buf);
|
|
stackpush(&stack, i);
|
|
} break;
|
|
case OpConst4u:
|
|
stackpush(&stack, dwarfget4(buf));
|
|
break;
|
|
case OpConst8s:
|
|
case OpConst8u:
|
|
werrstr("const 8 not yet supported");
|
|
goto fatal;
|
|
case OpConsts:
|
|
stackpush(&stack, dwarfget128s(buf));
|
|
break;
|
|
case OpConstu:
|
|
stackpush(&stack, dwarfget128(buf));
|
|
break;
|
|
case OpDup: {
|
|
ulong popped = stackpop(&stack);
|
|
stackpush(&stack, popped);
|
|
stackpush(&stack, popped);
|
|
} break;
|
|
case OpDrop:
|
|
stackpop(&stack);
|
|
break;
|
|
case OpOver: {
|
|
if (stack.length < 2) goto fatal;
|
|
stackpush(&stack, stack.data[stack.length-2]);
|
|
} break;
|
|
case OpPick: {
|
|
ulong arg = dwarfget1(buf);
|
|
if (arg >= stack.length) goto fatal;
|
|
arg = stack.data[stack.length-1-arg];
|
|
stackpush(&stack, arg);
|
|
} break;
|
|
case OpSwap: {
|
|
ulong a = stackpop(&stack), b = stackpop(&stack);
|
|
stackpush(&stack, b);
|
|
stackpush(&stack, a);
|
|
} break;
|
|
case OpRot: {
|
|
ulong a = stackpop(&stack), b = stackpop(&stack), c = stackpop(&stack);
|
|
stackpush(&stack, b);
|
|
stackpush(&stack, c);
|
|
stackpush(&stack, a);
|
|
} break;
|
|
case OpXderef:
|
|
case OpXderefSize:
|
|
werrstr("Xderef not yet supported");
|
|
goto fatal;
|
|
case OpAbs: {
|
|
long a = stackpop(&stack);
|
|
stackpush(&stack, a < 0 ? -a : a);
|
|
} break;
|
|
case OpAnd:
|
|
stackpush(&stack, stackpop(&stack) & stackpop(&stack));
|
|
break;
|
|
case OpDiv: {
|
|
ulong a = stackpop(&stack), b = stackpop(&stack);
|
|
stackpush(&stack, b / a);
|
|
} break;
|
|
case OpMinus: {
|
|
ulong a = stackpop(&stack), b = stackpop(&stack);
|
|
stackpush(&stack, b - a);
|
|
} break;
|
|
case OpMod: {
|
|
ulong a = stackpop(&stack), b = stackpop(&stack);
|
|
stackpush(&stack, b % a);
|
|
} break;
|
|
case OpMul:
|
|
stackpush(&stack, stackpop(&stack) * stackpop(&stack));
|
|
break;
|
|
case OpNeg:
|
|
stackpush(&stack, -stackpop(&stack));
|
|
break;
|
|
case OpNot:
|
|
stackpush(&stack, ~stackpop(&stack));
|
|
break;
|
|
case OpOr:
|
|
stackpush(&stack, stackpop(&stack) | stackpop(&stack));
|
|
break;
|
|
case OpPlus:
|
|
stackpush(&stack, stackpop(&stack) + stackpop(&stack));
|
|
break;
|
|
case OpPlusUconst:
|
|
stackpush(&stack, stackpop(&stack) + dwarfget128(buf));
|
|
break;
|
|
case OpShl: {
|
|
ulong a = stackpop(&stack), b = stackpop(&stack);
|
|
stackpush(&stack, b << a);
|
|
} break;
|
|
case OpShr: {
|
|
ulong a = stackpop(&stack), b = stackpop(&stack);
|
|
stackpush(&stack, b >> a);
|
|
} break;
|
|
case OpShra: {
|
|
ulong a = stackpop(&stack);
|
|
long b = stackpop(&stack);
|
|
if (b < 0)
|
|
b = -(-b >> a);
|
|
else
|
|
b = b >> a;
|
|
stackpush(&stack, b);
|
|
} break;
|
|
case OpXor:
|
|
stackpush(&stack, stackpop(&stack) ^ stackpop(&stack));
|
|
break;
|
|
case OpSkip:
|
|
buf->p += dwarfget2(buf);
|
|
break;
|
|
case OpBra: {
|
|
ulong a = dwarfget2(buf);
|
|
if (stackpop(&stack))
|
|
buf->p += a;
|
|
} break;
|
|
case OpEq:
|
|
stackpush(&stack, stackpop(&stack) == stackpop(&stack));
|
|
break;
|
|
case OpGe: {
|
|
ulong a = stackpop(&stack), b = stackpop(&stack);
|
|
stackpush(&stack, b >= a);
|
|
} break;
|
|
case OpGt: {
|
|
ulong a = stackpop(&stack), b = stackpop(&stack);
|
|
stackpush(&stack, b > a);
|
|
} break;
|
|
case OpLe: {
|
|
ulong a = stackpop(&stack), b = stackpop(&stack);
|
|
stackpush(&stack, b <= a);
|
|
} break;
|
|
case OpLt: {
|
|
ulong a = stackpop(&stack), b = stackpop(&stack);
|
|
stackpush(&stack, b < a);
|
|
} break;
|
|
case OpNe:
|
|
stackpush(&stack, stackpop(&stack) != stackpop(&stack));
|
|
break;
|
|
case OpNop:
|
|
break;
|
|
case OpDeref: {
|
|
ulong val;
|
|
void* addr = (void*)stackpop(&stack);
|
|
if (!RosSymCallbacks.MemGetProc
|
|
(d->pe->fd,
|
|
&val,
|
|
addr,
|
|
d->addrsize))
|
|
goto fatal;
|
|
stackpush(&stack, val);
|
|
} break;
|
|
case OpDerefSize: {
|
|
ulong val, size = dwarfget1(buf);
|
|
void* addr = (void*)stackpop(&stack);
|
|
if (!RosSymCallbacks.MemGetProc
|
|
(d->pe->fd,
|
|
&val,
|
|
addr,
|
|
size))
|
|
goto fatal;
|
|
stackpush(&stack, val);
|
|
} break;
|
|
case OpFbreg: {
|
|
ulong val, offset = dwarfget128s(buf);
|
|
void* addr = (void*)cfa;
|
|
werrstr("FBREG cfa %x offset %x", cfa, offset);
|
|
if (!RosSymCallbacks.MemGetProc
|
|
(d->pe->fd,
|
|
&val,
|
|
(PVOID)((ULONG_PTR)addr+offset),
|
|
d->addrsize))
|
|
goto fatal;
|
|
stackpush(&stack, val);
|
|
} break;
|
|
case OpPiece:
|
|
werrstr("OpPiece not supported");
|
|
goto fatal;
|
|
default:
|
|
if (opcode >= OpLit0 && opcode < OpReg0)
|
|
stackpush(&stack, opcode - OpLit0);
|
|
else if (opcode >= OpReg0 && opcode < OpBreg0) {
|
|
ulong reg = opcode - OpReg0;
|
|
werrstr("REG[%d] value %x", reg, (ulong)registers->Registers[reg]);
|
|
stackpush(&stack, registers->Registers[reg]);
|
|
} else if (opcode >= OpBreg0 && opcode < OpRegx) {
|
|
ulong val,
|
|
reg = opcode - OpBreg0,
|
|
offset = dwarfget128s(buf);
|
|
void* addr = (void*)(ULONG_PTR)registers->Registers[reg];
|
|
werrstr("BREG[%d] reg %x offset %x", reg, addr, offset);
|
|
if (!RosSymCallbacks.MemGetProc
|
|
((PVOID)d->pe->fd,
|
|
&val,
|
|
(PVOID)((ULONG_PTR)addr + offset),
|
|
d->addrsize))
|
|
goto fatal;
|
|
stackpush(&stack, val);
|
|
} else {
|
|
werrstr("opcode %x not supported", opcode);
|
|
goto fatal;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (stack.length < 1) goto fatal;
|
|
*result = stackpop(&stack);
|
|
werrstr("%s: value %x", name, *result);
|
|
goto finish;
|
|
|
|
fatal:
|
|
ret = -1;
|
|
|
|
finish:
|
|
stackfree(&stack);
|
|
return ret;
|
|
}
|
|
|
|
int dwarfargvalue(Dwarf *d, DwarfSym *proc, ulong pc, ulong cfa, PROSSYM_REGISTERS registers, DwarfParam *parameter)
|
|
{
|
|
int gotarg;
|
|
DwarfSym unit = { };
|
|
|
|
if (dwarfenumunit(d, proc->unit, &unit) == -1)
|
|
return -1;
|
|
|
|
werrstr("lookup in unit %x-%x, pc %x", unit.attrs.lowpc, unit.attrs.highpc, pc);
|
|
pc -= unit.attrs.lowpc;
|
|
|
|
werrstr("paramblock %s -> unit %x type %x fde %x len %d registers %x",
|
|
parameter->name,
|
|
parameter->unit,
|
|
parameter->type,
|
|
parameter->fde,
|
|
parameter->len,
|
|
registers);
|
|
|
|
// Seek our range in loc
|
|
DwarfBuf locbuf;
|
|
DwarfBuf instream = { };
|
|
|
|
locbuf.d = d;
|
|
locbuf.addrsize = d->addrsize;
|
|
|
|
if (parameter->loctype == TConstant) {
|
|
locbuf.p = d->loc.data + parameter->fde;
|
|
locbuf.ep = d->loc.data + d->loc.len;
|
|
ulong start, end, len;
|
|
do {
|
|
len = 0;
|
|
start = dwarfget4(&locbuf);
|
|
end = dwarfget4(&locbuf);
|
|
if (start && end) {
|
|
len = dwarfget2(&locbuf);
|
|
instream = locbuf;
|
|
instream.ep = instream.p + len;
|
|
locbuf.p = instream.ep;
|
|
}
|
|
werrstr("ip %x s %x e %x (%x bytes)", pc, start, end, len);
|
|
} while (start && end && (start > pc || end <= pc));
|
|
} else if (parameter->loctype == TBlock) {
|
|
instream = locbuf;
|
|
instream.p = (void *)parameter->fde;
|
|
instream.ep = instream.p + parameter->len;
|
|
} else {
|
|
werrstr("Wrong block type for parameter %s", parameter->name);
|
|
return -1;
|
|
}
|
|
|
|
gotarg = dwarfgetarg(d, parameter->name, &instream, cfa, registers, ¶meter->value);
|
|
if (gotarg == -1)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
dwarfdumpsym(Dwarf *d, DwarfSym *s)
|
|
{
|
|
int j;
|
|
werrstr("tag %x\n", s->attrs.tag);
|
|
for (j = 0; plist[j].name; j++) {
|
|
char *have = ((char*)&s->attrs) + plist[j].haveoff;
|
|
char *attr = ((char*)&s->attrs) + plist[j].off;
|
|
if (*have == TString) {
|
|
char *str = *((char **)attr);
|
|
werrstr("%s: %s\n", plist[j].namestr, str);
|
|
} else if (*have == TReference) {
|
|
DwarfVal *val = ((DwarfVal*)attr);
|
|
werrstr("%s: %x:%x\n", plist[j].namestr, val->b.data, val->b.len);
|
|
} else if (*have)
|
|
werrstr("%s: (%x)\n", plist[j].namestr, *have);
|
|
}
|
|
}
|
|
|
|
int
|
|
dwarfgetparams(Dwarf *d, DwarfSym *s, ulong pc, int pnum, DwarfParam *paramblocks)
|
|
{
|
|
int ip = 0;
|
|
DwarfSym param = { };
|
|
int res = dwarfnextsymat(d, s, ¶m);
|
|
while (res == 0 && ip < pnum) {
|
|
if (param.attrs.tag == TagFormalParameter &&
|
|
param.attrs.have.name &&
|
|
param.attrs.have.location) {
|
|
paramblocks[ip].name = malloc(strlen(param.attrs.name)+1);
|
|
strcpy(paramblocks[ip].name, param.attrs.name);
|
|
paramblocks[ip].unit = param.unit;
|
|
paramblocks[ip].type = param.attrs.type;
|
|
paramblocks[ip].loctype = param.attrs.have.location;
|
|
paramblocks[ip].len = param.attrs.location.b.len;
|
|
paramblocks[ip].fde = (ulong)param.attrs.location.b.data;
|
|
werrstr("param[%d] block %s -> type %x loctype %x fde %x len %x",
|
|
ip,
|
|
paramblocks[ip].name,
|
|
paramblocks[ip].type,
|
|
paramblocks[ip].loctype,
|
|
paramblocks[ip].fde,
|
|
paramblocks[ip].len);
|
|
ip++;
|
|
}
|
|
res = dwarfnextsymat(d, s, ¶m);
|
|
}
|
|
return ip;
|
|
}
|