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';
63 long long unsigned llu;
66 static int full_numeric_leaf(union full_value* fv, const unsigned short int* leaf)
68 unsigned short int type = *leaf++;
71 if (type < LF_NUMERIC)
81 fv->i = *(const char*)leaf;
86 fv->i = *(const short*)leaf;
91 fv->i = *(const unsigned short*)leaf;
96 fv->i = *(const int*)leaf;
101 fv->i = *(const unsigned int*)leaf;
106 fv->llu = *(const long long int*)leaf;
111 fv->llu = *(const long long unsigned int*)leaf;
116 printf(">>> unsupported leaf value %04x\n", type);
117 fv->i = 0; /* FIXME */
122 fv->i = 0; /* FIXME */
123 printf(">>> unsupported leaf value %04x\n", type);
128 fv->i = 0; /* FIXME */
129 printf(">>> unsupported leaf value %04x\n", type);
134 fv->i = 0; /* FIXME */
135 printf(">>> unsupported leaf value %04x\n", type);
140 fv->i = 0; /* FIXME */
141 printf(">>> unsupported leaf value %04x\n", type);
146 fv->i = 0; /* FIXME */
147 printf(">>> unsupported leaf value %04x\n", type);
152 fv->i = 0; /* FIXME */
153 printf(">>> unsupported leaf value %04x\n", type);
158 fv->i = 0; /* FIXME */
159 printf(">>> unsupported leaf value %04x\n", type);
164 fv->i = 0; /* FIXME */
165 printf(">>> unsupported leaf value %04x\n", type);
170 fv->i = 0; /* FIXME */
171 printf(">>> unsupported leaf value %04x\n", type);
175 printf(">>> Unsupported numeric leaf-id %04x\n", type);
183 static int numeric_leaf(int* value, const unsigned short int* leaf)
186 int len = len = full_numeric_leaf(&fv, leaf);
192 static const char* get_attr(unsigned attr)
194 static char tmp[256];
198 case 0: strcpy(tmp, ""); break;
199 case 1: strcpy(tmp, "private "); break;
200 case 2: strcpy(tmp, "protected "); break;
201 case 3: strcpy(tmp, "public "); break;
203 switch ((attr >> 2) & 7)
205 case 0: strcat(tmp, ""); break;
206 case 1: strcat(tmp, "virtual "); break;
207 case 2: strcat(tmp, "static "); break;
208 case 3: strcat(tmp, "friend "); break;
209 case 4: strcat(tmp, "introducing virtual "); break;
210 case 5: strcat(tmp, "pure virtual "); break;
211 case 6: strcat(tmp, "pure introducing virtual "); break;
212 case 7: strcat(tmp, "reserved "); break;
214 if ((attr >> 5) & 1) strcat(tmp, "pseudo ");
215 if ((attr >> 6) & 1) strcat(tmp, "no-inherit ");
216 if ((attr >> 7) & 1) strcat(tmp, "no-construct ");
220 static const char* get_property(unsigned prop)
222 static char tmp[1024];
225 if (!prop) return "none";
226 #define X(s) {if (pos) tmp[pos++] = ';'; strcpy(tmp + pos, s); pos += strlen(s);}
227 if (prop & 0x0001) X("packed");
228 if (prop & 0x0002) X("w/{cd}tor");
229 if (prop & 0x0004) X("w/overloaded-ops");
230 if (prop & 0x0008) X("nested-class");
231 if (prop & 0x0010) X("has-nested-classes");
232 if (prop & 0x0020) X("w/overloaded-assign");
233 if (prop & 0x0040) X("w/casting-methods");
234 if (prop & 0x0080) X("forward");
235 if (prop & 0x0100) X("scoped");
238 if (prop & ~0x01FF) pos += sprintf(tmp, "unk%x", prop & ~0x01FF);
239 else tmp[pos] = '\0';
240 assert(pos < sizeof(tmp));
245 static void do_field(const unsigned char* start, const unsigned char* end)
248 * A 'field list' is a CodeView-specific data type which doesn't
249 * directly correspond to any high-level data type. It is used
250 * to hold the collection of members of a struct, class, union
251 * or enum type. The actual definition of that type will follow
252 * later, and refer to the field list definition record.
254 * As we don't have a field list type ourselves, we look ahead
255 * in the field list to try to find out whether this field list
256 * will be used for an enum or struct type, and create a dummy
257 * type of the corresponding sort. Later on, the definition of
258 * the 'real' type will copy the member / enumeration data.
260 const unsigned char* ptr = start;
262 const struct p_string* pstr;
267 const union codeview_fieldtype* fieldtype = (const union codeview_fieldtype*)ptr;
269 if (*ptr >= 0xf0) /* LF_PAD... */
275 switch (fieldtype->generic.id)
277 case LF_ENUMERATE_V1:
278 leaf_len = numeric_leaf(&value, &fieldtype->enumerate_v1.value);
279 pstr = PSTRING(&fieldtype->enumerate_v1.value, leaf_len);
280 printf("\t\tEnumerate V1: '%s' value:%d\n",
281 p_string(pstr), value);
282 ptr += 2 + 2 + leaf_len + 1 + pstr->namelen;
285 case LF_ENUMERATE_V3:
286 leaf_len = numeric_leaf(&value, &fieldtype->enumerate_v3.value);
287 cstr = (const char*)&fieldtype->enumerate_v3.value + leaf_len;
288 printf("\t\tEnumerate V3: '%s' value:%d\n",
290 ptr += 2 + 2 + leaf_len + strlen(cstr) + 1;
294 leaf_len = numeric_leaf(&value, &fieldtype->member_v1.offset);
295 pstr = PSTRING(&fieldtype->member_v1.offset, leaf_len);
296 printf("\t\tMember V1: '%s' type:%x attr:%s @%d\n",
297 p_string(pstr), fieldtype->member_v1.type,
298 get_attr(fieldtype->member_v1.attribute), value);
299 ptr += 2 + 2 + 2 + leaf_len + 1 + pstr->namelen;
303 leaf_len = numeric_leaf(&value, &fieldtype->member_v2.offset);
304 pstr = PSTRING(&fieldtype->member_v2.offset, leaf_len);
305 printf("\t\tMember V2: '%s' type:%x attr:%s @%d\n",
306 p_string(pstr), fieldtype->member_v2.type,
307 get_attr(fieldtype->member_v2.attribute), value);
308 ptr += 2 + 2 + 4 + leaf_len + 1 + pstr->namelen;
312 leaf_len = numeric_leaf(&value, &fieldtype->member_v3.offset);
313 cstr = (const char*)&fieldtype->member_v3.offset + leaf_len;
314 printf("\t\tMember V3: '%s' type:%x attr:%s @%d\n",
315 cstr, fieldtype->member_v3.type,
316 get_attr(fieldtype->member_v3.attribute), value);
317 ptr += 2 + 2 + 4 + leaf_len + strlen(cstr) + 1;
320 case LF_ONEMETHOD_V1:
321 switch ((fieldtype->onemethod_v1.attribute >> 2) & 7)
324 printf("\t\tVirtual-method V1: '%s' attr:%s type:%x vtable_offset:%u\n",
325 p_string(&fieldtype->onemethod_virt_v1.p_name),
326 get_attr(fieldtype->onemethod_virt_v1.attribute),
327 fieldtype->onemethod_virt_v1.type,
328 fieldtype->onemethod_virt_v1.vtab_offset);
329 ptr += 2 + 2 + 2 + 4 + (1 + fieldtype->onemethod_virt_v1.p_name.namelen);
333 printf("\t\tMethod V1: '%s' attr:%s type:%x\n",
334 p_string(&fieldtype->onemethod_v1.p_name),
335 get_attr(fieldtype->onemethod_v1.attribute),
336 fieldtype->onemethod_v1.type);
337 ptr += 2 + 2 + 2 + (1 + fieldtype->onemethod_v1.p_name.namelen);
342 case LF_ONEMETHOD_V2:
343 switch ((fieldtype->onemethod_v2.attribute >> 2) & 7)
346 printf("\t\tVirtual-method V2: '%s' attr:%s type:%x vtable_offset:%u\n",
347 p_string(&fieldtype->onemethod_virt_v2.p_name),
348 get_attr(fieldtype->onemethod_virt_v2.attribute),
349 fieldtype->onemethod_virt_v2.type,
350 fieldtype->onemethod_virt_v2.vtab_offset);
351 ptr += 2 + 2 + 4 + 4 + (1 + fieldtype->onemethod_virt_v2.p_name.namelen);
355 printf("\t\tMethod V2: '%s' attr:%s type:%x\n",
356 p_string(&fieldtype->onemethod_v2.p_name),
357 get_attr(fieldtype->onemethod_v2.attribute),
358 fieldtype->onemethod_v2.type);
359 ptr += 2 + 2 + 4 + (1 + fieldtype->onemethod_v2.p_name.namelen);
364 case LF_ONEMETHOD_V3:
365 switch ((fieldtype->onemethod_v3.attribute >> 2) & 7)
368 printf("\t\tVirtual-method V3: '%s' attr:%s type:%x vtable_offset:%u\n",
369 fieldtype->onemethod_virt_v3.name,
370 get_attr(fieldtype->onemethod_virt_v3.attribute),
371 fieldtype->onemethod_virt_v3.type,
372 fieldtype->onemethod_virt_v3.vtab_offset);
373 ptr += 2 + 2 + 4 + 4 + (strlen(fieldtype->onemethod_virt_v3.name) + 1);
377 printf("\t\tMethod V3: '%s' attr:%s type:%x\n",
378 fieldtype->onemethod_v3.name,
379 get_attr(fieldtype->onemethod_v3.attribute),
380 fieldtype->onemethod_v3.type);
381 ptr += 2 + 2 + 4 + (strlen(fieldtype->onemethod_v3.name) + 1);
387 printf("\t\tMethod V1: '%s' overloaded=#%d method-list=%x\n",
388 p_string(&fieldtype->method_v1.p_name),
389 fieldtype->method_v1.count, fieldtype->method_v1.mlist);
390 ptr += 2 + 2 + 2 + (1 + fieldtype->method_v1.p_name.namelen);
394 printf("\t\tMethod V2: '%s' overloaded=#%d method-list=%x\n",
395 p_string(&fieldtype->method_v2.p_name),
396 fieldtype->method_v2.count, fieldtype->method_v2.mlist);
397 ptr += 2 + 2 + 4 + (1 + fieldtype->method_v2.p_name.namelen);
401 printf("\t\tMethod V3: '%s' overloaded=#%d method-list=%x\n",
402 fieldtype->method_v3.name,
403 fieldtype->method_v3.count, fieldtype->method_v3.mlist);
404 ptr += 2 + 2 + 4 + (strlen(fieldtype->method_v3.name) + 1);
408 printf("\t\tStatic member V1: '%s' attr:%s type:%x\n",
409 p_string(&fieldtype->stmember_v1.p_name),
410 get_attr(fieldtype->stmember_v1.attribute),
411 fieldtype->stmember_v1.type);
412 ptr += 2 + 2 + 2 + (1 + fieldtype->stmember_v1.p_name.namelen);
416 printf("\t\tStatic member V2: '%s' attr:%s type:%x\n",
417 p_string(&fieldtype->stmember_v2.p_name),
418 get_attr(fieldtype->stmember_v2.attribute),
419 fieldtype->stmember_v2.type);
420 ptr += 2 + 2 + 4 + (1 + fieldtype->stmember_v2.p_name.namelen);
424 printf("\t\tStatic member V3: '%s' attr:%s type:%x\n",
425 fieldtype->stmember_v3.name,
426 get_attr(fieldtype->stmember_v3.attribute),
427 fieldtype->stmember_v3.type);
428 ptr += 2 + 2 + 4 + (strlen(fieldtype->stmember_v3.name) + 1);
431 case LF_FRIENDFCN_V1:
432 printf("\t\tFriend function V1: '%s' type:%x\n",
433 p_string(&fieldtype->friendfcn_v1.p_name),
434 fieldtype->friendfcn_v1.type);
437 case LF_FRIENDFCN_V2:
438 printf("\t\tFriend function V2: '%s' type:%x\n",
439 p_string(&fieldtype->friendfcn_v2.p_name),
440 fieldtype->friendfcn_v2.type);
444 case LF_FRIENDFCN_V3:
445 printf("\t\tFriend function V3: '%s' type:%x\n",
446 fieldtype->friendfcn_v3.name,
447 fieldtype->friendfcn_v3.type);
452 leaf_len = numeric_leaf(&value, &fieldtype->bclass_v1.offset);
453 printf("\t\tBase class V1: type:%x attr:%s @%d\n",
454 fieldtype->bclass_v1.type,
455 get_attr(fieldtype->bclass_v1.attribute), value);
456 ptr += 2 + 2 + 2 + leaf_len;
460 leaf_len = numeric_leaf(&value, &fieldtype->bclass_v2.offset);
461 printf("\t\tBase class V2: type:%x attr:%s @%d\n",
462 fieldtype->bclass_v2.type,
463 get_attr(fieldtype->bclass_v2.attribute), value);
464 ptr += 2 + 2 + 4 + leaf_len;
469 leaf_len = numeric_leaf(&value, &fieldtype->vbclass_v1.vbpoff);
470 printf("\t\t%sirtual base class V1: type:%x (ptr:%x) attr:%s vbpoff:%d ",
471 (fieldtype->generic.id == LF_VBCLASS_V2) ? "V" : "Indirect v",
472 fieldtype->vbclass_v1.btype, fieldtype->vbclass_v1.vbtype,
473 get_attr(fieldtype->vbclass_v1.attribute), value);
474 ptr += 2 + 2 + 2 + 2 + leaf_len;
475 leaf_len = numeric_leaf(&value, (const unsigned short*)ptr);
476 printf("vboff:%d\n", value);
482 leaf_len = numeric_leaf(&value, &fieldtype->vbclass_v1.vbpoff);
483 printf("\t\t%sirtual base class V2: type:%x (ptr:%x) attr:%s vbpoff:%d ",
484 (fieldtype->generic.id == LF_VBCLASS_V2) ? "V" : "Indirect v",
485 fieldtype->vbclass_v2.btype, fieldtype->vbclass_v2.vbtype,
486 get_attr(fieldtype->vbclass_v2.attribute), value);
487 ptr += 2 + 2 + 4 + 4 + leaf_len;
488 leaf_len = numeric_leaf(&value, (const unsigned short*)ptr);
489 printf("vboff:%d\n", value);
493 case LF_FRIENDCLS_V1:
494 printf("\t\tFriend class V1: type:%x\n", fieldtype->friendcls_v1.type);
497 case LF_FRIENDCLS_V2:
498 printf("\t\tFriend class V2: type:%x\n", fieldtype->friendcls_v2.type);
502 printf("\t\tNested type V1: '%s' type:%x\n",
503 p_string(&fieldtype->nesttype_v1.p_name),
504 fieldtype->nesttype_v1.type);
505 ptr += 2 + 2 + (1 + fieldtype->nesttype_v1.p_name.namelen);
509 printf("\t\tNested type V2: '%s' pad0:%u type:%x\n",
510 p_string(&fieldtype->nesttype_v2.p_name),
511 fieldtype->nesttype_v2._pad0, fieldtype->nesttype_v2.type);
512 ptr += 2 + 2 + 4 + (1 + fieldtype->nesttype_v2.p_name.namelen);
516 printf("\t\tNested type V3: '%s' pad0:%u type:%x\n",
517 fieldtype->nesttype_v3.name,
518 fieldtype->nesttype_v3._pad0, fieldtype->nesttype_v3.type);
519 ptr += 2 + 2 + 4 + (strlen(fieldtype->nesttype_v3.name) + 1);
523 printf("\t\tVirtual function table V1: type:%x\n",
524 fieldtype->vfunctab_v1.type);
529 printf("\t\tVirtual function table V2: type:%x\n",
530 fieldtype->vfunctab_v2.type);
535 printf("\t\tVirtual function table offset V1: type:%x offset:%x\n",
536 fieldtype->vfuncoff_v1.type, fieldtype->vfuncoff_v1.offset);
540 printf("\t\tVirtual function table offset V2: type:%x offset:%x\n",
541 fieldtype->vfuncoff_v2.type, fieldtype->vfuncoff_v2.offset);
545 printf(">>> Unsupported field-id %x\n", fieldtype->generic.id);
546 dump_data((const void*)fieldtype, 0x30, "\t");
552 static void codeview_dump_one_type(unsigned curr_type, const union codeview_type* type)
554 const union codeview_reftype* reftype = (const union codeview_reftype*)type;
555 int i, leaf_len, value;
559 switch (type->generic.id)
562 printf("\t%x => Pointer V1 to type:%x\n",
563 curr_type, type->pointer_v1.datatype);
566 printf("\t%x => Pointer V2 to type:%x\n",
567 curr_type, type->pointer_v2.datatype);
570 leaf_len = numeric_leaf(&value, &type->array_v1.arrlen);
571 printf("\t%x => Array V1-'%s'[%u type:%x] type:%x\n",
572 curr_type, p_string(PSTRING(&type->array_v1.arrlen, leaf_len)),
573 value, type->array_v1.idxtype, type->array_v1.elemtype);
576 leaf_len = numeric_leaf(&value, &type->array_v2.arrlen);
577 printf("\t%x => Array V2-'%s'[%u type:%x] type:%x\n",
578 curr_type, p_string(PSTRING(&type->array_v2.arrlen, leaf_len)),
579 value, type->array_v2.idxtype, type->array_v2.elemtype);
582 leaf_len = numeric_leaf(&value, &type->array_v3.arrlen);
583 str = (const char*)&type->array_v3.arrlen + leaf_len;
584 printf("\t%x => Array V3-'%s'[%u type:%x] type:%x\n",
585 curr_type, str, value,
586 type->array_v3.idxtype, type->array_v3.elemtype);
589 /* a bitfields is a CodeView specific data type which represent a bitfield
590 * in a structure or a class. For now, we store it in a SymTag-like type
591 * (so that the rest of the process is seamless), but check at udt inclusion
592 * type for its presence
595 printf("\t%x => Bitfield V1:%x offset:%u #bits:%u\n",
596 curr_type, reftype->bitfield_v1.type, reftype->bitfield_v1.bitoff,
597 reftype->bitfield_v1.nbits);
601 printf("\t%x => Bitfield V2:%x offset:%u #bits:%u\n",
602 curr_type, reftype->bitfield_v2.type, reftype->bitfield_v2.bitoff,
603 reftype->bitfield_v2.nbits);
606 case LF_FIELDLIST_V1:
607 case LF_FIELDLIST_V2:
608 printf("\t%x => Fieldlist\n", curr_type);
609 do_field(reftype->fieldlist.list, (const BYTE*)type + reftype->generic.len + 2);
612 case LF_STRUCTURE_V1:
614 leaf_len = numeric_leaf(&value, &type->struct_v1.structlen);
615 printf("\t%x => %s V1 '%s' elts:%u property:%s fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
616 curr_type, type->generic.id == LF_CLASS_V1 ? "Class" : "Struct",
617 p_string(PSTRING(&type->struct_v1.structlen, leaf_len)),
618 type->struct_v1.n_element, get_property(type->struct_v1.property),
619 type->struct_v1.fieldlist, type->struct_v1.derived,
620 type->struct_v1.vshape, value);
623 case LF_STRUCTURE_V2:
625 leaf_len = numeric_leaf(&value, &type->struct_v2.structlen);
626 printf("\t%x => %s V2 '%s' elts:%u property:%s\n"
627 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
628 curr_type, type->generic.id == LF_CLASS_V2 ? "Class" : "Struct",
629 p_string(PSTRING(&type->struct_v2.structlen, leaf_len)),
630 type->struct_v2.n_element, get_property(type->struct_v2.property),
631 type->struct_v2.fieldlist, type->struct_v2.derived,
632 type->struct_v2.vshape, value);
635 case LF_STRUCTURE_V3:
637 leaf_len = numeric_leaf(&value, &type->struct_v3.structlen);
638 str = (const char*)&type->struct_v3.structlen + leaf_len;
639 printf("\t%x => %s V3 '%s' elts:%u property:%s\n"
640 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
641 curr_type, type->generic.id == LF_CLASS_V3 ? "Class" : "Struct",
642 str, type->struct_v3.n_element, get_property(type->struct_v3.property),
643 type->struct_v3.fieldlist, type->struct_v3.derived,
644 type->struct_v3.vshape, value);
648 leaf_len = numeric_leaf(&value, &type->union_v1.un_len);
649 printf("\t%x => Union V1 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
650 curr_type, p_string(PSTRING(&type->union_v1.un_len, leaf_len)),
651 type->union_v1.count, get_property(type->union_v1.property),
652 type->union_v1.fieldlist, value);
656 leaf_len = numeric_leaf(&value, &type->union_v2.un_len);
657 printf("\t%x => Union V2 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
658 curr_type, p_string(PSTRING(&type->union_v2.un_len, leaf_len)),
659 type->union_v2.count, get_property(type->union_v2.property),
660 type->union_v2.fieldlist, value);
664 leaf_len = numeric_leaf(&value, &type->union_v3.un_len);
665 str = (const char*)&type->union_v3.un_len + leaf_len;
666 printf("\t%x => Union V3 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
667 curr_type, str, type->union_v3.count,
668 get_property(type->union_v3.property),
669 type->union_v3.fieldlist, value);
673 printf("\t%x => Enum V1 '%s' type:%x field-type:%x count:%u property:%s\n",
674 curr_type, p_string(&type->enumeration_v1.p_name),
675 type->enumeration_v1.type,
676 type->enumeration_v1.fieldlist,
677 type->enumeration_v1.count,
678 get_property(type->enumeration_v1.property));
682 printf("\t%x => Enum V2 '%s' type:%x field-type:%x count:%u property:%s\n",
683 curr_type, p_string(&type->enumeration_v2.p_name),
684 type->enumeration_v2.type,
685 type->enumeration_v2.fieldlist,
686 type->enumeration_v2.count,
687 get_property(type->enumeration_v2.property));
691 printf("\t%x => Enum V3 '%s' type:%x field-type:%x count:%u property:%s\n",
692 curr_type, type->enumeration_v3.name,
693 type->enumeration_v3.type,
694 type->enumeration_v3.fieldlist,
695 type->enumeration_v3.count,
696 get_property(type->enumeration_v3.property));
700 printf("\t%x => Arglist V1(#%u):", curr_type, reftype->arglist_v1.num);
701 for (i = 0; i < reftype->arglist_v1.num; i++)
703 printf(" %x", reftype->arglist_v1.args[i]);
709 printf("\t%x => Arglist V2(#%u):", curr_type, reftype->arglist_v2.num);
710 for (j = 0; j < reftype->arglist_v2.num; j++)
712 printf("\t %x", reftype->arglist_v2.args[j]);
717 case LF_PROCEDURE_V1:
718 /* FIXME: unknown could be the calling convention for the proc */
719 printf("\t%x => Procedure V1 ret_type:%x call:%x (#%u args_type:%x)\n",
720 curr_type, type->procedure_v1.rvtype,
721 type->procedure_v1.call, type->procedure_v1.params,
722 type->procedure_v1.arglist);
725 case LF_PROCEDURE_V2:
726 printf("\t%x => Procedure V2 ret_type:%x unk:%x (#%u args_type:%x)\n",
727 curr_type, type->procedure_v2.rvtype,
728 type->procedure_v2.call, type->procedure_v2.params,
729 type->procedure_v2.arglist);
732 case LF_MFUNCTION_V2:
733 printf("\t%x => MFunction V2 ret-type:%x call:%x class-type:%x this-type:%x\n"
734 "\t\t#args:%x args-type:%x this_adjust:%x\n",
736 type->mfunction_v2.rvtype,
737 type->mfunction_v2.call,
738 type->mfunction_v2.class_type,
739 type->mfunction_v2.this_type,
740 type->mfunction_v2.params,
741 type->mfunction_v2.arglist,
742 type->mfunction_v2.this_adjust);
746 printf("\t%x => Modifier V1 type:%x modif:%x\n",
747 curr_type, type->modifier_v1.type, type->modifier_v1.attribute);
751 printf("\t%x => Modifier V2 type:%x modif:%x\n",
752 curr_type, type->modifier_v2.type, type->modifier_v2.attribute);
755 case LF_METHODLIST_V1:
757 const unsigned short* pattr = (const unsigned short*)((const char*)type + 4);
759 printf("\t%x => Method list\n", curr_type);
760 while ((const char*)pattr < (const char*)type + type->generic.len + 2)
762 switch ((*pattr >> 2) & 7)
765 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
766 get_attr(pattr[0]), pattr[1],
767 *(const unsigned*)(&pattr[2]));
771 printf("\t\t\tattr:%s type:%x\n",
772 get_attr(pattr[0]), pattr[1]);
779 case LF_METHODLIST_V2:
781 const unsigned* pattr = (const unsigned*)((const char*)type + 4);
783 printf("\t%x => Method list\n", curr_type);
784 while ((const char*)pattr < (const char*)type + type->generic.len + 2)
786 switch ((*pattr >> 2) & 7)
789 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
790 get_attr(pattr[0]), pattr[1], pattr[2]);
794 printf("\t\t\tattr:%s type:%x\n",
795 get_attr(pattr[0]), pattr[1]);
804 int count = *(const unsigned short*)((const char*)type + 4);
806 const char* ptr = (const char*)type + 6;
807 const char* desc[] = {"Near", "Far", "Thin", "Disp to outtermost",
808 "Pointer to metaclass", "Near32", "Far32"};
809 printf("\t%x => VT Shape #%d: ", curr_type, count);
812 if (((*ptr << shift) & 0xF) <= 6)
813 printf("%s ", desc[(*ptr << shift) & 0xF]);
815 printf("%x ", (*ptr << shift) & 0xF);
816 if (shift == 0) shift = 4; else {shift = 0; ptr++;}
823 printf("\t%x => Derived V1(#%u):", curr_type, reftype->derived_v1.num);
824 for (i = 0; i < reftype->derived_v1.num; i++)
826 printf(" %x", reftype->derived_v1.drvdcls[i]);
832 printf("\t%x => Derived V2(#%u):", curr_type, reftype->derived_v2.num);
833 for (j = 0; j < reftype->derived_v2.num; j++)
835 printf(" %x", reftype->derived_v2.drvdcls[j]);
841 printf(">>> Unsupported type-id %x for %x\n", type->generic.id, curr_type);
842 dump_data((const void*)type, type->generic.len + 2, "");
847 int codeview_dump_types_from_offsets(const void* table, const DWORD* offsets, unsigned num_types)
851 for (i = 0; i < num_types; i++)
853 codeview_dump_one_type(0x1000 + i,
854 (const union codeview_type*)((const char*)table + offsets[i]));
860 int codeview_dump_types_from_block(const void* table, unsigned long len)
862 unsigned int curr_type = 0x1000;
863 const unsigned char*ptr = table;
865 while (ptr - (const unsigned char*)table < len)
867 const union codeview_type* type = (const union codeview_type*)ptr;
869 codeview_dump_one_type(curr_type, type);
871 ptr += (type->generic.len + 2 + 3) & ~3;
877 int codeview_dump_symbols(const void* root, unsigned long size)
881 char* curr_func = NULL;
884 * Loop over the different types of records and whenever we
885 * find something we are interested in, record it and move on.
887 for (i = 0; i < size; i += length)
889 const union codeview_symbol* sym = (const union codeview_symbol*)((const char*)root + i);
890 length = sym->generic.len + 2;
891 if (!sym->generic.id || length < 4) break;
892 switch (sym->generic.id)
895 * Global and local data symbols. We don't associate these
896 * with any given source file.
900 printf("\tS-%s-Data V2 '%s' %04x:%08x type:%08x\n",
901 sym->generic.id == S_GDATA_V2 ? "Global" : "Local",
902 get_symbol_str(p_string(&sym->data_v2.p_name)),
903 sym->data_v2.segment, sym->data_v2.offset, sym->data_v2.symtype);
908 /* EPP case S_DATA_V3: */
909 printf("\tS-%s-Data V3 '%s' (%04x:%08x) type:%08x\n",
910 sym->generic.id == S_GDATA_V3 ? "Global" : "Local",
911 get_symbol_str(sym->data_v3.name),
912 sym->data_v3.segment, sym->data_v3.offset,
913 sym->data_v3.symtype);
917 printf("\tS-Public V2 '%s' %04x:%08x type:%08x\n",
918 get_symbol_str(p_string(&sym->public_v2.p_name)),
919 sym->public_v2.segment, sym->public_v2.offset,
920 sym->public_v2.symtype);
924 /* not completely sure of those two anyway */
927 printf("\tS-Public%s V3 '%s' %04x:%08x type:%08x\n",
928 sym->generic.id == S_PUB_V3 ? "" :
929 (sym->generic.id == S_PUB_FUNC1_V3 ? "<subkind1" : "<subkind2"),
930 get_symbol_str(sym->public_v3.name),
931 sym->public_v3.segment,
932 sym->public_v3.offset, sym->public_v3.symtype);
936 * Sort of like a global function, but it just points
937 * to a thunk, which is a stupid name for what amounts to
938 * a PLT slot in the normal jargon that everyone else uses.
941 printf("\tS-Thunk V1 '%s' (%04x:%08x#%x) type:%x\n",
942 p_string(&sym->thunk_v1.p_name),
943 sym->thunk_v1.segment, sym->thunk_v1.offset,
944 sym->thunk_v1.thunk_len, sym->thunk_v1.thtype);
945 curr_func = strdup(p_string(&sym->thunk_v1.p_name));
949 printf("\tS-Thunk V3 '%s' (%04x:%08x#%x) type:%x\n",
951 sym->thunk_v3.segment, sym->thunk_v3.offset,
952 sym->thunk_v3.thunk_len, sym->thunk_v3.thtype);
953 curr_func = strdup(sym->thunk_v3.name);
956 /* Global and static functions */
959 printf("\tS-%s-Proc V1: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
960 sym->generic.id == S_GPROC_V1 ? "Global" : "-Local",
961 p_string(&sym->proc_v1.p_name),
962 sym->proc_v1.segment, sym->proc_v1.offset,
963 sym->proc_v1.proc_len, sym->proc_v1.proctype,
965 printf("\t Debug: start=%08x end=%08x\n",
966 sym->proc_v1.debug_start, sym->proc_v1.debug_end);
969 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
972 curr_func = strdup(p_string(&sym->proc_v1.p_name));
973 /* EPP unsigned int pparent; */
974 /* EPP unsigned int pend; */
975 /* EPP unsigned int next; */
980 printf("\tS-%s-Proc V2: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
981 sym->generic.id == S_GPROC_V2 ? "Global" : "-Local",
982 p_string(&sym->proc_v2.p_name),
983 sym->proc_v2.segment, sym->proc_v2.offset,
984 sym->proc_v2.proc_len, sym->proc_v2.proctype,
986 printf("\t Debug: start=%08x end=%08x\n",
987 sym->proc_v2.debug_start, sym->proc_v2.debug_end);
990 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
993 curr_func = strdup(p_string(&sym->proc_v2.p_name));
994 /* EPP unsigned int pparent; */
995 /* EPP unsigned int pend; */
996 /* EPP unsigned int next; */
1001 printf("\tS-%s-Procedure V3 '%s' (%04x:%08x#%x) type:%x attr:%x\n",
1002 sym->generic.id == S_GPROC_V3 ? "Global" : "Local",
1004 sym->proc_v3.segment, sym->proc_v3.offset,
1005 sym->proc_v3.proc_len, sym->proc_v3.proctype,
1006 sym->proc_v3.flags);
1007 printf("\t Debug: start=%08x end=%08x\n",
1008 sym->proc_v3.debug_start, sym->proc_v3.debug_end);
1011 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
1014 curr_func = strdup(sym->proc_v3.name);
1015 /* EPP unsigned int pparent; */
1016 /* EPP unsigned int pend; */
1017 /* EPP unsigned int next; */
1020 /* Function parameters and stack variables */
1022 printf("\tS-BP-relative V1: '%s' @%d type:%x (%s)\n",
1023 p_string(&sym->stack_v1.p_name),
1024 sym->stack_v1.offset, sym->stack_v1.symtype, curr_func);
1028 printf("\tS-BP-relative V2: '%s' @%d type:%x (%s)\n",
1029 p_string(&sym->stack_v2.p_name),
1030 sym->stack_v2.offset, sym->stack_v2.symtype, curr_func);
1034 printf("\tS-BP-relative V3: '%s' @%d type:%x (in %s)\n",
1035 sym->stack_v3.name, sym->stack_v3.offset,
1036 sym->stack_v3.symtype, curr_func);
1039 case S_BPREL_XXXX_V3:
1040 printf("\tS-BP-relative XXXX V3: '%s' @%d type:%x unkn:%x (in %s)\n",
1041 sym->stack_xxxx_v3.name, sym->stack_xxxx_v3.offset,
1042 sym->stack_xxxx_v3.symtype, sym->stack_xxxx_v3.unknown, curr_func);
1046 printf("\tS-Register V1 '%s' in %s type:%x register:%x\n",
1047 p_string(&sym->register_v1.p_name),
1048 curr_func, sym->register_v1.reg, sym->register_v1.type);
1052 printf("\tS-Register V2 '%s' in %s type:%x register:%x\n",
1053 p_string(&sym->register_v2.p_name),
1054 curr_func, sym->register_v2.reg, sym->register_v2.type);
1058 printf("\tS-Register V3 '%s' in %s type:%x register:%x\n",
1059 sym->register_v3.name,
1060 curr_func, sym->register_v3.reg, sym->register_v3.type);
1064 printf("\tS-Block V1 '%s' in '%s' (%04x:%08x#%08x)\n",
1065 p_string(&sym->block_v1.p_name),
1067 sym->block_v1.segment, sym->block_v1.offset,
1068 sym->block_v1.length);
1073 printf("\tS-Block V3 '%s' in '%s' (%04x:%08x#%08x) parent:%u end:%x\n",
1074 sym->block_v3.name, curr_func,
1075 sym->block_v3.segment, sym->block_v3.offset, sym->block_v3.length,
1076 sym->block_v3.parent, sym->block_v3.end);
1080 /* Additional function information */
1082 printf("\tFunction info V2 unk1:%x unk2:%x unk3:%x unk4:%x unk5:%x unk6:%x flags:%04x unk7:%x\n",
1083 sym->func_info_v2.unknown1,
1084 sym->func_info_v2.unknown2,
1085 sym->func_info_v2.unknown3,
1086 sym->func_info_v2.unknown4,
1087 sym->func_info_v2.unknown5,
1088 sym->func_info_v2.unknown6,
1089 sym->func_info_v2.flags,
1090 sym->func_info_v2.unknown7);
1093 case S_SECUCOOKIE_V3:
1094 printf("\tSecurity Cookie V3 @%d unk:%x\n",
1095 sym->security_cookie_v3.offset, sym->security_cookie_v3.unknown);
1102 printf("\tS-End-Of block (%u)\n", nest_block);
1106 printf("\tS-End-Of %s\n", curr_func);
1112 case S_COMPILAND_V1:
1114 const char* machine;
1117 switch (sym->compiland_v1.unknown & 0xFF)
1119 case 0x00: machine = "Intel 8080"; break;
1120 case 0x01: machine = "Intel 8086"; break;
1121 case 0x02: machine = "Intel 80286"; break;
1122 case 0x03: machine = "Intel 80386"; break;
1123 case 0x04: machine = "Intel 80486"; break;
1124 case 0x05: machine = "Intel Pentium"; break;
1125 case 0x10: machine = "MIPS R4000"; break;
1128 static char tmp[16];
1129 sprintf(tmp, "machine=%x", sym->compiland_v1.unknown & 0xFF);
1134 switch ((sym->compiland_v1.unknown >> 8) & 0xFF)
1136 case 0x00: lang = "C"; break;
1137 case 0x01: lang = "C++"; break;
1138 case 0x02: lang = "Fortran"; break;
1139 case 0x03: lang = "Masm"; break;
1140 case 0x04: lang = "Pascal"; break;
1141 case 0x05: lang = "Basic"; break;
1142 case 0x06: lang = "Cobol"; break;
1145 static char tmp[16];
1146 sprintf(tmp, "language=%x", (sym->compiland_v1.unknown >> 8) & 0xFF);
1152 printf("\tS-Compiland V1 '%s' %s %s unk:%x\n",
1153 p_string(&sym->compiland_v1.p_name), machine, lang,
1154 sym->compiland_v1.unknown >> 16);
1158 case S_COMPILAND_V2:
1159 printf("\tS-Compiland V2 '%s'\n",
1160 p_string(&sym->compiland_v2.p_name));
1161 dump_data((const void*)sym, sym->generic.len + 2, " ");
1163 const char* ptr = sym->compiland_v2.p_name.name + sym->compiland_v2.p_name.namelen;
1166 printf("\t\t%s => ", ptr); ptr += strlen(ptr) + 1;
1167 printf("%s\n", ptr); ptr += strlen(ptr) + 1;
1172 case S_COMPILAND_V3:
1173 printf("\tS-Compiland V3 '%s' unknown:%x\n",
1174 sym->compiland_v3.name, sym->compiland_v3.unknown);
1178 printf("\tS-ObjName V1 sig:%.4s '%s'\n",
1179 sym->objname_v1.signature, p_string(&sym->objname_v1.p_name));
1183 printf("\tS-Label V1 '%s' in '%s' (%04x:%08x)\n",
1184 p_string(&sym->label_v1.p_name),
1185 curr_func, sym->label_v1.segment, sym->label_v1.offset);
1189 printf("\tS-Label V3 '%s' in '%s' (%04x:%08x) flag:%x\n",
1190 sym->label_v3.name, curr_func, sym->label_v3.segment,
1191 sym->label_v3.offset, sym->label_v3.flags);
1197 union full_value fv;
1199 vlen = full_numeric_leaf(&fv, &sym->constant_v2.cvalue);
1200 printf("\tS-Constant V2 '%s' = 0x%x%08x type:%x\n",
1201 p_string(PSTRING(&sym->constant_v2.cvalue, vlen)),
1202 (unsigned)(fv.llu >> 32), (unsigned)fv.llu, sym->constant_v2.type);
1209 union full_value fv;
1211 vlen = full_numeric_leaf(&fv, &sym->constant_v3.cvalue);
1212 printf("\tS-Constant V3 '%s' = 0x%x%08x type:%x\n",
1213 (const char*)&sym->constant_v3.cvalue + vlen,
1214 (unsigned)(fv.llu >> 32), (unsigned)fv.llu, sym->constant_v3.type);
1219 printf("\tS-Udt V1 '%s': type:0x%x\n",
1220 p_string(&sym->udt_v1.p_name), sym->udt_v1.type);
1224 printf("\tS-Udt V2 '%s': type:0x%x\n",
1225 p_string(&sym->udt_v2.p_name), sym->udt_v2.type);
1229 printf("\tS-Udt V3 '%s': type:0x%x\n",
1230 sym->udt_v3.name, sym->udt_v3.type);
1233 * These are special, in that they are always followed by an
1234 * additional length-prefixed string which is *not* included
1235 * into the symbol length count. We need to skip it.
1238 printf("\tS-Procref V1 "); goto doaref;
1240 printf("\tS-Dataref V1 "); goto doaref;
1242 printf("\tS-L-Procref V1 "); goto doaref;
1245 const struct p_string* pname;
1247 pname = PSTRING(sym, length);
1248 length += (pname->namelen + 1 + 3) & ~3;
1249 printf("\t%08x %08x %08x '%s'\n",
1250 *(((const DWORD*)sym) + 1), *(((const DWORD*)sym) + 2), *(((const DWORD*)sym) + 3),
1254 case S_MSTOOL_V3: /* info about tool used to create CU */
1256 const unsigned short* ptr = ((const unsigned short*)sym) + 2;
1258 const char* x2 = (const char*)&ptr[9];
1259 /* FIXME: what are all those values for ? */
1260 printf("\tTool V3 unk=%04x%04x%04x front=%d.%d.%d.0 back=%d.%d.%d.0 %s\n",
1261 ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
1263 while (*(x1 = x2 + strlen(x2) + 1))
1265 x2 = x1 + strlen(x1) + 1;
1267 printf("\t\t%s: %s\n", x1, x2);
1272 case S_MSTOOLINFO_V3:
1274 const unsigned short* ptr = ((const unsigned short*)sym) + 2;
1276 printf("\tTool info V3: unk=%04x%04x%04x front=%d.%d.%d.%d back=%d.%d.%d.%d %s\n",
1277 ptr[0], ptr[1], ptr[2],
1278 ptr[3], ptr[4], ptr[5], ptr[6],
1279 ptr[7], ptr[8], ptr[9], ptr[10],
1280 (const char*)(ptr + 11));
1284 case S_MSTOOLENV_V3:
1286 const char* x1 = (const char*)sym + 4 + 1;
1289 printf("\tTool conf V3\n");
1292 x2 = x1 + strlen(x1) + 1;
1294 printf("\t\t%s: %s\n", x1, x2);
1295 x1 = x2 + strlen(x2) + 1;
1301 /* simply skip it */
1305 printf("\tSSearch V1: (%04x:%08x)\n",
1306 sym->ssearch_v1.segment, sym->ssearch_v1.offset);
1310 printf("\tSSection Info: seg=%04x ?=%04x rva=%08x size=%08x attr=%08x %s\n",
1311 *(unsigned short*)((const char*)sym + 4),
1312 *(unsigned short*)((const char*)sym + 6),
1313 *(unsigned*)((const char*)sym + 8),
1314 *(unsigned*)((const char*)sym + 12),
1315 *(unsigned*)((const char*)sym + 16),
1316 (const char*)sym + 20);
1319 case S_SUBSECTINFO_V3:
1320 printf("\tSSubSection Info: addr=%04x:%08x size=%08x attr=%08x %s\n",
1321 *(unsigned short*)((const char*)sym + 16),
1322 *(unsigned*)((const char*)sym + 12),
1323 *(unsigned*)((const char*)sym + 4),
1324 *(unsigned*)((const char*)sym + 8),
1325 (const char*)sym + 18);
1328 case S_ENTRYPOINT_V3:
1329 printf("\tSEntryPoint: id=%x '%s'\n",
1330 *(unsigned*)((const char*)sym + 4), (const char*)sym + 8);
1334 printf(">>> Unsupported symbol-id %x sz=%d\n", sym->generic.id, sym->generic.len + 2);
1335 dump_data((const void*)sym, sym->generic.len + 2, " ");
1341 void codeview_dump_linetab(const char* linetab, DWORD size, BOOL pascal_str, const char* pfx)
1343 const char* ptr = linetab;
1344 int nfile, nseg, nline;
1346 const unsigned int* filetab;
1347 const unsigned int* lt_ptr;
1348 const struct startend* start;
1350 nfile = *(const short*)linetab;
1351 filetab = (const unsigned int*)(linetab + 2 * sizeof(short));
1352 printf("%s%d files with %d ???\n", pfx, nfile, *(const short*)(linetab + sizeof(short)));
1354 for (i = 0; i < nfile; i++)
1356 ptr = linetab + filetab[i];
1357 nseg = *(const short*)ptr;
1358 ptr += 2 * sizeof(short);
1359 lt_ptr = (const unsigned int*)ptr;
1360 start = (const struct startend*)(lt_ptr + nseg);
1363 * Now snarf the filename for all of the segments for this file.
1367 char filename[MAX_PATH];
1368 const struct p_string* p_fn;
1370 p_fn = (const struct p_string*)(start + nseg);
1371 memset(filename, 0, sizeof(filename));
1372 memcpy(filename, p_fn->name, p_fn->namelen);
1373 printf("%slines for file #%d/%d %s %d\n", pfx, i, nfile, filename, nseg);
1376 printf("%slines for file #%d/%d %s %d\n", pfx, i, nfile, (const char*)(start + nseg), nseg);
1378 for (j = 0; j < nseg; j++)
1380 ptr = linetab + *lt_ptr++;
1381 nline = *(const short*)(ptr + 2);
1382 printf("%s %04x:%08x-%08x #%d\n",
1383 pfx, *(const short*)(ptr + 0), start[j].start, start[j].end, nline);
1385 for (k = 0; k < nline; k++)
1387 printf("%s %x %d\n",
1388 pfx, ((const unsigned int*)ptr)[k],
1389 ((const unsigned short*)((const unsigned int*)ptr + nline))[k]);
1395 void codeview_dump_linetab2(const char* linetab, DWORD size, const char* strimage, DWORD strsize, const char* pfx)
1399 const struct codeview_linetab2_block* lbh;
1400 const struct codeview_linetab2_file* fd;
1402 if (*(const DWORD*)linetab != 0x000000f4) return;
1403 offset = *((const DWORD*)linetab + 1);
1404 lbh = (const struct codeview_linetab2_block*)(linetab + 8 + offset);
1405 while ((const char*)lbh < linetab + size)
1407 if (lbh->header != 0x000000f2)
1408 /* FIXME: should also check that whole lbh fits in linetab + size */
1410 /* printf("%sblock end %x\n", pfx, lbh->header); */
1413 printf("%sblock from %04x:%08x #%x (%x lines)\n",
1414 pfx, lbh->seg, lbh->start, lbh->size, lbh->nlines);
1415 fd = (const struct codeview_linetab2_file*)(linetab + 8 + lbh->file_offset);
1416 printf("%s md5=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
1417 pfx, fd->md5[ 0], fd->md5[ 1], fd->md5[ 2], fd->md5[ 3],
1418 fd->md5[ 4], fd->md5[ 5], fd->md5[ 6], fd->md5[ 7],
1419 fd->md5[ 8], fd->md5[ 9], fd->md5[10], fd->md5[11],
1420 fd->md5[12], fd->md5[13], fd->md5[14], fd->md5[15]);
1421 /* FIXME: should check that string is within strimage + strsize */
1422 printf("%s file=%s\n", pfx, strimage ? strimage + fd->offset : "--none--");
1423 for (i = 0; i < lbh->nlines; i++)
1425 printf("%s offset=%08x line=%d\n", pfx, lbh->l[i].offset, lbh->l[i].lineno ^ 0x80000000);
1427 lbh = (const struct codeview_linetab2_block*)((const char*)lbh + 8 + lbh->size_of_block);