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';
62 enum {fv_integer
, fv_longlong
} type
;
66 long long unsigned llu
;
70 static int full_numeric_leaf(struct full_value
* fv
, const unsigned short int* leaf
)
72 unsigned short int type
= *leaf
++;
75 fv
->type
= fv_integer
;
76 if (type
< LF_NUMERIC
)
86 fv
->v
.i
= *(const char*)leaf
;
91 fv
->v
.i
= *(const short*)leaf
;
96 fv
->v
.i
= *(const unsigned short*)leaf
;
101 fv
->v
.i
= *(const int*)leaf
;
106 fv
->v
.i
= *(const unsigned int*)leaf
;
111 fv
->type
= fv_longlong
;
112 fv
->v
.llu
= *(const long long int*)leaf
;
117 fv
->type
= fv_longlong
;
118 fv
->v
.llu
= *(const long long unsigned int*)leaf
;
123 printf(">>> unsupported leaf value %04x\n", type
);
124 fv
->v
.i
= 0; /* FIXME */
129 fv
->v
.i
= 0; /* FIXME */
130 printf(">>> unsupported leaf value %04x\n", type
);
135 fv
->v
.i
= 0; /* FIXME */
136 printf(">>> unsupported leaf value %04x\n", type
);
141 fv
->v
.i
= 0; /* FIXME */
142 printf(">>> unsupported leaf value %04x\n", type
);
147 fv
->v
.i
= 0; /* FIXME */
148 printf(">>> unsupported leaf value %04x\n", type
);
153 fv
->v
.i
= 0; /* FIXME */
154 printf(">>> unsupported leaf value %04x\n", type
);
159 fv
->v
.i
= 0; /* FIXME */
160 printf(">>> unsupported leaf value %04x\n", type
);
165 fv
->v
.i
= 0; /* FIXME */
166 printf(">>> unsupported leaf value %04x\n", type
);
171 fv
->v
.i
= 0; /* FIXME */
172 printf(">>> unsupported leaf value %04x\n", type
);
177 fv
->v
.i
= 0; /* FIXME */
178 printf(">>> unsupported leaf value %04x\n", type
);
182 printf(">>> Unsupported numeric leaf-id %04x\n", type
);
190 static const char* full_value_string(const struct full_value
* fv
)
192 static char tmp
[128];
196 case fv_integer
: sprintf(tmp
, "0x%x", fv
->v
.i
); break;
197 case fv_longlong
: sprintf(tmp
, "0x%x%08x", (unsigned)(fv
->v
.llu
>> 32), (unsigned)fv
->v
.llu
); break;
202 static int numeric_leaf(int* value
, const unsigned short int* leaf
)
204 struct full_value fv
;
205 int len
= full_numeric_leaf(&fv
, leaf
);
209 case fv_integer
: *value
= fv
.v
.i
; break;
210 case fv_longlong
: *value
= (unsigned)fv
.v
.llu
; printf("bad conversion\n"); break;
215 static const char* get_attr(unsigned attr
)
217 static char tmp
[256];
221 case 0: strcpy(tmp
, ""); break;
222 case 1: strcpy(tmp
, "private "); break;
223 case 2: strcpy(tmp
, "protected "); break;
224 case 3: strcpy(tmp
, "public "); break;
226 switch ((attr
>> 2) & 7)
228 case 0: strcat(tmp
, ""); break;
229 case 1: strcat(tmp
, "virtual "); break;
230 case 2: strcat(tmp
, "static "); break;
231 case 3: strcat(tmp
, "friend "); break;
232 case 4: strcat(tmp
, "introducing virtual "); break;
233 case 5: strcat(tmp
, "pure virtual "); break;
234 case 6: strcat(tmp
, "pure introducing virtual "); break;
235 case 7: strcat(tmp
, "reserved "); break;
237 if ((attr
>> 5) & 1) strcat(tmp
, "pseudo ");
238 if ((attr
>> 6) & 1) strcat(tmp
, "no-inherit ");
239 if ((attr
>> 7) & 1) strcat(tmp
, "no-construct ");
243 static const char* get_property(unsigned prop
)
245 static char tmp
[1024];
248 if (!prop
) return "none";
249 #define X(s) {if (pos) tmp[pos++] = ';'; strcpy(tmp + pos, s); pos += strlen(s);}
250 if (prop
& 0x0001) X("packed");
251 if (prop
& 0x0002) X("w/{cd}tor");
252 if (prop
& 0x0004) X("w/overloaded-ops");
253 if (prop
& 0x0008) X("nested-class");
254 if (prop
& 0x0010) X("has-nested-classes");
255 if (prop
& 0x0020) X("w/overloaded-assign");
256 if (prop
& 0x0040) X("w/casting-methods");
257 if (prop
& 0x0080) X("forward");
258 if (prop
& 0x0100) X("scoped");
261 if (prop
& ~0x01FF) pos
+= sprintf(tmp
, "unk%x", prop
& ~0x01FF);
262 else tmp
[pos
] = '\0';
263 assert(pos
< sizeof(tmp
));
268 static void do_field(const unsigned char* start
, const unsigned char* end
)
271 * A 'field list' is a CodeView-specific data type which doesn't
272 * directly correspond to any high-level data type. It is used
273 * to hold the collection of members of a struct, class, union
274 * or enum type. The actual definition of that type will follow
275 * later, and refer to the field list definition record.
277 * As we don't have a field list type ourselves, we look ahead
278 * in the field list to try to find out whether this field list
279 * will be used for an enum or struct type, and create a dummy
280 * type of the corresponding sort. Later on, the definition of
281 * the 'real' type will copy the member / enumeration data.
283 const unsigned char* ptr
= start
;
285 const struct p_string
* pstr
;
290 const union codeview_fieldtype
* fieldtype
= (const union codeview_fieldtype
*)ptr
;
292 if (*ptr
>= 0xf0) /* LF_PAD... */
298 switch (fieldtype
->generic
.id
)
300 case LF_ENUMERATE_V1
:
301 leaf_len
= numeric_leaf(&value
, &fieldtype
->enumerate_v1
.value
);
302 pstr
= PSTRING(&fieldtype
->enumerate_v1
.value
, leaf_len
);
303 printf("\t\tEnumerate V1: '%s' value:%d\n",
304 p_string(pstr
), value
);
305 ptr
+= 2 + 2 + leaf_len
+ 1 + pstr
->namelen
;
308 case LF_ENUMERATE_V3
:
309 leaf_len
= numeric_leaf(&value
, &fieldtype
->enumerate_v3
.value
);
310 cstr
= (const char*)&fieldtype
->enumerate_v3
.value
+ leaf_len
;
311 printf("\t\tEnumerate V3: '%s' value:%d\n",
313 ptr
+= 2 + 2 + leaf_len
+ strlen(cstr
) + 1;
317 leaf_len
= numeric_leaf(&value
, &fieldtype
->member_v1
.offset
);
318 pstr
= PSTRING(&fieldtype
->member_v1
.offset
, leaf_len
);
319 printf("\t\tMember V1: '%s' type:%x attr:%s @%d\n",
320 p_string(pstr
), fieldtype
->member_v1
.type
,
321 get_attr(fieldtype
->member_v1
.attribute
), value
);
322 ptr
+= 2 + 2 + 2 + leaf_len
+ 1 + pstr
->namelen
;
326 leaf_len
= numeric_leaf(&value
, &fieldtype
->member_v2
.offset
);
327 pstr
= PSTRING(&fieldtype
->member_v2
.offset
, leaf_len
);
328 printf("\t\tMember V2: '%s' type:%x attr:%s @%d\n",
329 p_string(pstr
), fieldtype
->member_v2
.type
,
330 get_attr(fieldtype
->member_v2
.attribute
), value
);
331 ptr
+= 2 + 2 + 4 + leaf_len
+ 1 + pstr
->namelen
;
335 leaf_len
= numeric_leaf(&value
, &fieldtype
->member_v3
.offset
);
336 cstr
= (const char*)&fieldtype
->member_v3
.offset
+ leaf_len
;
337 printf("\t\tMember V3: '%s' type:%x attr:%s @%d\n",
338 cstr
, fieldtype
->member_v3
.type
,
339 get_attr(fieldtype
->member_v3
.attribute
), value
);
340 ptr
+= 2 + 2 + 4 + leaf_len
+ strlen(cstr
) + 1;
343 case LF_ONEMETHOD_V1
:
344 switch ((fieldtype
->onemethod_v1
.attribute
>> 2) & 7)
347 printf("\t\tVirtual-method V1: '%s' attr:%s type:%x vtable_offset:%u\n",
348 p_string(&fieldtype
->onemethod_virt_v1
.p_name
),
349 get_attr(fieldtype
->onemethod_virt_v1
.attribute
),
350 fieldtype
->onemethod_virt_v1
.type
,
351 fieldtype
->onemethod_virt_v1
.vtab_offset
);
352 ptr
+= 2 + 2 + 2 + 4 + (1 + fieldtype
->onemethod_virt_v1
.p_name
.namelen
);
356 printf("\t\tMethod V1: '%s' attr:%s type:%x\n",
357 p_string(&fieldtype
->onemethod_v1
.p_name
),
358 get_attr(fieldtype
->onemethod_v1
.attribute
),
359 fieldtype
->onemethod_v1
.type
);
360 ptr
+= 2 + 2 + 2 + (1 + fieldtype
->onemethod_v1
.p_name
.namelen
);
365 case LF_ONEMETHOD_V2
:
366 switch ((fieldtype
->onemethod_v2
.attribute
>> 2) & 7)
369 printf("\t\tVirtual-method V2: '%s' attr:%s type:%x vtable_offset:%u\n",
370 p_string(&fieldtype
->onemethod_virt_v2
.p_name
),
371 get_attr(fieldtype
->onemethod_virt_v2
.attribute
),
372 fieldtype
->onemethod_virt_v2
.type
,
373 fieldtype
->onemethod_virt_v2
.vtab_offset
);
374 ptr
+= 2 + 2 + 4 + 4 + (1 + fieldtype
->onemethod_virt_v2
.p_name
.namelen
);
378 printf("\t\tMethod V2: '%s' attr:%s type:%x\n",
379 p_string(&fieldtype
->onemethod_v2
.p_name
),
380 get_attr(fieldtype
->onemethod_v2
.attribute
),
381 fieldtype
->onemethod_v2
.type
);
382 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->onemethod_v2
.p_name
.namelen
);
387 case LF_ONEMETHOD_V3
:
388 switch ((fieldtype
->onemethod_v3
.attribute
>> 2) & 7)
391 printf("\t\tVirtual-method V3: '%s' attr:%s type:%x vtable_offset:%u\n",
392 fieldtype
->onemethod_virt_v3
.name
,
393 get_attr(fieldtype
->onemethod_virt_v3
.attribute
),
394 fieldtype
->onemethod_virt_v3
.type
,
395 fieldtype
->onemethod_virt_v3
.vtab_offset
);
396 ptr
+= 2 + 2 + 4 + 4 + (strlen(fieldtype
->onemethod_virt_v3
.name
) + 1);
400 printf("\t\tMethod V3: '%s' attr:%s type:%x\n",
401 fieldtype
->onemethod_v3
.name
,
402 get_attr(fieldtype
->onemethod_v3
.attribute
),
403 fieldtype
->onemethod_v3
.type
);
404 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->onemethod_v3
.name
) + 1);
410 printf("\t\tMethod V1: '%s' overloaded=#%d method-list=%x\n",
411 p_string(&fieldtype
->method_v1
.p_name
),
412 fieldtype
->method_v1
.count
, fieldtype
->method_v1
.mlist
);
413 ptr
+= 2 + 2 + 2 + (1 + fieldtype
->method_v1
.p_name
.namelen
);
417 printf("\t\tMethod V2: '%s' overloaded=#%d method-list=%x\n",
418 p_string(&fieldtype
->method_v2
.p_name
),
419 fieldtype
->method_v2
.count
, fieldtype
->method_v2
.mlist
);
420 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->method_v2
.p_name
.namelen
);
424 printf("\t\tMethod V3: '%s' overloaded=#%d method-list=%x\n",
425 fieldtype
->method_v3
.name
,
426 fieldtype
->method_v3
.count
, fieldtype
->method_v3
.mlist
);
427 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->method_v3
.name
) + 1);
431 printf("\t\tStatic member V1: '%s' attr:%s type:%x\n",
432 p_string(&fieldtype
->stmember_v1
.p_name
),
433 get_attr(fieldtype
->stmember_v1
.attribute
),
434 fieldtype
->stmember_v1
.type
);
435 ptr
+= 2 + 2 + 2 + (1 + fieldtype
->stmember_v1
.p_name
.namelen
);
439 printf("\t\tStatic member V2: '%s' attr:%s type:%x\n",
440 p_string(&fieldtype
->stmember_v2
.p_name
),
441 get_attr(fieldtype
->stmember_v2
.attribute
),
442 fieldtype
->stmember_v2
.type
);
443 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->stmember_v2
.p_name
.namelen
);
447 printf("\t\tStatic member V3: '%s' attr:%s type:%x\n",
448 fieldtype
->stmember_v3
.name
,
449 get_attr(fieldtype
->stmember_v3
.attribute
),
450 fieldtype
->stmember_v3
.type
);
451 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->stmember_v3
.name
) + 1);
454 case LF_FRIENDFCN_V1
:
455 printf("\t\tFriend function V1: '%s' type:%x\n",
456 p_string(&fieldtype
->friendfcn_v1
.p_name
),
457 fieldtype
->friendfcn_v1
.type
);
460 case LF_FRIENDFCN_V2
:
461 printf("\t\tFriend function V2: '%s' type:%x\n",
462 p_string(&fieldtype
->friendfcn_v2
.p_name
),
463 fieldtype
->friendfcn_v2
.type
);
467 case LF_FRIENDFCN_V3
:
468 printf("\t\tFriend function V3: '%s' type:%x\n",
469 fieldtype
->friendfcn_v3
.name
,
470 fieldtype
->friendfcn_v3
.type
);
475 leaf_len
= numeric_leaf(&value
, &fieldtype
->bclass_v1
.offset
);
476 printf("\t\tBase class V1: type:%x attr:%s @%d\n",
477 fieldtype
->bclass_v1
.type
,
478 get_attr(fieldtype
->bclass_v1
.attribute
), value
);
479 ptr
+= 2 + 2 + 2 + leaf_len
;
483 leaf_len
= numeric_leaf(&value
, &fieldtype
->bclass_v2
.offset
);
484 printf("\t\tBase class V2: type:%x attr:%s @%d\n",
485 fieldtype
->bclass_v2
.type
,
486 get_attr(fieldtype
->bclass_v2
.attribute
), value
);
487 ptr
+= 2 + 2 + 4 + leaf_len
;
492 leaf_len
= numeric_leaf(&value
, &fieldtype
->vbclass_v1
.vbpoff
);
493 printf("\t\t%sirtual base class V1: type:%x (ptr:%x) attr:%s vbpoff:%d ",
494 (fieldtype
->generic
.id
== LF_VBCLASS_V2
) ? "V" : "Indirect v",
495 fieldtype
->vbclass_v1
.btype
, fieldtype
->vbclass_v1
.vbtype
,
496 get_attr(fieldtype
->vbclass_v1
.attribute
), value
);
497 ptr
+= 2 + 2 + 2 + 2 + leaf_len
;
498 leaf_len
= numeric_leaf(&value
, (const unsigned short*)ptr
);
499 printf("vboff:%d\n", value
);
505 leaf_len
= numeric_leaf(&value
, &fieldtype
->vbclass_v1
.vbpoff
);
506 printf("\t\t%sirtual base class V2: type:%x (ptr:%x) attr:%s vbpoff:%d ",
507 (fieldtype
->generic
.id
== LF_VBCLASS_V2
) ? "V" : "Indirect v",
508 fieldtype
->vbclass_v2
.btype
, fieldtype
->vbclass_v2
.vbtype
,
509 get_attr(fieldtype
->vbclass_v2
.attribute
), value
);
510 ptr
+= 2 + 2 + 4 + 4 + leaf_len
;
511 leaf_len
= numeric_leaf(&value
, (const unsigned short*)ptr
);
512 printf("vboff:%d\n", value
);
516 case LF_FRIENDCLS_V1
:
517 printf("\t\tFriend class V1: type:%x\n", fieldtype
->friendcls_v1
.type
);
520 case LF_FRIENDCLS_V2
:
521 printf("\t\tFriend class V2: type:%x\n", fieldtype
->friendcls_v2
.type
);
525 printf("\t\tNested type V1: '%s' type:%x\n",
526 p_string(&fieldtype
->nesttype_v1
.p_name
),
527 fieldtype
->nesttype_v1
.type
);
528 ptr
+= 2 + 2 + (1 + fieldtype
->nesttype_v1
.p_name
.namelen
);
532 printf("\t\tNested type V2: '%s' pad0:%u type:%x\n",
533 p_string(&fieldtype
->nesttype_v2
.p_name
),
534 fieldtype
->nesttype_v2
._pad0
, fieldtype
->nesttype_v2
.type
);
535 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->nesttype_v2
.p_name
.namelen
);
539 printf("\t\tNested type V3: '%s' pad0:%u type:%x\n",
540 fieldtype
->nesttype_v3
.name
,
541 fieldtype
->nesttype_v3
._pad0
, fieldtype
->nesttype_v3
.type
);
542 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->nesttype_v3
.name
) + 1);
546 printf("\t\tVirtual function table V1: type:%x\n",
547 fieldtype
->vfunctab_v1
.type
);
552 printf("\t\tVirtual function table V2: type:%x\n",
553 fieldtype
->vfunctab_v2
.type
);
558 printf("\t\tVirtual function table offset V1: type:%x offset:%x\n",
559 fieldtype
->vfuncoff_v1
.type
, fieldtype
->vfuncoff_v1
.offset
);
563 printf("\t\tVirtual function table offset V2: type:%x offset:%x\n",
564 fieldtype
->vfuncoff_v2
.type
, fieldtype
->vfuncoff_v2
.offset
);
568 printf(">>> Unsupported field-id %x\n", fieldtype
->generic
.id
);
569 dump_data((const void*)fieldtype
, 0x30, "\t");
575 static void codeview_dump_one_type(unsigned curr_type
, const union codeview_type
* type
)
577 const union codeview_reftype
* reftype
= (const union codeview_reftype
*)type
;
578 int i
, leaf_len
, value
;
582 switch (type
->generic
.id
)
585 printf("\t%x => Pointer V1 to type:%x\n",
586 curr_type
, type
->pointer_v1
.datatype
);
589 printf("\t%x => Pointer V2 to type:%x\n",
590 curr_type
, type
->pointer_v2
.datatype
);
593 leaf_len
= numeric_leaf(&value
, &type
->array_v1
.arrlen
);
594 printf("\t%x => Array V1-'%s'[%u type:%x] type:%x\n",
595 curr_type
, p_string(PSTRING(&type
->array_v1
.arrlen
, leaf_len
)),
596 value
, type
->array_v1
.idxtype
, type
->array_v1
.elemtype
);
599 leaf_len
= numeric_leaf(&value
, &type
->array_v2
.arrlen
);
600 printf("\t%x => Array V2-'%s'[%u type:%x] type:%x\n",
601 curr_type
, p_string(PSTRING(&type
->array_v2
.arrlen
, leaf_len
)),
602 value
, type
->array_v2
.idxtype
, type
->array_v2
.elemtype
);
605 leaf_len
= numeric_leaf(&value
, &type
->array_v3
.arrlen
);
606 str
= (const char*)&type
->array_v3
.arrlen
+ leaf_len
;
607 printf("\t%x => Array V3-'%s'[%u type:%x] type:%x\n",
608 curr_type
, str
, value
,
609 type
->array_v3
.idxtype
, type
->array_v3
.elemtype
);
612 /* a bitfields is a CodeView specific data type which represent a bitfield
613 * in a structure or a class. For now, we store it in a SymTag-like type
614 * (so that the rest of the process is seamless), but check at udt inclusion
615 * type for its presence
618 printf("\t%x => Bitfield V1:%x offset:%u #bits:%u\n",
619 curr_type
, reftype
->bitfield_v1
.type
, reftype
->bitfield_v1
.bitoff
,
620 reftype
->bitfield_v1
.nbits
);
624 printf("\t%x => Bitfield V2:%x offset:%u #bits:%u\n",
625 curr_type
, reftype
->bitfield_v2
.type
, reftype
->bitfield_v2
.bitoff
,
626 reftype
->bitfield_v2
.nbits
);
629 case LF_FIELDLIST_V1
:
630 case LF_FIELDLIST_V2
:
631 printf("\t%x => Fieldlist\n", curr_type
);
632 do_field(reftype
->fieldlist
.list
, (const BYTE
*)type
+ reftype
->generic
.len
+ 2);
635 case LF_STRUCTURE_V1
:
637 leaf_len
= numeric_leaf(&value
, &type
->struct_v1
.structlen
);
638 printf("\t%x => %s V1 '%s' elts:%u property:%s fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
639 curr_type
, type
->generic
.id
== LF_CLASS_V1
? "Class" : "Struct",
640 p_string(PSTRING(&type
->struct_v1
.structlen
, leaf_len
)),
641 type
->struct_v1
.n_element
, get_property(type
->struct_v1
.property
),
642 type
->struct_v1
.fieldlist
, type
->struct_v1
.derived
,
643 type
->struct_v1
.vshape
, value
);
646 case LF_STRUCTURE_V2
:
648 leaf_len
= numeric_leaf(&value
, &type
->struct_v2
.structlen
);
649 printf("\t%x => %s V2 '%s' elts:%u property:%s\n"
650 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
651 curr_type
, type
->generic
.id
== LF_CLASS_V2
? "Class" : "Struct",
652 p_string(PSTRING(&type
->struct_v2
.structlen
, leaf_len
)),
653 type
->struct_v2
.n_element
, get_property(type
->struct_v2
.property
),
654 type
->struct_v2
.fieldlist
, type
->struct_v2
.derived
,
655 type
->struct_v2
.vshape
, value
);
658 case LF_STRUCTURE_V3
:
660 leaf_len
= numeric_leaf(&value
, &type
->struct_v3
.structlen
);
661 str
= (const char*)&type
->struct_v3
.structlen
+ leaf_len
;
662 printf("\t%x => %s V3 '%s' elts:%u property:%s\n"
663 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
664 curr_type
, type
->generic
.id
== LF_CLASS_V3
? "Class" : "Struct",
665 str
, type
->struct_v3
.n_element
, get_property(type
->struct_v3
.property
),
666 type
->struct_v3
.fieldlist
, type
->struct_v3
.derived
,
667 type
->struct_v3
.vshape
, value
);
671 leaf_len
= numeric_leaf(&value
, &type
->union_v1
.un_len
);
672 printf("\t%x => Union V1 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
673 curr_type
, p_string(PSTRING(&type
->union_v1
.un_len
, leaf_len
)),
674 type
->union_v1
.count
, get_property(type
->union_v1
.property
),
675 type
->union_v1
.fieldlist
, value
);
679 leaf_len
= numeric_leaf(&value
, &type
->union_v2
.un_len
);
680 printf("\t%x => Union V2 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
681 curr_type
, p_string(PSTRING(&type
->union_v2
.un_len
, leaf_len
)),
682 type
->union_v2
.count
, get_property(type
->union_v2
.property
),
683 type
->union_v2
.fieldlist
, value
);
687 leaf_len
= numeric_leaf(&value
, &type
->union_v3
.un_len
);
688 str
= (const char*)&type
->union_v3
.un_len
+ leaf_len
;
689 printf("\t%x => Union V3 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
690 curr_type
, str
, type
->union_v3
.count
,
691 get_property(type
->union_v3
.property
),
692 type
->union_v3
.fieldlist
, value
);
696 printf("\t%x => Enum V1 '%s' type:%x field-type:%x count:%u property:%s\n",
697 curr_type
, p_string(&type
->enumeration_v1
.p_name
),
698 type
->enumeration_v1
.type
,
699 type
->enumeration_v1
.fieldlist
,
700 type
->enumeration_v1
.count
,
701 get_property(type
->enumeration_v1
.property
));
705 printf("\t%x => Enum V2 '%s' type:%x field-type:%x count:%u property:%s\n",
706 curr_type
, p_string(&type
->enumeration_v2
.p_name
),
707 type
->enumeration_v2
.type
,
708 type
->enumeration_v2
.fieldlist
,
709 type
->enumeration_v2
.count
,
710 get_property(type
->enumeration_v2
.property
));
714 printf("\t%x => Enum V3 '%s' type:%x field-type:%x count:%u property:%s\n",
715 curr_type
, type
->enumeration_v3
.name
,
716 type
->enumeration_v3
.type
,
717 type
->enumeration_v3
.fieldlist
,
718 type
->enumeration_v3
.count
,
719 get_property(type
->enumeration_v3
.property
));
723 printf("\t%x => Arglist V1(#%u):", curr_type
, reftype
->arglist_v1
.num
);
724 for (i
= 0; i
< reftype
->arglist_v1
.num
; i
++)
726 printf(" %x", reftype
->arglist_v1
.args
[i
]);
732 printf("\t%x => Arglist V2(#%u):", curr_type
, reftype
->arglist_v2
.num
);
733 for (j
= 0; j
< reftype
->arglist_v2
.num
; j
++)
735 printf("\t %x", reftype
->arglist_v2
.args
[j
]);
740 case LF_PROCEDURE_V1
:
741 /* FIXME: unknown could be the calling convention for the proc */
742 printf("\t%x => Procedure V1 ret_type:%x call:%x (#%u args_type:%x)\n",
743 curr_type
, type
->procedure_v1
.rvtype
,
744 type
->procedure_v1
.call
, type
->procedure_v1
.params
,
745 type
->procedure_v1
.arglist
);
748 case LF_PROCEDURE_V2
:
749 printf("\t%x => Procedure V2 ret_type:%x unk:%x (#%u args_type:%x)\n",
750 curr_type
, type
->procedure_v2
.rvtype
,
751 type
->procedure_v2
.call
, type
->procedure_v2
.params
,
752 type
->procedure_v2
.arglist
);
755 case LF_MFUNCTION_V2
:
756 printf("\t%x => MFunction V2 ret-type:%x call:%x class-type:%x this-type:%x\n"
757 "\t\t#args:%x args-type:%x this_adjust:%x\n",
759 type
->mfunction_v2
.rvtype
,
760 type
->mfunction_v2
.call
,
761 type
->mfunction_v2
.class_type
,
762 type
->mfunction_v2
.this_type
,
763 type
->mfunction_v2
.params
,
764 type
->mfunction_v2
.arglist
,
765 type
->mfunction_v2
.this_adjust
);
769 printf("\t%x => Modifier V1 type:%x modif:%x\n",
770 curr_type
, type
->modifier_v1
.type
, type
->modifier_v1
.attribute
);
774 printf("\t%x => Modifier V2 type:%x modif:%x\n",
775 curr_type
, type
->modifier_v2
.type
, type
->modifier_v2
.attribute
);
778 case LF_METHODLIST_V1
:
780 const unsigned short* pattr
= (const unsigned short*)((const char*)type
+ 4);
782 printf("\t%x => Method list\n", curr_type
);
783 while ((const char*)pattr
< (const char*)type
+ type
->generic
.len
+ 2)
785 switch ((*pattr
>> 2) & 7)
788 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
789 get_attr(pattr
[0]), pattr
[1],
790 *(const unsigned*)(&pattr
[2]));
794 printf("\t\t\tattr:%s type:%x\n",
795 get_attr(pattr
[0]), pattr
[1]);
802 case LF_METHODLIST_V2
:
804 const unsigned* pattr
= (const unsigned*)((const char*)type
+ 4);
806 printf("\t%x => Method list\n", curr_type
);
807 while ((const char*)pattr
< (const char*)type
+ type
->generic
.len
+ 2)
809 switch ((*pattr
>> 2) & 7)
812 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
813 get_attr(pattr
[0]), pattr
[1], pattr
[2]);
817 printf("\t\t\tattr:%s type:%x\n",
818 get_attr(pattr
[0]), pattr
[1]);
827 int count
= *(const unsigned short*)((const char*)type
+ 4);
829 const char* ptr
= (const char*)type
+ 6;
830 const char* desc
[] = {"Near", "Far", "Thin", "Disp to outtermost",
831 "Pointer to metaclass", "Near32", "Far32"};
832 printf("\t%x => VT Shape #%d: ", curr_type
, count
);
835 if (((*ptr
<< shift
) & 0xF) <= 6)
836 printf("%s ", desc
[(*ptr
<< shift
) & 0xF]);
838 printf("%x ", (*ptr
<< shift
) & 0xF);
839 if (shift
== 0) shift
= 4; else {shift
= 0; ptr
++;}
846 printf("\t%x => Derived V1(#%u):", curr_type
, reftype
->derived_v1
.num
);
847 for (i
= 0; i
< reftype
->derived_v1
.num
; i
++)
849 printf(" %x", reftype
->derived_v1
.drvdcls
[i
]);
855 printf("\t%x => Derived V2(#%u):", curr_type
, reftype
->derived_v2
.num
);
856 for (j
= 0; j
< reftype
->derived_v2
.num
; j
++)
858 printf(" %x", reftype
->derived_v2
.drvdcls
[j
]);
864 printf(">>> Unsupported type-id %x for %x\n", type
->generic
.id
, curr_type
);
865 dump_data((const void*)type
, type
->generic
.len
+ 2, "");
870 int codeview_dump_types_from_offsets(const void* table
, const DWORD
* offsets
, unsigned num_types
)
874 for (i
= 0; i
< num_types
; i
++)
876 codeview_dump_one_type(0x1000 + i
,
877 (const union codeview_type
*)((const char*)table
+ offsets
[i
]));
883 int codeview_dump_types_from_block(const void* table
, unsigned long len
)
885 unsigned int curr_type
= 0x1000;
886 const unsigned char*ptr
= table
;
888 while (ptr
- (const unsigned char*)table
< len
)
890 const union codeview_type
* type
= (const union codeview_type
*)ptr
;
892 codeview_dump_one_type(curr_type
, type
);
894 ptr
+= (type
->generic
.len
+ 2 + 3) & ~3;
900 int codeview_dump_symbols(const void* root
, unsigned long size
)
904 char* curr_func
= NULL
;
907 * Loop over the different types of records and whenever we
908 * find something we are interested in, record it and move on.
910 for (i
= 0; i
< size
; i
+= length
)
912 const union codeview_symbol
* sym
= (const union codeview_symbol
*)((const char*)root
+ i
);
913 length
= sym
->generic
.len
+ 2;
914 if (!sym
->generic
.id
|| length
< 4) break;
915 switch (sym
->generic
.id
)
918 * Global and local data symbols. We don't associate these
919 * with any given source file.
923 printf("\tS-%s-Data V2 '%s' %04x:%08x type:%08x\n",
924 sym
->generic
.id
== S_GDATA_V2
? "Global" : "Local",
925 get_symbol_str(p_string(&sym
->data_v2
.p_name
)),
926 sym
->data_v2
.segment
, sym
->data_v2
.offset
, sym
->data_v2
.symtype
);
931 /* EPP case S_DATA_V3: */
932 printf("\tS-%s-Data V3 '%s' (%04x:%08x) type:%08x\n",
933 sym
->generic
.id
== S_GDATA_V3
? "Global" : "Local",
934 get_symbol_str(sym
->data_v3
.name
),
935 sym
->data_v3
.segment
, sym
->data_v3
.offset
,
936 sym
->data_v3
.symtype
);
940 printf("\tS-Public V2 '%s' %04x:%08x type:%08x\n",
941 get_symbol_str(p_string(&sym
->public_v2
.p_name
)),
942 sym
->public_v2
.segment
, sym
->public_v2
.offset
,
943 sym
->public_v2
.symtype
);
947 /* not completely sure of those two anyway */
950 printf("\tS-Public%s V3 '%s' %04x:%08x type:%08x\n",
951 sym
->generic
.id
== S_PUB_V3
? "" :
952 (sym
->generic
.id
== S_PUB_FUNC1_V3
? "<subkind1" : "<subkind2"),
953 get_symbol_str(sym
->public_v3
.name
),
954 sym
->public_v3
.segment
,
955 sym
->public_v3
.offset
, sym
->public_v3
.symtype
);
959 * Sort of like a global function, but it just points
960 * to a thunk, which is a stupid name for what amounts to
961 * a PLT slot in the normal jargon that everyone else uses.
964 printf("\tS-Thunk V1 '%s' (%04x:%08x#%x) type:%x\n",
965 p_string(&sym
->thunk_v1
.p_name
),
966 sym
->thunk_v1
.segment
, sym
->thunk_v1
.offset
,
967 sym
->thunk_v1
.thunk_len
, sym
->thunk_v1
.thtype
);
968 curr_func
= strdup(p_string(&sym
->thunk_v1
.p_name
));
972 printf("\tS-Thunk V3 '%s' (%04x:%08x#%x) type:%x\n",
974 sym
->thunk_v3
.segment
, sym
->thunk_v3
.offset
,
975 sym
->thunk_v3
.thunk_len
, sym
->thunk_v3
.thtype
);
976 curr_func
= strdup(sym
->thunk_v3
.name
);
979 /* Global and static functions */
982 printf("\tS-%s-Proc V1: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
983 sym
->generic
.id
== S_GPROC_V1
? "Global" : "-Local",
984 p_string(&sym
->proc_v1
.p_name
),
985 sym
->proc_v1
.segment
, sym
->proc_v1
.offset
,
986 sym
->proc_v1
.proc_len
, sym
->proc_v1
.proctype
,
988 printf("\t Debug: start=%08x end=%08x\n",
989 sym
->proc_v1
.debug_start
, sym
->proc_v1
.debug_end
);
992 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func
, nest_block
);
995 curr_func
= strdup(p_string(&sym
->proc_v1
.p_name
));
996 /* EPP unsigned int pparent; */
997 /* EPP unsigned int pend; */
998 /* EPP unsigned int next; */
1003 printf("\tS-%s-Proc V2: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
1004 sym
->generic
.id
== S_GPROC_V2
? "Global" : "-Local",
1005 p_string(&sym
->proc_v2
.p_name
),
1006 sym
->proc_v2
.segment
, sym
->proc_v2
.offset
,
1007 sym
->proc_v2
.proc_len
, sym
->proc_v2
.proctype
,
1008 sym
->proc_v2
.flags
);
1009 printf("\t Debug: start=%08x end=%08x\n",
1010 sym
->proc_v2
.debug_start
, sym
->proc_v2
.debug_end
);
1013 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func
, nest_block
);
1016 curr_func
= strdup(p_string(&sym
->proc_v2
.p_name
));
1017 /* EPP unsigned int pparent; */
1018 /* EPP unsigned int pend; */
1019 /* EPP unsigned int next; */
1024 printf("\tS-%s-Procedure V3 '%s' (%04x:%08x#%x) type:%x attr:%x\n",
1025 sym
->generic
.id
== S_GPROC_V3
? "Global" : "Local",
1027 sym
->proc_v3
.segment
, sym
->proc_v3
.offset
,
1028 sym
->proc_v3
.proc_len
, sym
->proc_v3
.proctype
,
1029 sym
->proc_v3
.flags
);
1030 printf("\t Debug: start=%08x end=%08x\n",
1031 sym
->proc_v3
.debug_start
, sym
->proc_v3
.debug_end
);
1034 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func
, nest_block
);
1037 curr_func
= strdup(sym
->proc_v3
.name
);
1038 /* EPP unsigned int pparent; */
1039 /* EPP unsigned int pend; */
1040 /* EPP unsigned int next; */
1043 /* Function parameters and stack variables */
1045 printf("\tS-BP-relative V1: '%s' @%d type:%x (%s)\n",
1046 p_string(&sym
->stack_v1
.p_name
),
1047 sym
->stack_v1
.offset
, sym
->stack_v1
.symtype
, curr_func
);
1051 printf("\tS-BP-relative V2: '%s' @%d type:%x (%s)\n",
1052 p_string(&sym
->stack_v2
.p_name
),
1053 sym
->stack_v2
.offset
, sym
->stack_v2
.symtype
, curr_func
);
1057 printf("\tS-BP-relative V3: '%s' @%d type:%x (in %s)\n",
1058 sym
->stack_v3
.name
, sym
->stack_v3
.offset
,
1059 sym
->stack_v3
.symtype
, curr_func
);
1063 printf("\tS-Reg-relative V3: '%s' @%d type:%x reg:%x (in %s)\n",
1064 sym
->regrel_v3
.name
, sym
->regrel_v3
.offset
,
1065 sym
->regrel_v3
.symtype
, sym
->regrel_v3
.reg
, curr_func
);
1069 printf("\tS-Register V1 '%s' in %s type:%x register:%x\n",
1070 p_string(&sym
->register_v1
.p_name
),
1071 curr_func
, sym
->register_v1
.reg
, sym
->register_v1
.type
);
1075 printf("\tS-Register V2 '%s' in %s type:%x register:%x\n",
1076 p_string(&sym
->register_v2
.p_name
),
1077 curr_func
, sym
->register_v2
.reg
, sym
->register_v2
.type
);
1081 printf("\tS-Register V3 '%s' in %s type:%x register:%x\n",
1082 sym
->register_v3
.name
,
1083 curr_func
, sym
->register_v3
.reg
, sym
->register_v3
.type
);
1087 printf("\tS-Block V1 '%s' in '%s' (%04x:%08x#%08x)\n",
1088 p_string(&sym
->block_v1
.p_name
),
1090 sym
->block_v1
.segment
, sym
->block_v1
.offset
,
1091 sym
->block_v1
.length
);
1096 printf("\tS-Block V3 '%s' in '%s' (%04x:%08x#%08x) parent:%u end:%x\n",
1097 sym
->block_v3
.name
, curr_func
,
1098 sym
->block_v3
.segment
, sym
->block_v3
.offset
, sym
->block_v3
.length
,
1099 sym
->block_v3
.parent
, sym
->block_v3
.end
);
1103 /* Additional function information */
1104 case S_FRAMEINFO_V2
:
1105 printf("\tS-Frame-Info V2: frame-size:%x unk2:%x unk3:%x saved-regs-sz:%x eh(%04x:%08x) flags:%08x\n",
1106 sym
->frame_info_v2
.sz_frame
,
1107 sym
->frame_info_v2
.unknown2
,
1108 sym
->frame_info_v2
.unknown3
,
1109 sym
->frame_info_v2
.sz_saved_regs
,
1110 sym
->frame_info_v2
.eh_sect
,
1111 sym
->frame_info_v2
.eh_offset
,
1112 sym
->frame_info_v2
.flags
);
1115 case S_SECUCOOKIE_V3
:
1116 printf("\tSecurity Cookie V3 @%d unk:%x\n",
1117 sym
->security_cookie_v3
.offset
, sym
->security_cookie_v3
.unknown
);
1124 printf("\tS-End-Of block (%u)\n", nest_block
);
1128 printf("\tS-End-Of %s\n", curr_func
);
1134 case S_COMPILAND_V1
:
1136 const char* machine
;
1139 switch (sym
->compiland_v1
.unknown
& 0xFF)
1141 case 0x00: machine
= "Intel 8080"; break;
1142 case 0x01: machine
= "Intel 8086"; break;
1143 case 0x02: machine
= "Intel 80286"; break;
1144 case 0x03: machine
= "Intel 80386"; break;
1145 case 0x04: machine
= "Intel 80486"; break;
1146 case 0x05: machine
= "Intel Pentium"; break;
1147 case 0x10: machine
= "MIPS R4000"; break;
1150 static char tmp
[16];
1151 sprintf(tmp
, "machine=%x", sym
->compiland_v1
.unknown
& 0xFF);
1156 switch ((sym
->compiland_v1
.unknown
>> 8) & 0xFF)
1158 case 0x00: lang
= "C"; break;
1159 case 0x01: lang
= "C++"; break;
1160 case 0x02: lang
= "Fortran"; break;
1161 case 0x03: lang
= "Masm"; break;
1162 case 0x04: lang
= "Pascal"; break;
1163 case 0x05: lang
= "Basic"; break;
1164 case 0x06: lang
= "Cobol"; break;
1167 static char tmp
[16];
1168 sprintf(tmp
, "language=%x", (sym
->compiland_v1
.unknown
>> 8) & 0xFF);
1174 printf("\tS-Compiland V1 '%s' %s %s unk:%x\n",
1175 p_string(&sym
->compiland_v1
.p_name
), machine
, lang
,
1176 sym
->compiland_v1
.unknown
>> 16);
1180 case S_COMPILAND_V2
:
1181 printf("\tS-Compiland V2 '%s'\n",
1182 p_string(&sym
->compiland_v2
.p_name
));
1183 dump_data((const void*)sym
, sym
->generic
.len
+ 2, " ");
1185 const char* ptr
= sym
->compiland_v2
.p_name
.name
+ sym
->compiland_v2
.p_name
.namelen
;
1188 printf("\t\t%s => ", ptr
); ptr
+= strlen(ptr
) + 1;
1189 printf("%s\n", ptr
); ptr
+= strlen(ptr
) + 1;
1194 case S_COMPILAND_V3
:
1195 printf("\tS-Compiland V3 '%s' unknown:%x\n",
1196 sym
->compiland_v3
.name
, sym
->compiland_v3
.unknown
);
1200 printf("\tS-ObjName V1 sig:%.4s '%s'\n",
1201 sym
->objname_v1
.signature
, p_string(&sym
->objname_v1
.p_name
));
1205 printf("\tS-Label V1 '%s' in '%s' (%04x:%08x)\n",
1206 p_string(&sym
->label_v1
.p_name
),
1207 curr_func
, sym
->label_v1
.segment
, sym
->label_v1
.offset
);
1211 printf("\tS-Label V3 '%s' in '%s' (%04x:%08x) flag:%x\n",
1212 sym
->label_v3
.name
, curr_func
, sym
->label_v3
.segment
,
1213 sym
->label_v3
.offset
, sym
->label_v3
.flags
);
1219 struct full_value fv
;
1221 vlen
= full_numeric_leaf(&fv
, &sym
->constant_v2
.cvalue
);
1222 printf("\tS-Constant V2 '%s' = %s type:%x\n",
1223 p_string(PSTRING(&sym
->constant_v2
.cvalue
, vlen
)),
1224 full_value_string(&fv
), sym
->constant_v2
.type
);
1231 struct full_value fv
;
1233 vlen
= full_numeric_leaf(&fv
, &sym
->constant_v3
.cvalue
);
1234 printf("\tS-Constant V3 '%s' = %s type:%x\n",
1235 (const char*)&sym
->constant_v3
.cvalue
+ vlen
,
1236 full_value_string(&fv
), sym
->constant_v3
.type
);
1241 printf("\tS-Udt V1 '%s': type:0x%x\n",
1242 p_string(&sym
->udt_v1
.p_name
), sym
->udt_v1
.type
);
1246 printf("\tS-Udt V2 '%s': type:0x%x\n",
1247 p_string(&sym
->udt_v2
.p_name
), sym
->udt_v2
.type
);
1251 printf("\tS-Udt V3 '%s': type:0x%x\n",
1252 sym
->udt_v3
.name
, sym
->udt_v3
.type
);
1255 * These are special, in that they are always followed by an
1256 * additional length-prefixed string which is *not* included
1257 * into the symbol length count. We need to skip it.
1260 printf("\tS-Procref V1 "); goto doaref
;
1262 printf("\tS-Dataref V1 "); goto doaref
;
1264 printf("\tS-L-Procref V1 "); goto doaref
;
1267 const struct p_string
* pname
;
1269 pname
= PSTRING(sym
, length
);
1270 length
+= (pname
->namelen
+ 1 + 3) & ~3;
1271 printf("\t%08x %08x %08x '%s'\n",
1272 *(((const DWORD
*)sym
) + 1), *(((const DWORD
*)sym
) + 2), *(((const DWORD
*)sym
) + 3),
1276 case S_MSTOOL_V3
: /* info about tool used to create CU */
1278 const unsigned short* ptr
= ((const unsigned short*)sym
) + 2;
1280 const char* x2
= (const char*)&ptr
[9];
1281 /* FIXME: what are all those values for ? */
1282 printf("\tTool V3 unk=%04x%04x%04x front=%d.%d.%d.0 back=%d.%d.%d.0 %s\n",
1283 ptr
[0], ptr
[1], ptr
[2], ptr
[3], ptr
[4], ptr
[5], ptr
[6], ptr
[7],
1285 while (*(x1
= x2
+ strlen(x2
) + 1))
1287 x2
= x1
+ strlen(x1
) + 1;
1289 printf("\t\t%s: %s\n", x1
, x2
);
1294 case S_MSTOOLINFO_V3
:
1296 const unsigned short* ptr
= ((const unsigned short*)sym
) + 2;
1298 printf("\tTool info V3: unk=%04x%04x%04x front=%d.%d.%d.%d back=%d.%d.%d.%d %s\n",
1299 ptr
[0], ptr
[1], ptr
[2],
1300 ptr
[3], ptr
[4], ptr
[5], ptr
[6],
1301 ptr
[7], ptr
[8], ptr
[9], ptr
[10],
1302 (const char*)(ptr
+ 11));
1306 case S_MSTOOLENV_V3
:
1308 const char* x1
= (const char*)sym
+ 4 + 1;
1311 printf("\tTool conf V3\n");
1314 x2
= x1
+ strlen(x1
) + 1;
1316 printf("\t\t%s: %s\n", x1
, x2
);
1317 x1
= x2
+ strlen(x2
) + 1;
1323 /* simply skip it */
1327 printf("\tSSearch V1: (%04x:%08x)\n",
1328 sym
->ssearch_v1
.segment
, sym
->ssearch_v1
.offset
);
1332 printf("\tSSection Info: seg=%04x ?=%04x rva=%08x size=%08x attr=%08x %s\n",
1333 *(const unsigned short*)((const char*)sym
+ 4),
1334 *(const unsigned short*)((const char*)sym
+ 6),
1335 *(const unsigned*)((const char*)sym
+ 8),
1336 *(const unsigned*)((const char*)sym
+ 12),
1337 *(const unsigned*)((const char*)sym
+ 16),
1338 (const char*)sym
+ 20);
1341 case S_SUBSECTINFO_V3
:
1342 printf("\tSSubSection Info: addr=%04x:%08x size=%08x attr=%08x %s\n",
1343 *(const unsigned short*)((const char*)sym
+ 16),
1344 *(const unsigned*)((const char*)sym
+ 12),
1345 *(const unsigned*)((const char*)sym
+ 4),
1346 *(const unsigned*)((const char*)sym
+ 8),
1347 (const char*)sym
+ 18);
1350 case S_ENTRYPOINT_V3
:
1351 printf("\tSEntryPoint: id=%x '%s'\n",
1352 *(const unsigned*)((const char*)sym
+ 4), (const char*)sym
+ 8);
1357 printf("\tS-Thread %s Var V1 '%s' seg=%04x offset=%08x type=%x\n",
1358 sym
->generic
.id
== S_LTHREAD_V1
? "global" : "local",
1359 p_string(&sym
->thread_v1
.p_name
),
1360 sym
->thread_v1
.segment
, sym
->thread_v1
.offset
, sym
->thread_v1
.symtype
);
1365 printf("\tS-Thread %s Var V2 '%s' seg=%04x offset=%08x type=%x\n",
1366 sym
->generic
.id
== S_LTHREAD_V2
? "global" : "local",
1367 p_string(&sym
->thread_v2
.p_name
),
1368 sym
->thread_v2
.segment
, sym
->thread_v2
.offset
, sym
->thread_v2
.symtype
);
1373 printf("\tS-Thread %s Var V3 '%s' seg=%04x offset=%08x type=%x\n",
1374 sym
->generic
.id
== S_LTHREAD_V3
? "global" : "local", sym
->thread_v3
.name
,
1375 sym
->thread_v3
.segment
, sym
->thread_v3
.offset
, sym
->thread_v3
.symtype
);
1379 printf(">>> Unsupported symbol-id %x sz=%d\n", sym
->generic
.id
, sym
->generic
.len
+ 2);
1380 dump_data((const void*)sym
, sym
->generic
.len
+ 2, " ");
1386 void codeview_dump_linetab(const char* linetab
, DWORD size
, BOOL pascal_str
, const char* pfx
)
1388 const char* ptr
= linetab
;
1389 int nfile
, nseg
, nline
;
1391 const unsigned int* filetab
;
1392 const unsigned int* lt_ptr
;
1393 const struct startend
* start
;
1395 nfile
= *(const short*)linetab
;
1396 filetab
= (const unsigned int*)(linetab
+ 2 * sizeof(short));
1397 printf("%s%d files with %d ???\n", pfx
, nfile
, *(const short*)(linetab
+ sizeof(short)));
1399 for (i
= 0; i
< nfile
; i
++)
1401 ptr
= linetab
+ filetab
[i
];
1402 nseg
= *(const short*)ptr
;
1403 ptr
+= 2 * sizeof(short);
1404 lt_ptr
= (const unsigned int*)ptr
;
1405 start
= (const struct startend
*)(lt_ptr
+ nseg
);
1408 * Now snarf the filename for all of the segments for this file.
1412 char filename
[MAX_PATH
];
1413 const struct p_string
* p_fn
;
1415 p_fn
= (const struct p_string
*)(start
+ nseg
);
1416 memset(filename
, 0, sizeof(filename
));
1417 memcpy(filename
, p_fn
->name
, p_fn
->namelen
);
1418 printf("%slines for file #%d/%d %s %d\n", pfx
, i
, nfile
, filename
, nseg
);
1421 printf("%slines for file #%d/%d %s %d\n", pfx
, i
, nfile
, (const char*)(start
+ nseg
), nseg
);
1423 for (j
= 0; j
< nseg
; j
++)
1425 ptr
= linetab
+ *lt_ptr
++;
1426 nline
= *(const short*)(ptr
+ 2);
1427 printf("%s %04x:%08x-%08x #%d\n",
1428 pfx
, *(const short*)(ptr
+ 0), start
[j
].start
, start
[j
].end
, nline
);
1430 for (k
= 0; k
< nline
; k
++)
1432 printf("%s %x %d\n",
1433 pfx
, ((const unsigned int*)ptr
)[k
],
1434 ((const unsigned short*)((const unsigned int*)ptr
+ nline
))[k
]);
1440 void codeview_dump_linetab2(const char* linetab
, DWORD size
, const char* strimage
, DWORD strsize
, const char* pfx
)
1443 const struct codeview_linetab2
* lt2
;
1444 const struct codeview_linetab2
* lt2_files
= NULL
;
1445 const struct codeview_lt2blk_lines
* lines_blk
;
1446 const struct codeview_linetab2_file
*fd
;
1448 /* locate LT2_FILES_BLOCK (if any) */
1449 lt2
= (const struct codeview_linetab2
*)linetab
;
1450 while ((const char*)(lt2
+ 1) < linetab
+ size
)
1452 if (lt2
->header
== LT2_FILES_BLOCK
)
1457 lt2
= codeview_linetab2_next_block(lt2
);
1461 printf("%sNo LT2_FILES_BLOCK found\n", pfx
);
1465 lt2
= (const struct codeview_linetab2
*)linetab
;
1466 while ((const char*)(lt2
+ 1) < linetab
+ size
)
1468 /* FIXME: should also check that whole lbh fits in linetab + size */
1469 switch (lt2
->header
)
1471 case LT2_LINES_BLOCK
:
1472 lines_blk
= (const struct codeview_lt2blk_lines
*)lt2
;
1473 printf("%sblock from %04x:%08x #%x (%x lines) fo=%x\n",
1474 pfx
, lines_blk
->seg
, lines_blk
->start
, lines_blk
->size
,
1475 lines_blk
->nlines
, lines_blk
->file_offset
);
1476 /* FIXME: should check that file_offset is within the LT2_FILES_BLOCK we've seen */
1477 fd
= (const struct codeview_linetab2_file
*)((const char*)lt2_files
+ 8 + lines_blk
->file_offset
);
1478 printf("%s md5=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
1479 pfx
, fd
->md5
[ 0], fd
->md5
[ 1], fd
->md5
[ 2], fd
->md5
[ 3],
1480 fd
->md5
[ 4], fd
->md5
[ 5], fd
->md5
[ 6], fd
->md5
[ 7],
1481 fd
->md5
[ 8], fd
->md5
[ 9], fd
->md5
[10], fd
->md5
[11],
1482 fd
->md5
[12], fd
->md5
[13], fd
->md5
[14], fd
->md5
[15]);
1483 /* FIXME: should check that string is within strimage + strsize */
1484 printf("%s file=%s\n", pfx
, strimage
? strimage
+ fd
->offset
: "--none--");
1485 for (i
= 0; i
< lines_blk
->nlines
; i
++)
1487 printf("%s offset=%08x line=%d\n",
1488 pfx
, lines_blk
->l
[i
].offset
, lines_blk
->l
[i
].lineno
^ 0x80000000);
1491 case LT2_FILES_BLOCK
: /* skip */
1494 printf("%sblock end %x\n", pfx
, lt2
->header
);
1495 lt2
= (const struct codeview_linetab2
*)((const char*)linetab
+ size
);
1498 lt2
= codeview_linetab2_next_block(lt2
);