[CMAKE]
[reactos.git] / lib / rossym / dwarfinfo.c
index cc25499..397702f 100644 (file)
 #include <debug.h>
 
 #include "dwarf.h"
+#include "pe.h"
 #include <windef.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
+    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 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(DwarfBuf*, int, char**);
+static int getstring(Dwarf *d, DwarfBuf*, int, char**);
 static int getblock(DwarfBuf*, int, DwarfBlock*);
-static int skipform(DwarfBuf*, int);
-static int constblock(Dwarf*, DwarfBlock*, ulong*);
+static int skipform(Dwarf *d, DwarfBuf*, int);
 
 int
 dwarflookupnameinunit(Dwarf *d, ulong unit, char *name, DwarfSym *s)
 {
-       if(dwarfenumunit(d, unit, s) < 0)
-               return -1;
-
-       dwarfnextsymat(d, s, 0);        /* s is now the CompileUnit */
-       while(dwarfnextsymat(d, s, 1) == 1)
-               if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
-                       return 0;
-       werrstr("symbol '%s' not found", name);
-       return -1;
+    DwarfSym compunit = { };
+    if(dwarfenumunit(d, unit, &compunit) < 0)
+        return -1;
+    while(dwarfnextsymat(d, &compunit, s) == 1)
+        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, s, parent->depth+1))
-               if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
-                       return 0;
-       werrstr("symbol '%s' not found", name);
-       return -1;
+    *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
-dwarflookuptag(Dwarf *d, ulong unit, ulong tag, DwarfSym *s)
+dwarflookupchildtag(Dwarf *d, DwarfSym *parent, ulong tag, DwarfSym *s)
 {
-       if(dwarfenumunit(d, unit, s) < 0) {
-               return -1;
-       }
+    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;
+}
 
-       dwarfnextsymat(d, s, 0);        /* s is now the CompileUnit */
-       if(s->attrs.tag == tag) {
-               return 0;
-       }
-       while(dwarfnextsymat(d, s, 1) == 1)
-               if(s->attrs.tag == tag) {
-                       return 0;
-               }
-       werrstr("symbol with tag 0x%lux not found", tag);
-       return -1;
+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)
 {
-       if(dwarfenumunit(d, unit, s) < 0)
-               return -1;
-       s->b.p = d->info.data + unit + off;
-       if(dwarfnextsymat(d, s, 0) != 1)
-               return -1;
-       return 0;
+    DwarfSym compunit = { };
+    if(dwarfenumunit(d, unit, &compunit) < 0)
+        return -1;
+    s->b.p = d->info.data + unit + off;
+    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)
 {
-       if(dwarfenumunit(d, unit, s) < 0)
-               return -1;
-
-       if(dwarfnextsymat(d, s, 0) != 1)
-               return -1;
-       /* s is now the CompileUnit */
-
-       while(dwarfnextsymat(d, s, 1) == 1){
-               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;
+    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->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;
+    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->depth = 0;
-       return 0;
-}
-
-int
-dwarfenum(Dwarf *d, DwarfSym *s)
-{
-       if(dwarfenumunit(d, 0, s) < 0)
-               return -1;
-       s->allunits = 1;
-       return 0;
+    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)) != 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;
+
+    return dwarfnextsym(d, s);
 }
 
 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){
-               werrstr("getabbrev %ud %ud for %ud,%ud: %r\n", s->aoff, num, s->unit, s->uoff);
-               return -1;
-       }
-       if(parseattrs(&s->b, s->unit, a, &s->attrs) < 0) {
-               return -1;
-       }
-       return 1;
+    ulong num;
+    DwarfAbbrev *a;
+
+    num = dwarfget128(&s->b);
+    s->num = num;
+    if(num == 0){
+        return -1;
+    }
+
+    a = dwarfgetabbrev(d, s->aoff, num);
+    if(a == nil){
+        werrstr("getabbrev %ud %ud for %ud,%ud", 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;
+        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 *s, int depth)
+dwarfnextsymat(Dwarf *d, DwarfSym *parent, DwarfSym *child)
 {
-       int r;
-       DwarfSym t;
-       uint sib;
-
-       if(s->depth == depth && 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;
-       }
-
-       /*
-        * The funny game with t and s make sure that 
-        * if we get to the end of a run of a particular
-        * depth, we leave s so that a call to nextsymat with depth-1
-        * will actually produce the desired guy.  We could change
-        * the interface to dwarfnextsym instead, but I'm scared 
-        * to touch it.
-        */
-       t = *s;
-       for(;;){
-               if((r = dwarfnextsym(d, &t)) != 1) {
-                       return r;
-               }
-               if(t.depth < depth){
-                       /* went too far - nothing to see */
-                       return 0;
-               }
-               *s = t;
-               if(t.depth == depth) {
-                       return 1;
-               }
-       }
+    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;
+    }
+
+    return dwarfnextsym(d, child);
 }
 
 typedef struct Parse Parse;
 struct Parse {
-       int name;
-       int off;
-       int haveoff;
-       int type;
+    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 },
-       { DwarfAttrEntrypc,         OFFSET(entrypc),            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 },
-       { }
+    { 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 },
+    { DwarfAttrEntrypc,         OFFSET(entrypc),            TAddress },
+    { DwarfAttrIdentifierCase, OFFSET(identifiercase),         TConstant },
+    { DwarfAttrImport,                 OFFSET(import),                         TReference },
+    { DwarfAttrInline,                 OFFSET(inlined),                        TConstant },
+    { DwarfAttrIsOptional,             OFFSET(isoptional),                     TFlag },
+    { DwarfAttrLanguage,               OFFSET(language),                       TConstant },
+    { DwarfAttrLocation,               OFFSET(location),                       TReference|TBlock },
+    { 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)
+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;
-               if(n < 0 || n >= DwarfAttrMax || ptab[n].name==0){
-                       if(++nbad == 1)
-                               werrstr("dwarf parse attrs: unexpected attribute name 0x%x", n);
-                       continue; //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)
-                                       werrstr("dwarf parse attrs: cannot skip form %d", f);
-                               return -1;
-                       }
-               }
-               if(got == TBlock && (ptab[n].type&TConstant))
-                       got = constblock(b->d, v, v);
-               *((uchar*)attrs+ptab[n].haveoff) = got;
-       }
-       return 0;
+    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;
+        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 {
+            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;
+    }
+    return 0;
 }
 
 static int
 getulong(DwarfBuf *b, int form, ulong unit, ulong *u, int *type)
 {
-       static int nbad;
-       uvlong uv;
+    static int nbad;
+    uvlong uv;
 
-       switch(form){
-       default:
-               return -1;
+    switch(form){
+    default:
+        return -1;
 
        /* addresses */
-       case FormAddr:
-               *type = TAddress;
-               *u = dwarfgetaddr(b);
-               return 0;
+    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;
+    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;
-       }
+    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;
-       }
+    switch(form){
+    default:
+        return -1;
+
+    case FormFlag:
+        *u = dwarfget1(b);
+        return 0;
+    }
 }
 
 static int
