aboutsummaryrefslogtreecommitdiff
path: root/src/libmach/dwarfinfo.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/dwarfinfo.c
parent0e3cc9f456ea49919459bf1164d0c8309a6134fa (diff)
downloadplan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.gz
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.bz2
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.zip
libmach
Diffstat (limited to 'src/libmach/dwarfinfo.c')
-rw-r--r--src/libmach/dwarfinfo.c646
1 files changed, 646 insertions, 0 deletions
diff --git a/src/libmach/dwarfinfo.c b/src/libmach/dwarfinfo.c
new file mode 100644
index 00000000..79065bba
--- /dev/null
+++ b/src/libmach/dwarfinfo.c
@@ -0,0 +1,646 @@
+/*
+ * Dwarf info parse and search.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "elf.h"
+#include "dwarf.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(DwarfBuf*, ulong, DwarfAbbrev*, DwarfAttrs*);
+static int getulong(DwarfBuf*, int, ulong, ulong*, int*);
+static int getuchar(DwarfBuf*, int, uchar*);
+static int getstring(DwarfBuf*, int, char**);
+static int getblock(DwarfBuf*, int, DwarfBlock*);
+static int skipform(DwarfBuf*, int);
+static int constblock(Dwarf*, DwarfBlock*, ulong*);
+
+int
+dwarflookupnameinunit(Dwarf *d, ulong unit, char *name, DwarfSym *s)
+{
+ if(dwarfenumunit(d, unit, s) < 0)
+ return -1;
+
+ dwarfnextsym(d, s, 1); /* s is now the CompileUnit */
+ if(dwarfnextsym(d, s, 1) == 1){ /* s is now the first child of the compile unit */
+ do{
+ if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
+ return 0;
+ }while(dwarfnextsym(d, s, 0) == 1);
+ }
+ werrstr("symbol '%s' not found", name);
+ return -1;
+}
+
+
+int
+dwarflookupsubname(Dwarf *d, DwarfSym *parent, char *name, DwarfSym *s)
+{
+ *s = *parent;
+ dwarfnextsym(d, s, 1);
+ if(s->depth == parent->depth+1)
+ do{
+ if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
+ return 0;
+ }while(dwarfnextsym(d, s, 0) == 1);
+ werrstr("symbol '%s' not found", name);
+ return -1;
+}
+
+int
+dwarflookuptag(Dwarf *d, ulong unit, ulong tag, DwarfSym *s)
+{
+ if(dwarfenumunit(d, unit, s) < 0)
+ return -1;
+
+ dwarfnextsym(d, s, 1); /* s is now the CompileUnit */
+ if(s->attrs.tag == tag)
+ return 0;
+
+ if(dwarfnextsym(d, s, 1) == 1){ /* s is now the first child of the compile unit */
+ do{
+ if(s->attrs.tag == tag)
+ return 0;
+ }while(dwarfnextsym(d, s, 0) == 1);
+ }
+ werrstr("symbol with tag 0x%lux not found", tag);
+ return -1;
+}
+
+int
+dwarfseeksym(Dwarf *d, ulong unit, ulong off, DwarfSym *s)
+{
+ if(dwarfenumunit(d, unit, s) < 0)
+ return -1;
+ s->b.p = d->info.data + unit + off;
+ if(dwarfnextsym(d, s, 1) != 1)
+ return -1;
+ return 0;
+}
+
+int
+dwarflookupfn(Dwarf *d, ulong unit, ulong pc, DwarfSym *s)
+{
+ if(dwarfenumunit(d, unit, s) < 0)
+ return -1;
+
+ if(dwarfnextsym(d, s, 1) != 1)
+ return -1;
+ /* s is now the CompileUnit */
+
+ if(dwarfnextsym(d, s, 1) == 1){ /* s is now the first child of the compile unit */
+ do{
+ if(s->attrs.tag != TagSubprogram)
+ continue;
+ if(s->attrs.lowpc <= pc && pc < s->attrs.highpc)
+ return 0;
+ }while(dwarfnextsym(d, s, 0) == 1);
+ }
+ 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%lux >= 0x%lux 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->nextunit = unit + 4 + len;
+
+ if(s->b.ep - s->b.p < len){
+ badheader:
+ werrstr("bad dwarf unit header at unit 0x%lux", unit);
+ return -1;
+ }
+ s->b.ep = s->b.p+len;
+ if((i=dwarfget2(&s->b)) != 2)
+ 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;
+ s->unit = unit;
+ s->depth = 0;
+ return 0;
+}
+
+int
+dwarfenum(Dwarf *d, DwarfSym *s)
+{
+ if(dwarfenumunit(d, 0, s) < 0)
+ return -1;
+ s->allunits = 1;
+ return 0;
+}
+
+static int
+_dwarfnextsym(Dwarf *d, DwarfSym *s)
+{
+ ulong num;
+ DwarfAbbrev *a;
+
+ if(s->attrs.haskids)
+ s->depth++;
+top:
+ if(s->b.p >= s->b.ep){
+ if(s->allunits && s->nextunit < d->info.len){
+ if(dwarfenumunit(d, s->nextunit, s) < 0)
+ return -1;
+ s->allunits = 1;
+ goto top;
+ }
+ return 0;
+ }
+
+ s->uoff = s->b.p - (d->info.data+s->unit);
+ num = dwarfget128(&s->b);
+ if(num == 0){
+ if(s->depth == 0)
+ return 0;
+ if(s->depth > 0)
+ s->depth--;
+ goto top;
+ }
+
+ a = dwarfgetabbrev(d, s->aoff, num);
+ if(a == nil){
+ fprint(2, "getabbrev %ud: %r\n", num);
+ return -1;
+ }
+ if(parseattrs(&s->b, s->unit, a, &s->attrs) < 0)
+ return -1;
+ return 1;
+}
+
+int
+dwarfnextsym(Dwarf *d, DwarfSym *s, int recurse)
+{
+ int r;
+ int depth;
+ ulong sib;
+
+ if(recurse)
+ return _dwarfnextsym(d, s);
+
+ depth = s->depth;
+ if(s->attrs.have.sibling){
+ sib = s->attrs.sibling;
+ if(sib < d->info.len && d->info.data+sib >= s->b.p)
+ s->b.p = d->info.data+sib;
+ s->attrs.haskids = 0;
+ }
+
+ do{
+ r = _dwarfnextsym(d, s);
+ if(r <= 0)
+ return r;
+ }while(s->depth != depth);
+ if(s->depth < depth)
+ return 0;
+ return 1;
+}
+
+typedef struct Parse Parse;
+struct Parse {
+ int name;
+ int off;
+ int haveoff;
+ int type;
+};
+
+#define OFFSET(x) offsetof(DwarfAttrs, x), offsetof(DwarfAttrs, have.x)
+
+static Parse plist[] = { /* Font Tab 4 */
+ DwarfAttrAbstractOrigin, OFFSET(abstractorigin), TReference,
+ DwarfAttrAccessibility, OFFSET(accessibility), TConstant,
+ DwarfAttrAddrClass, OFFSET(addrclass), TConstant,
+ DwarfAttrArtificial, OFFSET(isartificial), TFlag,
+ DwarfAttrBaseTypes, OFFSET(basetypes), TReference,
+ DwarfAttrBitOffset, OFFSET(bitoffset), TConstant,
+ DwarfAttrBitSize, OFFSET(bitsize), TConstant,
+ DwarfAttrByteSize, OFFSET(bytesize), TConstant,
+ DwarfAttrCalling, OFFSET(calling), TConstant,
+ DwarfAttrCommonRef, OFFSET(commonref), TReference,
+ DwarfAttrCompDir, OFFSET(compdir), TString,
+ DwarfAttrConstValue, OFFSET(constvalue), TString|TConstant|TBlock,
+ DwarfAttrContainingType, OFFSET(containingtype), TReference,
+ DwarfAttrCount, OFFSET(count), TConstant|TReference,
+ DwarfAttrDataMemberLoc, OFFSET(datamemberloc), TBlock|TConstant|TReference,
+ DwarfAttrDeclColumn, OFFSET(declcolumn), TConstant,
+ DwarfAttrDeclFile, OFFSET(declfile), TConstant,
+ DwarfAttrDeclLine, OFFSET(declline), TConstant,
+ DwarfAttrDeclaration, OFFSET(isdeclaration), TFlag,
+ DwarfAttrDefaultValue, OFFSET(defaultvalue), TReference,
+ DwarfAttrDiscr, OFFSET(discr), TReference,
+ DwarfAttrDiscrList, OFFSET(discrlist), TBlock,
+ DwarfAttrDiscrValue, OFFSET(discrvalue), TConstant,
+ DwarfAttrEncoding, OFFSET(encoding), TConstant,
+ DwarfAttrExternal, OFFSET(isexternal), TFlag,
+ DwarfAttrFrameBase, OFFSET(framebase), TBlock|TConstant,
+ DwarfAttrFriend, OFFSET(friend), TReference,
+ DwarfAttrHighpc, OFFSET(highpc), TAddress,
+ DwarfAttrIdentifierCase, OFFSET(identifiercase), TConstant,
+ DwarfAttrImport, OFFSET(import), TReference,
+ DwarfAttrInline, OFFSET(inlined), TConstant,
+ DwarfAttrIsOptional, OFFSET(isoptional), TFlag,
+ DwarfAttrLanguage, OFFSET(language), TConstant,
+ DwarfAttrLocation, OFFSET(location), TBlock|TConstant,
+ DwarfAttrLowerBound, OFFSET(lowerbound), TConstant|TReference,
+ DwarfAttrLowpc, OFFSET(lowpc), TAddress,
+ DwarfAttrMacroInfo, OFFSET(macroinfo), TConstant,
+ DwarfAttrName, OFFSET(name), TString,
+ DwarfAttrNamelistItem, OFFSET(namelistitem), TBlock,
+ DwarfAttrOrdering, OFFSET(ordering), TConstant,
+ DwarfAttrPriority, OFFSET(priority), TReference,
+ DwarfAttrProducer, OFFSET(producer), TString,
+ DwarfAttrPrototyped, OFFSET(isprototyped), TFlag,
+ DwarfAttrRanges, OFFSET(ranges), TReference,
+ DwarfAttrReturnAddr, OFFSET(returnaddr), TBlock|TConstant,
+ DwarfAttrSegment, OFFSET(segment), TBlock|TConstant,
+ DwarfAttrSibling, OFFSET(sibling), TReference,
+ DwarfAttrSpecification, OFFSET(specification), TReference,
+ DwarfAttrStartScope, OFFSET(startscope), TConstant,
+ DwarfAttrStaticLink, OFFSET(staticlink), TBlock|TConstant,
+ DwarfAttrStmtList, OFFSET(stmtlist), TConstant,
+ DwarfAttrStrideSize, OFFSET(stridesize), TConstant,
+ DwarfAttrStringLength, OFFSET(stringlength), TBlock|TConstant,
+ DwarfAttrType, OFFSET(type), TReference,
+ DwarfAttrUpperBound, OFFSET(upperbound), TConstant|TReference,
+ DwarfAttrUseLocation, OFFSET(uselocation), TBlock|TConstant,
+ DwarfAttrVarParam, OFFSET(isvarparam), TFlag,
+ DwarfAttrVirtuality, OFFSET(virtuality), TConstant,
+ DwarfAttrVisibility, OFFSET(visibility), TConstant,
+ DwarfAttrVtableElemLoc, OFFSET(vtableelemloc), TBlock|TReference,
+};
+
+static Parse ptab[DwarfAttrMax];
+
+static int
+parseattrs(DwarfBuf *b, 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; i<nelem(plist); 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;
+ if(n < 0 || n >= nelem(ptab) || ptab[n].name==0){
+ if(++nbad == 1)
+ fprint(2, "dwarf parse attrs: unexpected attribute name 0x%ux\n", n);
+ return -1;
+ }
+ 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(b, f, v) >= 0)
+ got = TString;
+ else if((ptab[n].type&TBlock) && getblock(b, f, v) >= 0)
+ got = TBlock;
+ else{
+ if(skipform(b, f) < 0){
+ if(++nbad == 1)
+ fprint(2, "dwarf parse attrs: cannot skip form %d\n", f);
+ return -1;
+ }
+ }
+ if(got == TBlock && (ptab[n].type&TConstant))
+ got = constblock(b->d, v, v);
+ *((uchar*)attrs+ptab[n].haveoff) = got;
+ }
+ 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)
+ fprint(2, "dwarf: truncating 64-bit attribute constants\n");
+ 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(DwarfBuf *b, int form, char **s)
+{
+ static int nbad;
+ ulong u;
+
+ switch(form){
+ default:
+ return -1;
+
+ case FormString:
+ *s = dwarfgetstring(b);
+ return 0;
+
+ case FormStrp:
+ u = dwarfget4(b);
+ if(u >= b->d->str.len){
+ if(++nbad == 1)
+ fprint(2, "dwarf: bad string pointer 0x%lux in attribute\n", u);
+ /* don't return error - maybe can proceed */
+ *s = nil;
+ }else
+ *s = 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;
+ }
+}
+
+static int
+constblock(Dwarf *d, DwarfBlock *bl, ulong *pval)
+{
+ DwarfBuf b;
+
+ memset(&b, 0, sizeof b);
+ b.p = bl->data;
+ b.ep = bl->data+bl->len;
+ b.d = d;
+
+ switch(dwarfget1(&b)){
+ case OpAddr:
+ *pval = dwarfgetaddr(&b);
+ return TConstant;
+ case OpConst1u:
+ *pval = dwarfget1(&b);
+ return TConstant;
+ case OpConst1s:
+ *pval = (schar)dwarfget1(&b);
+ return TConstant;
+ case OpConst2u:
+ *pval = dwarfget2(&b);
+ return TConstant;
+ case OpConst2s:
+ *pval = (s16int)dwarfget2(&b);
+ return TConstant;
+ case OpConst4u:
+ *pval = dwarfget4(&b);
+ return TConstant;
+ case OpConst4s:
+ *pval = (s32int)dwarfget4(&b);
+ return TConstant;
+ case OpConst8u:
+ *pval = (u64int)dwarfget8(&b);
+ return TConstant;
+ case OpConst8s:
+ *pval = (s64int)dwarfget8(&b);
+ return TConstant;
+ case OpConstu:
+ *pval = dwarfget128(&b);
+ return TConstant;
+ case OpConsts:
+ *pval = dwarfget128s(&b);
+ return TConstant;
+ case OpPlusUconst:
+ *pval = dwarfget128(&b);
+ return TConstant;
+ default:
+ return TBlock;
+ }
+}
+
+/* last resort */
+static int
+skipform(DwarfBuf *b, int form)
+{
+ int type;
+ DwarfVal val;
+
+ if(getulong(b, form, 0, &val.c, &type) < 0
+ && getuchar(b, form, (uchar*)&val) < 0
+ && getstring(b, form, &val.s) < 0
+ && getblock(b, form, &val.b) < 0)
+ return -1;
+ return 0;
+}