Blob


1 /*
2 * Dwarf info parse and search.
3 */
5 #include <u.h>
6 #include <libc.h>
7 #include <bio.h>
8 #include "elf.h"
9 #include "dwarf.h"
11 enum
12 {
13 DwarfAttrSibling = 0x01,
14 DwarfAttrLocation = 0x02,
15 DwarfAttrName = 0x03,
16 DwarfAttrOrdering = 0x09,
17 DwarfAttrByteSize = 0x0B,
18 DwarfAttrBitOffset = 0x0C,
19 DwarfAttrBitSize = 0x0D,
20 DwarfAttrStmtList = 0x10,
21 DwarfAttrLowpc = 0x11,
22 DwarfAttrHighpc = 0x12,
23 DwarfAttrLanguage = 0x13,
24 DwarfAttrDiscr = 0x15,
25 DwarfAttrDiscrValue = 0x16,
26 DwarfAttrVisibility = 0x17,
27 DwarfAttrImport = 0x18,
28 DwarfAttrStringLength = 0x19,
29 DwarfAttrCommonRef = 0x1A,
30 DwarfAttrCompDir = 0x1B,
31 DwarfAttrConstValue = 0x1C,
32 DwarfAttrContainingType = 0x1D,
33 DwarfAttrDefaultValue = 0x1E,
34 DwarfAttrInline = 0x20,
35 DwarfAttrIsOptional = 0x21,
36 DwarfAttrLowerBound = 0x22,
37 DwarfAttrProducer = 0x25,
38 DwarfAttrPrototyped = 0x27,
39 DwarfAttrReturnAddr = 0x2A,
40 DwarfAttrStartScope = 0x2C,
41 DwarfAttrStrideSize = 0x2E,
42 DwarfAttrUpperBound = 0x2F,
43 DwarfAttrAbstractOrigin = 0x31,
44 DwarfAttrAccessibility = 0x32,
45 DwarfAttrAddrClass = 0x33,
46 DwarfAttrArtificial = 0x34,
47 DwarfAttrBaseTypes = 0x35,
48 DwarfAttrCalling = 0x36,
49 DwarfAttrCount = 0x37,
50 DwarfAttrDataMemberLoc = 0x38,
51 DwarfAttrDeclColumn = 0x39,
52 DwarfAttrDeclFile = 0x3A,
53 DwarfAttrDeclLine = 0x3B,
54 DwarfAttrDeclaration = 0x3C,
55 DwarfAttrDiscrList = 0x3D,
56 DwarfAttrEncoding = 0x3E,
57 DwarfAttrExternal = 0x3F,
58 DwarfAttrFrameBase = 0x40,
59 DwarfAttrFriend = 0x41,
60 DwarfAttrIdentifierCase = 0x42,
61 DwarfAttrMacroInfo = 0x43,
62 DwarfAttrNamelistItem = 0x44,
63 DwarfAttrPriority = 0x45,
64 DwarfAttrSegment = 0x46,
65 DwarfAttrSpecification = 0x47,
66 DwarfAttrStaticLink = 0x48,
67 DwarfAttrType = 0x49,
68 DwarfAttrUseLocation = 0x4A,
69 DwarfAttrVarParam = 0x4B,
70 DwarfAttrVirtuality = 0x4C,
71 DwarfAttrVtableElemLoc = 0x4D,
72 DwarfAttrAllocated = 0x4E,
73 DwarfAttrAssociated = 0x4F,
74 DwarfAttrDataLocation = 0x50,
75 DwarfAttrStride = 0x51,
76 DwarfAttrEntrypc = 0x52,
77 DwarfAttrUseUTF8 = 0x53,
78 DwarfAttrExtension = 0x54,
79 DwarfAttrRanges = 0x55,
80 DwarfAttrTrampoline = 0x56,
81 DwarfAttrCallColumn = 0x57,
82 DwarfAttrCallFile = 0x58,
83 DwarfAttrCallLine = 0x59,
84 DwarfAttrDescription = 0x5A,
85 DwarfAttrMax,
87 FormAddr = 0x01,
88 FormDwarfBlock2 = 0x03,
89 FormDwarfBlock4 = 0x04,
90 FormData2 = 0x05,
91 FormData4 = 0x06,
92 FormData8 = 0x07,
93 FormString = 0x08,
94 FormDwarfBlock = 0x09,
95 FormDwarfBlock1 = 0x0A,
96 FormData1 = 0x0B,
97 FormFlag = 0x0C,
98 FormSdata = 0x0D,
99 FormStrp = 0x0E,
100 FormUdata = 0x0F,
101 FormRefAddr = 0x10,
102 FormRef1 = 0x11,
103 FormRef2 = 0x12,
104 FormRef4 = 0x13,
105 FormRef8 = 0x14,
106 FormRefUdata = 0x15,
107 FormIndirect = 0x16
108 };
110 static int parseattrs(DwarfBuf*, ulong, DwarfAbbrev*, DwarfAttrs*);
111 static int getulong(DwarfBuf*, int, ulong, ulong*, int*);
112 static int getuchar(DwarfBuf*, int, uchar*);
113 static int getstring(DwarfBuf*, int, char**);
114 static int getblock(DwarfBuf*, int, DwarfBlock*);
115 static int skipform(DwarfBuf*, int);
116 static int constblock(Dwarf*, DwarfBlock*, ulong*);
118 int
119 dwarflookupnameinunit(Dwarf *d, ulong unit, char *name, DwarfSym *s)
121 if(dwarfenumunit(d, unit, s) < 0)
122 return -1;
124 dwarfnextsymat(d, s, 0); /* s is now the CompileUnit */
125 while(dwarfnextsymat(d, s, 1) == 1)
126 if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
127 return 0;
128 werrstr("symbol '%s' not found", name);
129 return -1;
133 int
134 dwarflookupsubname(Dwarf *d, DwarfSym *parent, char *name, DwarfSym *s)
136 *s = *parent;
137 while(dwarfnextsymat(d, s, parent->depth+1))
138 if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
139 return 0;
140 werrstr("symbol '%s' not found", name);
141 return -1;
144 int
145 dwarflookuptag(Dwarf *d, ulong unit, ulong tag, DwarfSym *s)
147 if(dwarfenumunit(d, unit, s) < 0)
148 return -1;
150 dwarfnextsymat(d, s, 0); /* s is now the CompileUnit */
151 if(s->attrs.tag == tag)
152 return 0;
153 while(dwarfnextsymat(d, s, 1) == 1)
154 if(s->attrs.tag == tag)
155 return 0;
156 werrstr("symbol with tag 0x%lux not found", tag);
157 return -1;
160 int
161 dwarfseeksym(Dwarf *d, ulong unit, ulong off, DwarfSym *s)
163 if(dwarfenumunit(d, unit, s) < 0)
164 return -1;
165 s->b.p = d->info.data + unit + off;
166 if(dwarfnextsymat(d, s, 0) != 1)
167 return -1;
168 return 0;
171 int
172 dwarflookupfn(Dwarf *d, ulong unit, ulong pc, DwarfSym *s)
174 if(dwarfenumunit(d, unit, s) < 0)
175 return -1;
177 if(dwarfnextsymat(d, s, 0) != 1)
178 return -1;
179 /* s is now the CompileUnit */
181 while(dwarfnextsymat(d, s, 1) == 1){
182 if(s->attrs.tag != TagSubprogram)
183 continue;
184 if(s->attrs.lowpc <= pc && pc < s->attrs.highpc)
185 return 0;
187 werrstr("fn containing pc 0x%lux not found", pc);
188 return -1;
191 int
192 dwarfenumunit(Dwarf *d, ulong unit, DwarfSym *s)
194 int i;
195 ulong aoff, len;
197 if(unit >= d->info.len){
198 werrstr("dwarf unit address 0x%lux >= 0x%lux out of range", unit, d->info.len);
199 return -1;
201 memset(s, 0, sizeof *s);
202 memset(&s->b, 0, sizeof s->b);
203 s->b.d = d;
204 s->b.p = d->info.data + unit;
205 s->b.ep = d->info.data + d->info.len;
206 len = dwarfget4(&s->b);
207 s->nextunit = unit + 4 + len;
209 if(s->b.ep - s->b.p < len){
210 badheader:
211 werrstr("bad dwarf unit header at unit 0x%lux", unit);
212 return -1;
214 s->b.ep = s->b.p+len;
215 if((i=dwarfget2(&s->b)) != 2)
216 goto badheader;
217 aoff = dwarfget4(&s->b);
218 s->b.addrsize = dwarfget1(&s->b);
219 if(d->addrsize == 0)
220 d->addrsize = s->b.addrsize;
221 if(s->b.p == nil)
222 goto badheader;
224 s->aoff = aoff;
225 s->unit = unit;
226 s->depth = 0;
227 return 0;
230 int
231 dwarfenum(Dwarf *d, DwarfSym *s)
233 if(dwarfenumunit(d, 0, s) < 0)
234 return -1;
235 s->allunits = 1;
236 return 0;
239 int
240 dwarfnextsym(Dwarf *d, DwarfSym *s)
242 ulong num;
243 DwarfAbbrev *a;
245 if(s->attrs.haskids)
246 s->depth++;
247 top:
248 if(s->b.p >= s->b.ep){
249 if(s->allunits && s->nextunit < d->info.len){
250 if(dwarfenumunit(d, s->nextunit, s) < 0)
251 return -1;
252 s->allunits = 1;
253 goto top;
255 return 0;
258 s->uoff = s->b.p - (d->info.data+s->unit);
259 num = dwarfget128(&s->b);
260 if(num == 0){
261 if(s->depth == 0)
262 return 0;
263 if(s->depth > 0)
264 s->depth--;
265 goto top;
268 a = dwarfgetabbrev(d, s->aoff, num);
269 if(a == nil){
270 fprint(2, "getabbrev %ud %ud for %ud,%ud: %r\n", s->aoff, num, s->unit, s->uoff);
271 abort();
272 return -1;
274 if(parseattrs(&s->b, s->unit, a, &s->attrs) < 0)
275 return -1;
276 return 1;
279 int
280 dwarfnextsymat(Dwarf *d, DwarfSym *s, int depth)
282 int r;
283 DwarfSym t;
284 uint sib;
286 if(s->depth == depth && s->attrs.have.sibling){
287 sib = s->attrs.sibling;
288 if(sib < d->info.len && d->info.data+sib >= s->b.p)
289 s->b.p = d->info.data+sib;
290 s->attrs.haskids = 0;
293 /*
294 * The funny game with t and s make sure that
295 * if we get to the end of a run of a particular
296 * depth, we leave s so that a call to nextsymat with depth-1
297 * will actually produce the desired guy. We could change
298 * the interface to dwarfnextsym instead, but I'm scared
299 * to touch it.
300 */
301 t = *s;
302 for(;;){
303 if((r = dwarfnextsym(d, &t)) != 1)
304 return r;
305 if(t.depth < depth){
306 /* went too far - nothing to see */
307 return 0;
309 *s = t;
310 if(t.depth == depth)
311 return 1;
315 typedef struct Parse Parse;
316 struct Parse {
317 int name;
318 int off;
319 int haveoff;
320 int type;
321 };
323 #define OFFSET(x) offsetof(DwarfAttrs, x), offsetof(DwarfAttrs, have.x)
325 static Parse plist[] = { /* Font Tab 4 */
326 DwarfAttrAbstractOrigin, OFFSET(abstractorigin), TReference,
327 DwarfAttrAccessibility, OFFSET(accessibility), TConstant,
328 DwarfAttrAddrClass, OFFSET(addrclass), TConstant,
329 DwarfAttrArtificial, OFFSET(isartificial), TFlag,
330 DwarfAttrBaseTypes, OFFSET(basetypes), TReference,
331 DwarfAttrBitOffset, OFFSET(bitoffset), TConstant,
332 DwarfAttrBitSize, OFFSET(bitsize), TConstant,
333 DwarfAttrByteSize, OFFSET(bytesize), TConstant,
334 DwarfAttrCalling, OFFSET(calling), TConstant,
335 DwarfAttrCommonRef, OFFSET(commonref), TReference,
336 DwarfAttrCompDir, OFFSET(compdir), TString,
337 DwarfAttrConstValue, OFFSET(constvalue), TString|TConstant|TBlock,
338 DwarfAttrContainingType, OFFSET(containingtype), TReference,
339 DwarfAttrCount, OFFSET(count), TConstant|TReference,
340 DwarfAttrDataMemberLoc, OFFSET(datamemberloc), TBlock|TConstant|TReference,
341 DwarfAttrDeclColumn, OFFSET(declcolumn), TConstant,
342 DwarfAttrDeclFile, OFFSET(declfile), TConstant,
343 DwarfAttrDeclLine, OFFSET(declline), TConstant,
344 DwarfAttrDeclaration, OFFSET(isdeclaration), TFlag,
345 DwarfAttrDefaultValue, OFFSET(defaultvalue), TReference,
346 DwarfAttrDiscr, OFFSET(discr), TReference,
347 DwarfAttrDiscrList, OFFSET(discrlist), TBlock,
348 DwarfAttrDiscrValue, OFFSET(discrvalue), TConstant,
349 DwarfAttrEncoding, OFFSET(encoding), TConstant,
350 DwarfAttrExternal, OFFSET(isexternal), TFlag,
351 DwarfAttrFrameBase, OFFSET(framebase), TBlock|TConstant,
352 DwarfAttrFriend, OFFSET(friend), TReference,
353 DwarfAttrHighpc, OFFSET(highpc), TAddress,
354 DwarfAttrIdentifierCase, OFFSET(identifiercase), TConstant,
355 DwarfAttrImport, OFFSET(import), TReference,
356 DwarfAttrInline, OFFSET(inlined), TConstant,
357 DwarfAttrIsOptional, OFFSET(isoptional), TFlag,
358 DwarfAttrLanguage, OFFSET(language), TConstant,
359 DwarfAttrLocation, OFFSET(location), TBlock|TConstant,
360 DwarfAttrLowerBound, OFFSET(lowerbound), TConstant|TReference,
361 DwarfAttrLowpc, OFFSET(lowpc), TAddress,
362 DwarfAttrMacroInfo, OFFSET(macroinfo), TConstant,
363 DwarfAttrName, OFFSET(name), TString,
364 DwarfAttrNamelistItem, OFFSET(namelistitem), TBlock,
365 DwarfAttrOrdering, OFFSET(ordering), TConstant,
366 DwarfAttrPriority, OFFSET(priority), TReference,
367 DwarfAttrProducer, OFFSET(producer), TString,
368 DwarfAttrPrototyped, OFFSET(isprototyped), TFlag,
369 DwarfAttrRanges, OFFSET(ranges), TReference,
370 DwarfAttrReturnAddr, OFFSET(returnaddr), TBlock|TConstant,
371 DwarfAttrSegment, OFFSET(segment), TBlock|TConstant,
372 DwarfAttrSibling, OFFSET(sibling), TReference,
373 DwarfAttrSpecification, OFFSET(specification), TReference,
374 DwarfAttrStartScope, OFFSET(startscope), TConstant,
375 DwarfAttrStaticLink, OFFSET(staticlink), TBlock|TConstant,
376 DwarfAttrStmtList, OFFSET(stmtlist), TConstant,
377 DwarfAttrStrideSize, OFFSET(stridesize), TConstant,
378 DwarfAttrStringLength, OFFSET(stringlength), TBlock|TConstant,
379 DwarfAttrType, OFFSET(type), TReference,
380 DwarfAttrUpperBound, OFFSET(upperbound), TConstant|TReference,
381 DwarfAttrUseLocation, OFFSET(uselocation), TBlock|TConstant,
382 DwarfAttrVarParam, OFFSET(isvarparam), TFlag,
383 DwarfAttrVirtuality, OFFSET(virtuality), TConstant,
384 DwarfAttrVisibility, OFFSET(visibility), TConstant,
385 DwarfAttrVtableElemLoc, OFFSET(vtableelemloc), TBlock|TReference,
386 };
388 static Parse ptab[DwarfAttrMax];
390 static int
391 parseattrs(DwarfBuf *b, ulong unit, DwarfAbbrev *a, DwarfAttrs *attrs)
393 int i, f, n, got;
394 static int nbad;
395 void *v;
397 /* initialize ptab first time through for quick access */
398 if(ptab[DwarfAttrName].name != DwarfAttrName)
399 for(i=0; i<nelem(plist); i++)
400 ptab[plist[i].name] = plist[i];
402 memset(attrs, 0, sizeof *attrs);
403 attrs->tag = a->tag;
404 attrs->haskids = a->haskids;
406 for(i=0; i<a->nattr; i++){
407 n = a->attr[i].name;
408 f = a->attr[i].form;
409 if(n < 0 || n >= nelem(ptab) || ptab[n].name==0){
410 if(++nbad == 1)
411 fprint(2, "dwarf parse attrs: unexpected attribute name 0x%ux\n", n);
412 return -1;
414 v = (char*)attrs + ptab[n].off;
415 got = 0;
416 if(f == FormIndirect)
417 f = dwarfget128(b);
418 if((ptab[n].type&(TConstant|TReference|TAddress))
419 && getulong(b, f, unit, v, &got) >= 0)
421 else if((ptab[n].type&TFlag) && getuchar(b, f, v) >= 0)
422 got = TFlag;
423 else if((ptab[n].type&TString) && getstring(b, f, v) >= 0)
424 got = TString;
425 else if((ptab[n].type&TBlock) && getblock(b, f, v) >= 0)
426 got = TBlock;
427 else{
428 if(skipform(b, f) < 0){
429 if(++nbad == 1)
430 fprint(2, "dwarf parse attrs: cannot skip form %d\n", f);
431 return -1;
434 if(got == TBlock && (ptab[n].type&TConstant))
435 got = constblock(b->d, v, v);
436 *((uchar*)attrs+ptab[n].haveoff) = got;
438 return 0;
441 static int
442 getulong(DwarfBuf *b, int form, ulong unit, ulong *u, int *type)
444 static int nbad;
445 uvlong uv;
447 switch(form){
448 default:
449 return -1;
451 /* addresses */
452 case FormAddr:
453 *type = TAddress;
454 *u = dwarfgetaddr(b);
455 return 0;
457 /* references */
458 case FormRefAddr:
459 /* absolute ref in .debug_info */
460 *type = TReference;
461 *u = dwarfgetaddr(b);
462 return 0;
463 case FormRef1:
464 *u = dwarfget1(b);
465 goto relativeref;
466 case FormRef2:
467 *u = dwarfget2(b);
468 goto relativeref;
469 case FormRef4:
470 *u = dwarfget4(b);
471 goto relativeref;
472 case FormRef8:
473 *u = dwarfget8(b);
474 goto relativeref;
475 case FormRefUdata:
476 *u = dwarfget128(b);
477 relativeref:
478 *u += unit;
479 *type = TReference;
480 return 0;
482 /* constants */
483 case FormData1:
484 *u = dwarfget1(b);
485 goto constant;
486 case FormData2:
487 *u = dwarfget2(b);
488 goto constant;
489 case FormData4:
490 *u = dwarfget4(b);
491 goto constant;
492 case FormData8:
493 uv = dwarfget8(b);
494 *u = uv;
495 if(uv != *u && ++nbad == 1)
496 fprint(2, "dwarf: truncating 64-bit attribute constants\n");
497 goto constant;
498 case FormSdata:
499 *u = dwarfget128s(b);
500 goto constant;
501 case FormUdata:
502 *u = dwarfget128(b);
503 constant:
504 *type = TConstant;
505 return 0;
509 static int
510 getuchar(DwarfBuf *b, int form, uchar *u)
512 switch(form){
513 default:
514 return -1;
516 case FormFlag:
517 *u = dwarfget1(b);
518 return 0;
522 static int
523 getstring(DwarfBuf *b, int form, char **s)
525 static int nbad;
526 ulong u;
528 switch(form){
529 default:
530 return -1;
532 case FormString:
533 *s = dwarfgetstring(b);
534 return 0;
536 case FormStrp:
537 u = dwarfget4(b);
538 if(u >= b->d->str.len){
539 if(++nbad == 1)
540 fprint(2, "dwarf: bad string pointer 0x%lux in attribute\n", u);
541 /* don't return error - maybe can proceed */
542 *s = nil;
543 }else
544 *s = (char*)b->d->str.data + u;
545 return 0;
550 static int
551 getblock(DwarfBuf *b, int form, DwarfBlock *bl)
553 ulong n;
555 switch(form){
556 default:
557 return -1;
558 case FormDwarfBlock:
559 n = dwarfget128(b);
560 goto copyn;
561 case FormDwarfBlock1:
562 n = dwarfget1(b);
563 goto copyn;
564 case FormDwarfBlock2:
565 n = dwarfget2(b);
566 goto copyn;
567 case FormDwarfBlock4:
568 n = dwarfget4(b);
569 copyn:
570 bl->data = dwarfgetnref(b, n);
571 bl->len = n;
572 if(bl->data == nil)
573 return -1;
574 return 0;
578 static int
579 constblock(Dwarf *d, DwarfBlock *bl, ulong *pval)
581 DwarfBuf b;
583 memset(&b, 0, sizeof b);
584 b.p = bl->data;
585 b.ep = bl->data+bl->len;
586 b.d = d;
588 switch(dwarfget1(&b)){
589 case OpAddr:
590 *pval = dwarfgetaddr(&b);
591 return TConstant;
592 case OpConst1u:
593 *pval = dwarfget1(&b);
594 return TConstant;
595 case OpConst1s:
596 *pval = (schar)dwarfget1(&b);
597 return TConstant;
598 case OpConst2u:
599 *pval = dwarfget2(&b);
600 return TConstant;
601 case OpConst2s:
602 *pval = (s16int)dwarfget2(&b);
603 return TConstant;
604 case OpConst4u:
605 *pval = dwarfget4(&b);
606 return TConstant;
607 case OpConst4s:
608 *pval = (s32int)dwarfget4(&b);
609 return TConstant;
610 case OpConst8u:
611 *pval = (u64int)dwarfget8(&b);
612 return TConstant;
613 case OpConst8s:
614 *pval = (s64int)dwarfget8(&b);
615 return TConstant;
616 case OpConstu:
617 *pval = dwarfget128(&b);
618 return TConstant;
619 case OpConsts:
620 *pval = dwarfget128s(&b);
621 return TConstant;
622 case OpPlusUconst:
623 *pval = dwarfget128(&b);
624 return TConstant;
625 default:
626 return TBlock;
630 /* last resort */
631 static int
632 skipform(DwarfBuf *b, int form)
634 int type;
635 DwarfVal val;
637 if(getulong(b, form, 0, &val.c, &type) < 0
638 && getuchar(b, form, (uchar*)&val) < 0
639 && getstring(b, form, &val.s) < 0
640 && getblock(b, form, &val.b) < 0)
641 return -1;
642 return 0;