2 * MS debug info dumping utility
4 * Copyright 2006 Eric Pouech
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wine/mscvpdb.h"
35 #define PSTRING(adr, ofs) \
36 ((const struct p_string*)((const char*)(adr) + (ofs)))
38 static const char* p_string(const struct p_string
* s
)
40 static char tmp
[256 + 1];
41 memcpy(tmp
, s
->name
, s
->namelen
);
42 tmp
[s
->namelen
] = '\0';
48 enum {fv_integer
, fv_longlong
} type
;
52 long long unsigned llu
;
56 static int full_numeric_leaf(struct full_value
* fv
, const unsigned short int* leaf
)
58 unsigned short int type
= *leaf
++;
61 fv
->type
= fv_integer
;
62 if (type
< LF_NUMERIC
)
72 fv
->v
.i
= *(const char*)leaf
;
77 fv
->v
.i
= *(const short*)leaf
;
87 fv
->v
.i
= *(const int*)leaf
;
92 fv
->v
.i
= *(const unsigned int*)leaf
;
97 fv
->type
= fv_longlong
;
98 fv
->v
.llu
= *(const long long int*)leaf
;
103 fv
->type
= fv_longlong
;
104 fv
->v
.llu
= *(const long long unsigned int*)leaf
;
109 printf(">>> unsupported leaf value %04x\n", type
);
110 fv
->v
.i
= 0; /* FIXME */
115 fv
->v
.i
= 0; /* FIXME */
116 printf(">>> unsupported leaf value %04x\n", type
);
121 fv
->v
.i
= 0; /* FIXME */
122 printf(">>> unsupported leaf value %04x\n", type
);
127 fv
->v
.i
= 0; /* FIXME */
128 printf(">>> unsupported leaf value %04x\n", type
);
133 fv
->v
.i
= 0; /* FIXME */
134 printf(">>> unsupported leaf value %04x\n", type
);
139 fv
->v
.i
= 0; /* FIXME */
140 printf(">>> unsupported leaf value %04x\n", type
);
145 fv
->v
.i
= 0; /* FIXME */
146 printf(">>> unsupported leaf value %04x\n", type
);
151 fv
->v
.i
= 0; /* FIXME */
152 printf(">>> unsupported leaf value %04x\n", type
);
157 fv
->v
.i
= 0; /* FIXME */
158 printf(">>> unsupported leaf value %04x\n", type
);
163 fv
->v
.i
= 0; /* FIXME */
164 printf(">>> unsupported leaf value %04x\n", type
);
168 printf(">>> Unsupported numeric leaf-id %04x\n", type
);
176 static const char* full_value_string(const struct full_value
* fv
)
178 static char tmp
[128];
182 case fv_integer
: sprintf(tmp
, "0x%x", fv
->v
.i
); break;
183 case fv_longlong
: sprintf(tmp
, "0x%x%08x", (unsigned)(fv
->v
.llu
>> 32), (unsigned)fv
->v
.llu
); break;
188 static int numeric_leaf(int* value
, const unsigned short int* leaf
)
190 struct full_value fv
;
191 int len
= full_numeric_leaf(&fv
, leaf
);
195 case fv_integer
: *value
= fv
.v
.i
; break;
196 case fv_longlong
: *value
= (unsigned)fv
.v
.llu
; printf("bad conversion\n"); break;
197 default: assert( 0 ); *value
= 0;
202 static const char* get_attr(unsigned attr
)
204 static char tmp
[256];
208 case 0: strcpy(tmp
, ""); break;
209 case 1: strcpy(tmp
, "private "); break;
210 case 2: strcpy(tmp
, "protected "); break;
211 case 3: strcpy(tmp
, "public "); break;
213 switch ((attr
>> 2) & 7)
215 case 0: strcat(tmp
, ""); break;
216 case 1: strcat(tmp
, "virtual "); break;
217 case 2: strcat(tmp
, "static "); break;
218 case 3: strcat(tmp
, "friend "); break;
219 case 4: strcat(tmp
, "introducing virtual "); break;
220 case 5: strcat(tmp
, "pure virtual "); break;
221 case 6: strcat(tmp
, "pure introducing virtual "); break;
222 case 7: strcat(tmp
, "reserved "); break;
224 if ((attr
>> 5) & 1) strcat(tmp
, "pseudo ");
225 if ((attr
>> 6) & 1) strcat(tmp
, "no-inherit ");
226 if ((attr
>> 7) & 1) strcat(tmp
, "no-construct ");
230 static const char* get_property(unsigned prop
)
232 static char tmp
[1024];
235 if (!prop
) return "none";
236 #define X(s) {if (pos) tmp[pos++] = ';'; strcpy(tmp + pos, s); pos += strlen(s);}
237 if (prop
& 0x0001) X("packed");
238 if (prop
& 0x0002) X("w/{cd}tor");
239 if (prop
& 0x0004) X("w/overloaded-ops");
240 if (prop
& 0x0008) X("nested-class");
241 if (prop
& 0x0010) X("has-nested-classes");
242 if (prop
& 0x0020) X("w/overloaded-assign");
243 if (prop
& 0x0040) X("w/casting-methods");
244 if (prop
& 0x0080) X("forward");
245 if (prop
& 0x0100) X("scoped");
246 if (prop
& 0x0200) X("decorated-name");
247 if (prop
& 0x0400) X("sealed-name");
248 if (prop
& 0x1800) pos
+= sprintf(tmp
, "hfa%x", (prop
>> 11) & 3);
249 if (prop
& 0x2000) X("intrinsic");
250 if (prop
& 0xC000) pos
+= sprintf(tmp
, "mocom%x", prop
>> 14);
254 assert(pos
< sizeof(tmp
));
259 static const char* get_funcattr(unsigned attr
)
261 static char tmp
[1024];
264 if (!attr
) return "none";
265 #define X(s) {if (pos) tmp[pos++] = ';'; strcpy(tmp + pos, s); pos += strlen(s);}
266 if (attr
& 0x0001) X("C++ReturnUDT");
267 if (attr
& 0x0002) X("Ctor");
268 if (attr
& 0x0004) X("Ctor-w/virtualbase");
269 if (attr
& 0xfff8) pos
+= sprintf(tmp
, "unk:%x", attr
& 0xfff8);
273 assert(pos
< sizeof(tmp
));
278 static const char* get_varflags(unsigned flags
)
280 static char tmp
[1024];
283 if (!flags
) return "none";
284 #define X(s) {if (pos) tmp[pos++] = ';'; strcpy(tmp + pos, s); pos += strlen(s);}
285 if (flags
& 0x0001) X("param");
286 if (flags
& 0x0002) X("addr-taken");
287 if (flags
& 0x0004) X("compiler-gen");
288 if (flags
& 0x0008) X("aggregated");
289 if (flags
& 0x0010) X("in-aggregate");
290 if (flags
& 0x0020) X("aliased");
291 if (flags
& 0x0040) X("alias");
292 if (flags
& 0x0080) X("retval");
293 if (flags
& 0x0100) X("optimized-out");
294 if (flags
& 0x0200) X("enreg-global");
295 if (flags
& 0x0400) X("enreg-static");
296 if (flags
& 0xf800) pos
+= sprintf(tmp
, "unk:%x", flags
& 0xf800);
300 assert(pos
< sizeof(tmp
));
305 static const char* get_machine(unsigned m
)
311 case CV_CFL_8080
: machine
= "Intel 8080"; break;
312 case CV_CFL_8086
: machine
= "Intel 8086"; break;
313 case CV_CFL_80286
: machine
= "Intel 80286"; break;
314 case CV_CFL_80386
: machine
= "Intel 80386"; break;
315 case CV_CFL_80486
: machine
= "Intel 80486"; break;
316 case CV_CFL_PENTIUM
: machine
= "Intel Pentium"; break;
317 case CV_CFL_PENTIUMII
: machine
= "Intel Pentium II"; break;
318 case CV_CFL_PENTIUMIII
: machine
= "Intel Pentium III"; break;
320 case CV_CFL_MIPS
: machine
= "MIPS R4000"; break;
321 case CV_CFL_MIPS16
: machine
= "MIPS16"; break;
322 case CV_CFL_MIPS32
: machine
= "MIPS32"; break;
323 case CV_CFL_MIPS64
: machine
= "MIPS64"; break;
324 case CV_CFL_MIPSI
: machine
= "MIPS I"; break;
325 case CV_CFL_MIPSII
: machine
= "MIPS II"; break;
326 case CV_CFL_MIPSIII
: machine
= "MIPS III"; break;
327 case CV_CFL_MIPSIV
: machine
= "MIPS IV"; break;
328 case CV_CFL_MIPSV
: machine
= "MIPS V"; break;
330 case CV_CFL_M68000
: machine
= "M68000"; break;
331 case CV_CFL_M68010
: machine
= "M68010"; break;
332 case CV_CFL_M68020
: machine
= "M68020"; break;
333 case CV_CFL_M68030
: machine
= "M68030"; break;
334 case CV_CFL_M68040
: machine
= "M68040"; break;
336 case CV_CFL_ALPHA_21064
: machine
= "Alpha 21064"; break;
337 case CV_CFL_ALPHA_21164
: machine
= "Alpha 21164"; break;
338 case CV_CFL_ALPHA_21164A
: machine
= "Alpha 21164A"; break;
339 case CV_CFL_ALPHA_21264
: machine
= "Alpha 21264"; break;
340 case CV_CFL_ALPHA_21364
: machine
= "Alpha 21364"; break;
342 case CV_CFL_PPC601
: machine
= "PowerPC 601"; break;
343 case CV_CFL_PPC603
: machine
= "PowerPC 603"; break;
344 case CV_CFL_PPC604
: machine
= "PowerPC 604"; break;
345 case CV_CFL_PPC620
: machine
= "PowerPC 620"; break;
346 case CV_CFL_PPCFP
: machine
= "PowerPC FP"; break;
348 case CV_CFL_SH3
: machine
= "SH3"; break;
349 case CV_CFL_SH3E
: machine
= "SH3E"; break;
350 case CV_CFL_SH3DSP
: machine
= "SH3DSP"; break;
351 case CV_CFL_SH4
: machine
= "SH4"; break;
352 case CV_CFL_SHMEDIA
: machine
= "SHMEDIA"; break;
354 case CV_CFL_ARM3
: machine
= "ARM 3"; break;
355 case CV_CFL_ARM4
: machine
= "ARM 4"; break;
356 case CV_CFL_ARM4T
: machine
= "ARM 4T"; break;
357 case CV_CFL_ARM5
: machine
= "ARM 5"; break;
358 case CV_CFL_ARM5T
: machine
= "ARM 5T"; break;
359 case CV_CFL_ARM6
: machine
= "ARM 6"; break;
360 case CV_CFL_ARM_XMAC
: machine
= "ARM XMAC"; break;
361 case CV_CFL_ARM_WMMX
: machine
= "ARM WMMX"; break;
362 case CV_CFL_ARM7
: machine
= "ARM 7"; break;
364 case CV_CFL_OMNI
: machine
= "OMNI"; break;
366 case CV_CFL_IA64_1
: machine
= "Itanium"; break;
367 case CV_CFL_IA64_2
: machine
= "Itanium 2"; break;
369 case CV_CFL_CEE
: machine
= "CEE"; break;
371 case CV_CFL_AM33
: machine
= "AM33"; break;
373 case CV_CFL_M32R
: machine
= "M32R"; break;
375 case CV_CFL_TRICORE
: machine
= "TRICORE"; break;
377 case CV_CFL_X64
: machine
= "x86_64"; break;
379 case CV_CFL_EBC
: machine
= "EBC"; break;
381 case CV_CFL_THUMB
: machine
= "Thumb"; break;
382 case CV_CFL_ARMNT
: machine
= "ARM NT"; break;
383 case CV_CFL_ARM64
: machine
= "ARM 64"; break;
385 case CV_CFL_D3D11_SHADER
: machine
= "D3D11 shader"; break;
389 sprintf(tmp
, "machine=%x", m
);
397 static const char* get_language(unsigned l
)
403 case CV_CFL_C
: lang
= "C"; break;
404 case CV_CFL_CXX
: lang
= "C++"; break;
405 case CV_CFL_FORTRAN
: lang
= "Fortran"; break;
406 case CV_CFL_MASM
: lang
= "Masm"; break;
407 case CV_CFL_PASCAL
: lang
= "Pascal"; break;
408 case CV_CFL_BASIC
: lang
= "Basic"; break;
409 case CV_CFL_COBOL
: lang
= "Cobol"; break;
410 case CV_CFL_LINK
: lang
= "Link"; break;
411 case CV_CFL_CVTRES
: lang
= "Resource"; break;
412 case CV_CFL_CVTPGD
: lang
= "PoGo"; break;
413 case CV_CFL_CSHARP
: lang
= "C#"; break;
414 case CV_CFL_VB
: lang
= "VisualBasic"; break;
415 case CV_CFL_ILASM
: lang
= "IL ASM"; break;
416 case CV_CFL_JAVA
: lang
= "Java"; break;
417 case CV_CFL_JSCRIPT
: lang
= "JavaScript"; break;
418 case CV_CFL_MSIL
: lang
= "MSIL"; break;
419 case CV_CFL_HLSL
: lang
= "HLSL"; break;
423 sprintf(tmp
, "lang=%x", l
);
431 static const char* get_callconv(unsigned cc
)
433 const char* callconv
;
437 case CV_CALL_NEAR_C
: callconv
= "near C"; break;
438 case CV_CALL_FAR_C
: callconv
= "far C"; break;
439 case CV_CALL_NEAR_PASCAL
: callconv
= "near pascal"; break;
440 case CV_CALL_FAR_PASCAL
: callconv
= "far pascal"; break;
441 case CV_CALL_NEAR_FAST
: callconv
= "near fast"; break;
442 case CV_CALL_FAR_FAST
: callconv
= "far fast"; break;
443 case CV_CALL_SKIPPED
: callconv
= "skipped"; break;
444 case CV_CALL_NEAR_STD
: callconv
= "near std"; break;
445 case CV_CALL_FAR_STD
: callconv
= "far std"; break;
446 case CV_CALL_NEAR_SYS
: callconv
= "near sys"; break;
447 case CV_CALL_FAR_SYS
: callconv
= "far sys"; break;
448 case CV_CALL_THISCALL
: callconv
= "this call"; break;
449 case CV_CALL_MIPSCALL
: callconv
= "mips call"; break;
450 case CV_CALL_GENERIC
: callconv
= "generic"; break;
451 case CV_CALL_ALPHACALL
: callconv
= "alpha call"; break;
452 case CV_CALL_PPCCALL
: callconv
= "ppc call"; break;
453 case CV_CALL_SHCALL
: callconv
= "sh call"; break;
454 case CV_CALL_ARMCALL
: callconv
= "arm call"; break;
455 case CV_CALL_AM33CALL
: callconv
= "am33 call"; break;
456 case CV_CALL_TRICALL
: callconv
= "tri call"; break;
457 case CV_CALL_SH5CALL
: callconv
= "sh5 call"; break;
458 case CV_CALL_M32RCALL
: callconv
= "m32r call"; break;
459 case CV_CALL_CLRCALL
: callconv
= "clr call"; break;
460 case CV_CALL_INLINE
: callconv
= "inline"; break;
461 case CV_CALL_NEAR_VECTOR
: callconv
= "near vector"; break;
462 case CV_CALL_RESERVED
: callconv
= "reserved"; break;
466 sprintf(tmp
, "callconv=%x", cc
);
474 static const char* get_pubflags(unsigned flags
)
479 #define X(s) {if (ret[0]) strcat(ret, ";"); strcat(ret, s);}
480 if (flags
& 1) X("code");
481 if (flags
& 2) X("func");
482 if (flags
& 4) X("manage");
483 if (flags
& 8) X("msil");
488 static void do_field(const unsigned char* start
, const unsigned char* end
)
491 * A 'field list' is a CodeView-specific data type which doesn't
492 * directly correspond to any high-level data type. It is used
493 * to hold the collection of members of a struct, class, union
494 * or enum type. The actual definition of that type will follow
495 * later, and refer to the field list definition record.
497 * As we don't have a field list type ourselves, we look ahead
498 * in the field list to try to find out whether this field list
499 * will be used for an enum or struct type, and create a dummy
500 * type of the corresponding sort. Later on, the definition of
501 * the 'real' type will copy the member / enumeration data.
503 const unsigned char* ptr
= start
;
505 const struct p_string
* pstr
;
507 struct full_value full_value
;
511 const union codeview_fieldtype
* fieldtype
= (const union codeview_fieldtype
*)ptr
;
513 if (*ptr
>= 0xf0) /* LF_PAD... */
519 switch (fieldtype
->generic
.id
)
521 case LF_ENUMERATE_V1
:
522 leaf_len
= full_numeric_leaf(&full_value
, &fieldtype
->enumerate_v1
.value
);
523 pstr
= PSTRING(&fieldtype
->enumerate_v1
.value
, leaf_len
);
524 printf("\t\tEnumerate V1: '%s' value:%s\n",
525 p_string(pstr
), full_value_string(&full_value
));
526 ptr
+= 2 + 2 + leaf_len
+ 1 + pstr
->namelen
;
529 case LF_ENUMERATE_V3
:
530 leaf_len
= full_numeric_leaf(&full_value
, &fieldtype
->enumerate_v3
.value
);
531 cstr
= (const char*)&fieldtype
->enumerate_v3
.value
+ leaf_len
;
532 printf("\t\tEnumerate V3: '%s' value:%s\n",
533 cstr
, full_value_string(&full_value
));
534 ptr
+= 2 + 2 + leaf_len
+ strlen(cstr
) + 1;
538 leaf_len
= numeric_leaf(&value
, &fieldtype
->member_v1
.offset
);
539 pstr
= PSTRING(&fieldtype
->member_v1
.offset
, leaf_len
);
540 printf("\t\tMember V1: '%s' type:%x attr:%s @%d\n",
541 p_string(pstr
), fieldtype
->member_v1
.type
,
542 get_attr(fieldtype
->member_v1
.attribute
), value
);
543 ptr
+= 2 + 2 + 2 + leaf_len
+ 1 + pstr
->namelen
;
547 leaf_len
= numeric_leaf(&value
, &fieldtype
->member_v2
.offset
);
548 pstr
= PSTRING(&fieldtype
->member_v2
.offset
, leaf_len
);
549 printf("\t\tMember V2: '%s' type:%x attr:%s @%d\n",
550 p_string(pstr
), fieldtype
->member_v2
.type
,
551 get_attr(fieldtype
->member_v2
.attribute
), value
);
552 ptr
+= 2 + 2 + 4 + leaf_len
+ 1 + pstr
->namelen
;
556 leaf_len
= numeric_leaf(&value
, &fieldtype
->member_v3
.offset
);
557 cstr
= (const char*)&fieldtype
->member_v3
.offset
+ leaf_len
;
558 printf("\t\tMember V3: '%s' type:%x attr:%s @%d\n",
559 cstr
, fieldtype
->member_v3
.type
,
560 get_attr(fieldtype
->member_v3
.attribute
), value
);
561 ptr
+= 2 + 2 + 4 + leaf_len
+ strlen(cstr
) + 1;
564 case LF_ONEMETHOD_V1
:
565 switch ((fieldtype
->onemethod_v1
.attribute
>> 2) & 7)
568 printf("\t\tVirtual-method V1: '%s' attr:%s type:%x vtable_offset:%u\n",
569 p_string(&fieldtype
->onemethod_virt_v1
.p_name
),
570 get_attr(fieldtype
->onemethod_virt_v1
.attribute
),
571 fieldtype
->onemethod_virt_v1
.type
,
572 fieldtype
->onemethod_virt_v1
.vtab_offset
);
573 ptr
+= 2 + 2 + 2 + 4 + (1 + fieldtype
->onemethod_virt_v1
.p_name
.namelen
);
577 printf("\t\tMethod V1: '%s' attr:%s type:%x\n",
578 p_string(&fieldtype
->onemethod_v1
.p_name
),
579 get_attr(fieldtype
->onemethod_v1
.attribute
),
580 fieldtype
->onemethod_v1
.type
);
581 ptr
+= 2 + 2 + 2 + (1 + fieldtype
->onemethod_v1
.p_name
.namelen
);
586 case LF_ONEMETHOD_V2
:
587 switch ((fieldtype
->onemethod_v2
.attribute
>> 2) & 7)
590 printf("\t\tVirtual-method V2: '%s' attr:%s type:%x vtable_offset:%u\n",
591 p_string(&fieldtype
->onemethod_virt_v2
.p_name
),
592 get_attr(fieldtype
->onemethod_virt_v2
.attribute
),
593 fieldtype
->onemethod_virt_v2
.type
,
594 fieldtype
->onemethod_virt_v2
.vtab_offset
);
595 ptr
+= 2 + 2 + 4 + 4 + (1 + fieldtype
->onemethod_virt_v2
.p_name
.namelen
);
599 printf("\t\tMethod V2: '%s' attr:%s type:%x\n",
600 p_string(&fieldtype
->onemethod_v2
.p_name
),
601 get_attr(fieldtype
->onemethod_v2
.attribute
),
602 fieldtype
->onemethod_v2
.type
);
603 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->onemethod_v2
.p_name
.namelen
);
608 case LF_ONEMETHOD_V3
:
609 switch ((fieldtype
->onemethod_v3
.attribute
>> 2) & 7)
612 printf("\t\tVirtual-method V3: '%s' attr:%s type:%x vtable_offset:%u\n",
613 fieldtype
->onemethod_virt_v3
.name
,
614 get_attr(fieldtype
->onemethod_virt_v3
.attribute
),
615 fieldtype
->onemethod_virt_v3
.type
,
616 fieldtype
->onemethod_virt_v3
.vtab_offset
);
617 ptr
+= 2 + 2 + 4 + 4 + (strlen(fieldtype
->onemethod_virt_v3
.name
) + 1);
621 printf("\t\tMethod V3: '%s' attr:%s type:%x\n",
622 fieldtype
->onemethod_v3
.name
,
623 get_attr(fieldtype
->onemethod_v3
.attribute
),
624 fieldtype
->onemethod_v3
.type
);
625 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->onemethod_v3
.name
) + 1);
631 printf("\t\tMethod V1: '%s' overloaded=#%d method-list=%x\n",
632 p_string(&fieldtype
->method_v1
.p_name
),
633 fieldtype
->method_v1
.count
, fieldtype
->method_v1
.mlist
);
634 ptr
+= 2 + 2 + 2 + (1 + fieldtype
->method_v1
.p_name
.namelen
);
638 printf("\t\tMethod V2: '%s' overloaded=#%d method-list=%x\n",
639 p_string(&fieldtype
->method_v2
.p_name
),
640 fieldtype
->method_v2
.count
, fieldtype
->method_v2
.mlist
);
641 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->method_v2
.p_name
.namelen
);
645 printf("\t\tMethod V3: '%s' overloaded=#%d method-list=%x\n",
646 fieldtype
->method_v3
.name
,
647 fieldtype
->method_v3
.count
, fieldtype
->method_v3
.mlist
);
648 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->method_v3
.name
) + 1);
652 printf("\t\tStatic member V1: '%s' attr:%s type:%x\n",
653 p_string(&fieldtype
->stmember_v1
.p_name
),
654 get_attr(fieldtype
->stmember_v1
.attribute
),
655 fieldtype
->stmember_v1
.type
);
656 ptr
+= 2 + 2 + 2 + (1 + fieldtype
->stmember_v1
.p_name
.namelen
);
660 printf("\t\tStatic member V2: '%s' attr:%s type:%x\n",
661 p_string(&fieldtype
->stmember_v2
.p_name
),
662 get_attr(fieldtype
->stmember_v2
.attribute
),
663 fieldtype
->stmember_v2
.type
);
664 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->stmember_v2
.p_name
.namelen
);
668 printf("\t\tStatic member V3: '%s' attr:%s type:%x\n",
669 fieldtype
->stmember_v3
.name
,
670 get_attr(fieldtype
->stmember_v3
.attribute
),
671 fieldtype
->stmember_v3
.type
);
672 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->stmember_v3
.name
) + 1);
675 case LF_FRIENDFCN_V1
:
676 printf("\t\tFriend function V1: '%s' type:%x\n",
677 p_string(&fieldtype
->friendfcn_v1
.p_name
),
678 fieldtype
->friendfcn_v1
.type
);
679 ptr
+= 2 + 2 + (1 + fieldtype
->stmember_v2
.p_name
.namelen
);
682 case LF_FRIENDFCN_V2
:
683 printf("\t\tFriend function V2: '%s' type:%x\n",
684 p_string(&fieldtype
->friendfcn_v2
.p_name
),
685 fieldtype
->friendfcn_v2
.type
);
686 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->stmember_v2
.p_name
.namelen
);
689 case LF_FRIENDFCN_V3
:
690 printf("\t\tFriend function V3: '%s' type:%x\n",
691 fieldtype
->friendfcn_v3
.name
,
692 fieldtype
->friendfcn_v3
.type
);
693 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->stmember_v3
.name
) + 1);
697 leaf_len
= numeric_leaf(&value
, &fieldtype
->bclass_v1
.offset
);
698 printf("\t\tBase class V1: type:%x attr:%s @%d\n",
699 fieldtype
->bclass_v1
.type
,
700 get_attr(fieldtype
->bclass_v1
.attribute
), value
);
701 ptr
+= 2 + 2 + 2 + leaf_len
;
705 leaf_len
= numeric_leaf(&value
, &fieldtype
->bclass_v2
.offset
);
706 printf("\t\tBase class V2: type:%x attr:%s @%d\n",
707 fieldtype
->bclass_v2
.type
,
708 get_attr(fieldtype
->bclass_v2
.attribute
), value
);
709 ptr
+= 2 + 2 + 4 + leaf_len
;
714 leaf_len
= numeric_leaf(&value
, &fieldtype
->vbclass_v1
.vbpoff
);
715 printf("\t\t%sirtual base class V1: type:%x (ptr:%x) attr:%s vbpoff:%d ",
716 (fieldtype
->generic
.id
== LF_VBCLASS_V2
) ? "V" : "Indirect v",
717 fieldtype
->vbclass_v1
.btype
, fieldtype
->vbclass_v1
.vbtype
,
718 get_attr(fieldtype
->vbclass_v1
.attribute
), value
);
719 ptr
+= 2 + 2 + 2 + 2 + leaf_len
;
720 leaf_len
= numeric_leaf(&value
, (const unsigned short*)ptr
);
721 printf("vboff:%d\n", value
);
727 leaf_len
= numeric_leaf(&value
, &fieldtype
->vbclass_v1
.vbpoff
);
728 printf("\t\t%sirtual base class V2: type:%x (ptr:%x) attr:%s vbpoff:%d ",
729 (fieldtype
->generic
.id
== LF_VBCLASS_V2
) ? "V" : "Indirect v",
730 fieldtype
->vbclass_v2
.btype
, fieldtype
->vbclass_v2
.vbtype
,
731 get_attr(fieldtype
->vbclass_v2
.attribute
), value
);
732 ptr
+= 2 + 2 + 4 + 4 + leaf_len
;
733 leaf_len
= numeric_leaf(&value
, (const unsigned short*)ptr
);
734 printf("vboff:%d\n", value
);
738 case LF_FRIENDCLS_V1
:
739 printf("\t\tFriend class V1: type:%x\n", fieldtype
->friendcls_v1
.type
);
743 case LF_FRIENDCLS_V2
:
744 printf("\t\tFriend class V2: type:%x\n", fieldtype
->friendcls_v2
.type
);
749 printf("\t\tNested type V1: '%s' type:%x\n",
750 p_string(&fieldtype
->nesttype_v1
.p_name
),
751 fieldtype
->nesttype_v1
.type
);
752 ptr
+= 2 + 2 + (1 + fieldtype
->nesttype_v1
.p_name
.namelen
);
756 printf("\t\tNested type V2: '%s' pad0:%u type:%x\n",
757 p_string(&fieldtype
->nesttype_v2
.p_name
),
758 fieldtype
->nesttype_v2
._pad0
, fieldtype
->nesttype_v2
.type
);
759 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->nesttype_v2
.p_name
.namelen
);
763 printf("\t\tNested type V3: '%s' pad0:%u type:%x\n",
764 fieldtype
->nesttype_v3
.name
,
765 fieldtype
->nesttype_v3
._pad0
, fieldtype
->nesttype_v3
.type
);
766 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->nesttype_v3
.name
) + 1);
770 printf("\t\tVirtual function table V1: type:%x\n",
771 fieldtype
->vfunctab_v1
.type
);
776 printf("\t\tVirtual function table V2: type:%x\n",
777 fieldtype
->vfunctab_v2
.type
);
782 printf("\t\tVirtual function table offset V1: type:%x offset:%x\n",
783 fieldtype
->vfuncoff_v1
.type
, fieldtype
->vfuncoff_v1
.offset
);
788 printf("\t\tVirtual function table offset V2: type:%x offset:%x\n",
789 fieldtype
->vfuncoff_v2
.type
, fieldtype
->vfuncoff_v2
.offset
);
790 ptr
+= 2 + 2 + 4 + 4;
794 printf("\t\tIndex V1: index:%x\n", fieldtype
->index_v1
.ref
);
799 printf("\t\tIndex V2: index:%x\n", fieldtype
->index_v2
.ref
);
804 printf(">>> Unsupported field-id %x\n", fieldtype
->generic
.id
);
805 dump_data((const void*)fieldtype
, 0x30, "\t");
811 static void codeview_dump_one_type(unsigned curr_type
, const union codeview_type
* type
)
813 const union codeview_reftype
* reftype
= (const union codeview_reftype
*)type
;
814 int i
, leaf_len
, value
;
818 switch (type
->generic
.id
)
820 /* types from TPI (aka #2) stream */
822 printf("\t%x => Pointer V1 to type:%x\n",
823 curr_type
, type
->pointer_v1
.datatype
);
826 printf("\t%x => Pointer V2 to type:%x\n",
827 curr_type
, type
->pointer_v2
.datatype
);
830 leaf_len
= numeric_leaf(&value
, &type
->array_v1
.arrlen
);
831 printf("\t%x => Array V1-'%s'[%u type:%x] type:%x\n",
832 curr_type
, p_string(PSTRING(&type
->array_v1
.arrlen
, leaf_len
)),
833 value
, type
->array_v1
.idxtype
, type
->array_v1
.elemtype
);
836 leaf_len
= numeric_leaf(&value
, &type
->array_v2
.arrlen
);
837 printf("\t%x => Array V2-'%s'[%u type:%x] type:%x\n",
838 curr_type
, p_string(PSTRING(&type
->array_v2
.arrlen
, leaf_len
)),
839 value
, type
->array_v2
.idxtype
, type
->array_v2
.elemtype
);
842 leaf_len
= numeric_leaf(&value
, &type
->array_v3
.arrlen
);
843 str
= (const char*)&type
->array_v3
.arrlen
+ leaf_len
;
844 printf("\t%x => Array V3-'%s'[%u type:%x] type:%x\n",
845 curr_type
, str
, value
,
846 type
->array_v3
.idxtype
, type
->array_v3
.elemtype
);
849 /* a bitfields is a CodeView specific data type which represent a bitfield
850 * in a structure or a class. For now, we store it in a SymTag-like type
851 * (so that the rest of the process is seamless), but check at udt inclusion
852 * type for its presence
855 printf("\t%x => Bitfield V1:%x offset:%u #bits:%u\n",
856 curr_type
, reftype
->bitfield_v1
.type
, reftype
->bitfield_v1
.bitoff
,
857 reftype
->bitfield_v1
.nbits
);
861 printf("\t%x => Bitfield V2:%x offset:%u #bits:%u\n",
862 curr_type
, reftype
->bitfield_v2
.type
, reftype
->bitfield_v2
.bitoff
,
863 reftype
->bitfield_v2
.nbits
);
866 case LF_FIELDLIST_V1
:
867 case LF_FIELDLIST_V2
:
868 printf("\t%x => Fieldlist\n", curr_type
);
869 do_field(reftype
->fieldlist
.list
, (const BYTE
*)type
+ reftype
->generic
.len
+ 2);
872 case LF_STRUCTURE_V1
:
874 leaf_len
= numeric_leaf(&value
, &type
->struct_v1
.structlen
);
875 printf("\t%x => %s V1 '%s' elts:%u property:%s fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
876 curr_type
, type
->generic
.id
== LF_CLASS_V1
? "Class" : "Struct",
877 p_string(PSTRING(&type
->struct_v1
.structlen
, leaf_len
)),
878 type
->struct_v1
.n_element
, get_property(type
->struct_v1
.property
),
879 type
->struct_v1
.fieldlist
, type
->struct_v1
.derived
,
880 type
->struct_v1
.vshape
, value
);
883 case LF_STRUCTURE_V2
:
885 leaf_len
= numeric_leaf(&value
, &type
->struct_v2
.structlen
);
886 printf("\t%x => %s V2 '%s' elts:%u property:%s\n"
887 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
888 curr_type
, type
->generic
.id
== LF_CLASS_V2
? "Class" : "Struct",
889 p_string(PSTRING(&type
->struct_v2
.structlen
, leaf_len
)),
890 type
->struct_v2
.n_element
, get_property(type
->struct_v2
.property
),
891 type
->struct_v2
.fieldlist
, type
->struct_v2
.derived
,
892 type
->struct_v2
.vshape
, value
);
895 case LF_STRUCTURE_V3
:
897 leaf_len
= numeric_leaf(&value
, &type
->struct_v3
.structlen
);
898 str
= (const char*)&type
->struct_v3
.structlen
+ leaf_len
;
899 printf("\t%x => %s V3 '%s' elts:%u property:%s\n"
900 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
901 curr_type
, type
->generic
.id
== LF_CLASS_V3
? "Class" : "Struct",
902 str
, type
->struct_v3
.n_element
, get_property(type
->struct_v3
.property
),
903 type
->struct_v3
.fieldlist
, type
->struct_v3
.derived
,
904 type
->struct_v3
.vshape
, value
);
905 if (type
->union_v3
.property
& 0x200)
906 printf("\t\tDecorated name:%s\n", str
+ strlen(str
) + 1);
910 leaf_len
= numeric_leaf(&value
, &type
->union_v1
.un_len
);
911 printf("\t%x => Union V1 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
912 curr_type
, p_string(PSTRING(&type
->union_v1
.un_len
, leaf_len
)),
913 type
->union_v1
.count
, get_property(type
->union_v1
.property
),
914 type
->union_v1
.fieldlist
, value
);
918 leaf_len
= numeric_leaf(&value
, &type
->union_v2
.un_len
);
919 printf("\t%x => Union V2 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
920 curr_type
, p_string(PSTRING(&type
->union_v2
.un_len
, leaf_len
)),
921 type
->union_v2
.count
, get_property(type
->union_v2
.property
),
922 type
->union_v2
.fieldlist
, value
);
926 leaf_len
= numeric_leaf(&value
, &type
->union_v3
.un_len
);
927 str
= (const char*)&type
->union_v3
.un_len
+ leaf_len
;
928 printf("\t%x => Union V3 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
929 curr_type
, str
, type
->union_v3
.count
,
930 get_property(type
->union_v3
.property
),
931 type
->union_v3
.fieldlist
, value
);
932 if (type
->union_v3
.property
& 0x200)
933 printf("\t\tDecorated name:%s\n", str
+ strlen(str
) + 1);
937 printf("\t%x => Enum V1 '%s' type:%x field-type:%x count:%u property:%s\n",
938 curr_type
, p_string(&type
->enumeration_v1
.p_name
),
939 type
->enumeration_v1
.type
,
940 type
->enumeration_v1
.fieldlist
,
941 type
->enumeration_v1
.count
,
942 get_property(type
->enumeration_v1
.property
));
946 printf("\t%x => Enum V2 '%s' type:%x field-type:%x count:%u property:%s\n",
947 curr_type
, p_string(&type
->enumeration_v2
.p_name
),
948 type
->enumeration_v2
.type
,
949 type
->enumeration_v2
.fieldlist
,
950 type
->enumeration_v2
.count
,
951 get_property(type
->enumeration_v2
.property
));
955 printf("\t%x => Enum V3 '%s' type:%x field-type:%x count:%u property:%s\n",
956 curr_type
, type
->enumeration_v3
.name
,
957 type
->enumeration_v3
.type
,
958 type
->enumeration_v3
.fieldlist
,
959 type
->enumeration_v3
.count
,
960 get_property(type
->enumeration_v3
.property
));
961 if (type
->union_v3
.property
& 0x200)
962 printf("\t\tDecorated name:%s\n", type
->enumeration_v3
.name
+ strlen(type
->enumeration_v3
.name
) + 1);
966 printf("\t%x => Arglist V1(#%u):", curr_type
, reftype
->arglist_v1
.num
);
967 for (i
= 0; i
< reftype
->arglist_v1
.num
; i
++)
969 printf(" %x", reftype
->arglist_v1
.args
[i
]);
975 printf("\t%x => Arglist V2(#%u):", curr_type
, reftype
->arglist_v2
.num
);
976 for (j
= 0; j
< reftype
->arglist_v2
.num
; j
++)
978 printf("\t %x", reftype
->arglist_v2
.args
[j
]);
983 case LF_PROCEDURE_V1
:
984 printf("\t%x => Procedure V1 ret_type:%x callconv:%s attr:%s (#%u args_type:%x)\n",
985 curr_type
, type
->procedure_v1
.rvtype
,
986 get_callconv(type
->procedure_v1
.callconv
), get_funcattr(type
->procedure_v1
.funcattr
),
987 type
->procedure_v1
.params
, type
->procedure_v1
.arglist
);
990 case LF_PROCEDURE_V2
:
991 printf("\t%x => Procedure V2 ret_type:%x callconv:%s attr:%s (#%u args_type:%x)\n",
992 curr_type
, type
->procedure_v2
.rvtype
,
993 get_callconv(type
->procedure_v2
.callconv
), get_funcattr(type
->procedure_v1
.funcattr
),
994 type
->procedure_v2
.params
, type
->procedure_v2
.arglist
);
997 case LF_MFUNCTION_V2
:
998 printf("\t%x => MFunction V2 ret-type:%x callconv:%s class-type:%x this-type:%x attr:%s\n"
999 "\t\t#args:%x args-type:%x this_adjust:%x\n",
1001 type
->mfunction_v2
.rvtype
,
1002 get_callconv(type
->mfunction_v2
.callconv
),
1003 type
->mfunction_v2
.class_type
,
1004 type
->mfunction_v2
.this_type
,
1005 get_funcattr(type
->mfunction_v2
.funcattr
),
1006 type
->mfunction_v2
.params
,
1007 type
->mfunction_v2
.arglist
,
1008 type
->mfunction_v2
.this_adjust
);
1011 case LF_MODIFIER_V1
:
1012 printf("\t%x => Modifier V1 type:%x modif:%x\n",
1013 curr_type
, type
->modifier_v1
.type
, type
->modifier_v1
.attribute
);
1016 case LF_MODIFIER_V2
:
1017 printf("\t%x => Modifier V2 type:%x modif:%x\n",
1018 curr_type
, type
->modifier_v2
.type
, type
->modifier_v2
.attribute
);
1021 case LF_METHODLIST_V1
:
1023 const unsigned short* pattr
= (const unsigned short*)((const char*)type
+ 4);
1025 printf("\t%x => Method list\n", curr_type
);
1026 while ((const char*)pattr
< (const char*)type
+ type
->generic
.len
+ 2)
1028 switch ((*pattr
>> 2) & 7)
1031 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
1032 get_attr(pattr
[0]), pattr
[1],
1033 *(const unsigned*)(&pattr
[2]));
1037 printf("\t\t\tattr:%s type:%x\n",
1038 get_attr(pattr
[0]), pattr
[1]);
1045 case LF_METHODLIST_V2
:
1047 const unsigned* pattr
= (const unsigned*)((const char*)type
+ 4);
1049 printf("\t%x => Method list\n", curr_type
);
1050 while ((const char*)pattr
< (const char*)type
+ type
->generic
.len
+ 2)
1052 switch ((*pattr
>> 2) & 7)
1055 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
1056 get_attr(pattr
[0]), pattr
[1], pattr
[2]);
1060 printf("\t\t\tattr:%s type:%x\n",
1061 get_attr(pattr
[0]), pattr
[1]);
1070 int count
= *(const unsigned short*)((const char*)type
+ 4);
1072 const char* ptr
= (const char*)type
+ 6;
1073 const char* desc
[] = {"Near", "Far", "Thin", "Disp to outermost",
1074 "Pointer to metaclass", "Near32", "Far32"};
1075 printf("\t%x => VT Shape #%d: ", curr_type
, count
);
1078 if (((*ptr
<< shift
) & 0xF) <= 6)
1079 printf("%s ", desc
[(*ptr
<< shift
) & 0xF]);
1081 printf("%x ", (*ptr
<< shift
) & 0xF);
1082 if (shift
== 0) shift
= 4; else {shift
= 0; ptr
++;}
1089 printf("\t%x => Derived V1(#%u):", curr_type
, reftype
->derived_v1
.num
);
1090 for (i
= 0; i
< reftype
->derived_v1
.num
; i
++)
1092 printf(" %x", reftype
->derived_v1
.drvdcls
[i
]);
1098 printf("\t%x => Derived V2(#%u):", curr_type
, reftype
->derived_v2
.num
);
1099 for (j
= 0; j
< reftype
->derived_v2
.num
; j
++)
1101 printf(" %x", reftype
->derived_v2
.drvdcls
[j
]);
1107 printf("\t%x => VFTable V3 base:%x baseVfTable:%x offset%u\n",
1108 curr_type
, reftype
->vftable_v3
.type
, reftype
->vftable_v3
.baseVftable
, reftype
->vftable_v3
.offsetInObjectLayout
);
1110 const char* str
= reftype
->vftable_v3
.names
;
1111 const char* last
= str
+ reftype
->vftable_v3
.cbstr
;
1114 printf("\t\t%s\n", str
);
1115 str
+= strlen(str
) + 1;
1120 /* types from IPI (aka #4) stream */
1122 printf("\t%x => FuncId %s scopeId:%04x type:%04x\n",
1123 curr_type
, type
->func_id_v3
.name
,
1124 type
->func_id_v3
.scopeId
, type
->func_id_v3
.type
);
1127 printf("\t%x => MFuncId %s parent:%04x type:%04x\n",
1128 curr_type
, type
->mfunc_id_v3
.name
,
1129 type
->mfunc_id_v3
.parentType
, type
->mfunc_id_v3
.type
);
1132 printf("\t%x => BuildInfo count:%d\n", curr_type
, type
->buildinfo_v3
.count
);
1133 if (type
->buildinfo_v3
.count
>= 1) printf("\t\tcurrent dir: %04x\n", type
->buildinfo_v3
.arg
[0]);
1134 if (type
->buildinfo_v3
.count
>= 2) printf("\t\tbuild tool: %04x\n", type
->buildinfo_v3
.arg
[1]);
1135 if (type
->buildinfo_v3
.count
>= 3) printf("\t\tsource file: %04x\n", type
->buildinfo_v3
.arg
[2]);
1136 if (type
->buildinfo_v3
.count
>= 4) printf("\t\tPDB file: %04x\n", type
->buildinfo_v3
.arg
[3]);
1137 if (type
->buildinfo_v3
.count
>= 5) printf("\t\tArguments: %04x\n", type
->buildinfo_v3
.arg
[4]);
1139 case LF_SUBSTR_LIST
:
1140 printf("\t%x => SubstrList V3(#%u):", curr_type
, reftype
->arglist_v2
.num
);
1141 for (j
= 0; j
< reftype
->arglist_v2
.num
; j
++)
1143 printf("\t %x", reftype
->arglist_v2
.args
[j
]);
1148 printf("\t%x => StringId %s strid:%04x\n",
1149 curr_type
, type
->string_id_v3
.name
, type
->string_id_v3
.strid
);
1151 case LF_UDT_SRC_LINE
:
1152 printf("\t%x => Udt-SrcLine type:%04x src:%04x line:%d\n",
1153 curr_type
, type
->udt_src_line_v3
.type
,
1154 type
->udt_src_line_v3
.src
, type
->udt_src_line_v3
.line
);
1156 case LF_UDT_MOD_SRC_LINE
:
1157 printf("\t%x => Udt-ModSrcLine type:%04x src:%04x line:%d mod:%d\n",
1158 curr_type
, type
->udt_mod_src_line_v3
.type
,
1159 type
->udt_mod_src_line_v3
.src
, type
->udt_mod_src_line_v3
.line
,
1160 type
->udt_mod_src_line_v3
.imod
);
1164 printf(">>> Unsupported type-id %x for %x\n", type
->generic
.id
, curr_type
);
1165 dump_data((const void*)type
, type
->generic
.len
+ 2, "");
1170 BOOL
codeview_dump_types_from_offsets(const void* table
, const DWORD
* offsets
, unsigned num_types
)
1174 for (i
= 0; i
< num_types
; i
++)
1176 codeview_dump_one_type(0x1000 + i
,
1177 (const union codeview_type
*)((const char*)table
+ offsets
[i
]));
1183 BOOL
codeview_dump_types_from_block(const void* table
, unsigned long len
)
1185 unsigned int curr_type
= 0x1000;
1186 const unsigned char*ptr
= table
;
1188 while (ptr
- (const unsigned char*)table
< len
)
1190 const union codeview_type
* type
= (const union codeview_type
*)ptr
;
1192 codeview_dump_one_type(curr_type
, type
);
1194 ptr
+= type
->generic
.len
+ 2;
1200 static void dump_defrange(const struct cv_addr_range
* range
, const void* last
, unsigned indent
)
1202 const struct cv_addr_gap
* gap
;
1204 printf("%*s\\- %04x:%08x range:#%x\n", indent
, "", range
->isectStart
, range
->offStart
, range
->cbRange
);
1205 for (gap
= (const struct cv_addr_gap
*)(range
+ 1); (const void*)(gap
+ 1) <= last
; ++gap
)
1206 printf("%*s | offset:%x range:#%x\n", indent
, "", gap
->gapStartOffset
, gap
->cbRange
);
1209 /* return address of first byte after the symbol */
1210 static inline const char* get_last(const union codeview_symbol
* sym
)
1212 return (const char*)sym
+ sym
->generic
.len
+ 2;
1215 static unsigned binannot_uncompress(const unsigned char** pptr
)
1217 unsigned res
= (unsigned)(-1);
1218 const unsigned char* ptr
= *pptr
;
1220 if ((*ptr
& 0x80) == 0x00)
1221 res
= (unsigned)(*ptr
++);
1222 else if ((*ptr
& 0xC0) == 0x80)
1224 res
= (unsigned)((*ptr
++ & 0x3f) << 8);
1227 else if ((*ptr
& 0xE0) == 0xC0)
1229 res
= (*ptr
++ & 0x1f) << 24;
1230 res
|= *ptr
++ << 16;
1234 else res
= (unsigned)(-1);
1239 static inline int binannot_getsigned(unsigned i
)
1241 return (i
& 1) ? -(int)(i
>> 1) : (i
>> 1);
1244 static void dump_binannot(const unsigned char* ba
, const char* last
, unsigned indent
)
1246 while (ba
< (const unsigned char*)last
)
1248 unsigned opcode
= binannot_uncompress(&ba
);
1252 /* not clear if param? */
1253 printf("%*s | Invalid\n", indent
, "");
1255 case BA_OP_CodeOffset
:
1256 printf("%*s | CodeOffset %u\n", indent
, "", binannot_uncompress(&ba
));
1258 case BA_OP_ChangeCodeOffsetBase
:
1259 printf("%*s | ChangeCodeOffsetBase %u\n", indent
, "", binannot_uncompress(&ba
));
1261 case BA_OP_ChangeCodeOffset
:
1262 printf("%*s | ChangeCodeOffset %u\n", indent
, "", binannot_uncompress(&ba
));
1264 case BA_OP_ChangeCodeLength
:
1265 printf("%*s | ChangeCodeLength %u\n", indent
, "", binannot_uncompress(&ba
));
1267 case BA_OP_ChangeFile
:
1268 printf("%*s | ChangeFile %u\n", indent
, "", binannot_uncompress(&ba
));
1270 case BA_OP_ChangeLineOffset
:
1271 printf("%*s | ChangeLineOffset %d\n", indent
, "", binannot_getsigned(binannot_uncompress(&ba
)));
1273 case BA_OP_ChangeLineEndDelta
:
1274 printf("%*s | ChangeLineEndDelta %u\n", indent
, "", binannot_uncompress(&ba
));
1276 case BA_OP_ChangeRangeKind
:
1277 printf("%*s | ChangeRangeKind %u\n", indent
, "", binannot_uncompress(&ba
));
1279 case BA_OP_ChangeColumnStart
:
1280 printf("%*s | ChangeColumnStart %u\n", indent
, "", binannot_uncompress(&ba
));
1282 case BA_OP_ChangeColumnEndDelta
:
1283 printf("%*s | ChangeColumnEndDelta %u\n", indent
, "", binannot_uncompress(&ba
));
1285 case BA_OP_ChangeCodeOffsetAndLineOffset
:
1287 unsigned p1
= binannot_uncompress(&ba
);
1288 printf("%*s | ChangeCodeOffsetAndLineOffset %u %u (0x%x)\n", indent
, "", p1
& 0xf, binannot_getsigned(p1
>> 4), p1
);
1291 case BA_OP_ChangeCodeLengthAndCodeOffset
:
1293 unsigned p1
= binannot_uncompress(&ba
);
1294 unsigned p2
= binannot_uncompress(&ba
);
1295 printf("%*s | ChangeCodeLengthAndCodeOffset %u %u\n", indent
, "", p1
, p2
);
1298 case BA_OP_ChangeColumnEnd
:
1299 printf("%*s | ChangeColumnEnd %u\n", indent
, "", binannot_uncompress(&ba
));
1302 default: printf(">>> Unsupported op %d %x\n", opcode
, opcode
); /* may cause issues because of param */
1307 struct symbol_dumper
1314 const union codeview_symbol
* sym
;
1318 static void init_symbol_dumper(struct symbol_dumper
* sd
)
1322 sd
->stack
= malloc(sd
->alloc
* sizeof(sd
->stack
[0]));
1325 static void push_symbol_dumper(struct symbol_dumper
* sd
, const union codeview_symbol
* sym
, unsigned end
)
1327 if (!sd
->stack
) return;
1328 if (sd
->depth
>= sd
->alloc
&&
1329 !(sd
->stack
= realloc(sd
->stack
, (sd
->alloc
*= 2) * sizeof(sd
->stack
[0]))))
1331 sd
->stack
[sd
->depth
].end
= end
;
1332 sd
->stack
[sd
->depth
].sym
= sym
;
1336 static unsigned short pop_symbol_dumper(struct symbol_dumper
* sd
, unsigned end
)
1338 if (!sd
->stack
) return 0;
1341 printf(">>> Error in stack\n");
1345 if (sd
->stack
[sd
->depth
].end
!= end
)
1346 printf(">>> Wrong end reference\n");
1347 return sd
->stack
[sd
->depth
].sym
->generic
.id
;
1350 static void dispose_symbol_dumper(struct symbol_dumper
* sd
)
1355 BOOL
codeview_dump_symbols(const void* root
, unsigned long start
, unsigned long size
)
1359 struct symbol_dumper sd
;
1361 init_symbol_dumper(&sd
);
1363 * Loop over the different types of records and whenever we
1364 * find something we are interested in, record it and move on.
1366 for (i
= start
; i
< size
; i
+= length
)
1368 const union codeview_symbol
* sym
= (const union codeview_symbol
*)((const char*)root
+ i
);
1369 unsigned indent
, ref
;
1371 length
= sym
->generic
.len
+ 2;
1372 if (!sym
->generic
.id
|| length
< 4) break;
1373 indent
= printf(" %04x => ", i
);
1375 switch (sym
->generic
.id
)
1378 case S_INLINESITE_END
:
1379 indent
+= printf("%*s", 2 * sd
.depth
- 2, "");
1382 indent
+= printf("%*s", 2 * sd
.depth
, "");
1386 switch (sym
->generic
.id
)
1389 * Global and local data symbols. We don't associate these
1390 * with any given source file.
1394 printf("%s-Data V2 '%s' %04x:%08x type:%08x\n",
1395 sym
->generic
.id
== S_GDATA32_ST
? "Global" : "Local",
1396 get_symbol_str(p_string(&sym
->data_v2
.p_name
)),
1397 sym
->data_v2
.segment
, sym
->data_v2
.offset
, sym
->data_v2
.symtype
);
1402 /* EPP case S_DATA32: */
1403 printf("%s-Data V3 '%s' (%04x:%08x) type:%08x\n",
1404 sym
->generic
.id
== S_GDATA32
? "Global" : "Local",
1405 get_symbol_str(sym
->data_v3
.name
),
1406 sym
->data_v3
.segment
, sym
->data_v3
.offset
,
1407 sym
->data_v3
.symtype
);
1411 printf("Public V1 '%s' %04x:%08x flags:%s\n",
1412 get_symbol_str(p_string(&sym
->public_v1
.p_name
)),
1413 sym
->public_v1
.segment
, sym
->public_v1
.offset
,
1414 get_pubflags(sym
->public_v1
.pubsymflags
));
1418 printf("Public V2 '%s' %04x:%08x flags:%s\n",
1419 get_symbol_str(p_string(&sym
->public_v2
.p_name
)),
1420 sym
->public_v2
.segment
, sym
->public_v2
.offset
,
1421 get_pubflags(sym
->public_v2
.pubsymflags
));
1425 printf("Public V3 '%s' %04x:%08x flags:%s\n",
1426 get_symbol_str(sym
->public_v3
.name
),
1427 sym
->public_v3
.segment
, sym
->public_v3
.offset
,
1428 get_pubflags(sym
->public_v3
.pubsymflags
));
1434 printf("%sref V3 '%s' %04x:%08x name:%08x\n",
1435 sym
->generic
.id
== S_DATAREF
? "Data" :
1436 (sym
->generic
.id
== S_PROCREF
? "Proc" : "Lproc"),
1437 get_symbol_str(sym
->refsym2_v3
.name
),
1438 sym
->refsym2_v3
.imod
, sym
->refsym2_v3
.ibSym
, sym
->refsym2_v3
.sumName
);
1442 * Sort of like a global function, but it just points
1443 * to a thunk, which is a stupid name for what amounts to
1444 * a PLT slot in the normal jargon that everyone else uses.
1447 printf("Thunk V1 '%s' (%04x:%08x#%x) type:%x\n",
1448 p_string(&sym
->thunk_v1
.p_name
),
1449 sym
->thunk_v1
.segment
, sym
->thunk_v1
.offset
,
1450 sym
->thunk_v1
.thunk_len
, sym
->thunk_v1
.thtype
);
1451 push_symbol_dumper(&sd
, sym
, sym
->thunk_v1
.pend
);
1455 printf("Thunk V3 '%s' (%04x:%08x#%x) type:%x\n",
1457 sym
->thunk_v3
.segment
, sym
->thunk_v3
.offset
,
1458 sym
->thunk_v3
.thunk_len
, sym
->thunk_v3
.thtype
);
1459 push_symbol_dumper(&sd
, sym
, sym
->thunk_v3
.pend
);
1462 /* Global and static functions */
1465 printf("%s-Proc V1: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
1466 sym
->generic
.id
== S_GPROC32_16t
? "Global" : "Local",
1467 p_string(&sym
->proc_v1
.p_name
),
1468 sym
->proc_v1
.segment
, sym
->proc_v1
.offset
,
1469 sym
->proc_v1
.proc_len
, sym
->proc_v1
.proctype
,
1470 sym
->proc_v1
.flags
);
1471 printf("%*s\\- Debug: start=%08x end=%08x\n",
1472 indent
, "", sym
->proc_v1
.debug_start
, sym
->proc_v1
.debug_end
);
1473 printf("%*s\\- parent:<%x> end:<%x> next<%x>\n",
1474 indent
, "", sym
->proc_v1
.pparent
, sym
->proc_v1
.pend
, sym
->proc_v1
.next
);
1475 push_symbol_dumper(&sd
, sym
, sym
->proc_v1
.pend
);
1480 printf("%s-Proc V2: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
1481 sym
->generic
.id
== S_GPROC32_ST
? "Global" : "Local",
1482 p_string(&sym
->proc_v2
.p_name
),
1483 sym
->proc_v2
.segment
, sym
->proc_v2
.offset
,
1484 sym
->proc_v2
.proc_len
, sym
->proc_v2
.proctype
,
1485 sym
->proc_v2
.flags
);
1486 printf("%*s\\- Debug: start=%08x end=%08x\n",
1487 indent
, "", sym
->proc_v2
.debug_start
, sym
->proc_v2
.debug_end
);
1488 printf("%*s\\- parent:<%x> end:<%x> next<%x>\n",
1489 indent
, "", sym
->proc_v2
.pparent
, sym
->proc_v2
.pend
, sym
->proc_v2
.next
);
1490 push_symbol_dumper(&sd
, sym
, sym
->proc_v2
.pend
);
1495 printf("%s-Procedure V3 '%s' (%04x:%08x#%x) type:%x attr:%x\n",
1496 sym
->generic
.id
== S_GPROC32
? "Global" : "Local",
1498 sym
->proc_v3
.segment
, sym
->proc_v3
.offset
,
1499 sym
->proc_v3
.proc_len
, sym
->proc_v3
.proctype
,
1500 sym
->proc_v3
.flags
);
1501 printf("%*s\\- Debug: start=%08x end=%08x\n",
1502 indent
, "", sym
->proc_v3
.debug_start
, sym
->proc_v3
.debug_end
);
1503 printf("%*s\\- parent:<%x> end:<%x> next<%x>\n",
1504 indent
, "", sym
->proc_v3
.pparent
, sym
->proc_v3
.pend
, sym
->proc_v3
.next
);
1505 push_symbol_dumper(&sd
, sym
, sym
->proc_v3
.pend
);
1508 /* Function parameters and stack variables */
1510 printf("BP-relative V1: '%s' @%d type:%x\n",
1511 p_string(&sym
->stack_v1
.p_name
),
1512 sym
->stack_v1
.offset
, sym
->stack_v1
.symtype
);
1516 printf("BP-relative V2: '%s' @%d type:%x\n",
1517 p_string(&sym
->stack_v2
.p_name
),
1518 sym
->stack_v2
.offset
, sym
->stack_v2
.symtype
);
1522 printf("BP-relative V3: '%s' @%d type:%x\n",
1523 sym
->stack_v3
.name
, sym
->stack_v3
.offset
,
1524 sym
->stack_v3
.symtype
);
1528 printf("Reg-relative V3: '%s' @%d type:%x reg:%x\n",
1529 sym
->regrel_v3
.name
, sym
->regrel_v3
.offset
,
1530 sym
->regrel_v3
.symtype
, sym
->regrel_v3
.reg
);
1533 case S_REGISTER_16t
:
1534 printf("Register V1 '%s' type:%x register:%x\n",
1535 p_string(&sym
->register_v1
.p_name
),
1536 sym
->register_v1
.reg
, sym
->register_v1
.type
);
1540 printf("Register V2 '%s' type:%x register:%x\n",
1541 p_string(&sym
->register_v2
.p_name
),
1542 sym
->register_v2
.reg
, sym
->register_v2
.type
);
1546 printf("Register V3 '%s' type:%x register:%x\n",
1547 sym
->register_v3
.name
, sym
->register_v3
.reg
, sym
->register_v3
.type
);
1551 printf("Block V1 '%s' (%04x:%08x#%08x)\n",
1552 p_string(&sym
->block_v1
.p_name
),
1553 sym
->block_v1
.segment
, sym
->block_v1
.offset
,
1554 sym
->block_v1
.length
);
1555 push_symbol_dumper(&sd
, sym
, sym
->block_v1
.end
);
1559 printf("Block V3 '%s' (%04x:%08x#%08x) parent:<%u> end:<%x>\n",
1561 sym
->block_v3
.segment
, sym
->block_v3
.offset
, sym
->block_v3
.length
,
1562 sym
->block_v3
.parent
, sym
->block_v3
.end
);
1563 push_symbol_dumper(&sd
, sym
, sym
->block_v3
.end
);
1566 /* Additional function information */
1568 printf("Frame-Info V2: frame-size:%x unk2:%x unk3:%x saved-regs-sz:%x eh(%04x:%08x) flags:%08x\n",
1569 sym
->frame_info_v2
.sz_frame
,
1570 sym
->frame_info_v2
.unknown2
,
1571 sym
->frame_info_v2
.unknown3
,
1572 sym
->frame_info_v2
.sz_saved_regs
,
1573 sym
->frame_info_v2
.eh_sect
,
1574 sym
->frame_info_v2
.eh_offset
,
1575 sym
->frame_info_v2
.flags
);
1579 printf("Security Cookie V3 @%d unk:%x\n",
1580 sym
->security_cookie_v3
.offset
, sym
->security_cookie_v3
.unknown
);
1584 ref
= sd
.depth
? (const char*)sd
.stack
[sd
.depth
- 1].sym
- (const char*)root
: 0;
1585 switch (pop_symbol_dumper(&sd
, i
))
1589 printf("End-Of block <%x>\n", ref
);
1592 printf("End-Of <%x>\n", ref
);
1598 printf("Compile V1 machine:%s lang:%s _unk:%x '%s'\n",
1599 get_machine(sym
->compile_v1
.machine
),
1600 get_language(sym
->compile_v1
.flags
.language
),
1601 sym
->compile_v1
.flags
._dome
,
1602 p_string(&sym
->compile_v1
.p_name
));
1606 printf("Compile2-V2 lang:%s machine:%s _unk:%x front-end:%d.%d.%d back-end:%d.%d.%d '%s'\n",
1607 get_language(sym
->compile2_v2
.flags
.iLanguage
),
1608 get_machine(sym
->compile2_v2
.machine
),
1609 sym
->compile2_v2
.flags
._dome
,
1610 sym
->compile2_v2
.fe_major
, sym
->compile2_v2
.fe_minor
, sym
->compile2_v2
.fe_build
,
1611 sym
->compile2_v2
.be_major
, sym
->compile2_v2
.be_minor
, sym
->compile2_v2
.be_build
,
1612 p_string(&sym
->compile2_v2
.p_name
));
1614 const char* ptr
= sym
->compile2_v2
.p_name
.name
+ sym
->compile2_v2
.p_name
.namelen
;
1617 printf("%*s| %s => ", indent
, "", ptr
); ptr
+= strlen(ptr
) + 1;
1618 printf("%s\n", ptr
); ptr
+= strlen(ptr
) + 1;
1624 printf("Compile2-V3 lang:%s machine:%s _unk:%x front-end:%d.%d.%d back-end:%d.%d.%d '%s'\n",
1625 get_language(sym
->compile2_v3
.flags
.iLanguage
),
1626 get_machine(sym
->compile2_v3
.machine
),
1627 sym
->compile2_v3
.flags
._dome
,
1628 sym
->compile2_v3
.fe_major
, sym
->compile2_v3
.fe_minor
, sym
->compile2_v3
.fe_build
,
1629 sym
->compile2_v3
.be_major
, sym
->compile2_v3
.be_minor
, sym
->compile2_v3
.be_build
,
1630 sym
->compile2_v3
.name
);
1632 const char* ptr
= sym
->compile2_v3
.name
+ strlen(sym
->compile2_v3
.name
) + 1;
1635 printf("%*s| %s => ", indent
, "", ptr
); ptr
+= strlen(ptr
) + 1;
1636 printf("%s\n", ptr
); ptr
+= strlen(ptr
) + 1;
1642 printf("Compile3-V3 lang:%s machine:%s _unk:%x front-end:%d.%d.%d back-end:%d.%d.%d '%s'\n",
1643 get_language(sym
->compile3_v3
.flags
.iLanguage
),
1644 get_machine(sym
->compile3_v3
.machine
),
1645 sym
->compile3_v3
.flags
._dome
,
1646 sym
->compile3_v3
.fe_major
, sym
->compile3_v3
.fe_minor
, sym
->compile3_v3
.fe_build
,
1647 sym
->compile3_v3
.be_major
, sym
->compile3_v3
.be_minor
, sym
->compile3_v3
.be_build
,
1648 sym
->compile3_v3
.name
);
1653 const char* x1
= (const char*)sym
+ 4 + 1;
1656 printf("Tool conf V3\n");
1659 x2
= x1
+ strlen(x1
) + 1;
1661 printf("%*s| %s: %s\n", indent
, "", x1
, x2
);
1662 x1
= x2
+ strlen(x2
) + 1;
1668 printf("ObjName V3 sig:%x '%s'\n",
1669 sym
->objname_v3
.signature
, sym
->objname_v3
.name
);
1673 printf("ObjName V1 sig:%x '%s'\n",
1674 sym
->objname_v1
.signature
, p_string(&sym
->objname_v1
.p_name
));
1678 printf("Trampoline V3 kind:%u %04x:%08x#%x -> %04x:%08x\n",
1679 sym
->trampoline_v3
.trampType
,
1680 sym
->trampoline_v3
.sectThunk
,
1681 sym
->trampoline_v3
.offThunk
,
1682 sym
->trampoline_v3
.cbThunk
,
1683 sym
->trampoline_v3
.sectTarget
,
1684 sym
->trampoline_v3
.offTarget
);
1688 printf("Label V1 '%s' (%04x:%08x)\n",
1689 p_string(&sym
->label_v1
.p_name
),
1690 sym
->label_v1
.segment
, sym
->label_v1
.offset
);
1694 printf("Label V3 '%s' (%04x:%08x) flag:%x\n",
1695 sym
->label_v3
.name
, sym
->label_v3
.segment
,
1696 sym
->label_v3
.offset
, sym
->label_v3
.flags
);
1702 struct full_value fv
;
1704 vlen
= full_numeric_leaf(&fv
, &sym
->constant_v2
.cvalue
);
1705 printf("Constant V2 '%s' = %s type:%x\n",
1706 p_string(PSTRING(&sym
->constant_v2
.cvalue
, vlen
)),
1707 full_value_string(&fv
), sym
->constant_v2
.type
);
1714 struct full_value fv
;
1716 vlen
= full_numeric_leaf(&fv
, &sym
->constant_v3
.cvalue
);
1717 printf("Constant V3 '%s' = %s type:%x\n",
1718 (const char*)&sym
->constant_v3
.cvalue
+ vlen
,
1719 full_value_string(&fv
), sym
->constant_v3
.type
);
1724 printf("Udt V1 '%s': type:0x%x\n",
1725 p_string(&sym
->udt_v1
.p_name
), sym
->udt_v1
.type
);
1729 printf("Udt V2 '%s': type:0x%x\n",
1730 p_string(&sym
->udt_v2
.p_name
), sym
->udt_v2
.type
);
1734 printf("Udt V3 '%s': type:0x%x\n",
1735 sym
->udt_v3
.name
, sym
->udt_v3
.type
);
1738 * These are special, in that they are always followed by an
1739 * additional length-prefixed string which is *not* included
1740 * into the symbol length count. We need to skip it.
1743 printf("Procref V1 "); goto doaref
;
1745 printf("Dataref V1 "); goto doaref
;
1747 printf("L-Procref V1 "); goto doaref
;
1750 const struct p_string
* pname
;
1752 pname
= PSTRING(sym
, length
);
1753 length
+= (pname
->namelen
+ 1 + 3) & ~3;
1754 printf("%08x %08x %08x '%s'\n",
1755 *(((const DWORD
*)sym
) + 1), *(((const DWORD
*)sym
) + 2), *(((const DWORD
*)sym
) + 3),
1761 /* simply skip it */
1765 printf("Search V1: (%04x:%08x)\n",
1766 sym
->ssearch_v1
.segment
, sym
->ssearch_v1
.offset
);
1770 printf("Section Info: seg=%04x ?=%04x rva=%08x size=%08x attr=%08x %s\n",
1771 *(const unsigned short*)((const char*)sym
+ 4),
1772 *(const unsigned short*)((const char*)sym
+ 6),
1773 *(const unsigned*)((const char*)sym
+ 8),
1774 *(const unsigned*)((const char*)sym
+ 12),
1775 *(const unsigned*)((const char*)sym
+ 16),
1776 (const char*)sym
+ 20);
1780 printf("SubSection Info: addr=%04x:%08x size=%08x attr=%08x %s\n",
1781 *(const unsigned short*)((const char*)sym
+ 16),
1782 *(const unsigned*)((const char*)sym
+ 12),
1783 *(const unsigned*)((const char*)sym
+ 4),
1784 *(const unsigned*)((const char*)sym
+ 8),
1785 (const char*)sym
+ 18);
1789 printf("EntryPoint: id=%x '%s'\n",
1790 *(const unsigned*)((const char*)sym
+ 4), (const char*)sym
+ 8);
1793 case S_LTHREAD32_16t
:
1794 case S_GTHREAD32_16t
:
1795 printf("Thread %s Var V1 '%s' seg=%04x offset=%08x type=%x\n",
1796 sym
->generic
.id
== S_LTHREAD32_16t
? "global" : "local",
1797 p_string(&sym
->thread_v1
.p_name
),
1798 sym
->thread_v1
.segment
, sym
->thread_v1
.offset
, sym
->thread_v1
.symtype
);
1801 case S_LTHREAD32_ST
:
1802 case S_GTHREAD32_ST
:
1803 printf("Thread %s Var V2 '%s' seg=%04x offset=%08x type=%x\n",
1804 sym
->generic
.id
== S_LTHREAD32_ST
? "global" : "local",
1805 p_string(&sym
->thread_v2
.p_name
),
1806 sym
->thread_v2
.segment
, sym
->thread_v2
.offset
, sym
->thread_v2
.symtype
);
1811 printf("Thread %s Var V3 '%s' seg=%04x offset=%08x type=%x\n",
1812 sym
->generic
.id
== S_LTHREAD32
? "global" : "local", sym
->thread_v3
.name
,
1813 sym
->thread_v3
.segment
, sym
->thread_v3
.offset
, sym
->thread_v3
.symtype
);
1817 printf("Local V3 '%s' type=%x flags=%s\n",
1818 sym
->local_v3
.name
, sym
->local_v3
.symtype
,
1819 get_varflags(sym
->local_v3
.varflags
));
1823 printf("DefRange dia:%x\n", sym
->defrange_v3
.program
);
1824 dump_defrange(&sym
->defrange_v3
.range
, get_last(sym
), indent
);
1826 case S_DEFRANGE_SUBFIELD
:
1827 printf("DefRange-subfield V3 dia:%x off-parent:%x\n",
1828 sym
->defrange_subfield_v3
.program
, sym
->defrange_subfield_v3
.offParent
);
1829 dump_defrange(&sym
->defrange_subfield_v3
.range
, get_last(sym
), indent
);
1831 case S_DEFRANGE_REGISTER
:
1832 printf("DefRange-register V3 reg:%x attr-unk:%x\n",
1833 sym
->defrange_register_v3
.reg
, sym
->defrange_register_v3
.attr
);
1834 dump_defrange(&sym
->defrange_register_v3
.range
, get_last(sym
), indent
);
1836 case S_DEFRANGE_FRAMEPOINTER_REL
:
1837 printf("DefRange-framepointer-rel V3 offFP:%x\n",
1838 sym
->defrange_frameptrrel_v3
.offFramePointer
);
1839 dump_defrange(&sym
->defrange_frameptrrel_v3
.range
, get_last(sym
), indent
);
1841 case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE
:
1842 printf("DefRange-framepointer-rel-fullscope V3 offFP:%x\n",
1843 sym
->defrange_frameptr_relfullscope_v3
.offFramePointer
);
1845 case S_DEFRANGE_SUBFIELD_REGISTER
:
1846 printf("DefRange-subfield-register V3 reg:%d attr-unk:%x off-parent:%x\n",
1847 sym
->defrange_subfield_register_v3
.reg
,
1848 sym
->defrange_subfield_register_v3
.attr
,
1849 sym
->defrange_subfield_register_v3
.offParent
);
1850 dump_defrange(&sym
->defrange_subfield_register_v3
.range
, get_last(sym
), indent
);
1852 case S_DEFRANGE_REGISTER_REL
:
1853 printf("DefRange-register-rel V3 reg:%x off-parent:%x off-BP:%x\n",
1854 sym
->defrange_registerrel_v3
.baseReg
, sym
->defrange_registerrel_v3
.offsetParent
,
1855 sym
->defrange_registerrel_v3
.offBasePointer
);
1856 dump_defrange(&sym
->defrange_registerrel_v3
.range
, get_last(sym
), indent
);
1859 case S_CALLSITEINFO
:
1860 printf("Call-site-info V3 %04x:%08x typeindex:%x\n",
1861 sym
->callsiteinfo_v3
.sect
, sym
->callsiteinfo_v3
.off
, sym
->callsiteinfo_v3
.typind
);
1865 printf("Build-info V3 item:%04x\n", sym
->build_info_v3
.itemid
);
1869 printf("Inline-site V3 parent:<%x> end:<%x> inlinee:%x\n",
1870 sym
->inline_site_v3
.pParent
, sym
->inline_site_v3
.pEnd
, sym
->inline_site_v3
.inlinee
);
1871 dump_binannot(sym
->inline_site_v3
.binaryAnnotations
, get_last(sym
), indent
);
1872 push_symbol_dumper(&sd
, sym
, sym
->inline_site_v3
.pEnd
);
1876 printf("Inline-site2 V3 parent:<%x> end:<%x> inlinee:%x #inv:%u\n",
1877 sym
->inline_site2_v3
.pParent
, sym
->inline_site2_v3
.pEnd
, sym
->inline_site2_v3
.inlinee
,
1878 sym
->inline_site2_v3
.invocations
);
1879 dump_binannot(sym
->inline_site2_v3
.binaryAnnotations
, get_last(sym
), indent
);
1880 push_symbol_dumper(&sd
, sym
, sym
->inline_site2_v3
.pEnd
);
1883 case S_INLINESITE_END
:
1884 ref
= sd
.depth
? (const char*)sd
.stack
[sd
.depth
- 1].sym
- (const char*)root
: 0;
1885 pop_symbol_dumper(&sd
, i
);
1886 printf("Inline-site-end <%x>\n", ref
);
1894 const unsigned* invoc
;
1897 if (sym
->generic
.id
== S_CALLERS
) tag
= "Callers";
1898 else if (sym
->generic
.id
== S_CALLEES
) tag
= "Callees";
1899 else tag
= "Inlinees";
1900 printf("%s V3 count:%u\n", tag
, sym
->function_list_v3
.count
);
1901 invoc
= (const unsigned*)&sym
->function_list_v3
.funcs
[sym
->function_list_v3
.count
];
1902 ninvoc
= (const unsigned*)get_last(sym
) - invoc
;
1904 for (i
= 0; i
< sym
->function_list_v3
.count
; ++i
)
1905 printf("%*s| func:%x invoc:%u\n",
1906 indent
, "", sym
->function_list_v3
.funcs
[i
], i
< ninvoc
? invoc
[i
] : 0);
1910 case S_HEAPALLOCSITE
:
1911 printf("Heap-alloc-site V3 %04x:%08x#%x type:%04x\n",
1912 sym
->heap_alloc_site_v3
.sect_idx
,
1913 sym
->heap_alloc_site_v3
.offset
,
1914 sym
->heap_alloc_site_v3
.inst_len
,
1915 sym
->heap_alloc_site_v3
.index
);
1919 printf("File-static V3 '%s' type:%04x modOff:%08x flags:%s\n",
1920 sym
->file_static_v3
.name
,
1921 sym
->file_static_v3
.typind
,
1922 sym
->file_static_v3
.modOffset
,
1923 get_varflags(sym
->file_static_v3
.varflags
));
1926 case S_UNAMESPACE_ST
:
1927 printf("UNameSpace V2 '%s'\n", p_string(&sym
->unamespace_v2
.pname
));
1931 printf("UNameSpace V3 '%s'\n", sym
->unamespace_v3
.name
);
1935 printf("SepCode V3 parent:<%x> end:<%x> separated:%04x:%08x (#%u) from %04x:%08x\n",
1936 sym
->sepcode_v3
.pParent
, sym
->sepcode_v3
.pEnd
,
1937 sym
->sepcode_v3
.sect
, sym
->sepcode_v3
.off
, sym
->sepcode_v3
.length
,
1938 sym
->sepcode_v3
.sectParent
, sym
->sepcode_v3
.offParent
);
1939 push_symbol_dumper(&sd
, sym
, sym
->sepcode_v3
.pEnd
);
1943 printf("Annotation V3 %04x:%08x\n",
1944 sym
->annotation_v3
.seg
, sym
->annotation_v3
.off
);
1946 const char* ptr
= sym
->annotation_v3
.rgsz
;
1947 const char* last
= ptr
+ sym
->annotation_v3
.csz
;
1948 for (; ptr
< last
; ptr
+= strlen(ptr
) + 1)
1949 printf("%*s| %s\n", indent
, "", ptr
);
1954 printf("PogoData V3 inv:%d dynCnt:%lld inst:%d staInst:%d\n",
1955 sym
->pogoinfo_v3
.invocations
, (long long)sym
->pogoinfo_v3
.dynCount
,
1956 sym
->pogoinfo_v3
.numInstrs
, sym
->pogoinfo_v3
.staInstLive
);
1960 printf("\n\t\t>>> Unsupported symbol-id %x sz=%d\n", sym
->generic
.id
, sym
->generic
.len
+ 2);
1961 dump_data((const void*)sym
, sym
->generic
.len
+ 2, " ");
1964 dispose_symbol_dumper(&sd
);
1968 void codeview_dump_linetab(const char* linetab
, BOOL pascal_str
, const char* pfx
)
1970 const char* ptr
= linetab
;
1971 int nfile
, nseg
, nline
;
1973 const unsigned int* filetab
;
1974 const unsigned int* lt_ptr
;
1975 const struct startend
* start
;
1977 nfile
= *(const short*)linetab
;
1978 filetab
= (const unsigned int*)(linetab
+ 2 * sizeof(short));
1979 printf("%s%d files with %d ???\n", pfx
, nfile
, *(const short*)(linetab
+ sizeof(short)));
1981 for (i
= 0; i
< nfile
; i
++)
1983 ptr
= linetab
+ filetab
[i
];
1984 nseg
= *(const short*)ptr
;
1985 ptr
+= 2 * sizeof(short);
1986 lt_ptr
= (const unsigned int*)ptr
;
1987 start
= (const struct startend
*)(lt_ptr
+ nseg
);
1990 * Now snarf the filename for all of the segments for this file.
1994 char filename
[MAX_PATH
];
1995 const struct p_string
* p_fn
;
1997 p_fn
= (const struct p_string
*)(start
+ nseg
);
1998 memset(filename
, 0, sizeof(filename
));
1999 memcpy(filename
, p_fn
->name
, p_fn
->namelen
);
2000 printf("%slines for file #%d/%d %s %d\n", pfx
, i
, nfile
, filename
, nseg
);
2003 printf("%slines for file #%d/%d %s %d\n", pfx
, i
, nfile
, (const char*)(start
+ nseg
), nseg
);
2005 for (j
= 0; j
< nseg
; j
++)
2007 ptr
= linetab
+ *lt_ptr
++;
2008 nline
= *(const short*)(ptr
+ 2);
2009 printf("%s %04x:%08x-%08x #%d\n",
2010 pfx
, *(const short*)(ptr
+ 0), start
[j
].start
, start
[j
].end
, nline
);
2012 for (k
= 0; k
< nline
; k
++)
2014 printf("%s %x %d\n",
2015 pfx
, ((const unsigned int*)ptr
)[k
],
2016 ((const unsigned short*)((const unsigned int*)ptr
+ nline
))[k
]);
2022 void codeview_dump_linetab2(const char* linetab
, DWORD size
, const char* strimage
, DWORD strsize
, const char* pfx
)
2025 const struct CV_DebugSSubsectionHeader_t
* hdr
;
2026 const struct CV_DebugSSubsectionHeader_t
* next_hdr
;
2027 const struct CV_DebugSLinesHeader_t
* lines_hdr
;
2028 const struct CV_DebugSLinesFileBlockHeader_t
* files_hdr
;
2029 const struct CV_Column_t
* cols
;
2030 const struct CV_Checksum_t
* chksms
;
2031 const struct CV_InlineeSourceLine_t
* inlsrc
;
2032 const struct CV_InlineeSourceLineEx_t
* inlsrcex
;
2034 static const char* subsect_types
[] = /* starting at 0xf1 */
2036 "SYMBOLS", "LINES", "STRINGTABLE", "FILECHKSMS",
2037 "FRAMEDATA", "INLINEELINES", "CROSSSCOPEIMPORTS", "CROSSSCOPEEXPORTS",
2038 "IL_LINES", "FUNC_MDTOKEN_MAP", "TYPE_MDTOKEN_MAP", "MERGED_ASSEMBLYINPUT",
2041 hdr
= (const struct CV_DebugSSubsectionHeader_t
*)linetab
;
2042 while (CV_IS_INSIDE(hdr
, linetab
+ size
))
2044 next_hdr
= CV_RECORD_GAP(hdr
, hdr
->cbLen
);
2045 if (hdr
->type
& DEBUG_S_IGNORE
)
2047 printf("%s------ debug subsection <ignored>\n", pfx
);
2052 printf("%s------ debug subsection %s\n", pfx
,
2053 (hdr
->type
>= 0xf1 && hdr
->type
- 0xf1 < ARRAY_SIZE(subsect_types
)) ?
2054 subsect_types
[hdr
->type
- 0xf1] : "<<unknown>>");
2058 lines_hdr
= CV_RECORD_AFTER(hdr
);
2059 printf("%s block from %04x:%08x flags:%x size=%u\n",
2060 pfx
, lines_hdr
->segCon
, lines_hdr
->offCon
, lines_hdr
->flags
, lines_hdr
->cbCon
);
2061 files_hdr
= CV_RECORD_AFTER(lines_hdr
);
2062 /* FIXME: as of today partial coverage:
2063 * - only one files_hdr has been seen in PDB files
2064 * OTOH, MS github presents two different structures
2066 * - next files_hdr (depending on previous question, can be a void question)
2067 * is code correct ; what do MS and llvm do?
2069 while (CV_IS_INSIDE(files_hdr
, next_hdr
))
2071 const struct CV_Line_t
* lines
;
2072 printf("%s file=%u lines=%d size=%x\n", pfx
, files_hdr
->offFile
,
2073 files_hdr
->nLines
, files_hdr
->cbBlock
);
2074 lines
= CV_RECORD_AFTER(files_hdr
);
2075 cols
= (const struct CV_Column_t
*)&lines
[files_hdr
->nLines
];
2076 for (i
= 0; i
< files_hdr
->nLines
; i
++)
2078 printf("%s offset=%8x line=%d deltaLineEnd=%u %s",
2079 pfx
, lines
[i
].offset
, lines
[i
].linenumStart
, lines
[i
].deltaLineEnd
,
2080 lines
[i
].fStatement
? "statement" : "expression");
2081 if (lines_hdr
->flags
& CV_LINES_HAVE_COLUMNS
)
2082 printf(" cols[start=%u end=%u]",
2083 cols
[i
].offColumnStart
, cols
[i
].offColumnEnd
);
2086 if (lines_hdr
->flags
& CV_LINES_HAVE_COLUMNS
)
2087 files_hdr
= (const struct CV_DebugSLinesFileBlockHeader_t
*)&cols
[files_hdr
->nLines
];
2089 files_hdr
= (const struct CV_DebugSLinesFileBlockHeader_t
*)&lines
[files_hdr
->nLines
];
2092 case DEBUG_S_FILECHKSMS
:
2093 chksms
= CV_RECORD_AFTER(hdr
);
2094 while (CV_IS_INSIDE(chksms
, next_hdr
))
2096 const char* meth
[] = {"None", "MD5", "SHA1", "SHA256"};
2097 printf("%s %d] name=%s size=%u method=%s checksum=[",
2098 pfx
, (unsigned)((const char*)chksms
- (const char*)(hdr
+ 1)),
2099 strimage
? strimage
+ chksms
->strOffset
: "--none--",
2100 chksms
->size
, chksms
->method
< ARRAY_SIZE(meth
) ? meth
[chksms
->method
] : "<<unknown>>");
2101 for (i
= 0; i
< chksms
->size
; ++i
) printf("%02x", chksms
->checksum
[i
]);
2103 chksms
= CV_ALIGN(CV_RECORD_GAP(chksms
, chksms
->size
), 4);
2106 case DEBUG_S_INLINEELINES
:
2107 /* subsection starts with a DWORD signature */
2108 switch (*(DWORD
*)CV_RECORD_AFTER(hdr
))
2110 case CV_INLINEE_SOURCE_LINE_SIGNATURE
:
2111 inlsrc
= CV_RECORD_GAP(hdr
, sizeof(DWORD
));
2112 while (CV_IS_INSIDE(inlsrc
, next_hdr
))
2114 printf("%s inlinee=%x fileref=%d srcstart=%d\n",
2115 pfx
, inlsrc
->inlinee
, inlsrc
->fileId
, inlsrc
->sourceLineNum
);
2119 case CV_INLINEE_SOURCE_LINE_SIGNATURE_EX
:
2120 inlsrcex
= CV_RECORD_GAP(hdr
, sizeof(DWORD
));
2121 while (CV_IS_INSIDE(inlsrcex
, next_hdr
))
2123 printf("%s inlinee=%x fileref=%d srcstart=%d numExtraFiles=%d\n",
2124 pfx
, inlsrcex
->inlinee
, inlsrcex
->fileId
, inlsrcex
->sourceLineNum
,
2125 inlsrcex
->countOfExtraFiles
);
2126 inlsrcex
= CV_RECORD_GAP(inlsrcex
, inlsrcex
->countOfExtraFiles
* sizeof(inlsrcex
->extraFileId
[0]));
2130 printf("%sUnknown signature %x in INLINEELINES subsection\n", pfx
, *(DWORD
*)CV_RECORD_AFTER(hdr
));
2135 dump_data(CV_RECORD_AFTER(hdr
), hdr
->cbLen
, pfx
);