-getstring(DwarfBuf *b, int form, char **s)
+getstring(Dwarf *d, 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)
-                               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 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;
-       }
+    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
-constblock(Dwarf *d, DwarfBlock *bl, ulong *pval)
+skipform(Dwarf *d, DwarfBuf *b, int form)
 {
-       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;
-       }
+    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;
 }
 
-/* last resort */
-static int
-skipform(DwarfBuf *b, int form)
+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)
 {
-       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;
+    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);
+    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, addr = stackpop(&stack);
+            if (!RosSymCallbacks.MemGetProc
+                (d->pe->fd,
+                 &val,
+                 addr,
+                 d->addrsize))
+                goto fatal;
+            stackpush(&stack, val);
+        } break;
+        case OpDerefSize: {
+            ulong val, addr = stackpop(&stack), size = dwarfget1(buf);
+            if (!RosSymCallbacks.MemGetProc
+                (d->pe->fd,
+                 &val,
+                 addr,
+                 size))
+                goto fatal;
+            stackpush(&stack, val);
+        } break;
+        case OpFbreg: {
+            ulong val, addr = cfa, offset = dwarfget128s(buf);
+            werrstr("FBREG cfa %x offset %x", cfa, offset);
+            if (!RosSymCallbacks.MemGetProc
+                (d->pe->fd,
+                 &val,
+                 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, 
+                    addr = registers->Registers[reg],
+                    offset = dwarfget128s(buf);
+                werrstr("BREG[%d] reg %x offset %x", reg, addr, offset);
+                if (!RosSymCallbacks.MemGetProc
+                    (d->pe->fd,
+                     &val,
+                     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, &parameter->value);
+    if (gotarg == -1)
+        return -1;
+    
+    return 0;
+}
+
+int
+dwarfgetparams(Dwarf *d, DwarfSym *s, ulong pc, int pnum, DwarfParam *paramblocks)
+{
+       int ip = 0;
+       DwarfSym param = { };
+       int res = dwarfnextsymat(d, s, &param);
+       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 = 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, &param);
+       }
+       return ip;
+}