sane: Fix memory leak in create_item (Coverity).
[wine.git] / tools / winedump / msc.c
blob3c632ec19e9e24ff559a640600e510dc89679308
1 /*
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
21 #include "config.h"
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <time.h>
27 #include <fcntl.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winedump.h"
32 #include "cvconst.h"
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';
43 return tmp;
46 struct full_value
48 enum {fv_integer, fv_longlong} type;
49 union
51 int i;
52 long long unsigned llu;
53 } v;
56 static int full_numeric_leaf(struct full_value* fv, const unsigned short int* leaf)
58 unsigned short int type = *leaf++;
59 int length = 2;
61 fv->type = fv_integer;
62 if (type < LF_NUMERIC)
64 fv->v.i = type;
66 else
68 switch (type)
70 case LF_CHAR:
71 length += 1;
72 fv->v.i = *(const char*)leaf;
73 break;
75 case LF_SHORT:
76 length += 2;
77 fv->v.i = *(const short*)leaf;
78 break;
80 case LF_USHORT:
81 length += 2;
82 fv->v.i = *leaf;
83 break;
85 case LF_LONG:
86 length += 4;
87 fv->v.i = *(const int*)leaf;
88 break;
90 case LF_ULONG:
91 length += 4;
92 fv->v.i = *(const unsigned int*)leaf;
93 break;
95 case LF_QUADWORD:
96 length += 8;
97 fv->type = fv_longlong;
98 fv->v.llu = *(const long long int*)leaf;
99 break;
101 case LF_UQUADWORD:
102 length += 8;
103 fv->type = fv_longlong;
104 fv->v.llu = *(const long long unsigned int*)leaf;
105 break;
107 case LF_REAL32:
108 length += 4;
109 printf(">>> unsupported leaf value %04x\n", type);
110 fv->v.i = 0; /* FIXME */
111 break;
113 case LF_REAL48:
114 length += 6;
115 fv->v.i = 0; /* FIXME */
116 printf(">>> unsupported leaf value %04x\n", type);
117 break;
119 case LF_REAL64:
120 length += 8;
121 fv->v.i = 0; /* FIXME */
122 printf(">>> unsupported leaf value %04x\n", type);
123 break;
125 case LF_REAL80:
126 length += 10;
127 fv->v.i = 0; /* FIXME */
128 printf(">>> unsupported leaf value %04x\n", type);
129 break;
131 case LF_REAL128:
132 length += 16;
133 fv->v.i = 0; /* FIXME */
134 printf(">>> unsupported leaf value %04x\n", type);
135 break;
137 case LF_COMPLEX32:
138 length += 4;
139 fv->v.i = 0; /* FIXME */
140 printf(">>> unsupported leaf value %04x\n", type);
141 break;
143 case LF_COMPLEX64:
144 length += 8;
145 fv->v.i = 0; /* FIXME */
146 printf(">>> unsupported leaf value %04x\n", type);
147 break;
149 case LF_COMPLEX80:
150 length += 10;
151 fv->v.i = 0; /* FIXME */
152 printf(">>> unsupported leaf value %04x\n", type);
153 break;
155 case LF_COMPLEX128:
156 length += 16;
157 fv->v.i = 0; /* FIXME */
158 printf(">>> unsupported leaf value %04x\n", type);
159 break;
161 case LF_VARSTRING:
162 length += 2 + *leaf;
163 fv->v.i = 0; /* FIXME */
164 printf(">>> unsupported leaf value %04x\n", type);
165 break;
167 default:
168 printf(">>> Unsupported numeric leaf-id %04x\n", type);
169 fv->v.i = 0;
170 break;
173 return length;
176 static const char* full_value_string(const struct full_value* fv)
178 static char tmp[128];
180 switch (fv->type)
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;
185 return tmp;
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);
193 switch (fv.type)
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;
199 return len;
202 static const char* get_attr(unsigned attr)
204 static char tmp[256];
206 switch (attr & 3)
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 ");
227 return tmp;
230 static const char* get_property(unsigned prop)
232 static char tmp[1024];
233 unsigned pos = 0;
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);
251 #undef X
253 tmp[pos] = '\0';
254 assert(pos < sizeof(tmp));
256 return tmp;
259 static const char* get_funcattr(unsigned attr)
261 static char tmp[1024];
262 unsigned pos = 0;
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);
270 #undef X
272 tmp[pos] = '\0';
273 assert(pos < sizeof(tmp));
275 return tmp;
278 static const char* get_varflags(unsigned flags)
280 static char tmp[1024];
281 unsigned pos = 0;
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);
297 #undef X
299 tmp[pos] = '\0';
300 assert(pos < sizeof(tmp));
302 return tmp;
305 static const char* get_machine(unsigned m)
307 const char* machine;
309 switch (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;
386 default:
388 static char tmp[16];
389 sprintf(tmp, "machine=%x", m);
390 machine = tmp;
392 break;
394 return machine;
397 static const char* get_language(unsigned l)
399 const char* lang;
401 switch (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;
420 default:
422 static char tmp[16];
423 sprintf(tmp, "lang=%x", l);
424 lang = tmp;
426 break;
428 return lang;
431 static const char* get_callconv(unsigned cc)
433 const char* callconv;
435 switch (cc)
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;
463 default:
465 static char tmp[16];
466 sprintf(tmp, "callconv=%x", cc);
467 callconv = tmp;
469 break;
471 return callconv;
474 static const char* get_pubflags(unsigned flags)
476 static char ret[32];
478 ret[0] = '\0';
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");
484 #undef X
485 return ret;
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;
504 const char* cstr;
505 const struct p_string* pstr;
506 int leaf_len, value;
507 struct full_value full_value;
509 while (ptr < end)
511 const union codeview_fieldtype* fieldtype = (const union codeview_fieldtype*)ptr;
513 if (*ptr >= 0xf0) /* LF_PAD... */
515 ptr +=* ptr & 0x0f;
516 continue;
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;
527 break;
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;
535 break;
537 case LF_MEMBER_V1:
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;
544 break;
546 case LF_MEMBER_V2:
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;
553 break;
555 case LF_MEMBER_V3:
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;
562 break;
564 case LF_ONEMETHOD_V1:
565 switch ((fieldtype->onemethod_v1.attribute >> 2) & 7)
567 case 4: case 6:
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);
574 break;
576 default:
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);
582 break;
584 break;
586 case LF_ONEMETHOD_V2:
587 switch ((fieldtype->onemethod_v2.attribute >> 2) & 7)
589 case 4: case 6:
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);
596 break;
598 default:
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);
604 break;
606 break;
608 case LF_ONEMETHOD_V3:
609 switch ((fieldtype->onemethod_v3.attribute >> 2) & 7)
611 case 4: case 6:
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);
618 break;
620 default:
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);
626 break;
628 break;
630 case LF_METHOD_V1:
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);
635 break;
637 case LF_METHOD_V2:
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);
642 break;
644 case LF_METHOD_V3:
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);
649 break;
651 case LF_STMEMBER_V1:
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);
657 break;
659 case LF_STMEMBER_V2:
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);
665 break;
667 case LF_STMEMBER_V3:
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);
673 break;
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);
680 break;
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);
687 break;
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);
694 break;
696 case LF_BCLASS_V1:
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;
702 break;
704 case LF_BCLASS_V2:
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;
710 break;
712 case LF_VBCLASS_V1:
713 case LF_IVBCLASS_V1:
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);
722 ptr += leaf_len;
723 break;
725 case LF_VBCLASS_V2:
726 case LF_IVBCLASS_V2:
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);
735 ptr += leaf_len;
736 break;
738 case LF_FRIENDCLS_V1:
739 printf("\t\tFriend class V1: type:%x\n", fieldtype->friendcls_v1.type);
740 ptr += 2 + 2;
741 break;
743 case LF_FRIENDCLS_V2:
744 printf("\t\tFriend class V2: type:%x\n", fieldtype->friendcls_v2.type);
745 ptr += 2 + 2 + 4;
746 break;
748 case LF_NESTTYPE_V1:
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);
753 break;
755 case LF_NESTTYPE_V2:
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);
760 break;
762 case LF_NESTTYPE_V3:
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);
767 break;
769 case LF_VFUNCTAB_V1:
770 printf("\t\tVirtual function table V1: type:%x\n",
771 fieldtype->vfunctab_v1.type);
772 ptr += 2 + 2;
773 break;
775 case LF_VFUNCTAB_V2:
776 printf("\t\tVirtual function table V2: type:%x\n",
777 fieldtype->vfunctab_v2.type);
778 ptr += 2 + 2 + 4;
779 break;
781 case LF_VFUNCOFF_V1:
782 printf("\t\tVirtual function table offset V1: type:%x offset:%x\n",
783 fieldtype->vfuncoff_v1.type, fieldtype->vfuncoff_v1.offset);
784 ptr += 2 + 2 + 4;
785 break;
787 case LF_VFUNCOFF_V2:
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;
791 break;
793 case LF_INDEX_V1:
794 printf("\t\tIndex V1: index:%x\n", fieldtype->index_v1.ref);
795 ptr += 2 + 2;
796 break;
798 case LF_INDEX_V2:
799 printf("\t\tIndex V2: index:%x\n", fieldtype->index_v2.ref);
800 ptr += 2 + 2 + 4;
801 break;
803 default:
804 printf(">>> Unsupported field-id %x\n", fieldtype->generic.id);
805 dump_data((const void*)fieldtype, 0x30, "\t");
806 break;
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;
815 unsigned int j;
816 const char* str;
818 switch (type->generic.id)
820 /* types from TPI (aka #2) stream */
821 case LF_POINTER_V1:
822 printf("\t%x => Pointer V1 to type:%x\n",
823 curr_type, type->pointer_v1.datatype);
824 break;
825 case LF_POINTER_V2:
826 printf("\t%x => Pointer V2 to type:%x\n",
827 curr_type, type->pointer_v2.datatype);
828 break;
829 case LF_ARRAY_V1:
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);
834 break;
835 case LF_ARRAY_V2:
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);
840 break;
841 case LF_ARRAY_V3:
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);
847 break;
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
854 case LF_BITFIELD_V1:
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);
858 break;
860 case LF_BITFIELD_V2:
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);
864 break;
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);
870 break;
872 case LF_STRUCTURE_V1:
873 case LF_CLASS_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);
881 break;
883 case LF_STRUCTURE_V2:
884 case LF_CLASS_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);
893 break;
895 case LF_STRUCTURE_V3:
896 case LF_CLASS_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);
907 break;
909 case LF_UNION_V1:
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);
915 break;
917 case LF_UNION_V2:
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);
923 break;
925 case LF_UNION_V3:
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);
934 break;
936 case LF_ENUM_V1:
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));
943 break;
945 case LF_ENUM_V2:
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));
952 break;
954 case LF_ENUM_V3:
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);
963 break;
965 case LF_ARGLIST_V1:
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]);
971 printf("\n");
972 break;
974 case LF_ARGLIST_V2:
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]);
980 printf("\t\n");
981 break;
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);
988 break;
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);
995 break;
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",
1000 curr_type,
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);
1009 break;
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);
1014 break;
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);
1019 break;
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)
1030 case 4: case 6:
1031 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
1032 get_attr(pattr[0]), pattr[1],
1033 *(const unsigned*)(&pattr[2]));
1034 pattr += 3;
1035 break;
1036 default:
1037 printf("\t\t\tattr:%s type:%x\n",
1038 get_attr(pattr[0]), pattr[1]);
1039 pattr += 2;
1043 break;
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)
1054 case 4: case 6:
1055 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
1056 get_attr(pattr[0]), pattr[1], pattr[2]);
1057 pattr += 3;
1058 break;
1059 default:
1060 printf("\t\t\tattr:%s type:%x\n",
1061 get_attr(pattr[0]), pattr[1]);
1062 pattr += 2;
1066 break;
1068 case LF_VTSHAPE_V1:
1070 int count = *(const unsigned short*)((const char*)type + 4);
1071 int shift = 0;
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);
1076 while (count--)
1078 if (((*ptr << shift) & 0xF) <= 6)
1079 printf("%s ", desc[(*ptr << shift) & 0xF]);
1080 else
1081 printf("%x ", (*ptr << shift) & 0xF);
1082 if (shift == 0) shift = 4; else {shift = 0; ptr++;}
1084 printf("\n");
1086 break;
1088 case LF_DERIVED_V1:
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]);
1094 printf("\n");
1095 break;
1097 case LF_DERIVED_V2:
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]);
1103 printf("\n");
1104 break;
1106 case LF_VFTABLE_V3:
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;
1112 while (str < last)
1114 printf("\t\t%s\n", str);
1115 str += strlen(str) + 1;
1118 break;
1120 /* types from IPI (aka #4) stream */
1121 case LF_FUNC_ID:
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);
1125 break;
1126 case LF_MFUNC_ID:
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);
1130 break;
1131 case LF_BUILDINFO:
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]);
1138 break;
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]);
1145 printf("\t\n");
1146 break;
1147 case LF_STRING_ID:
1148 printf("\t%x => StringId %s strid:%04x\n",
1149 curr_type, type->string_id_v3.name, type->string_id_v3.strid);
1150 break;
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);
1155 break;
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);
1161 break;
1163 default:
1164 printf(">>> Unsupported type-id %x for %x\n", type->generic.id, curr_type);
1165 dump_data((const void*)type, type->generic.len + 2, "");
1166 break;
1170 BOOL codeview_dump_types_from_offsets(const void* table, const DWORD* offsets, unsigned num_types)
1172 unsigned long i;
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]));
1180 return TRUE;
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);
1193 curr_type++;
1194 ptr += type->generic.len + 2;
1197 return TRUE;
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);
1225 res |= *ptr++;
1227 else if ((*ptr & 0xE0) == 0xC0)
1229 res = (*ptr++ & 0x1f) << 24;
1230 res |= *ptr++ << 16;
1231 res |= *ptr++ << 8;
1232 res |= *ptr++;
1234 else res = (unsigned)(-1);
1235 *pptr = ptr;
1236 return res;
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);
1249 switch (opcode)
1251 case BA_OP_Invalid:
1252 /* not clear if param? */
1253 printf("%*s | Invalid\n", indent, "");
1254 break;
1255 case BA_OP_CodeOffset:
1256 printf("%*s | CodeOffset %u\n", indent, "", binannot_uncompress(&ba));
1257 break;
1258 case BA_OP_ChangeCodeOffsetBase:
1259 printf("%*s | ChangeCodeOffsetBase %u\n", indent, "", binannot_uncompress(&ba));
1260 break;
1261 case BA_OP_ChangeCodeOffset:
1262 printf("%*s | ChangeCodeOffset %u\n", indent, "", binannot_uncompress(&ba));
1263 break;
1264 case BA_OP_ChangeCodeLength:
1265 printf("%*s | ChangeCodeLength %u\n", indent, "", binannot_uncompress(&ba));
1266 break;
1267 case BA_OP_ChangeFile:
1268 printf("%*s | ChangeFile %u\n", indent, "", binannot_uncompress(&ba));
1269 break;
1270 case BA_OP_ChangeLineOffset:
1271 printf("%*s | ChangeLineOffset %d\n", indent, "", binannot_getsigned(binannot_uncompress(&ba)));
1272 break;
1273 case BA_OP_ChangeLineEndDelta:
1274 printf("%*s | ChangeLineEndDelta %u\n", indent, "", binannot_uncompress(&ba));
1275 break;
1276 case BA_OP_ChangeRangeKind:
1277 printf("%*s | ChangeRangeKind %u\n", indent, "", binannot_uncompress(&ba));
1278 break;
1279 case BA_OP_ChangeColumnStart:
1280 printf("%*s | ChangeColumnStart %u\n", indent, "", binannot_uncompress(&ba));
1281 break;
1282 case BA_OP_ChangeColumnEndDelta:
1283 printf("%*s | ChangeColumnEndDelta %u\n", indent, "", binannot_uncompress(&ba));
1284 break;
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);
1290 break;
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);
1297 break;
1298 case BA_OP_ChangeColumnEnd:
1299 printf("%*s | ChangeColumnEnd %u\n", indent, "", binannot_uncompress(&ba));
1300 break;
1302 default: printf(">>> Unsupported op %d %x\n", opcode, opcode); /* may cause issues because of param */
1307 struct symbol_dumper
1309 unsigned depth;
1310 unsigned alloc;
1311 struct
1313 unsigned end;
1314 const union codeview_symbol* sym;
1315 }* stack;
1318 static void init_symbol_dumper(struct symbol_dumper* sd)
1320 sd->depth = 0;
1321 sd->alloc = 16;
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]))))
1330 return;
1331 sd->stack[sd->depth].end = end;
1332 sd->stack[sd->depth].sym = sym;
1333 sd->depth++;
1336 static unsigned short pop_symbol_dumper(struct symbol_dumper* sd, unsigned end)
1338 if (!sd->stack) return 0;
1339 if (!sd->depth)
1341 printf(">>> Error in stack\n");
1342 return 0;
1344 sd->depth--;
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)
1352 free(sd->stack);
1355 BOOL codeview_dump_symbols(const void* root, unsigned long start, unsigned long size)
1357 unsigned int i;
1358 int length;
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)
1377 case S_END:
1378 case S_INLINESITE_END:
1379 indent += printf("%*s", 2 * sd.depth - 2, "");
1380 break;
1381 default:
1382 indent += printf("%*s", 2 * sd.depth, "");
1383 break;
1386 switch (sym->generic.id)
1389 * Global and local data symbols. We don't associate these
1390 * with any given source file.
1392 case S_GDATA32_ST:
1393 case S_LDATA32_ST:
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);
1398 break;
1400 case S_LDATA32:
1401 case S_GDATA32:
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);
1408 break;
1410 case S_PUB32_16t:
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));
1415 break;
1417 case S_PUB32_ST:
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));
1422 break;
1424 case S_PUB32:
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));
1429 break;
1431 case S_DATAREF:
1432 case S_PROCREF:
1433 case S_LPROCREF:
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);
1439 break;
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.
1446 case S_THUNK32_ST:
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);
1452 break;
1454 case S_THUNK32:
1455 printf("Thunk V3 '%s' (%04x:%08x#%x) type:%x\n",
1456 sym->thunk_v3.name,
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);
1460 break;
1462 /* Global and static functions */
1463 case S_GPROC32_16t:
1464 case S_LPROC32_16t:
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);
1476 break;
1478 case S_GPROC32_ST:
1479 case S_LPROC32_ST:
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);
1491 break;
1493 case S_LPROC32:
1494 case S_GPROC32:
1495 printf("%s-Procedure V3 '%s' (%04x:%08x#%x) type:%x attr:%x\n",
1496 sym->generic.id == S_GPROC32 ? "Global" : "Local",
1497 sym->proc_v3.name,
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);
1506 break;
1508 /* Function parameters and stack variables */
1509 case S_BPREL32_16t:
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);
1513 break;
1515 case S_BPREL32_ST:
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);
1519 break;
1521 case S_BPREL32:
1522 printf("BP-relative V3: '%s' @%d type:%x\n",
1523 sym->stack_v3.name, sym->stack_v3.offset,
1524 sym->stack_v3.symtype);
1525 break;
1527 case S_REGREL32:
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);
1531 break;
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);
1537 break;
1539 case S_REGISTER_ST:
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);
1543 break;
1545 case S_REGISTER:
1546 printf("Register V3 '%s' type:%x register:%x\n",
1547 sym->register_v3.name, sym->register_v3.reg, sym->register_v3.type);
1548 break;
1550 case S_BLOCK32_ST:
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);
1556 break;
1558 case S_BLOCK32:
1559 printf("Block V3 '%s' (%04x:%08x#%08x) parent:<%u> end:<%x>\n",
1560 sym->block_v3.name,
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);
1564 break;
1566 /* Additional function information */
1567 case S_FRAMEPROC:
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);
1576 break;
1578 case S_FRAMECOOKIE:
1579 printf("Security Cookie V3 @%d unk:%x\n",
1580 sym->security_cookie_v3.offset, sym->security_cookie_v3.unknown);
1581 break;
1583 case S_END:
1584 ref = sd.depth ? (const char*)sd.stack[sd.depth - 1].sym - (const char*)root : 0;
1585 switch (pop_symbol_dumper(&sd, i))
1587 case S_BLOCK32_ST:
1588 case S_BLOCK32:
1589 printf("End-Of block <%x>\n", ref);
1590 break;
1591 default:
1592 printf("End-Of <%x>\n", ref);
1593 break;
1595 break;
1597 case S_COMPILE:
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));
1603 break;
1605 case S_COMPILE2_ST:
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;
1615 while (*ptr)
1617 printf("%*s| %s => ", indent, "", ptr); ptr += strlen(ptr) + 1;
1618 printf("%s\n", ptr); ptr += strlen(ptr) + 1;
1621 break;
1623 case S_COMPILE2:
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;
1633 while (*ptr)
1635 printf("%*s| %s => ", indent, "", ptr); ptr += strlen(ptr) + 1;
1636 printf("%s\n", ptr); ptr += strlen(ptr) + 1;
1639 break;
1641 case S_COMPILE3:
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);
1649 break;
1651 case S_ENVBLOCK:
1653 const char* x1 = (const char*)sym + 4 + 1;
1654 const char* x2;
1656 printf("Tool conf V3\n");
1657 while (*x1)
1659 x2 = x1 + strlen(x1) + 1;
1660 if (!*x2) break;
1661 printf("%*s| %s: %s\n", indent, "", x1, x2);
1662 x1 = x2 + strlen(x2) + 1;
1665 break;
1667 case S_OBJNAME:
1668 printf("ObjName V3 sig:%x '%s'\n",
1669 sym->objname_v3.signature, sym->objname_v3.name);
1670 break;
1672 case S_OBJNAME_ST:
1673 printf("ObjName V1 sig:%x '%s'\n",
1674 sym->objname_v1.signature, p_string(&sym->objname_v1.p_name));
1675 break;
1677 case S_TRAMPOLINE:
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);
1685 break;
1687 case S_LABEL32_ST:
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);
1691 break;
1693 case S_LABEL32:
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);
1697 break;
1699 case S_CONSTANT_ST:
1701 int vlen;
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);
1709 break;
1711 case S_CONSTANT:
1713 int vlen;
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);
1721 break;
1723 case S_UDT_16t:
1724 printf("Udt V1 '%s': type:0x%x\n",
1725 p_string(&sym->udt_v1.p_name), sym->udt_v1.type);
1726 break;
1728 case S_UDT_ST:
1729 printf("Udt V2 '%s': type:0x%x\n",
1730 p_string(&sym->udt_v2.p_name), sym->udt_v2.type);
1731 break;
1733 case S_UDT:
1734 printf("Udt V3 '%s': type:0x%x\n",
1735 sym->udt_v3.name, sym->udt_v3.type);
1736 break;
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.
1742 case S_PROCREF_ST:
1743 printf("Procref V1 "); goto doaref;
1744 case S_DATAREF_ST:
1745 printf("Dataref V1 "); goto doaref;
1746 case S_LPROCREF_ST:
1747 printf("L-Procref V1 "); goto doaref;
1748 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),
1756 p_string(pname));
1758 break;
1760 case S_ALIGN:
1761 /* simply skip it */
1762 break;
1764 case S_SSEARCH:
1765 printf("Search V1: (%04x:%08x)\n",
1766 sym->ssearch_v1.segment, sym->ssearch_v1.offset);
1767 break;
1769 case S_SECTION:
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);
1777 break;
1779 case S_COFFGROUP:
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);
1786 break;
1788 case S_EXPORT:
1789 printf("EntryPoint: id=%x '%s'\n",
1790 *(const unsigned*)((const char*)sym + 4), (const char*)sym + 8);
1791 break;
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);
1799 break;
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);
1807 break;
1809 case S_LTHREAD32:
1810 case S_GTHREAD32:
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);
1814 break;
1816 case S_LOCAL:
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));
1820 break;
1822 case S_DEFRANGE:
1823 printf("DefRange dia:%x\n", sym->defrange_v3.program);
1824 dump_defrange(&sym->defrange_v3.range, get_last(sym), indent);
1825 break;
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);
1830 break;
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);
1835 break;
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);
1840 break;
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);
1844 break;
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);
1851 break;
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);
1857 break;
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);
1862 break;
1864 case S_BUILDINFO:
1865 printf("Build-info V3 item:%04x\n", sym->build_info_v3.itemid);
1866 break;
1868 case S_INLINESITE:
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);
1873 break;
1875 case S_INLINESITE2:
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);
1881 break;
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);
1887 break;
1889 case S_CALLEES:
1890 case S_CALLERS:
1891 case S_INLINEES:
1893 unsigned i, ninvoc;
1894 const unsigned* invoc;
1895 const char* tag;
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);
1908 break;
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);
1916 break;
1918 case S_FILESTATIC:
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));
1924 break;
1926 case S_UNAMESPACE_ST:
1927 printf("UNameSpace V2 '%s'\n", p_string(&sym->unamespace_v2.pname));
1928 break;
1930 case S_UNAMESPACE:
1931 printf("UNameSpace V3 '%s'\n", sym->unamespace_v3.name);
1932 break;
1934 case S_SEPCODE:
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);
1940 break;
1942 case S_ANNOTATION:
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);
1951 break;
1953 case S_POGODATA:
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);
1957 break;
1959 default:
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);
1965 return TRUE;
1968 void codeview_dump_linetab(const char* linetab, BOOL pascal_str, const char* pfx)
1970 const char* ptr = linetab;
1971 int nfile, nseg, nline;
1972 int i, j, k;
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.
1992 if (pascal_str)
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);
2002 else
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);
2011 ptr += 4;
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)
2024 unsigned i;
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",
2039 "COFF_SYMBOL_RVA"
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);
2048 hdr = next_hdr;
2049 continue;
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>>");
2055 switch (hdr->type)
2057 case DEBUG_S_LINES:
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
2065 * llvm ? one or two
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);
2084 printf("\n");
2086 if (lines_hdr->flags & CV_LINES_HAVE_COLUMNS)
2087 files_hdr = (const struct CV_DebugSLinesFileBlockHeader_t*)&cols[files_hdr->nLines];
2088 else
2089 files_hdr = (const struct CV_DebugSLinesFileBlockHeader_t*)&lines[files_hdr->nLines];
2091 break;
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]);
2102 printf("]\n");
2103 chksms = CV_ALIGN(CV_RECORD_GAP(chksms, chksms->size), 4);
2105 break;
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);
2116 ++inlsrc;
2118 break;
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]));
2128 break;
2129 default:
2130 printf("%sUnknown signature %x in INLINEELINES subsection\n", pfx, *(DWORD*)CV_RECORD_AFTER(hdr));
2131 break;
2133 break;
2134 default:
2135 dump_data(CV_RECORD_AFTER(hdr), hdr->cbLen, pfx);
2136 break;
2138 hdr = next_hdr;