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
22 #include "wine/port.h"
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
34 #ifdef HAVE_SYS_STAT_H
35 # include <sys/stat.h>
37 #ifdef HAVE_SYS_MMAN_H
42 #define NONAMELESSUNION
43 #define NONAMELESSSTRUCT
47 #include "wine/mscvpdb.h"
49 #define PSTRING(adr, ofs) \
50 ((const struct p_string*)((const char*)(adr) + (ofs)))
52 static const char* p_string(const struct p_string
* s
)
54 static char tmp
[256 + 1];
55 memcpy(tmp
, s
->name
, s
->namelen
);
56 tmp
[s
->namelen
] = '\0';
60 static int numeric_leaf(int* value
, const unsigned short int* leaf
)
62 unsigned short int type
= *leaf
++;
65 if (type
< LF_NUMERIC
)
75 *value
= *(const char*)leaf
;
80 *value
= *(const short*)leaf
;
85 *value
= *(const unsigned short*)leaf
;
90 *value
= *(const int*)leaf
;
95 *value
= *(const unsigned int*)leaf
;
101 printf(">>> unsupported leaf value\n");
102 *value
= 0; /* FIXME */
107 printf(">>> unsupported leaf value\n");
108 *value
= 0; /* FIXME */
113 *value
= 0; /* FIXME */
114 printf(">>> unsupported leaf value\n");
119 *value
= 0; /* FIXME */
120 printf(">>> unsupported leaf value\n");
125 *value
= 0; /* FIXME */
126 printf(">>> unsupported leaf value\n");
131 *value
= 0; /* FIXME */
132 printf(">>> unsupported leaf value\n");
137 *value
= 0; /* FIXME */
138 printf(">>> unsupported leaf value\n");
143 *value
= 0; /* FIXME */
144 printf(">>> unsupported leaf value\n");
149 *value
= 0; /* FIXME */
150 printf(">>> unsupported leaf value\n");
155 *value
= 0; /* FIXME */
156 printf(">>> unsupported leaf value\n");
161 *value
= 0; /* FIXME */
162 printf(">>> unsupported leaf value\n");
166 printf(">>> Unsupported numeric leaf-id %04x\n", type
);
174 static const char* get_attr(unsigned attr
)
176 static char tmp
[256];
180 case 0: strcpy(tmp
, ""); break;
181 case 1: strcpy(tmp
, "private "); break;
182 case 2: strcpy(tmp
, "protected "); break;
183 case 3: strcpy(tmp
, "public "); break;
185 switch ((attr
>> 2) & 7)
187 case 0: strcat(tmp
, ""); break;
188 case 1: strcat(tmp
, "virtual "); break;
189 case 2: strcat(tmp
, "static "); break;
190 case 3: strcat(tmp
, "friend "); break;
191 case 4: strcat(tmp
, "introducing virtual "); break;
192 case 5: strcat(tmp
, "pure virtual "); break;
193 case 6: strcat(tmp
, "pure introducing virtual "); break;
194 case 7: strcat(tmp
, "reserved "); break;
196 if ((attr
>> 5) & 1) strcat(tmp
, "pseudo ");
197 if ((attr
>> 6) & 1) strcat(tmp
, "no-inherit ");
198 if ((attr
>> 7) & 1) strcat(tmp
, "no-construct ");
202 static void do_field(const unsigned char* start
, const unsigned char* end
)
205 * A 'field list' is a CodeView-specific data type which doesn't
206 * directly correspond to any high-level data type. It is used
207 * to hold the collection of members of a struct, class, union
208 * or enum type. The actual definition of that type will follow
209 * later, and refer to the field list definition record.
211 * As we don't have a field list type ourselves, we look ahead
212 * in the field list to try to find out whether this field list
213 * will be used for an enum or struct type, and create a dummy
214 * type of the corresponding sort. Later on, the definition of
215 * the 'real' type will copy the member / enumeration data.
217 const unsigned char* ptr
= start
;
219 const struct p_string
* pstr
;
224 const union codeview_fieldtype
* fieldtype
= (const union codeview_fieldtype
*)ptr
;
226 if (*ptr
>= 0xf0) /* LF_PAD... */
232 switch (fieldtype
->generic
.id
)
234 case LF_ENUMERATE_V1
:
235 leaf_len
= numeric_leaf(&value
, &fieldtype
->enumerate_v1
.value
);
236 pstr
= PSTRING(&fieldtype
->enumerate_v1
.value
, leaf_len
);
237 printf("\t\tEnumerate V1: '%s' value:%d\n",
238 p_string(pstr
), value
);
239 ptr
+= 2 + 2 + leaf_len
+ 1 + pstr
->namelen
;
242 case LF_ENUMERATE_V3
:
243 leaf_len
= numeric_leaf(&value
, &fieldtype
->enumerate_v3
.value
);
244 cstr
= (const char*)&fieldtype
->enumerate_v3
.value
+ leaf_len
;
245 printf("\t\tEnumerate V3: '%s' value:%d\n",
247 ptr
+= 2 + 2 + leaf_len
+ strlen(cstr
) + 1;
251 leaf_len
= numeric_leaf(&value
, &fieldtype
->member_v1
.offset
);
252 pstr
= PSTRING(&fieldtype
->member_v1
.offset
, leaf_len
);
253 printf("\t\tMember V1: '%s' type:%x attr:%s @%d\n",
254 p_string(pstr
), fieldtype
->member_v1
.type
,
255 get_attr(fieldtype
->member_v1
.attribute
), value
);
256 ptr
+= 2 + 2 + 2 + leaf_len
+ 1 + pstr
->namelen
;
260 leaf_len
= numeric_leaf(&value
, &fieldtype
->member_v2
.offset
);
261 pstr
= PSTRING(&fieldtype
->member_v2
.offset
, leaf_len
);
262 printf("\t\tMember V2: '%s' type:%x attr:%s @%d\n",
263 p_string(pstr
), fieldtype
->member_v2
.type
,
264 get_attr(fieldtype
->member_v2
.attribute
), value
);
265 ptr
+= 2 + 2 + 4 + leaf_len
+ 1 + pstr
->namelen
;
269 leaf_len
= numeric_leaf(&value
, &fieldtype
->member_v3
.offset
);
270 cstr
= (const char*)&fieldtype
->member_v3
.offset
+ leaf_len
;
271 printf("\t\tMember V3: '%s' type:%x attr:%s @%d\n",
272 cstr
, fieldtype
->member_v3
.type
,
273 get_attr(fieldtype
->member_v3
.attribute
), value
);
274 ptr
+= 2 + 2 + 4 + leaf_len
+ strlen(cstr
) + 1;
277 case LF_ONEMETHOD_V1
:
278 switch ((fieldtype
->onemethod_v1
.attribute
>> 2) & 7)
281 printf("\t\tVirtual-method V1: '%s' attr:%s type:%x vtable_offset:%u\n",
282 p_string(&fieldtype
->onemethod_virt_v1
.p_name
),
283 get_attr(fieldtype
->onemethod_virt_v1
.attribute
),
284 fieldtype
->onemethod_virt_v1
.type
,
285 fieldtype
->onemethod_virt_v1
.vtab_offset
);
286 ptr
+= 2 + 2 + 2 + 4 + (1 + fieldtype
->onemethod_virt_v1
.p_name
.namelen
);
290 printf("\t\tMethod V1: '%s' attr:%s type:%x\n",
291 p_string(&fieldtype
->onemethod_v1
.p_name
),
292 get_attr(fieldtype
->onemethod_v1
.attribute
),
293 fieldtype
->onemethod_v1
.type
);
294 ptr
+= 2 + 2 + 2 + (1 + fieldtype
->onemethod_v1
.p_name
.namelen
);
299 case LF_ONEMETHOD_V2
:
300 switch ((fieldtype
->onemethod_v2
.attribute
>> 2) & 7)
303 printf("\t\tVirtual-method V2: '%s' attr:%s type:%x vtable_offset:%u\n",
304 p_string(&fieldtype
->onemethod_virt_v2
.p_name
),
305 get_attr(fieldtype
->onemethod_virt_v2
.attribute
),
306 fieldtype
->onemethod_virt_v2
.type
,
307 fieldtype
->onemethod_virt_v2
.vtab_offset
);
308 ptr
+= 2 + 2 + 4 + 4 + (1 + fieldtype
->onemethod_virt_v2
.p_name
.namelen
);
312 printf("\t\tMethod V2: '%s' attr:%s type:%x\n",
313 p_string(&fieldtype
->onemethod_v2
.p_name
),
314 get_attr(fieldtype
->onemethod_v2
.attribute
),
315 fieldtype
->onemethod_v2
.type
);
316 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->onemethod_v2
.p_name
.namelen
);
321 case LF_ONEMETHOD_V3
:
322 switch ((fieldtype
->onemethod_v3
.attribute
>> 2) & 7)
325 printf("\t\tVirtual-method V3: '%s' attr:%s type:%x vtable_offset:%u\n",
326 fieldtype
->onemethod_virt_v3
.name
,
327 get_attr(fieldtype
->onemethod_virt_v3
.attribute
),
328 fieldtype
->onemethod_virt_v3
.type
,
329 fieldtype
->onemethod_virt_v3
.vtab_offset
);
330 ptr
+= 2 + 2 + 4 + 4 + (strlen(fieldtype
->onemethod_virt_v3
.name
) + 1);
334 printf("\t\tMethod V3: '%s' attr:%s type:%x\n",
335 fieldtype
->onemethod_v3
.name
,
336 get_attr(fieldtype
->onemethod_v3
.attribute
),
337 fieldtype
->onemethod_v3
.type
);
338 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->onemethod_v3
.name
) + 1);
344 printf("\t\tMethod V1: '%s' overloaded=#%d method-list=%x\n",
345 p_string(&fieldtype
->method_v1
.p_name
),
346 fieldtype
->method_v1
.count
, fieldtype
->method_v1
.mlist
);
347 ptr
+= 2 + 2 + 2 + (1 + fieldtype
->method_v1
.p_name
.namelen
);
351 printf("\t\tMethod V2: '%s' overloaded=#%d method-list=%x\n",
352 p_string(&fieldtype
->method_v2
.p_name
),
353 fieldtype
->method_v2
.count
, fieldtype
->method_v2
.mlist
);
354 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->method_v2
.p_name
.namelen
);
358 printf("\t\tMethod V3: '%s' overloaded=#%d method-list=%x\n",
359 fieldtype
->method_v3
.name
,
360 fieldtype
->method_v3
.count
, fieldtype
->method_v3
.mlist
);
361 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->method_v3
.name
) + 1);
365 printf("\t\tStatic member V1: '%s' attr:%s type:%x\n",
366 p_string(&fieldtype
->stmember_v1
.p_name
),
367 get_attr(fieldtype
->stmember_v1
.attribute
),
368 fieldtype
->stmember_v1
.type
);
369 ptr
+= 2 + 2 + 2 + (1 + fieldtype
->stmember_v1
.p_name
.namelen
);
373 printf("\t\tStatic member V2: '%s' attr:%s type:%x\n",
374 p_string(&fieldtype
->stmember_v2
.p_name
),
375 get_attr(fieldtype
->stmember_v2
.attribute
),
376 fieldtype
->stmember_v2
.type
);
377 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->stmember_v2
.p_name
.namelen
);
381 printf("\t\tStatic member V3: '%s' attr:%s type:%x\n",
382 fieldtype
->stmember_v3
.name
,
383 get_attr(fieldtype
->stmember_v3
.attribute
),
384 fieldtype
->stmember_v3
.type
);
385 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->stmember_v3
.name
) + 1);
388 case LF_FRIENDFCN_V1
:
389 printf("\t\tFriend function V1: '%s' type:%x\n",
390 p_string(&fieldtype
->friendfcn_v1
.p_name
),
391 fieldtype
->friendfcn_v1
.type
);
394 case LF_FRIENDFCN_V2
:
395 printf("\t\tFriend function V2: '%s' type:%x\n",
396 p_string(&fieldtype
->friendfcn_v2
.p_name
),
397 fieldtype
->friendfcn_v2
.type
);
401 case LF_FRIENDFCN_V3
:
402 printf("\t\tFriend function V3: '%s' type:%x\n",
403 fieldtype
->friendfcn_v3
.name
,
404 fieldtype
->friendfcn_v3
.type
);
409 leaf_len
= numeric_leaf(&value
, &fieldtype
->bclass_v1
.offset
);
410 printf("\t\tBase class V1: type:%x attr:%s @%d\n",
411 fieldtype
->bclass_v1
.type
,
412 get_attr(fieldtype
->bclass_v1
.attribute
), value
);
413 ptr
+= 2 + 2 + 2 + leaf_len
;
417 leaf_len
= numeric_leaf(&value
, &fieldtype
->bclass_v2
.offset
);
418 printf("\t\tBase class V2: type:%x attr:%s @%d\n",
419 fieldtype
->bclass_v2
.type
,
420 get_attr(fieldtype
->bclass_v2
.attribute
), value
);
421 ptr
+= 2 + 2 + 4 + leaf_len
;
426 leaf_len
= numeric_leaf(&value
, &fieldtype
->vbclass_v1
.vbpoff
);
427 printf("\t\t%sirtual base class V1: type:%x (ptr:%x) attr:%s vbpoff:%d ",
428 (fieldtype
->generic
.id
== LF_VBCLASS_V2
) ? "V" : "Indirect v",
429 fieldtype
->vbclass_v1
.btype
, fieldtype
->vbclass_v1
.vbtype
,
430 get_attr(fieldtype
->vbclass_v1
.attribute
), value
);
431 ptr
+= 2 + 2 + 2 + 2 + leaf_len
;
432 leaf_len
= numeric_leaf(&value
, (const unsigned short*)ptr
);
433 printf("vboff:%d\n", value
);
439 leaf_len
= numeric_leaf(&value
, &fieldtype
->vbclass_v1
.vbpoff
);
440 printf("\t\t%sirtual base class V2: type:%x (ptr:%x) attr:%s vbpoff:%d ",
441 (fieldtype
->generic
.id
== LF_VBCLASS_V2
) ? "V" : "Indirect v",
442 fieldtype
->vbclass_v2
.btype
, fieldtype
->vbclass_v2
.vbtype
,
443 get_attr(fieldtype
->vbclass_v2
.attribute
), value
);
444 ptr
+= 2 + 2 + 4 + 4 + leaf_len
;
445 leaf_len
= numeric_leaf(&value
, (const unsigned short*)ptr
);
446 printf("vboff:%d\n", value
);
450 case LF_FRIENDCLS_V1
:
451 printf("\t\tFriend class V1: type:%x\n", fieldtype
->friendcls_v1
.type
);
454 case LF_FRIENDCLS_V2
:
455 printf("\t\tFriend class V2: type:%x\n", fieldtype
->friendcls_v2
.type
);
459 printf("\t\tNested type V1: '%s' type:%x\n",
460 p_string(&fieldtype
->nesttype_v1
.p_name
),
461 fieldtype
->nesttype_v1
.type
);
462 ptr
+= 2 + 2 + (1 + fieldtype
->nesttype_v1
.p_name
.namelen
);
466 printf("\t\tNested type V2: '%s' pad0:%u type:%x\n",
467 p_string(&fieldtype
->nesttype_v2
.p_name
),
468 fieldtype
->nesttype_v2
._pad0
, fieldtype
->nesttype_v2
.type
);
469 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->nesttype_v2
.p_name
.namelen
);
473 printf("\t\tNested type V3: '%s' pad0:%u type:%x\n",
474 fieldtype
->nesttype_v3
.name
,
475 fieldtype
->nesttype_v3
._pad0
, fieldtype
->nesttype_v3
.type
);
476 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->nesttype_v3
.name
) + 1);
480 printf("\t\tVirtual function table V1: type:%x\n",
481 fieldtype
->vfunctab_v1
.type
);
486 printf("\t\tVirtual function table V2: type:%x\n",
487 fieldtype
->vfunctab_v2
.type
);
492 printf("\t\tVirtual function table offset V1: type:%x offset:%x\n",
493 fieldtype
->vfuncoff_v1
.type
, fieldtype
->vfuncoff_v1
.offset
);
497 printf("\t\tVirtual function table offset V2: type:%x offset:%x\n",
498 fieldtype
->vfuncoff_v2
.type
, fieldtype
->vfuncoff_v2
.offset
);
502 printf(">>> Unsupported field-id %x\n", fieldtype
->generic
.id
);
503 dump_data((const void*)fieldtype
, 0x30, "\t");
509 static void codeview_dump_one_type(unsigned curr_type
, const union codeview_type
* type
)
511 const union codeview_reftype
* reftype
= (const union codeview_reftype
*)type
;
512 int i
, leaf_len
, value
;
516 switch (type
->generic
.id
)
519 printf("\t%x => Pointer V1 to type:%x\n",
520 curr_type
, type
->pointer_v1
.datatype
);
523 printf("\t%x => Pointer V2 to type:%x\n",
524 curr_type
, type
->pointer_v2
.datatype
);
527 leaf_len
= numeric_leaf(&value
, &type
->array_v1
.arrlen
);
528 printf("\t%x => Array V1-'%s'[%u type:%x] type:%x\n",
529 curr_type
, p_string(PSTRING(&type
->array_v1
.arrlen
, leaf_len
)),
530 value
, type
->array_v1
.idxtype
, type
->array_v1
.elemtype
);
533 leaf_len
= numeric_leaf(&value
, &type
->array_v2
.arrlen
);
534 printf("\t%x => Array V2-'%s'[%u type:%x] type:%x\n",
535 curr_type
, p_string(PSTRING(&type
->array_v2
.arrlen
, leaf_len
)),
536 value
, type
->array_v2
.idxtype
, type
->array_v2
.elemtype
);
539 leaf_len
= numeric_leaf(&value
, &type
->array_v3
.arrlen
);
540 str
= (const char*)&type
->array_v3
.arrlen
+ leaf_len
;
541 printf("\t%x => Array V3-'%s'[%u type:%x] type:%x\n",
542 curr_type
, str
, value
,
543 type
->array_v3
.idxtype
, type
->array_v3
.elemtype
);
546 /* a bitfields is a CodeView specific data type which represent a bitfield
547 * in a structure or a class. For now, we store it in a SymTag-like type
548 * (so that the rest of the process is seamless), but check at udt inclusion
549 * type for its presence
552 printf("\t%x => Bitfield V1:%x offset:%u #bits:%u\n",
553 curr_type
, reftype
->bitfield_v1
.type
, reftype
->bitfield_v1
.bitoff
,
554 reftype
->bitfield_v1
.nbits
);
558 printf("\t%x => Bitfield V2:%x offset:%u #bits:%u\n",
559 curr_type
, reftype
->bitfield_v2
.type
, reftype
->bitfield_v2
.bitoff
,
560 reftype
->bitfield_v2
.nbits
);
563 case LF_FIELDLIST_V1
:
564 case LF_FIELDLIST_V2
:
565 printf("\t%x => Fieldlist\n", curr_type
);
566 do_field(reftype
->fieldlist
.list
, (const BYTE
*)type
+ reftype
->generic
.len
+ 2);
569 case LF_STRUCTURE_V1
:
571 leaf_len
= numeric_leaf(&value
, &type
->struct_v1
.structlen
);
572 printf("\t%x => %s V1 '%s' elts:%u prop:%u fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
573 curr_type
, type
->generic
.id
== LF_CLASS_V1
? "Class" : "Struct",
574 p_string(PSTRING(&type
->struct_v1
.structlen
, leaf_len
)),
575 type
->struct_v1
.n_element
, type
->struct_v1
.property
,
576 type
->struct_v1
.fieldlist
, type
->struct_v1
.derived
,
577 type
->struct_v1
.vshape
, value
);
580 case LF_STRUCTURE_V2
:
582 leaf_len
= numeric_leaf(&value
, &type
->struct_v2
.structlen
);
583 printf("\t%x => %s V2 '%s' elts:%u prop:%u\n"
584 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
585 curr_type
, type
->generic
.id
== LF_CLASS_V2
? "Class" : "Struct",
586 p_string(PSTRING(&type
->struct_v2
.structlen
, leaf_len
)),
587 type
->struct_v2
.n_element
, type
->struct_v2
.property
,
588 type
->struct_v2
.fieldlist
, type
->struct_v2
.derived
,
589 type
->struct_v2
.vshape
, value
);
592 case LF_STRUCTURE_V3
:
594 leaf_len
= numeric_leaf(&value
, &type
->struct_v3
.structlen
);
595 str
= (const char*)&type
->struct_v3
.structlen
+ leaf_len
;
596 printf("\t%x => %s V3 '%s' elts:%u prop:%u\n"
597 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
598 curr_type
, type
->generic
.id
== LF_CLASS_V3
? "Class" : "Struct",
599 str
, type
->struct_v3
.n_element
, type
->struct_v3
.property
,
600 type
->struct_v3
.fieldlist
, type
->struct_v3
.derived
,
601 type
->struct_v3
.vshape
, value
);
605 leaf_len
= numeric_leaf(&value
, &type
->union_v1
.un_len
);
606 printf("\t%x => Union V1 '%s' count:%u prop:%u fieldlist-type:%x size:%u\n",
607 curr_type
, p_string(PSTRING(&type
->union_v1
.un_len
, leaf_len
)),
608 type
->union_v1
.count
, type
->union_v1
.property
,
609 type
->union_v1
.fieldlist
, value
);
613 leaf_len
= numeric_leaf(&value
, &type
->union_v2
.un_len
);
614 printf("\t%x => Union V2 '%s' count:%u prop:%u fieldlist-type:%x size:%u\n",
615 curr_type
, p_string(PSTRING(&type
->union_v2
.un_len
, leaf_len
)),
616 type
->union_v2
.count
, type
->union_v2
.property
,
617 type
->union_v2
.fieldlist
, value
);
621 leaf_len
= numeric_leaf(&value
, &type
->union_v3
.un_len
);
622 str
= (const char*)&type
->union_v3
.un_len
+ leaf_len
;
623 printf("\t%x => Union V3 '%s' count:%u prop:%u fieldlist-type:%x size:%u\n",
624 curr_type
, str
, type
->union_v3
.count
,
625 type
->union_v3
.property
, type
->union_v3
.fieldlist
, value
);
629 printf("\t%x => Enum V1 '%s' type:%x field-type:%x count:%u property:%x\n",
630 curr_type
, p_string(&type
->enumeration_v1
.p_name
),
631 type
->enumeration_v1
.type
,
632 type
->enumeration_v1
.fieldlist
,
633 type
->enumeration_v1
.count
,
634 type
->enumeration_v1
.property
);
638 printf("\t%x => Enum V2 '%s' type:%x field-type:%x count:%u property:%x\n",
639 curr_type
, p_string(&type
->enumeration_v2
.p_name
),
640 type
->enumeration_v2
.type
,
641 type
->enumeration_v2
.fieldlist
,
642 type
->enumeration_v2
.count
,
643 type
->enumeration_v2
.property
);
647 printf("\t%x => Enum V3 '%s' type:%x field-type:%x count:%u property:%x\n",
648 curr_type
, type
->enumeration_v3
.name
,
649 type
->enumeration_v3
.type
,
650 type
->enumeration_v3
.fieldlist
,
651 type
->enumeration_v3
.count
,
652 type
->enumeration_v3
.property
);
656 printf("\t%x => Arglist V1(#%u):", curr_type
, reftype
->arglist_v1
.num
);
657 for (i
= 0; i
< reftype
->arglist_v1
.num
; i
++)
659 printf(" %x", reftype
->arglist_v1
.args
[i
]);
665 printf("\t%x => Arglist V2(#%u):", curr_type
, reftype
->arglist_v2
.num
);
666 for (j
= 0; j
< reftype
->arglist_v2
.num
; j
++)
668 printf("\t %x", reftype
->arglist_v2
.args
[j
]);
673 case LF_PROCEDURE_V1
:
674 /* FIXME: unknown could be the calling convention for the proc */
675 printf("\t%x => Procedure V1 ret_type:%x call:%x (#%u args_type:%x)\n",
676 curr_type
, type
->procedure_v1
.rvtype
,
677 type
->procedure_v1
.call
, type
->procedure_v1
.params
,
678 type
->procedure_v1
.arglist
);
681 case LF_PROCEDURE_V2
:
682 printf("\t%x => Procedure V2 ret_type:%x unk:%x (#%u args_type:%x)\n",
683 curr_type
, type
->procedure_v2
.rvtype
,
684 type
->procedure_v2
.call
, type
->procedure_v2
.params
,
685 type
->procedure_v2
.arglist
);
688 case LF_MFUNCTION_V2
:
689 printf("\t%x => MFunction V2 ret-type:%x call:%x class-type:%x this-type:%x\n"
690 "\t\t#args:%x args-type:%x this_adjust:%x\n",
692 type
->mfunction_v2
.rvtype
,
693 type
->mfunction_v2
.call
,
694 type
->mfunction_v2
.class_type
,
695 type
->mfunction_v2
.this_type
,
696 type
->mfunction_v2
.params
,
697 type
->mfunction_v2
.arglist
,
698 type
->mfunction_v2
.this_adjust
);
702 printf("\t%x => Modifier V1 type:%x modif:%x\n",
703 curr_type
, type
->modifier_v1
.type
, type
->modifier_v1
.attribute
);
707 printf("\t%x => Modifier V2 type:%x modif:%x\n",
708 curr_type
, type
->modifier_v2
.type
, type
->modifier_v2
.attribute
);
711 case LF_METHODLIST_V1
:
713 const unsigned short* pattr
= (const unsigned short*)((const char*)type
+ 4);
715 printf("\t%x => Method list\n", curr_type
);
716 while ((const char*)pattr
< (const char*)type
+ type
->generic
.len
+ 2)
718 switch ((*pattr
>> 2) & 7)
721 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
722 get_attr(pattr
[0]), pattr
[1],
723 *(const unsigned*)(&pattr
[2]));
727 printf("\t\t\tattr:%s type:%x\n",
728 get_attr(pattr
[0]), pattr
[1]);
735 case LF_METHODLIST_V2
:
737 const unsigned* pattr
= (const unsigned*)((const char*)type
+ 4);
739 printf("\t%x => Method list\n", curr_type
);
740 while ((const char*)pattr
< (const char*)type
+ type
->generic
.len
+ 2)
742 switch ((*pattr
>> 2) & 7)
745 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
746 get_attr(pattr
[0]), pattr
[1], pattr
[2]);
750 printf("\t\t\tattr:%s type:%x\n",
751 get_attr(pattr
[0]), pattr
[1]);
760 int count
= *(const unsigned short*)((const char*)type
+ 4);
762 const char* ptr
= (const char*)type
+ 6;
763 const char* desc
[] = {"Near", "Far", "Thin", "Disp to outtermost",
764 "Pointer to metaclass", "Near32", "Far32"};
765 printf("\t%x => VT Shape #%d: ", curr_type
, count
);
768 if (((*ptr
<< shift
) & 0xF) <= 6)
769 printf("%s ", desc
[(*ptr
<< shift
) & 0xF]);
771 printf("%x ", (*ptr
<< shift
) & 0xF);
772 if (shift
== 0) shift
= 4; else {shift
= 0; ptr
++;}
779 printf("\t%x => Derived V1(#%u):", curr_type
, reftype
->derived_v1
.num
);
780 for (i
= 0; i
< reftype
->derived_v1
.num
; i
++)
782 printf(" %x", reftype
->derived_v1
.drvdcls
[i
]);
788 printf("\t%x => Derived V2(#%u):", curr_type
, reftype
->derived_v2
.num
);
789 for (j
= 0; j
< reftype
->derived_v2
.num
; j
++)
791 printf(" %x", reftype
->derived_v2
.drvdcls
[j
]);
797 printf(">>> Unsupported type-id %x for %x\n", type
->generic
.id
, curr_type
);
798 dump_data((const void*)type
, type
->generic
.len
+ 2, "");
803 int codeview_dump_types_from_offsets(const void* table
, const DWORD
* offsets
, unsigned num_types
)
807 for (i
= 0; i
< num_types
; i
++)
809 codeview_dump_one_type(0x1000 + i
,
810 (const union codeview_type
*)((const char*)table
+ offsets
[i
]));
816 int codeview_dump_types_from_block(const void* table
, unsigned long len
)
818 unsigned int curr_type
= 0x1000;
819 const unsigned char*ptr
= table
;
821 while (ptr
- (const unsigned char*)table
< len
)
823 const union codeview_type
* type
= (const union codeview_type
*)ptr
;
825 codeview_dump_one_type(curr_type
, type
);
827 ptr
+= (type
->generic
.len
+ 2 + 3) & ~3;
833 int codeview_dump_symbols(const void* root
, unsigned long size
)
837 char* curr_func
= NULL
;
840 * Loop over the different types of records and whenever we
841 * find something we are interested in, record it and move on.
843 for (i
= 0; i
< size
; i
+= length
)
845 const union codeview_symbol
* sym
= (const union codeview_symbol
*)((const char*)root
+ i
);
846 length
= sym
->generic
.len
+ 2;
847 if (!sym
->generic
.id
|| length
< 4) break;
848 switch (sym
->generic
.id
)
851 * Global and local data symbols. We don't associate these
852 * with any given source file.
856 printf("\tS-%s-Data V2 '%s' %04x:%08x type:%08x\n",
857 sym
->generic
.id
== S_GDATA_V2
? "Global" : "Local",
858 get_symbol_str(p_string(&sym
->data_v2
.p_name
)),
859 sym
->data_v2
.segment
, sym
->data_v2
.offset
, sym
->data_v2
.symtype
);
864 /* EPP case S_DATA_V3: */
865 printf("\tS-%s-Data V3 '%s' (%04x:%08x) type:%08x\n",
866 sym
->generic
.id
== S_GDATA_V3
? "Global" : "Local",
867 get_symbol_str(sym
->data_v3
.name
),
868 sym
->data_v3
.segment
, sym
->data_v3
.offset
,
869 sym
->data_v3
.symtype
);
873 printf("\tS-Public V2 '%s' %04x:%08x type:%08x\n",
874 get_symbol_str(p_string(&sym
->public_v2
.p_name
)),
875 sym
->public_v2
.segment
, sym
->public_v2
.offset
,
876 sym
->public_v2
.symtype
);
880 /* not completely sure of those two anyway */
883 printf("\tS-Public%s V3 '%s' %04x:%08x type:%08x\n",
884 sym
->generic
.id
== S_PUB_V3
? "" :
885 (sym
->generic
.id
== S_PUB_FUNC1_V3
? "<subkind1" : "<subkind2"),
886 get_symbol_str(sym
->public_v3
.name
),
887 sym
->public_v3
.segment
,
888 sym
->public_v3
.offset
, sym
->public_v3
.symtype
);
892 * Sort of like a global function, but it just points
893 * to a thunk, which is a stupid name for what amounts to
894 * a PLT slot in the normal jargon that everyone else uses.
897 printf("\tS-Thunk V1 '%s' (%04x:%08x#%x) type:%x\n",
898 p_string(&sym
->thunk_v1
.p_name
),
899 sym
->thunk_v1
.segment
, sym
->thunk_v1
.offset
,
900 sym
->thunk_v1
.thunk_len
, sym
->thunk_v1
.thtype
);
901 curr_func
= strdup(p_string(&sym
->thunk_v1
.p_name
));
905 printf("\tS-Thunk V3 '%s' (%04x:%08x#%x) type:%x\n",
907 sym
->thunk_v3
.segment
, sym
->thunk_v3
.offset
,
908 sym
->thunk_v3
.thunk_len
, sym
->thunk_v3
.thtype
);
909 curr_func
= strdup(sym
->thunk_v3
.name
);
912 /* Global and static functions */
915 printf("\tS-%s-Proc V1: '%s' (%04x:%08x#%x) type:%x\n",
916 sym
->generic
.id
== S_GPROC_V1
? "Global" : "-Local",
917 p_string(&sym
->proc_v1
.p_name
),
918 sym
->proc_v1
.segment
, sym
->proc_v1
.offset
,
919 sym
->proc_v1
.proc_len
, sym
->proc_v1
.proctype
);
922 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func
, nest_block
);
925 curr_func
= strdup(p_string(&sym
->proc_v1
.p_name
));
926 /* EPP unsigned int pparent; */
927 /* EPP unsigned int pend; */
928 /* EPP unsigned int next; */
929 /* EPP unsigned int debug_start; */
930 /* EPP unsigned int debug_end; */
931 /* EPP unsigned char flags; */
936 printf("\tS-%s-Proc V2: '%s' (%04x:%08x#%x) type:%x\n",
937 sym
->generic
.id
== S_GPROC_V2
? "Global" : "-Local",
938 p_string(&sym
->proc_v2
.p_name
),
939 sym
->proc_v2
.segment
, sym
->proc_v2
.offset
,
940 sym
->proc_v2
.proc_len
, sym
->proc_v2
.proctype
);
943 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func
, nest_block
);
946 curr_func
= strdup(p_string(&sym
->proc_v2
.p_name
));
947 /* EPP unsigned int pparent; */
948 /* EPP unsigned int pend; */
949 /* EPP unsigned int next; */
950 /* EPP unsigned int debug_start; */
951 /* EPP unsigned int debug_end; */
952 /* EPP unsigned char flags; */
957 printf("\tS-%s-Procedure V3 '%s' (%04x:%08x#%x) type:%x\n",
958 sym
->generic
.id
== S_GPROC_V3
? "Global" : "Local",
960 sym
->proc_v3
.segment
, sym
->proc_v3
.offset
,
961 sym
->proc_v3
.proc_len
, sym
->proc_v3
.proctype
);
964 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func
, nest_block
);
967 curr_func
= strdup(sym
->proc_v3
.name
);
968 /* EPP unsigned int pparent; */
969 /* EPP unsigned int pend; */
970 /* EPP unsigned int next; */
971 /* EPP unsigned int debug_start; */
972 /* EPP unsigned int debug_end; */
973 /* EPP unsigned char flags; */
976 /* Function parameters and stack variables */
978 printf("\tS-BP-relative V1: '%s' @%d type:%x (%s)\n",
979 p_string(&sym
->stack_v1
.p_name
),
980 sym
->stack_v1
.offset
, sym
->stack_v1
.symtype
, curr_func
);
984 printf("\tS-BP-relative V2: '%s' @%d type:%x (%s)\n",
985 p_string(&sym
->stack_v2
.p_name
),
986 sym
->stack_v2
.offset
, sym
->stack_v2
.symtype
, curr_func
);
990 printf("\tS-BP-relative V3: '%s' @%d type:%x (in %s)\n",
991 sym
->stack_v3
.name
, sym
->stack_v3
.offset
,
992 sym
->stack_v3
.symtype
, curr_func
);
995 case S_BPREL_XXXX_V3
:
996 printf("\tS-BP-relative XXXX V3: '%s' @%d type:%x unkn:%x (in %s)\n",
997 sym
->stack_xxxx_v3
.name
, sym
->stack_xxxx_v3
.offset
,
998 sym
->stack_xxxx_v3
.symtype
, sym
->stack_xxxx_v3
.unknown
, curr_func
);
1002 printf("\tS-Register V1 '%s' in %s type:%x register:%x\n",
1003 p_string(&sym
->register_v1
.p_name
),
1004 curr_func
, sym
->register_v1
.reg
, sym
->register_v1
.type
);
1008 printf("\tS-Register V2 '%s' in %s type:%x register:%x\n",
1009 p_string(&sym
->register_v2
.p_name
),
1010 curr_func
, sym
->register_v2
.reg
, sym
->register_v2
.type
);
1014 printf("\tS-Register V3 '%s' in %s type:%x register:%x\n",
1015 sym
->register_v3
.name
,
1016 curr_func
, sym
->register_v3
.reg
, sym
->register_v3
.type
);
1020 printf("\tS-Block V1 '%s' in '%s' (%04x:%08x#%08x)\n",
1021 p_string(&sym
->block_v1
.p_name
),
1023 sym
->block_v1
.segment
, sym
->block_v1
.offset
,
1024 sym
->block_v1
.length
);
1029 printf("\tS-Block V3 '%s' in '%s' (%04x:%08x#%08x) parent:%u end:%x\n",
1030 sym
->block_v3
.name
, curr_func
,
1031 sym
->block_v3
.segment
, sym
->block_v3
.offset
, sym
->block_v3
.length
,
1032 sym
->block_v3
.parent
, sym
->block_v3
.end
);
1040 printf("\tS-End-Of block (%u)\n", nest_block
);
1044 printf("\tS-End-Of %s\n", curr_func
);
1050 case S_COMPILAND_V1
:
1052 const char* machine
;
1055 switch (sym
->compiland_v1
.unknown
& 0xFF)
1057 case 0x00: machine
= "Intel 8080"; break;
1058 case 0x01: machine
= "Intel 8086"; break;
1059 case 0x02: machine
= "Intel 80286"; break;
1060 case 0x03: machine
= "Intel 80386"; break;
1061 case 0x04: machine
= "Intel 80486"; break;
1062 case 0x05: machine
= "Intel Pentium"; break;
1063 case 0x10: machine
= "MIPS R4000"; break;
1066 static char tmp
[16];
1067 sprintf(tmp
, "machine=%x", sym
->compiland_v1
.unknown
& 0xFF);
1072 switch ((sym
->compiland_v1
.unknown
>> 8) & 0xFF)
1074 case 0x00: lang
= "C"; break;
1075 case 0x01: lang
= "C++"; break;
1076 case 0x02: lang
= "Fortran"; break;
1077 case 0x03: lang
= "Masm"; break;
1078 case 0x04: lang
= "Pascal"; break;
1079 case 0x05: lang
= "Basic"; break;
1080 case 0x06: lang
= "Cobol"; break;
1083 static char tmp
[16];
1084 sprintf(tmp
, "language=%x", (sym
->compiland_v1
.unknown
>> 8) & 0xFF);
1090 printf("\tS-Compiland V1 '%s' %s %s unk:%x\n",
1091 p_string(&sym
->compiland_v1
.p_name
), machine
, lang
,
1092 sym
->compiland_v1
.unknown
>> 16);
1096 case S_COMPILAND_V2
:
1097 printf("\tS-Compiland V2 '%s'\n",
1098 p_string(&sym
->compiland_v2
.p_name
));
1099 dump_data((const void*)sym
, sym
->generic
.len
+ 2, " ");
1101 const char* ptr
= sym
->compiland_v2
.p_name
.name
+ sym
->compiland_v2
.p_name
.namelen
;
1104 printf("\t\t%s => ", ptr
); ptr
+= strlen(ptr
) + 1;
1105 printf("%s\n", ptr
); ptr
+= strlen(ptr
) + 1;
1110 case S_COMPILAND_V3
:
1111 printf("\tS-Compiland V3 '%s' unknown:%x\n",
1112 sym
->compiland_v3
.name
, sym
->compiland_v3
.unknown
);
1116 printf("\tS-ObjName V1 sig:%.4s '%s'\n",
1117 sym
->objname_v1
.signature
, p_string(&sym
->objname_v1
.p_name
));
1121 printf("\tS-Label V1 '%s' in '%s' (%04x:%08x)\n",
1122 p_string(&sym
->label_v1
.p_name
),
1123 curr_func
, sym
->label_v1
.segment
, sym
->label_v1
.offset
);
1127 printf("\tS-Label V3 '%s' in '%s' (%04x:%08x) flag:%x\n",
1128 sym
->label_v3
.name
, curr_func
, sym
->label_v3
.segment
,
1129 sym
->label_v3
.offset
, sym
->label_v3
.flags
);
1136 vlen
= numeric_leaf(&val
, &sym
->constant_v2
.cvalue
);
1137 printf("\tS-Constant V2 '%s' = %u type:%x\n",
1138 p_string(PSTRING(&sym
->constant_v2
.cvalue
, vlen
)),
1139 val
, sym
->constant_v2
.type
);
1147 vlen
= numeric_leaf(&val
, &sym
->constant_v3
.cvalue
);
1148 printf("\tS-Constant V3 '%s' = %u type:%x\n",
1149 (const char*)&sym
->constant_v3
.cvalue
+ vlen
,
1150 val
, sym
->constant_v3
.type
);
1155 printf("\tS-Udt V1 '%s': type:0x%x\n",
1156 p_string(&sym
->udt_v1
.p_name
), sym
->udt_v1
.type
);
1160 printf("\tS-Udt V2 '%s': type:0x%x\n",
1161 p_string(&sym
->udt_v2
.p_name
), sym
->udt_v2
.type
);
1165 printf("\tS-Udt V3 '%s': type:0x%x\n",
1166 sym
->udt_v3
.name
, sym
->udt_v3
.type
);
1169 * These are special, in that they are always followed by an
1170 * additional length-prefixed string which is *not* included
1171 * into the symbol length count. We need to skip it.
1174 printf("\tS-Procref V1 "); goto doaref
;
1176 printf("\tS-Dataref V1 "); goto doaref
;
1178 printf("\tS-L-Procref V1 "); goto doaref
;
1181 const struct p_string
* pname
;
1183 pname
= PSTRING(sym
, length
);
1184 length
+= (pname
->namelen
+ 1 + 3) & ~3;
1185 printf("\t%08x %08x %08x '%s'\n",
1186 *(((const DWORD
*)sym
) + 1), *(((const DWORD
*)sym
) + 2), *(((const DWORD
*)sym
) + 3),
1190 case S_MSTOOL_V3
: /* info about tool used to create CU */
1192 const unsigned short* ptr
= ((const unsigned short*)sym
) + 2;
1194 const char* x2
= (const char*)&ptr
[9];
1195 /* FIXME: what are all those values for ? */
1196 printf("\tTool V3 ??? %x-%x-%x-%x-%x-%x-%x-%x-%x %s\n",
1197 ptr
[0], ptr
[1], ptr
[2], ptr
[3], ptr
[4], ptr
[5], ptr
[6], ptr
[7],
1199 while (*(x1
= x2
+ strlen(x2
) + 1))
1201 x2
= x1
+ strlen(x1
) + 1;
1203 printf("\t\t%s: %s\n", x1
, x2
);
1209 /* simply skip it */
1213 printf("\tSSearch V1: (%04x:%08x)\n",
1214 sym
->ssearch_v1
.segment
, sym
->ssearch_v1
.offset
);
1218 printf(">>> Unsupported symbol-id %x sz=%d\n", sym
->generic
.id
, sym
->generic
.len
+ 2);
1219 dump_data((const void*)sym
, sym
->generic
.len
+ 2, " ");