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