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 dwarfnextsym(d, s, 1); /* s is now the CompileUnit */
125 if(dwarfnextsym(d, s, 1) == 1){ /* s is now the first child of the compile unit */
126 do{
127 if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
128 return 0;
129 }while(dwarfnextsym(d, s, 0) == 1);
131 werrstr("symbol '%s' not found", name);
132 return -1;
136 int
137 dwarflookupsubname(Dwarf *d, DwarfSym *parent, char *name, DwarfSym *s)
139 *s = *parent;
140 dwarfnextsym(d, s, 1);
141 if(s->depth == parent->depth+1)
142 do{
143 if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
144 return 0;
145 }while(dwarfnextsym(d, s, 0) == 1);
146 werrstr("symbol '%s' not found", name);
147 return -1;
150 int
151 dwarflookuptag(Dwarf *d, ulong unit, ulong tag, DwarfSym *s)
153 if(dwarfenumunit(d, unit, s) < 0)
154 return -1;
156 dwarfnextsym(d, s, 1); /* s is now the CompileUnit */
157 if(s->attrs.tag == tag)
158 return 0;
160 if(dwarfnextsym(d, s, 1) == 1){ /* s is now the first child of the compile unit */
161 do{
162 if(s->attrs.tag == tag)
163 return 0;
164 }while(dwarfnextsym(d, s, 0) == 1);
166 werrstr("symbol with tag 0x%lux not found", tag);
167 return -1;
170 int
171 dwarfseeksym(Dwarf *d, ulong unit, ulong off, DwarfSym *s)
173 if(dwarfenumunit(d, unit, s) < 0)
174 return -1;
175 s->b.p = d->info.data + unit + off;
176 if(dwarfnextsym(d, s, 1) != 1)
177 return -1;
178 return 0;
181 int
182 dwarflookupfn(Dwarf *d, ulong unit, ulong pc, DwarfSym *s)
184 if(dwarfenumunit(d, unit, s) < 0)
185 return -1;
187 if(dwarfnextsym(d, s, 1) != 1)
188 return -1;
189 /* s is now the CompileUnit */
191 if(dwarfnextsym(d, s, 1) == 1){ /* s is now the first child of the compile unit */
192 do{
193 if(s->attrs.tag != TagSubprogram)
194 continue;
195 if(s->attrs.lowpc <= pc && pc < s->attrs.highpc)
196 return 0;
197 }while(dwarfnextsym(d, s, 0) == 1);
199 werrstr("fn containing pc 0x%lux not found", pc);
200 return -1;
203 int
204 dwarfenumunit(Dwarf *d, ulong unit, DwarfSym *s)
206 int i;
207 ulong aoff, len;
209 if(unit >= d->info.len){
210 werrstr("dwarf unit address 0x%lux >= 0x%lux out of range", unit, d->info.len);
211 return -1;
213 memset(s, 0, sizeof *s);
214 memset(&s->b, 0, sizeof s->b);
215 s->b.d = d;
216 s->b.p = d->info.data + unit;
217 s->b.ep = d->info.data + d->info.len;
218 len = dwarfget4(&s->b);
219 s->nextunit = unit + 4 + len;
221 if(s->b.ep - s->b.p < len){
222 badheader:
223 werrstr("bad dwarf unit header at unit 0x%lux", unit);
224 return -1;
226 s->b.ep = s->b.p+len;
227 if((i=dwarfget2(&s->b)) != 2)
228 goto badheader;
229 aoff = dwarfget4(&s->b);
230 s->b.addrsize = dwarfget1(&s->b);
231 if(d->addrsize == 0)
232 d->addrsize = s->b.addrsize;
233 if(s->b.p == nil)
234 goto badheader;
236 s->aoff = aoff;
237 s->unit = unit;
238 s->depth = 0;
239 return 0;
242 int
243 dwarfenum(Dwarf *d, DwarfSym *s)
245 if(dwarfenumunit(d, 0, s) < 0)
246 return -1;
247 s->allunits = 1;
248 return 0;
251 static int
252 _dwarfnextsym(Dwarf *d, DwarfSym *s)
254 ulong num;
255 DwarfAbbrev *a;
257 if(s->attrs.haskids)
258 s->depth++;
259 top:
260 if(s->b.p >= s->b.ep){
261 if(s->allunits && s->nextunit < d->info.len){
262 if(dwarfenumunit(d, s->nextunit, s) < 0)
263 return -1;
264 s->allunits = 1;
265 goto top;
267 return 0;
270 s->uoff = s->b.p - (d->info.data+s->unit);
271 num = dwarfget128(&s->b);
272 if(num == 0){
273 if(s->depth == 0)
274 return 0;
275 if(s->depth > 0)
276 s->depth--;
277 goto top;
280 a = dwarfgetabbrev(d, s->aoff, num);
281 if(a == nil){
282 fprint(2, "getabbrev %ud: %r\n", num);
283 return -1;
285 if(parseattrs(&s->b, s->unit, a, &s->attrs) < 0)
286 return -1;
287 return 1;
290 int
291 dwarfnextsym(Dwarf *d, DwarfSym *s, int recurse)
293 int r;
294 int depth;
295 ulong sib;
297 if(recurse)
298 return _dwarfnextsym(d, s);
300 depth = s->depth;
301 if(s->attrs.have.sibling){
302 sib = s->attrs.sibling;
303 if(sib < d->info.len && d->info.data+sib >= s->b.p)
304 s->b.p = d->info.data+sib;
305 s->attrs.haskids = 0;
308 do{
309 r = _dwarfnextsym(d, s);
310 if(r <= 0)
311 return r;
312 }while(s->depth != depth);
313 if(s->depth < depth)
314 return 0;
315 return 1;
318 typedef struct Parse Parse;
319 struct Parse {
320 int name;
321 int off;
322 int haveoff;
323 int type;
324 };
326 #define OFFSET(x) offsetof(DwarfAttrs, x), offsetof(DwarfAttrs, have.x)
328 static Parse plist[] = { /* Font Tab 4 */
329 DwarfAttrAbstractOrigin, OFFSET(abstractorigin), TReference,
330 DwarfAttrAccessibility, OFFSET(accessibility), TConstant,
331 DwarfAttrAddrClass, OFFSET(addrclass), TConstant,
332 DwarfAttrArtificial, OFFSET(isartificial), TFlag,
333 DwarfAttrBaseTypes, OFFSET(basetypes), TReference,
334 DwarfAttrBitOffset, OFFSET(bitoffset), TConstant,
335 DwarfAttrBitSize, OFFSET(bitsize), TConstant,
336 DwarfAttrByteSize, OFFSET(bytesize), TConstant,
337 DwarfAttrCalling, OFFSET(calling), TConstant,
338 DwarfAttrCommonRef, OFFSET(commonref), TReference,
339 DwarfAttrCompDir, OFFSET(compdir), TString,
340 DwarfAttrConstValue, OFFSET(constvalue), TString|TConstant|TBlock,
341 DwarfAttrContainingType, OFFSET(containingtype), TReference,
342 DwarfAttrCount, OFFSET(count), TConstant|TReference,
343 DwarfAttrDataMemberLoc, OFFSET(datamemberloc), TBlock|TConstant|TReference,
344 DwarfAttrDeclColumn, OFFSET(declcolumn), TConstant,
345 DwarfAttrDeclFile, OFFSET(declfile), TConstant,
346 DwarfAttrDeclLine, OFFSET(declline), TConstant,
347 DwarfAttrDeclaration, OFFSET(isdeclaration), TFlag,
348 DwarfAttrDefaultValue, OFFSET(defaultvalue), TReference,
349 DwarfAttrDiscr, OFFSET(discr), TReference,
350 DwarfAttrDiscrList, OFFSET(discrlist), TBlock,
351 DwarfAttrDiscrValue, OFFSET(discrvalue), TConstant,
352 DwarfAttrEncoding, OFFSET(encoding), TConstant,
353 DwarfAttrExternal, OFFSET(isexternal), TFlag,
354 DwarfAttrFrameBase, OFFSET(framebase), TBlock|TConstant,
355 DwarfAttrFriend, OFFSET(friend), TReference,
356 DwarfAttrHighpc, OFFSET(highpc), TAddress,
357 DwarfAttrIdentifierCase, OFFSET(identifiercase), TConstant,
358 DwarfAttrImport, OFFSET(import), TReference,
359 DwarfAttrInline, OFFSET(inlined), TConstant,
360 DwarfAttrIsOptional, OFFSET(isoptional), TFlag,
361 DwarfAttrLanguage, OFFSET(language), TConstant,
362 DwarfAttrLocation, OFFSET(location), TBlock|TConstant,
363 DwarfAttrLowerBound, OFFSET(lowerbound), TConstant|TReference,
364 DwarfAttrLowpc, OFFSET(lowpc), TAddress,
365 DwarfAttrMacroInfo, OFFSET(macroinfo), TConstant,
366 DwarfAttrName, OFFSET(name), TString,
367 DwarfAttrNamelistItem, OFFSET(namelistitem), TBlock,
368 DwarfAttrOrdering, OFFSET(ordering), TConstant,
369 DwarfAttrPriority, OFFSET(priority), TReference,
370 DwarfAttrProducer, OFFSET(producer), TString,
371 DwarfAttrPrototyped, OFFSET(isprototyped), TFlag,
372 DwarfAttrRanges, OFFSET(ranges), TReference,
373 DwarfAttrReturnAddr, OFFSET(returnaddr), TBlock|TConstant,
374 DwarfAttrSegment, OFFSET(segment), TBlock|TConstant,
375 DwarfAttrSibling, OFFSET(sibling), TReference,
376 DwarfAttrSpecification, OFFSET(specification), TReference,
377 DwarfAttrStartScope, OFFSET(startscope), TConstant,
378 DwarfAttrStaticLink, OFFSET(staticlink), TBlock|TConstant,
379 DwarfAttrStmtList, OFFSET(stmtlist), TConstant,
380 DwarfAttrStrideSize, OFFSET(stridesize), TConstant,
381 DwarfAttrStringLength, OFFSET(stringlength), TBlock|TConstant,
382 DwarfAttrType, OFFSET(type), TReference,
383 DwarfAttrUpperBound, OFFSET(upperbound), TConstant|TReference,
384 DwarfAttrUseLocation, OFFSET(uselocation), TBlock|TConstant,
385 DwarfAttrVarParam, OFFSET(isvarparam), TFlag,
386 DwarfAttrVirtuality, OFFSET(virtuality), TConstant,
387 DwarfAttrVisibility, OFFSET(visibility), TConstant,
388 DwarfAttrVtableElemLoc, OFFSET(vtableelemloc), TBlock|TReference,
389 };
391 static Parse ptab[DwarfAttrMax];
393 static int
394 parseattrs(DwarfBuf *b, ulong unit, DwarfAbbrev *a, DwarfAttrs *attrs)
396 int i, f, n, got;
397 static int nbad;
398 void *v;
400 /* initialize ptab first time through for quick access */
401 if(ptab[DwarfAttrName].name != DwarfAttrName)
402 for(i=0; i<nelem(plist); i++)
403 ptab[plist[i].name] = plist[i];
405 memset(attrs, 0, sizeof *attrs);
406 attrs->tag = a->tag;
407 attrs->haskids = a->haskids;
409 for(i=0; i<a->nattr; i++){
410 n = a->attr[i].name;
411 f = a->attr[i].form;
412 if(n < 0 || n >= nelem(ptab) || ptab[n].name==0){
413 if(++nbad == 1)
414 fprint(2, "dwarf parse attrs: unexpected attribute name 0x%ux\n", n);
415 return -1;
417 v = (char*)attrs + ptab[n].off;
418 got = 0;
419 if(f == FormIndirect)
420 f = dwarfget128(b);
421 if((ptab[n].type&(TConstant|TReference|TAddress))
422 && getulong(b, f, unit, v, &got) >= 0)
424 else if((ptab[n].type&TFlag) && getuchar(b, f, v) >= 0)
425 got = TFlag;
426 else if((ptab[n].type&TString) && getstring(b, f, v) >= 0)
427 got = TString;
428 else if((ptab[n].type&TBlock) && getblock(b, f, v) >= 0)
429 got = TBlock;
430 else{
431 if(skipform(b, f) < 0){
432 if(++nbad == 1)
433 fprint(2, "dwarf parse attrs: cannot skip form %d\n", f);
434 return -1;
437 if(got == TBlock && (ptab[n].type&TConstant))
438 got = constblock(b->d, v, v);
439 *((uchar*)attrs+ptab[n].haveoff) = got;
441 return 0;
444 static int
445 getulong(DwarfBuf *b, int form, ulong unit, ulong *u, int *type)
447 static int nbad;
448 uvlong uv;
450 switch(form){
451 default:
452 return -1;
454 /* addresses */
455 case FormAddr:
456 *type = TAddress;
457 *u = dwarfgetaddr(b);
458 return 0;
460 /* references */
461 case FormRefAddr:
462 /* absolute ref in .debug_info */
463 *type = TReference;
464 *u = dwarfgetaddr(b);
465 return 0;
466 case FormRef1:
467 *u = dwarfget1(b);
468 goto relativeref;
469 case FormRef2:
470 *u = dwarfget2(b);
471 goto relativeref;
472 case FormRef4:
473 *u = dwarfget4(b);
474 goto relativeref;
475 case FormRef8:
476 *u = dwarfget8(b);
477 goto relativeref;
478 case FormRefUdata:
479 *u = dwarfget128(b);
480 relativeref:
481 *u += unit;
482 *type = TReference;
483 return 0;
485 /* constants */
486 case FormData1:
487 *u = dwarfget1(b);
488 goto constant;
489 case FormData2:
490 *u = dwarfget2(b);
491 goto constant;
492 case FormData4:
493 *u = dwarfget4(b);
494 goto constant;
495 case FormData8:
496 uv = dwarfget8(b);
497 *u = uv;
498 if(uv != *u && ++nbad == 1)
499 fprint(2, "dwarf: truncating 64-bit attribute constants\n");
500 goto constant;
501 case FormSdata:
502 *u = dwarfget128s(b);
503 goto constant;
504 case FormUdata:
505 *u = dwarfget128(b);
506 constant:
507 *type = TConstant;
508 return 0;
512 static int
513 getuchar(DwarfBuf *b, int form, uchar *u)
515 switch(form){
516 default:
517 return -1;
519 case FormFlag:
520 *u = dwarfget1(b);
521 return 0;
525 static int
526 getstring(DwarfBuf *b, int form, char **s)
528 static int nbad;
529 ulong u;
531 switch(form){
532 default:
533 return -1;
535 case FormString:
536 *s = dwarfgetstring(b);
537 return 0;
539 case FormStrp:
540 u = dwarfget4(b);
541 if(u >= b->d->str.len){
542 if(++nbad == 1)
543 fprint(2, "dwarf: bad string pointer 0x%lux in attribute\n", u);
544 /* don't return error - maybe can proceed */
545 *s = nil;
546 }else
547 *s = b->d->str.data + u;
548 return 0;
553 static int
554 getblock(DwarfBuf *b, int form, DwarfBlock *bl)
556 ulong n;
558 switch(form){
559 default:
560 return -1;
561 case FormDwarfBlock:
562 n = dwarfget128(b);
563 goto copyn;
564 case FormDwarfBlock1:
565 n = dwarfget1(b);
566 goto copyn;
567 case FormDwarfBlock2:
568 n = dwarfget2(b);
569 goto copyn;
570 case FormDwarfBlock4:
571 n = dwarfget4(b);
572 copyn:
573 bl->data = dwarfgetnref(b, n);
574 bl->len = n;
575 if(bl->data == nil)
576 return -1;
577 return 0;
581 static int
582 constblock(Dwarf *d, DwarfBlock *bl, ulong *pval)
584 DwarfBuf b;
586 memset(&b, 0, sizeof b);
587 b.p = bl->data;
588 b.ep = bl->data+bl->len;
589 b.d = d;
591 switch(dwarfget1(&b)){
592 case OpAddr:
593 *pval = dwarfgetaddr(&b);
594 return TConstant;
595 case OpConst1u:
596 *pval = dwarfget1(&b);
597 return TConstant;
598 case OpConst1s:
599 *pval = (schar)dwarfget1(&b);
600 return TConstant;
601 case OpConst2u:
602 *pval = dwarfget2(&b);
603 return TConstant;
604 case OpConst2s:
605 *pval = (s16int)dwarfget2(&b);
606 return TConstant;
607 case OpConst4u:
608 *pval = dwarfget4(&b);
609 return TConstant;
610 case OpConst4s:
611 *pval = (s32int)dwarfget4(&b);
612 return TConstant;
613 case OpConst8u:
614 *pval = (u64int)dwarfget8(&b);
615 return TConstant;
616 case OpConst8s:
617 *pval = (s64int)dwarfget8(&b);
618 return TConstant;
619 case OpConstu:
620 *pval = dwarfget128(&b);
621 return TConstant;
622 case OpConsts:
623 *pval = dwarfget128s(&b);
624 return TConstant;
625 case OpPlusUconst:
626 *pval = dwarfget128(&b);
627 return TConstant;
628 default:
629 return TBlock;
633 /* last resort */
634 static int
635 skipform(DwarfBuf *b, int form)
637 int type;
638 DwarfVal val;
640 if(getulong(b, form, 0, &val.c, &type) < 0
641 && getuchar(b, form, (uchar*)&val) < 0
642 && getstring(b, form, &val.s) < 0
643 && getblock(b, form, &val.b) < 0)
644 return -1;
645 return 0;