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