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
dwarflookupnameinunit(Dwarf * d,ulong unit,char * name,DwarfSym * s)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
dwarflookupsubname(Dwarf * d,DwarfSym * parent,char * name,DwarfSym * s)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
dwarflookupchildtag(Dwarf * d,DwarfSym * parent,ulong tag,DwarfSym * s)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
dwarflookuptag(Dwarf * d,ulong unit,ulong tag,DwarfSym * s)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
dwarfseeksym(Dwarf * d,ulong unit,ulong off,DwarfSym * s)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
dwarflookupfn(Dwarf * d,ulong unit,ulong pc,DwarfSym * s)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
dwarfenumunit(Dwarf * d,ulong unit,DwarfSym * s)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
dwarfnextsym(Dwarf * d,DwarfSym * s)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
dwarfnextsymat(Dwarf * d,DwarfSym * parent,DwarfSym * child)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
parseattrs(Dwarf * d,DwarfBuf * b,ulong tag,ulong unit,DwarfAbbrev * a,DwarfAttrs * attrs)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
getulong(DwarfBuf * b,int form,ulong unit,ulong * u,int * type)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
getuchar(DwarfBuf * b,int form,uchar * u)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
getstring(Dwarf * d,DwarfBuf * b,int form,char ** s)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
getblock(DwarfBuf * b,int form,DwarfBlock * bl)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
skipform(Dwarf * d,DwarfBuf * b,int form)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
stackinit(DwarfStack * stack)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
stackpush(DwarfStack * stack,ulong value)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
stackpop(DwarfStack * stack)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
stackfree(DwarfStack * stack)651 void stackfree(DwarfStack *stack)
652 {
653 if (stack->data != stack->storage)
654 free(stack->data);
655 }
656
657 // Returns -1 on failure
dwarfgetarg(Dwarf * d,const char * name,DwarfBuf * buf,ulong cfa,PROSSYM_REGISTERS registers,ulong * result)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
dwarfargvalue(Dwarf * d,DwarfSym * proc,ulong pc,ulong cfa,PROSSYM_REGISTERS registers,DwarfParam * parameter)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, ¶meter->value);
961 if (gotarg == -1)
962 return -1;
963
964 return 0;
965 }
966
967 void
dwarfdumpsym(Dwarf * d,DwarfSym * s)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
dwarfgetparams(Dwarf * d,DwarfSym * s,ulong pc,int pnum,DwarfParam * paramblocks)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, ¶m);
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, ¶m);
1013 }
1014 return ip;
1015 }
1016