xref: /reactos/sdk/lib/rossym_new/dwarfinfo.c (revision 9393fc32)
1 /*
2  * Dwarf info parse and search.
3  */
4 
5 #include <precomp.h>
6 #define NDEBUG
7 #include <debug.h>
8 
9 enum
10 {
11     DwarfAttrSibling = 0x01,
12     DwarfAttrLocation = 0x02,
13     DwarfAttrName = 0x03,
14     DwarfAttrOrdering = 0x09,
15     DwarfAttrByteSize = 0x0B,
16     DwarfAttrBitOffset = 0x0C,
17     DwarfAttrBitSize = 0x0D,
18     DwarfAttrStmtList = 0x10,
19     DwarfAttrLowpc = 0x11,
20     DwarfAttrHighpc = 0x12,
21     DwarfAttrLanguage = 0x13,
22     DwarfAttrDiscr = 0x15,
23     DwarfAttrDiscrValue = 0x16,
24     DwarfAttrVisibility = 0x17,
25     DwarfAttrImport = 0x18,
26     DwarfAttrStringLength = 0x19,
27     DwarfAttrCommonRef = 0x1A,
28     DwarfAttrCompDir = 0x1B,
29     DwarfAttrConstValue = 0x1C,
30     DwarfAttrContainingType = 0x1D,
31     DwarfAttrDefaultValue = 0x1E,
32     DwarfAttrInline = 0x20,
33     DwarfAttrIsOptional = 0x21,
34     DwarfAttrLowerBound = 0x22,
35     DwarfAttrProducer = 0x25,
36     DwarfAttrPrototyped = 0x27,
37     DwarfAttrReturnAddr = 0x2A,
38     DwarfAttrStartScope = 0x2C,
39     DwarfAttrStrideSize = 0x2E,
40     DwarfAttrUpperBound = 0x2F,
41     DwarfAttrAbstractOrigin = 0x31,
42     DwarfAttrAccessibility = 0x32,
43     DwarfAttrAddrClass = 0x33,
44     DwarfAttrArtificial = 0x34,
45     DwarfAttrBaseTypes = 0x35,
46     DwarfAttrCalling = 0x36,
47     DwarfAttrCount = 0x37,
48     DwarfAttrDataMemberLoc = 0x38,
49     DwarfAttrDeclColumn = 0x39,
50     DwarfAttrDeclFile = 0x3A,
51     DwarfAttrDeclLine = 0x3B,
52     DwarfAttrDeclaration = 0x3C,
53     DwarfAttrDiscrList = 0x3D,
54     DwarfAttrEncoding = 0x3E,
55     DwarfAttrExternal = 0x3F,
56     DwarfAttrFrameBase = 0x40,
57     DwarfAttrFriend = 0x41,
58     DwarfAttrIdentifierCase = 0x42,
59     DwarfAttrMacroInfo = 0x43,
60     DwarfAttrNamelistItem = 0x44,
61     DwarfAttrPriority = 0x45,
62     DwarfAttrSegment = 0x46,
63     DwarfAttrSpecification = 0x47,
64     DwarfAttrStaticLink = 0x48,
65     DwarfAttrType = 0x49,
66     DwarfAttrUseLocation = 0x4A,
67     DwarfAttrVarParam = 0x4B,
68     DwarfAttrVirtuality = 0x4C,
69     DwarfAttrVtableElemLoc = 0x4D,
70     DwarfAttrAllocated = 0x4E,
71     DwarfAttrAssociated = 0x4F,
72     DwarfAttrDataLocation = 0x50,
73     DwarfAttrStride = 0x51,
74     DwarfAttrEntrypc = 0x52,
75     DwarfAttrUseUTF8 = 0x53,
76     DwarfAttrExtension = 0x54,
77     DwarfAttrRanges = 0x55,
78     DwarfAttrTrampoline = 0x56,
79     DwarfAttrCallColumn = 0x57,
80     DwarfAttrCallFile = 0x58,
81     DwarfAttrCallLine = 0x59,
82     DwarfAttrDescription = 0x5A,
83     DwarfAttrMax,
84 
85     FormAddr = 0x01,
86     FormDwarfBlock2 = 0x03,
87     FormDwarfBlock4 = 0x04,
88     FormData2 = 0x05,
89     FormData4 = 0x06,
90     FormData8 = 0x07,
91     FormString = 0x08,
92     FormDwarfBlock = 0x09,
93     FormDwarfBlock1 = 0x0A,
94     FormData1 = 0x0B,
95     FormFlag = 0x0C,
96     FormSdata = 0x0D,
97     FormStrp = 0x0E,
98     FormUdata = 0x0F,
99     FormRefAddr = 0x10,
100     FormRef1 = 0x11,
101     FormRef2 = 0x12,
102     FormRef4 = 0x13,
103     FormRef8 = 0x14,
104     FormRefUdata = 0x15,
105     FormIndirect = 0x16
106 };
107 
108 static int parseattrs(Dwarf *d, DwarfBuf*, ulong, ulong, DwarfAbbrev*, DwarfAttrs*);
109 static int getulong(DwarfBuf*, int, ulong, ulong*, int*);
110 static int getuchar(DwarfBuf*, int, uchar*);
111 static int getstring(Dwarf *d, DwarfBuf*, int, char**);
112 static int getblock(DwarfBuf*, int, DwarfBlock*);
113 static int skipform(Dwarf *d, DwarfBuf*, int);
114 
115 int
116 dwarflookupnameinunit(Dwarf *d, ulong unit, char *name, DwarfSym *s)
117 {
118     DwarfSym compunit = { };
119     if(dwarfenumunit(d, unit, &compunit) < 0)
120         return -1;
121     while(dwarfnextsymat(d, &compunit, s) == 0) {
122         werrstr("got %s looking for %s\n", s->attrs.name, name);
123         if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
124             return 0;
125     }
126     werrstr("symbol '%s' not found", name);
127     return -1;
128 }
129 
130 int
131 dwarflookupsubname(Dwarf *d, DwarfSym *parent, char *name, DwarfSym *s)
132 {
133     *s = *parent;
134     while(dwarfnextsymat(d, parent, s))
135         if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
136             return 0;
137     werrstr("symbol '%s' not found", name);
138     return -1;
139 }
140 
141 int
142 dwarflookupchildtag(Dwarf *d, DwarfSym *parent, ulong tag, DwarfSym *s)
143 {
144     int rsym = dwarfnextsymat(d, parent, s);
145     while (rsym == 0 && s->attrs.tag != tag) {
146         if (s->attrs.haskids) {
147             DwarfSym p = *s;
148             int csym = dwarflookupchildtag(d, &p, tag, s);
149             if (csym == 0) {
150                 return csym;
151             }
152         }
153         rsym = dwarfnextsym(d, s);
154     }
155     return rsym;
156 }
157 
158 int
159 dwarflookuptag(Dwarf *d, ulong unit, ulong tag, DwarfSym *s)
160 {
161     DwarfSym compunit = { };
162     if (dwarfenumunit(d, unit, &compunit) < 0) {
163         return -1;
164     }
165     do {
166         if (compunit.attrs.tag == tag) {
167             *s = compunit;
168             return 0;
169         }
170         if (dwarflookupchildtag(d, &compunit, tag, s) == 0)
171             return 0;
172     } while(dwarfnextsym(d, &compunit) == 0);
173     werrstr("symbol with tag 0x%lux not found", tag);
174     return -1;
175 }
176 
177 int
178 dwarfseeksym(Dwarf *d, ulong unit, ulong off, DwarfSym *s)
179 {
180     DwarfSym compunit = { };
181     if(dwarfenumunit(d, unit, &compunit) < 0)
182         return -1;
183     werrstr("dwarfseeksym: unit %x off %x\n", unit, off);
184     s->b.d = d;
185     s->b.p = d->info.data + unit + off;
186     s->b.ep = compunit.b.ep;
187     if(dwarfnextsymat(d, &compunit, s) == -1)
188         return -1;
189     werrstr("dwarfseeksym: unit %x off %x, tag %x", unit, off, s->attrs.tag);
190     return 0;
191 }
192 
193 int
194 dwarflookupfn(Dwarf *d, ulong unit, ulong pc, DwarfSym *s)
195 {
196     DwarfSym compunit = { };
197     if(dwarfenumunit(d, unit, &compunit) < 0)
198         return -1;
199     while(dwarfnextsymat(d, &compunit, s) == 0){
200         if(s->attrs.tag != TagSubprogram)
201             continue;
202         if(s->attrs.lowpc <= pc && pc < s->attrs.highpc)
203             return 0;
204     }
205     werrstr("fn containing pc 0x%lux not found", pc);
206     return -1;
207 }
208 
209 int
210 dwarfenumunit(Dwarf *d, ulong unit, DwarfSym *s)
211 {
212     int i;
213     ulong aoff, len;
214 
215     if(unit >= d->info.len){
216         werrstr("dwarf unit address 0x%x >= 0x%x out of range", unit, d->info.len);
217         return -1;
218     }
219     memset(s, 0, sizeof *s);
220     memset(&s->b, 0, sizeof s->b);
221 
222     s->b.d = d;
223     s->b.p = d->info.data + unit;
224     s->b.ep = d->info.data + d->info.len;
225     len = dwarfget4(&s->b);
226 	s->unit = unit;
227     s->nextunit = unit + 4 + len;
228     s->b.ep = d->info.data + s->nextunit;
229 
230     if(s->b.ep - s->b.p < len){
231     badheader:
232         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);
233         return -1;
234     }
235     s->b.ep = s->b.p+len;
236     if((i=dwarfget2(&s->b)) > 4)
237         goto badheader;
238     aoff = dwarfget4(&s->b);
239     s->b.addrsize = dwarfget1(&s->b);
240     if(d->addrsize == 0)
241         d->addrsize = s->b.addrsize;
242     if(s->b.p == nil)
243         goto badheader;
244 
245     s->aoff = aoff;
246 
247     return dwarfnextsym(d, s);
248 }
249 
250 int
251 dwarfnextsym(Dwarf *d, DwarfSym *s)
252 {
253     ulong num;
254     DwarfAbbrev *a;
255 
256     werrstr("sym at %x (left %x)\n", s->b.p - d->info.data, s->b.ep - s->b.p);
257 
258     num = dwarfget128(&s->b);
259     werrstr("abbrev num %x\n", num);
260     s->num = num;
261     if(num == 0){
262         return -1;
263     }
264 
265     a = dwarfgetabbrev(d, s->aoff, num);
266     werrstr("a %p\n", a);
267     if(a == nil){
268         werrstr("getabbrev %x %x for %x", s->aoff, num, s->unit);
269         return -1;
270     }
271 
272     if(parseattrs(d, &s->b, s->attrs.tag, s->unit, a, &s->attrs) < 0) {
273         return -1;
274     }
275 
276     if (s->attrs.haskids) {
277         DwarfSym childSkip = { };
278         s->childoff = s->b.p - d->info.data;
279         werrstr("Set childoff at %x\n", s->childoff);
280         int r = dwarfnextsymat(d, s, &childSkip);
281         while (r == 0) {
282             r = dwarfnextsym(d, &childSkip);
283         }
284         s->b = childSkip.b;
285     } else {
286         s->childoff = 0;
287     }
288     return 0;
289 }
290 
291 int
292 dwarfnextsymat(Dwarf *d, DwarfSym *parent, DwarfSym *child)
293 {
294     uint sib;
295 
296     if (!parent->attrs.haskids || !parent->childoff)
297         return -1;
298 
299 	child->unit = parent->unit;
300     child->aoff = parent->aoff;
301     child->depth = parent->depth + 1;
302     if(child->attrs.have.sibling){
303         sib = child->attrs.sibling;
304         if(sib < d->info.len && d->info.data+sib > child->b.p)
305             child->b.p = d->info.data+sib;
306         else if (sib >= d->info.len) {
307             werrstr("sibling reported as out of bounds %d vs %d", sib, d->info.len);
308             return -1;
309         } else if (d->info.data+sib+parent->unit < child->b.p) {
310             werrstr("subsequent sibling is listed before prev %d vs %d", sib+parent->unit, child->b.p - d->info.data);
311             return -1;
312         }
313     }
314 
315     // Uninitialized
316     if (!child->b.d) {
317         child->b = parent->b;
318         child->b.p = parent->childoff + parent->b.d->info.data;
319         werrstr("Rewound to childoff %x\n", parent->childoff);
320     }
321 
322     return dwarfnextsym(d, child);
323 }
324 
325 typedef struct Parse Parse;
326 struct Parse {
327     const char *namestr;
328     int name;
329     int off;
330     int haveoff;
331     int type;
332 };
333 
334 #define ATTR(x) (#x)+9, x
335 #define OFFSET(x) offsetof(DwarfAttrs, x), offsetof(DwarfAttrs, have.x)
336 
337 static Parse plist[] = {	/* Font Tab 4 */
338     { ATTR(DwarfAttrAbstractOrigin),	OFFSET(abstractorigin),		TReference },
339     { ATTR(DwarfAttrAccessibility),	OFFSET(accessibility),		TConstant },
340     { ATTR(DwarfAttrAddrClass), 		OFFSET(addrclass), 			TConstant },
341     { ATTR(DwarfAttrBaseTypes),		OFFSET(basetypes),			TReference },
342     { ATTR(DwarfAttrBitOffset),		OFFSET(bitoffset),			TConstant },
343     { ATTR(DwarfAttrBitSize),		OFFSET(bitsize),			TConstant },
344     { ATTR(DwarfAttrByteSize),		OFFSET(bytesize),			TConstant },
345     { ATTR(DwarfAttrCalling),		OFFSET(calling),			TConstant },
346     { ATTR(DwarfAttrCommonRef),		OFFSET(commonref),			TReference },
347     { ATTR(DwarfAttrCompDir),		OFFSET(compdir),			TString },
348     { ATTR(DwarfAttrConstValue),		OFFSET(constvalue),			TString|TConstant|TBlock },
349     { ATTR(DwarfAttrContainingType),	OFFSET(containingtype),		TReference },
350     { ATTR(DwarfAttrCount),			OFFSET(count),				TConstant|TReference },
351     { ATTR(DwarfAttrDataMemberLoc),	OFFSET(datamemberloc),		TBlock|TConstant|TReference },
352     { ATTR(DwarfAttrDeclColumn),		OFFSET(declcolumn),			TConstant },
353     { ATTR(DwarfAttrDeclFile),		OFFSET(declfile),			TConstant },
354     { ATTR(DwarfAttrDeclLine),		OFFSET(declline),			TConstant },
355     { ATTR(DwarfAttrDefaultValue),	OFFSET(defaultvalue),		TReference },
356     { ATTR(DwarfAttrDiscr),			OFFSET(discr),				TReference },
357     { ATTR(DwarfAttrDiscrList),		OFFSET(discrlist),			TBlock },
358     { ATTR(DwarfAttrDiscrValue),		OFFSET(discrvalue),			TConstant },
359     { ATTR(DwarfAttrEncoding),		OFFSET(encoding),			TConstant },
360     { ATTR(DwarfAttrFrameBase),		OFFSET(framebase),			TBlock|TConstant },
361     { ATTR(DwarfAttrFriend),			OFFSET(friend),				TReference },
362     { ATTR(DwarfAttrHighpc),			OFFSET(highpc),				TAddress },
363     { ATTR(DwarfAttrEntrypc),         OFFSET(entrypc),            TAddress },
364     { ATTR(DwarfAttrIdentifierCase),	OFFSET(identifiercase),		TConstant },
365     { ATTR(DwarfAttrImport),			OFFSET(import),				TReference },
366     { ATTR(DwarfAttrInline),			OFFSET(inlined),			TConstant },
367     { ATTR(DwarfAttrArtificial),		OFFSET(isartificial), 		TFlag },
368     { ATTR(DwarfAttrDeclaration),	    OFFSET(isdeclaration),		TFlag },
369     { ATTR(DwarfAttrExternal),		OFFSET(isexternal),			TFlag },
370     { ATTR(DwarfAttrIsOptional),		OFFSET(isoptional),			TFlag },
371     { ATTR(DwarfAttrPrototyped),		OFFSET(isprototyped),		TFlag },
372     { ATTR(DwarfAttrVarParam),		OFFSET(isvarparam),			TFlag },
373     { ATTR(DwarfAttrLanguage),		OFFSET(language),			TConstant },
374     { ATTR(DwarfAttrLocation),		OFFSET(location),			TReference|TBlock },
375     { ATTR(DwarfAttrLowerBound),		OFFSET(lowerbound),			TConstant|TReference },
376     { ATTR(DwarfAttrLowpc),			OFFSET(lowpc),				TAddress },
377     { ATTR(DwarfAttrMacroInfo),		OFFSET(macroinfo),			TConstant },
378     { ATTR(DwarfAttrName),			OFFSET(name),				TString },
379     { ATTR(DwarfAttrNamelistItem),	OFFSET(namelistitem),		TBlock },
380     { ATTR(DwarfAttrOrdering), 		OFFSET(ordering),			TConstant },
381     { ATTR(DwarfAttrPriority),		OFFSET(priority),			TReference },
382     { ATTR(DwarfAttrProducer),		OFFSET(producer),			TString },
383     { ATTR(DwarfAttrRanges),			OFFSET(ranges),				TReference },
384     { ATTR(DwarfAttrReturnAddr),		OFFSET(returnaddr),			TBlock|TConstant },
385     { ATTR(DwarfAttrSegment),		OFFSET(segment),			TBlock|TConstant },
386     { ATTR(DwarfAttrSibling),		OFFSET(sibling),			TReference },
387     { ATTR(DwarfAttrSpecification),	OFFSET(specification),		TReference },
388     { ATTR(DwarfAttrStartScope),		OFFSET(startscope),			TConstant },
389     { ATTR(DwarfAttrStaticLink),		OFFSET(staticlink),			TBlock|TConstant },
390     { ATTR(DwarfAttrStmtList),		OFFSET(stmtlist),			TConstant },
391     { ATTR(DwarfAttrStrideSize),		OFFSET(stridesize),			TConstant },
392     { ATTR(DwarfAttrStringLength),	OFFSET(stringlength),		TBlock|TConstant },
393     { ATTR(DwarfAttrType),			OFFSET(type),				TReference },
394     { ATTR(DwarfAttrUpperBound),		OFFSET(upperbound),			TConstant|TReference },
395     { ATTR(DwarfAttrUseLocation),	OFFSET(uselocation),		TBlock|TConstant },
396     { ATTR(DwarfAttrVirtuality),		OFFSET(virtuality),			TConstant },
397     { ATTR(DwarfAttrVisibility),		OFFSET(visibility),			TConstant },
398     { ATTR(DwarfAttrVtableElemLoc),	OFFSET(vtableelemloc),		TBlock|TReference },
399     { }
400 };
401 
402 static Parse ptab[DwarfAttrMax];
403 
404 static int
405 parseattrs(Dwarf *d, DwarfBuf *b, ulong tag, ulong unit, DwarfAbbrev *a, DwarfAttrs *attrs)
406 {
407     int i, f, n, got;
408     static int nbad;
409     void *v;
410 
411     /* initialize ptab first time through for quick access */
412     if(ptab[DwarfAttrName].name != DwarfAttrName)
413         for(i=0; plist[i].name; i++)
414             ptab[plist[i].name] = plist[i];
415 
416     memset(attrs, 0, sizeof *attrs);
417     attrs->tag = a->tag;
418     attrs->haskids = a->haskids;
419 
420     for(i=0; i<a->nattr; i++){
421         n = a->attr[i].name;
422         f = a->attr[i].form;
423         werrstr("struct: (@%x) n %x f %x (%d %d)\n", b->p - d->info.data, n, f, ptab[n].haveoff, ptab[n].off);
424         if(n < 0 || n >= DwarfAttrMax || ptab[n].name==0) {
425             if (skipform(d, b, f) < 0) {
426                 if(++nbad == 1)
427                     werrstr("dwarf parse attrs: cannot skip form %d", f);
428                 return -1;
429             }
430             continue;
431         }
432         v = (char*)attrs + ptab[n].off;
433         got = 0;
434         if(f == FormIndirect)
435             f = dwarfget128(b);
436         if((ptab[n].type&(TConstant|TReference|TAddress))
437            && getulong(b, f, unit, v, &got) >= 0)
438             ;
439         else if((ptab[n].type&TFlag) && getuchar(b, f, v) >= 0)
440             got = TFlag;
441         else if((ptab[n].type&TString) && getstring(d, b, f, v) >= 0)
442             got = TString;
443         else if((ptab[n].type&TBlock) && getblock(b, f, v) >= 0) {
444             got = TBlock;
445         } else {
446             werrstr("Skipping form %x\n", f);
447             if(skipform(d, b, f) < 0){
448                 //if(++nbad == 1)
449                     werrstr("dwarf parse attrs: cannot skip form %d", f);
450                 return -1;
451             }
452         }
453 #if 0
454         if(got == TBlock && (ptab[n].type&TConstant))
455             got = constblock(b->d, v, v);
456 #endif
457         *((uchar*)attrs+ptab[n].haveoff) = got;
458     }
459 
460     if (attrs->have.name)
461         werrstr("%s: tag %x kids %d (last %x)\n", attrs->name, attrs->tag, attrs->haskids, b->p - b->d->info.data);
462 
463     return 0;
464 }
465 
466 static int
467 getulong(DwarfBuf *b, int form, ulong unit, ulong *u, int *type)
468 {
469     static int nbad;
470     uvlong uv;
471 
472     switch(form){
473     default:
474         return -1;
475 
476 	/* addresses */
477     case FormAddr:
478         *type = TAddress;
479         *u = dwarfgetaddr(b);
480         return 0;
481 
482 	/* references */
483     case FormRefAddr:
484         /* absolute ref in .debug_info */
485         *type = TReference;
486         *u = dwarfgetaddr(b);
487         return 0;
488     case FormRef1:
489         *u = dwarfget1(b);
490         goto relativeref;
491     case FormRef2:
492         *u = dwarfget2(b);
493         goto relativeref;
494     case FormRef4:
495         *u = dwarfget4(b);
496         goto relativeref;
497     case FormRef8:
498         *u = dwarfget8(b);
499         goto relativeref;
500     case FormRefUdata:
501         *u = dwarfget128(b);
502     relativeref:
503         *u += unit;
504         *type = TReference;
505         return 0;
506 
507 	/* constants */
508     case FormData1:
509         *u = dwarfget1(b);
510         goto constant;
511     case FormData2:
512         *u = dwarfget2(b);
513         goto constant;
514     case FormData4:
515         *u = dwarfget4(b);
516         goto constant;
517     case FormData8:
518         uv = dwarfget8(b);
519         *u = uv;
520         if(uv != *u && ++nbad == 1)
521             werrstr("dwarf: truncating 64-bit attribute constants");
522         goto constant;
523     case FormSdata:
524         *u = dwarfget128s(b);
525         goto constant;
526     case FormUdata:
527         *u = dwarfget128(b);
528     constant:
529         *type = TConstant;
530         return 0;
531     }
532 }
533 
534 static int
535 getuchar(DwarfBuf *b, int form, uchar *u)
536 {
537     switch(form){
538     default:
539         return -1;
540 
541     case FormFlag:
542         *u = dwarfget1(b);
543         return 0;
544     }
545 }
546 
547 static int
548 getstring(Dwarf *d, DwarfBuf *b, int form, char **s)
549 {
550     static int nbad;
551     ulong u, x;
552 
553     switch(form){
554     default:
555         return -1;
556 
557     case FormString:
558         x = b->p - d->info.data;
559         *s = dwarfgetstring(b);
560         for (u = 0; (*s)[u]; u++) {
561             assert(isprint((*s)[u]));
562         }
563         return 0;
564 
565     case FormStrp:
566         u = dwarfget4(b);
567         if(u >= b->d->str.len){
568             if(++nbad == 1)
569                 werrstr("dwarf: bad string pointer 0x%lux in attribute", u);
570             /* don't return error - maybe can proceed */
571             *s = nil;
572         }else
573             *s = (char*)b->d->str.data + u;
574         return 0;
575 
576     }
577 }
578 
579 static int
580 getblock(DwarfBuf *b, int form, DwarfBlock *bl)
581 {
582     ulong n;
583 
584     switch(form){
585     default:
586         return -1;
587     case FormDwarfBlock:
588         n = dwarfget128(b);
589         goto copyn;
590     case FormDwarfBlock1:
591         n = dwarfget1(b);
592         goto copyn;
593     case FormDwarfBlock2:
594         n = dwarfget2(b);
595         goto copyn;
596     case FormDwarfBlock4:
597         n = dwarfget4(b);
598     copyn:
599         bl->data = dwarfgetnref(b, n);
600         bl->len = n;
601         if(bl->data == nil)
602             return -1;
603         return 0;
604     }
605 }
606 
607 /* last resort */
608 static int
609 skipform(Dwarf *d, DwarfBuf *b, int form)
610 {
611     int type;
612     DwarfVal val;
613 
614     if(getulong(b, form, 0, &val.c, &type) < 0
615        && getuchar(b, form, (uchar*)&val) < 0
616        && getstring(d, b, form, &val.s) < 0
617        && getblock(b, form, &val.b) < 0)
618         return -1;
619     return 0;
620 }
621 
622 void stackinit(DwarfStack *stack)
623 {
624     memset(stack, 0, sizeof(*stack));
625     stack->data = stack->storage;
626     stack->length = 0; stack->max = sizeof(stack->storage) / sizeof(stack->storage[0]);
627 }
628 
629 void stackpush(DwarfStack *stack, ulong value)
630 {
631     if (stack->length == stack->max) {
632         ulong *newstack = malloc(sizeof(ulong)*stack->max*2);
633         memcpy(newstack, stack->data, sizeof(ulong)*stack->length);
634         if (stack->data != stack->storage)
635             free(stack->data);
636         stack->data = newstack;
637         stack->max *= 2;
638     }
639     werrstr("stack[%d] = %x", stack->length, value);
640     stack->data[stack->length++] = value;
641 }
642 
643 ulong stackpop(DwarfStack *stack)
644 {
645     ASSERT(stack->length > 0);
646     ulong val = stack->data[--stack->length];
647     werrstr("pop stack[%d] -> %x", stack->length, val);
648     return val;
649 }
650 
651 void stackfree(DwarfStack *stack)
652 {
653     if (stack->data != stack->storage)
654         free(stack->data);
655 }
656 
657 // Returns -1 on failure
658 int dwarfgetarg(Dwarf *d, const char *name, DwarfBuf *buf, ulong cfa, PROSSYM_REGISTERS registers, ulong *result)
659 {
660     int ret = 0;
661     DwarfStack stack = { };
662     stackinit(&stack);
663     stackpush(&stack, cfa);
664     while (buf->p < buf->ep) {
665         int opcode = dwarfget1(buf);
666         werrstr("opcode %x", opcode);
667         switch (opcode) {
668         case 0:
669             buf->p = buf->ep;
670             break;
671         case OpAddr:
672             if (d->addrsize == 4) {
673                 stackpush(&stack, dwarfget4(buf));
674                 break;
675             } else {
676                 werrstr("%s: we only support 4 byte addrs", name);
677                 goto fatal;
678             }
679         case OpConst1s: {
680             signed char c = dwarfget1(buf);
681             stackpush(&stack, c);
682         } break;
683         case OpConst1u:
684             stackpush(&stack, dwarfget1(buf));
685             break;
686         case OpConst2s: {
687             signed short s = dwarfget2(buf);
688             stackpush(&stack, s);
689         } break;
690         case OpConst2u:
691             stackpush(&stack, dwarfget2(buf));
692             break;
693         case OpConst4s: {
694             signed int i = dwarfget4(buf);
695             stackpush(&stack, i);
696         } break;
697         case OpConst4u:
698             stackpush(&stack, dwarfget4(buf));
699             break;
700         case OpConst8s:
701         case OpConst8u:
702             werrstr("const 8 not yet supported");
703             goto fatal;
704         case OpConsts:
705             stackpush(&stack, dwarfget128s(buf));
706             break;
707         case OpConstu:
708             stackpush(&stack, dwarfget128(buf));
709             break;
710         case OpDup: {
711             ulong popped = stackpop(&stack);
712             stackpush(&stack, popped);
713             stackpush(&stack, popped);
714         } break;
715         case OpDrop:
716             stackpop(&stack);
717             break;
718         case OpOver: {
719             if (stack.length < 2) goto fatal;
720             stackpush(&stack, stack.data[stack.length-2]);
721         } break;
722         case OpPick: {
723             ulong arg = dwarfget1(buf);
724             if (arg >= stack.length) goto fatal;
725             arg = stack.data[stack.length-1-arg];
726             stackpush(&stack, arg);
727         } break;
728         case OpSwap: {
729             ulong a = stackpop(&stack), b = stackpop(&stack);
730             stackpush(&stack, b);
731             stackpush(&stack, a);
732         } break;
733         case OpRot: {
734             ulong a = stackpop(&stack), b = stackpop(&stack), c = stackpop(&stack);
735             stackpush(&stack, b);
736             stackpush(&stack, c);
737             stackpush(&stack, a);
738         } break;
739         case OpXderef:
740         case OpXderefSize:
741             werrstr("Xderef not yet supported");
742             goto fatal;
743         case OpAbs: {
744             long a = stackpop(&stack);
745             stackpush(&stack, a < 0 ? -a : a);
746         } break;
747         case OpAnd:
748             stackpush(&stack, stackpop(&stack) & stackpop(&stack));
749             break;
750         case OpDiv: {
751             ulong a = stackpop(&stack), b = stackpop(&stack);
752             stackpush(&stack, b / a);
753         } break;
754         case OpMinus: {
755             ulong a = stackpop(&stack), b = stackpop(&stack);
756             stackpush(&stack, b - a);
757         } break;
758         case OpMod: {
759             ulong a = stackpop(&stack), b = stackpop(&stack);
760             stackpush(&stack, b % a);
761         } break;
762         case OpMul:
763             stackpush(&stack, stackpop(&stack) * stackpop(&stack));
764             break;
765         case OpNeg:
766             stackpush(&stack, -stackpop(&stack));
767             break;
768         case OpNot:
769             stackpush(&stack, ~stackpop(&stack));
770             break;
771         case OpOr:
772             stackpush(&stack, stackpop(&stack) | stackpop(&stack));
773             break;
774         case OpPlus:
775             stackpush(&stack, stackpop(&stack) + stackpop(&stack));
776             break;
777         case OpPlusUconst:
778             stackpush(&stack, stackpop(&stack) + dwarfget128(buf));
779             break;
780         case OpShl: {
781             ulong a = stackpop(&stack), b = stackpop(&stack);
782             stackpush(&stack, b << a);
783         } break;
784         case OpShr: {
785             ulong a = stackpop(&stack), b = stackpop(&stack);
786             stackpush(&stack, b >> a);
787         } break;
788         case OpShra: {
789             ulong a = stackpop(&stack);
790             long b = stackpop(&stack);
791             if (b < 0)
792                 b = -(-b >> a);
793             else
794                 b = b >> a;
795             stackpush(&stack, b);
796         } break;
797         case OpXor:
798             stackpush(&stack, stackpop(&stack) ^ stackpop(&stack));
799             break;
800         case OpSkip:
801             buf->p += dwarfget2(buf);
802             break;
803         case OpBra: {
804             ulong a = dwarfget2(buf);
805             if (stackpop(&stack))
806                 buf->p += a;
807         } break;
808         case OpEq:
809             stackpush(&stack, stackpop(&stack) == stackpop(&stack));
810             break;
811         case OpGe: {
812             ulong a = stackpop(&stack), b = stackpop(&stack);
813             stackpush(&stack, b >= a);
814         } break;
815         case OpGt: {
816             ulong a = stackpop(&stack), b = stackpop(&stack);
817             stackpush(&stack, b > a);
818         } break;
819         case OpLe: {
820             ulong a = stackpop(&stack), b = stackpop(&stack);
821             stackpush(&stack, b <= a);
822         } break;
823         case OpLt: {
824             ulong a = stackpop(&stack), b = stackpop(&stack);
825             stackpush(&stack, b < a);
826         } break;
827         case OpNe:
828             stackpush(&stack, stackpop(&stack) != stackpop(&stack));
829             break;
830         case OpNop:
831             break;
832         case OpDeref: {
833             ulong val;
834             void* addr = (void*)stackpop(&stack);
835             if (!RosSymCallbacks.MemGetProc
836                 (d->pe->fd,
837                  &val,
838                  addr,
839                  d->addrsize))
840                 goto fatal;
841             stackpush(&stack, val);
842         } break;
843         case OpDerefSize: {
844             ulong val, size = dwarfget1(buf);
845             void* addr = (void*)stackpop(&stack);
846             if (!RosSymCallbacks.MemGetProc
847                 (d->pe->fd,
848                  &val,
849                  addr,
850                  size))
851                 goto fatal;
852             stackpush(&stack, val);
853         } break;
854         case OpFbreg: {
855             ulong val, offset = dwarfget128s(buf);
856             void* addr = (void*)cfa;
857             werrstr("FBREG cfa %x offset %x", cfa, offset);
858             if (!RosSymCallbacks.MemGetProc
859                 (d->pe->fd,
860                  &val,
861                  (PVOID)((ULONG_PTR)addr+offset),
862                  d->addrsize))
863                 goto fatal;
864             stackpush(&stack, val);
865         } break;
866         case OpPiece:
867             werrstr("OpPiece not supported");
868             goto fatal;
869         default:
870             if (opcode >= OpLit0 && opcode < OpReg0)
871                 stackpush(&stack, opcode - OpLit0);
872             else if (opcode >= OpReg0 && opcode < OpBreg0) {
873                 ulong reg = opcode - OpReg0;
874                 werrstr("REG[%d] value %x", reg, (ulong)registers->Registers[reg]);
875                 stackpush(&stack, registers->Registers[reg]);
876             } else if (opcode >= OpBreg0 && opcode < OpRegx) {
877                 ulong val,
878                     reg = opcode - OpBreg0,
879                     offset = dwarfget128s(buf);
880                 void* addr = (void*)(ULONG_PTR)registers->Registers[reg];
881                 werrstr("BREG[%d] reg %x offset %x", reg, addr, offset);
882                 if (!RosSymCallbacks.MemGetProc
883                     ((PVOID)d->pe->fd,
884                      &val,
885                      (PVOID)((ULONG_PTR)addr + offset),
886                      d->addrsize))
887                     goto fatal;
888                 stackpush(&stack, val);
889             } else {
890                 werrstr("opcode %x not supported", opcode);
891                 goto fatal;
892             }
893             break;
894         }
895     }
896     if (stack.length < 1) goto fatal;
897     *result = stackpop(&stack);
898     werrstr("%s: value %x", name, *result);
899     goto finish;
900 
901 fatal:
902     ret = -1;
903 
904 finish:
905     stackfree(&stack);
906     return ret;
907 }
908 
909 int dwarfargvalue(Dwarf *d, DwarfSym *proc, ulong pc, ulong cfa, PROSSYM_REGISTERS registers, DwarfParam *parameter)
910 {
911     int gotarg;
912     DwarfSym unit = { };
913 
914     if (dwarfenumunit(d, proc->unit, &unit) == -1)
915         return -1;
916 
917     werrstr("lookup in unit %x-%x, pc %x", unit.attrs.lowpc, unit.attrs.highpc, pc);
918     pc -= unit.attrs.lowpc;
919 
920     werrstr("paramblock %s -> unit %x type %x fde %x len %d registers %x",
921             parameter->name,
922             parameter->unit,
923             parameter->type,
924             parameter->fde,
925             parameter->len,
926             registers);
927 
928     // Seek our range in loc
929     DwarfBuf locbuf;
930     DwarfBuf instream = { };
931 
932     locbuf.d = d;
933     locbuf.addrsize = d->addrsize;
934 
935     if (parameter->loctype == TConstant) {
936         locbuf.p = d->loc.data + parameter->fde;
937         locbuf.ep = d->loc.data + d->loc.len;
938         ulong start, end, len;
939         do {
940             len = 0;
941             start = dwarfget4(&locbuf);
942             end = dwarfget4(&locbuf);
943             if (start && end) {
944                 len = dwarfget2(&locbuf);
945                 instream = locbuf;
946                 instream.ep = instream.p + len;
947                 locbuf.p = instream.ep;
948             }
949             werrstr("ip %x s %x e %x (%x bytes)", pc, start, end, len);
950         } while (start && end && (start > pc || end <= pc));
951     } else if (parameter->loctype == TBlock) {
952         instream = locbuf;
953         instream.p = (void *)parameter->fde;
954         instream.ep = instream.p + parameter->len;
955     } else {
956         werrstr("Wrong block type for parameter %s", parameter->name);
957         return -1;
958     }
959 
960     gotarg = dwarfgetarg(d, parameter->name, &instream, cfa, registers, &parameter->value);
961     if (gotarg == -1)
962         return -1;
963 
964     return 0;
965 }
966 
967 void
968 dwarfdumpsym(Dwarf *d, DwarfSym *s)
969 {
970     int j;
971     werrstr("tag %x\n", s->attrs.tag);
972     for (j = 0; plist[j].name; j++) {
973         char *have = ((char*)&s->attrs) + plist[j].haveoff;
974         char *attr = ((char*)&s->attrs) + plist[j].off;
975         if (*have == TString) {
976             char *str = *((char **)attr);
977             werrstr("%s: %s\n", plist[j].namestr, str);
978         } else if (*have == TReference) {
979             DwarfVal *val = ((DwarfVal*)attr);
980             werrstr("%s: %x:%x\n", plist[j].namestr, val->b.data, val->b.len);
981         } else if (*have)
982             werrstr("%s: (%x)\n", plist[j].namestr, *have);
983     }
984 }
985 
986 int
987 dwarfgetparams(Dwarf *d, DwarfSym *s, ulong pc, int pnum, DwarfParam *paramblocks)
988 {
989 	int ip = 0;
990 	DwarfSym param = { };
991 	int res = dwarfnextsymat(d, s, &param);
992 	while (res == 0 && ip < pnum) {
993 		if (param.attrs.tag == TagFormalParameter &&
994 			param.attrs.have.name &&
995 			param.attrs.have.location) {
996 			paramblocks[ip].name = malloc(strlen(param.attrs.name)+1);
997 			strcpy(paramblocks[ip].name, param.attrs.name);
998 			paramblocks[ip].unit = param.unit;
999 			paramblocks[ip].type = param.attrs.type;
1000             paramblocks[ip].loctype = param.attrs.have.location;
1001             paramblocks[ip].len = param.attrs.location.b.len;
1002 			paramblocks[ip].fde = (ulong)param.attrs.location.b.data;
1003             werrstr("param[%d] block %s -> type %x loctype %x fde %x len %x",
1004                    ip,
1005                    paramblocks[ip].name,
1006                    paramblocks[ip].type,
1007                    paramblocks[ip].loctype,
1008                    paramblocks[ip].fde,
1009                    paramblocks[ip].len);
1010             ip++;
1011 		}
1012 		res = dwarfnextsymat(d, s, &param);
1013 	}
1014 	return ip;
1015 }
1016