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 void do_field(const unsigned char* start
, const unsigned char* end
)
223 * A 'field list' is a CodeView-specific data type which doesn't
224 * directly correspond to any high-level data type. It is used
225 * to hold the collection of members of a struct, class, union
226 * or enum type. The actual definition of that type will follow
227 * later, and refer to the field list definition record.
229 * As we don't have a field list type ourselves, we look ahead
230 * in the field list to try to find out whether this field list
231 * will be used for an enum or struct type, and create a dummy
232 * type of the corresponding sort. Later on, the definition of
233 * the 'real' type will copy the member / enumeration data.
235 const unsigned char* ptr
= start
;
237 const struct p_string
* pstr
;
242 const union codeview_fieldtype
* fieldtype
= (const union codeview_fieldtype
*)ptr
;
244 if (*ptr
>= 0xf0) /* LF_PAD... */
250 switch (fieldtype
->generic
.id
)
252 case LF_ENUMERATE_V1
:
253 leaf_len
= numeric_leaf(&value
, &fieldtype
->enumerate_v1
.value
);
254 pstr
= PSTRING(&fieldtype
->enumerate_v1
.value
, leaf_len
);
255 printf("\t\tEnumerate V1: '%s' value:%d\n",
256 p_string(pstr
), value
);
257 ptr
+= 2 + 2 + leaf_len
+ 1 + pstr
->namelen
;
260 case LF_ENUMERATE_V3
:
261 leaf_len
= numeric_leaf(&value
, &fieldtype
->enumerate_v3
.value
);
262 cstr
= (const char*)&fieldtype
->enumerate_v3
.value
+ leaf_len
;
263 printf("\t\tEnumerate V3: '%s' value:%d\n",
265 ptr
+= 2 + 2 + leaf_len
+ strlen(cstr
) + 1;
269 leaf_len
= numeric_leaf(&value
, &fieldtype
->member_v1
.offset
);
270 pstr
= PSTRING(&fieldtype
->member_v1
.offset
, leaf_len
);
271 printf("\t\tMember V1: '%s' type:%x attr:%s @%d\n",
272 p_string(pstr
), fieldtype
->member_v1
.type
,
273 get_attr(fieldtype
->member_v1
.attribute
), value
);
274 ptr
+= 2 + 2 + 2 + leaf_len
+ 1 + pstr
->namelen
;
278 leaf_len
= numeric_leaf(&value
, &fieldtype
->member_v2
.offset
);
279 pstr
= PSTRING(&fieldtype
->member_v2
.offset
, leaf_len
);
280 printf("\t\tMember V2: '%s' type:%x attr:%s @%d\n",
281 p_string(pstr
), fieldtype
->member_v2
.type
,
282 get_attr(fieldtype
->member_v2
.attribute
), value
);
283 ptr
+= 2 + 2 + 4 + leaf_len
+ 1 + pstr
->namelen
;
287 leaf_len
= numeric_leaf(&value
, &fieldtype
->member_v3
.offset
);
288 cstr
= (const char*)&fieldtype
->member_v3
.offset
+ leaf_len
;
289 printf("\t\tMember V3: '%s' type:%x attr:%s @%d\n",
290 cstr
, fieldtype
->member_v3
.type
,
291 get_attr(fieldtype
->member_v3
.attribute
), value
);
292 ptr
+= 2 + 2 + 4 + leaf_len
+ strlen(cstr
) + 1;
295 case LF_ONEMETHOD_V1
:
296 switch ((fieldtype
->onemethod_v1
.attribute
>> 2) & 7)
299 printf("\t\tVirtual-method V1: '%s' attr:%s type:%x vtable_offset:%u\n",
300 p_string(&fieldtype
->onemethod_virt_v1
.p_name
),
301 get_attr(fieldtype
->onemethod_virt_v1
.attribute
),
302 fieldtype
->onemethod_virt_v1
.type
,
303 fieldtype
->onemethod_virt_v1
.vtab_offset
);
304 ptr
+= 2 + 2 + 2 + 4 + (1 + fieldtype
->onemethod_virt_v1
.p_name
.namelen
);
308 printf("\t\tMethod V1: '%s' attr:%s type:%x\n",
309 p_string(&fieldtype
->onemethod_v1
.p_name
),
310 get_attr(fieldtype
->onemethod_v1
.attribute
),
311 fieldtype
->onemethod_v1
.type
);
312 ptr
+= 2 + 2 + 2 + (1 + fieldtype
->onemethod_v1
.p_name
.namelen
);
317 case LF_ONEMETHOD_V2
:
318 switch ((fieldtype
->onemethod_v2
.attribute
>> 2) & 7)
321 printf("\t\tVirtual-method V2: '%s' attr:%s type:%x vtable_offset:%u\n",
322 p_string(&fieldtype
->onemethod_virt_v2
.p_name
),
323 get_attr(fieldtype
->onemethod_virt_v2
.attribute
),
324 fieldtype
->onemethod_virt_v2
.type
,
325 fieldtype
->onemethod_virt_v2
.vtab_offset
);
326 ptr
+= 2 + 2 + 4 + 4 + (1 + fieldtype
->onemethod_virt_v2
.p_name
.namelen
);
330 printf("\t\tMethod V2: '%s' attr:%s type:%x\n",
331 p_string(&fieldtype
->onemethod_v2
.p_name
),
332 get_attr(fieldtype
->onemethod_v2
.attribute
),
333 fieldtype
->onemethod_v2
.type
);
334 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->onemethod_v2
.p_name
.namelen
);
339 case LF_ONEMETHOD_V3
:
340 switch ((fieldtype
->onemethod_v3
.attribute
>> 2) & 7)
343 printf("\t\tVirtual-method V3: '%s' attr:%s type:%x vtable_offset:%u\n",
344 fieldtype
->onemethod_virt_v3
.name
,
345 get_attr(fieldtype
->onemethod_virt_v3
.attribute
),
346 fieldtype
->onemethod_virt_v3
.type
,
347 fieldtype
->onemethod_virt_v3
.vtab_offset
);
348 ptr
+= 2 + 2 + 4 + 4 + (strlen(fieldtype
->onemethod_virt_v3
.name
) + 1);
352 printf("\t\tMethod V3: '%s' attr:%s type:%x\n",
353 fieldtype
->onemethod_v3
.name
,
354 get_attr(fieldtype
->onemethod_v3
.attribute
),
355 fieldtype
->onemethod_v3
.type
);
356 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->onemethod_v3
.name
) + 1);
362 printf("\t\tMethod V1: '%s' overloaded=#%d method-list=%x\n",
363 p_string(&fieldtype
->method_v1
.p_name
),
364 fieldtype
->method_v1
.count
, fieldtype
->method_v1
.mlist
);
365 ptr
+= 2 + 2 + 2 + (1 + fieldtype
->method_v1
.p_name
.namelen
);
369 printf("\t\tMethod V2: '%s' overloaded=#%d method-list=%x\n",
370 p_string(&fieldtype
->method_v2
.p_name
),
371 fieldtype
->method_v2
.count
, fieldtype
->method_v2
.mlist
);
372 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->method_v2
.p_name
.namelen
);
376 printf("\t\tMethod V3: '%s' overloaded=#%d method-list=%x\n",
377 fieldtype
->method_v3
.name
,
378 fieldtype
->method_v3
.count
, fieldtype
->method_v3
.mlist
);
379 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->method_v3
.name
) + 1);
383 printf("\t\tStatic member V1: '%s' attr:%s type:%x\n",
384 p_string(&fieldtype
->stmember_v1
.p_name
),
385 get_attr(fieldtype
->stmember_v1
.attribute
),
386 fieldtype
->stmember_v1
.type
);
387 ptr
+= 2 + 2 + 2 + (1 + fieldtype
->stmember_v1
.p_name
.namelen
);
391 printf("\t\tStatic member V2: '%s' attr:%s type:%x\n",
392 p_string(&fieldtype
->stmember_v2
.p_name
),
393 get_attr(fieldtype
->stmember_v2
.attribute
),
394 fieldtype
->stmember_v2
.type
);
395 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->stmember_v2
.p_name
.namelen
);
399 printf("\t\tStatic member V3: '%s' attr:%s type:%x\n",
400 fieldtype
->stmember_v3
.name
,
401 get_attr(fieldtype
->stmember_v3
.attribute
),
402 fieldtype
->stmember_v3
.type
);
403 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->stmember_v3
.name
) + 1);
406 case LF_FRIENDFCN_V1
:
407 printf("\t\tFriend function V1: '%s' type:%x\n",
408 p_string(&fieldtype
->friendfcn_v1
.p_name
),
409 fieldtype
->friendfcn_v1
.type
);
412 case LF_FRIENDFCN_V2
:
413 printf("\t\tFriend function V2: '%s' type:%x\n",
414 p_string(&fieldtype
->friendfcn_v2
.p_name
),
415 fieldtype
->friendfcn_v2
.type
);
419 case LF_FRIENDFCN_V3
:
420 printf("\t\tFriend function V3: '%s' type:%x\n",
421 fieldtype
->friendfcn_v3
.name
,
422 fieldtype
->friendfcn_v3
.type
);
427 leaf_len
= numeric_leaf(&value
, &fieldtype
->bclass_v1
.offset
);
428 printf("\t\tBase class V1: type:%x attr:%s @%d\n",
429 fieldtype
->bclass_v1
.type
,
430 get_attr(fieldtype
->bclass_v1
.attribute
), value
);
431 ptr
+= 2 + 2 + 2 + leaf_len
;
435 leaf_len
= numeric_leaf(&value
, &fieldtype
->bclass_v2
.offset
);
436 printf("\t\tBase class V2: type:%x attr:%s @%d\n",
437 fieldtype
->bclass_v2
.type
,
438 get_attr(fieldtype
->bclass_v2
.attribute
), value
);
439 ptr
+= 2 + 2 + 4 + leaf_len
;
444 leaf_len
= numeric_leaf(&value
, &fieldtype
->vbclass_v1
.vbpoff
);
445 printf("\t\t%sirtual base class V1: type:%x (ptr:%x) attr:%s vbpoff:%d ",
446 (fieldtype
->generic
.id
== LF_VBCLASS_V2
) ? "V" : "Indirect v",
447 fieldtype
->vbclass_v1
.btype
, fieldtype
->vbclass_v1
.vbtype
,
448 get_attr(fieldtype
->vbclass_v1
.attribute
), value
);
449 ptr
+= 2 + 2 + 2 + 2 + leaf_len
;
450 leaf_len
= numeric_leaf(&value
, (const unsigned short*)ptr
);
451 printf("vboff:%d\n", value
);
457 leaf_len
= numeric_leaf(&value
, &fieldtype
->vbclass_v1
.vbpoff
);
458 printf("\t\t%sirtual base class V2: type:%x (ptr:%x) attr:%s vbpoff:%d ",
459 (fieldtype
->generic
.id
== LF_VBCLASS_V2
) ? "V" : "Indirect v",
460 fieldtype
->vbclass_v2
.btype
, fieldtype
->vbclass_v2
.vbtype
,
461 get_attr(fieldtype
->vbclass_v2
.attribute
), value
);
462 ptr
+= 2 + 2 + 4 + 4 + leaf_len
;
463 leaf_len
= numeric_leaf(&value
, (const unsigned short*)ptr
);
464 printf("vboff:%d\n", value
);
468 case LF_FRIENDCLS_V1
:
469 printf("\t\tFriend class V1: type:%x\n", fieldtype
->friendcls_v1
.type
);
472 case LF_FRIENDCLS_V2
:
473 printf("\t\tFriend class V2: type:%x\n", fieldtype
->friendcls_v2
.type
);
477 printf("\t\tNested type V1: '%s' type:%x\n",
478 p_string(&fieldtype
->nesttype_v1
.p_name
),
479 fieldtype
->nesttype_v1
.type
);
480 ptr
+= 2 + 2 + (1 + fieldtype
->nesttype_v1
.p_name
.namelen
);
484 printf("\t\tNested type V2: '%s' pad0:%u type:%x\n",
485 p_string(&fieldtype
->nesttype_v2
.p_name
),
486 fieldtype
->nesttype_v2
._pad0
, fieldtype
->nesttype_v2
.type
);
487 ptr
+= 2 + 2 + 4 + (1 + fieldtype
->nesttype_v2
.p_name
.namelen
);
491 printf("\t\tNested type V3: '%s' pad0:%u type:%x\n",
492 fieldtype
->nesttype_v3
.name
,
493 fieldtype
->nesttype_v3
._pad0
, fieldtype
->nesttype_v3
.type
);
494 ptr
+= 2 + 2 + 4 + (strlen(fieldtype
->nesttype_v3
.name
) + 1);
498 printf("\t\tVirtual function table V1: type:%x\n",
499 fieldtype
->vfunctab_v1
.type
);
504 printf("\t\tVirtual function table V2: type:%x\n",
505 fieldtype
->vfunctab_v2
.type
);
510 printf("\t\tVirtual function table offset V1: type:%x offset:%x\n",
511 fieldtype
->vfuncoff_v1
.type
, fieldtype
->vfuncoff_v1
.offset
);
515 printf("\t\tVirtual function table offset V2: type:%x offset:%x\n",
516 fieldtype
->vfuncoff_v2
.type
, fieldtype
->vfuncoff_v2
.offset
);
520 printf(">>> Unsupported field-id %x\n", fieldtype
->generic
.id
);
521 dump_data((const void*)fieldtype
, 0x30, "\t");
527 static void codeview_dump_one_type(unsigned curr_type
, const union codeview_type
* type
)
529 const union codeview_reftype
* reftype
= (const union codeview_reftype
*)type
;
530 int i
, leaf_len
, value
;
534 switch (type
->generic
.id
)
537 printf("\t%x => Pointer V1 to type:%x\n",
538 curr_type
, type
->pointer_v1
.datatype
);
541 printf("\t%x => Pointer V2 to type:%x\n",
542 curr_type
, type
->pointer_v2
.datatype
);
545 leaf_len
= numeric_leaf(&value
, &type
->array_v1
.arrlen
);
546 printf("\t%x => Array V1-'%s'[%u type:%x] type:%x\n",
547 curr_type
, p_string(PSTRING(&type
->array_v1
.arrlen
, leaf_len
)),
548 value
, type
->array_v1
.idxtype
, type
->array_v1
.elemtype
);
551 leaf_len
= numeric_leaf(&value
, &type
->array_v2
.arrlen
);
552 printf("\t%x => Array V2-'%s'[%u type:%x] type:%x\n",
553 curr_type
, p_string(PSTRING(&type
->array_v2
.arrlen
, leaf_len
)),
554 value
, type
->array_v2
.idxtype
, type
->array_v2
.elemtype
);
557 leaf_len
= numeric_leaf(&value
, &type
->array_v3
.arrlen
);
558 str
= (const char*)&type
->array_v3
.arrlen
+ leaf_len
;
559 printf("\t%x => Array V3-'%s'[%u type:%x] type:%x\n",
560 curr_type
, str
, value
,
561 type
->array_v3
.idxtype
, type
->array_v3
.elemtype
);
564 /* a bitfields is a CodeView specific data type which represent a bitfield
565 * in a structure or a class. For now, we store it in a SymTag-like type
566 * (so that the rest of the process is seamless), but check at udt inclusion
567 * type for its presence
570 printf("\t%x => Bitfield V1:%x offset:%u #bits:%u\n",
571 curr_type
, reftype
->bitfield_v1
.type
, reftype
->bitfield_v1
.bitoff
,
572 reftype
->bitfield_v1
.nbits
);
576 printf("\t%x => Bitfield V2:%x offset:%u #bits:%u\n",
577 curr_type
, reftype
->bitfield_v2
.type
, reftype
->bitfield_v2
.bitoff
,
578 reftype
->bitfield_v2
.nbits
);
581 case LF_FIELDLIST_V1
:
582 case LF_FIELDLIST_V2
:
583 printf("\t%x => Fieldlist\n", curr_type
);
584 do_field(reftype
->fieldlist
.list
, (const BYTE
*)type
+ reftype
->generic
.len
+ 2);
587 case LF_STRUCTURE_V1
:
589 leaf_len
= numeric_leaf(&value
, &type
->struct_v1
.structlen
);
590 printf("\t%x => %s V1 '%s' elts:%u prop:%u fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
591 curr_type
, type
->generic
.id
== LF_CLASS_V1
? "Class" : "Struct",
592 p_string(PSTRING(&type
->struct_v1
.structlen
, leaf_len
)),
593 type
->struct_v1
.n_element
, type
->struct_v1
.property
,
594 type
->struct_v1
.fieldlist
, type
->struct_v1
.derived
,
595 type
->struct_v1
.vshape
, value
);
598 case LF_STRUCTURE_V2
:
600 leaf_len
= numeric_leaf(&value
, &type
->struct_v2
.structlen
);
601 printf("\t%x => %s V2 '%s' elts:%u prop:%u\n"
602 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
603 curr_type
, type
->generic
.id
== LF_CLASS_V2
? "Class" : "Struct",
604 p_string(PSTRING(&type
->struct_v2
.structlen
, leaf_len
)),
605 type
->struct_v2
.n_element
, type
->struct_v2
.property
,
606 type
->struct_v2
.fieldlist
, type
->struct_v2
.derived
,
607 type
->struct_v2
.vshape
, value
);
610 case LF_STRUCTURE_V3
:
612 leaf_len
= numeric_leaf(&value
, &type
->struct_v3
.structlen
);
613 str
= (const char*)&type
->struct_v3
.structlen
+ leaf_len
;
614 printf("\t%x => %s V3 '%s' elts:%u prop:%u\n"
615 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
616 curr_type
, type
->generic
.id
== LF_CLASS_V3
? "Class" : "Struct",
617 str
, type
->struct_v3
.n_element
, type
->struct_v3
.property
,
618 type
->struct_v3
.fieldlist
, type
->struct_v3
.derived
,
619 type
->struct_v3
.vshape
, value
);
623 leaf_len
= numeric_leaf(&value
, &type
->union_v1
.un_len
);
624 printf("\t%x => Union V1 '%s' count:%u prop:%u fieldlist-type:%x size:%u\n",
625 curr_type
, p_string(PSTRING(&type
->union_v1
.un_len
, leaf_len
)),
626 type
->union_v1
.count
, type
->union_v1
.property
,
627 type
->union_v1
.fieldlist
, value
);
631 leaf_len
= numeric_leaf(&value
, &type
->union_v2
.un_len
);
632 printf("\t%x => Union V2 '%s' count:%u prop:%u fieldlist-type:%x size:%u\n",
633 curr_type
, p_string(PSTRING(&type
->union_v2
.un_len
, leaf_len
)),
634 type
->union_v2
.count
, type
->union_v2
.property
,
635 type
->union_v2
.fieldlist
, value
);
639 leaf_len
= numeric_leaf(&value
, &type
->union_v3
.un_len
);
640 str
= (const char*)&type
->union_v3
.un_len
+ leaf_len
;
641 printf("\t%x => Union V3 '%s' count:%u prop:%u fieldlist-type:%x size:%u\n",
642 curr_type
, str
, type
->union_v3
.count
,
643 type
->union_v3
.property
, type
->union_v3
.fieldlist
, value
);
647 printf("\t%x => Enum V1 '%s' type:%x field-type:%x count:%u property:%x\n",
648 curr_type
, p_string(&type
->enumeration_v1
.p_name
),
649 type
->enumeration_v1
.type
,
650 type
->enumeration_v1
.fieldlist
,
651 type
->enumeration_v1
.count
,
652 type
->enumeration_v1
.property
);
656 printf("\t%x => Enum V2 '%s' type:%x field-type:%x count:%u property:%x\n",
657 curr_type
, p_string(&type
->enumeration_v2
.p_name
),
658 type
->enumeration_v2
.type
,
659 type
->enumeration_v2
.fieldlist
,
660 type
->enumeration_v2
.count
,
661 type
->enumeration_v2
.property
);
665 printf("\t%x => Enum V3 '%s' type:%x field-type:%x count:%u property:%x\n",
666 curr_type
, type
->enumeration_v3
.name
,
667 type
->enumeration_v3
.type
,
668 type
->enumeration_v3
.fieldlist
,
669 type
->enumeration_v3
.count
,
670 type
->enumeration_v3
.property
);
674 printf("\t%x => Arglist V1(#%u):", curr_type
, reftype
->arglist_v1
.num
);
675 for (i
= 0; i
< reftype
->arglist_v1
.num
; i
++)
677 printf(" %x", reftype
->arglist_v1
.args
[i
]);
683 printf("\t%x => Arglist V2(#%u):", curr_type
, reftype
->arglist_v2
.num
);
684 for (j
= 0; j
< reftype
->arglist_v2
.num
; j
++)
686 printf("\t %x", reftype
->arglist_v2
.args
[j
]);
691 case LF_PROCEDURE_V1
:
692 /* FIXME: unknown could be the calling convention for the proc */
693 printf("\t%x => Procedure V1 ret_type:%x call:%x (#%u args_type:%x)\n",
694 curr_type
, type
->procedure_v1
.rvtype
,
695 type
->procedure_v1
.call
, type
->procedure_v1
.params
,
696 type
->procedure_v1
.arglist
);
699 case LF_PROCEDURE_V2
:
700 printf("\t%x => Procedure V2 ret_type:%x unk:%x (#%u args_type:%x)\n",
701 curr_type
, type
->procedure_v2
.rvtype
,
702 type
->procedure_v2
.call
, type
->procedure_v2
.params
,
703 type
->procedure_v2
.arglist
);
706 case LF_MFUNCTION_V2
:
707 printf("\t%x => MFunction V2 ret-type:%x call:%x class-type:%x this-type:%x\n"
708 "\t\t#args:%x args-type:%x this_adjust:%x\n",
710 type
->mfunction_v2
.rvtype
,
711 type
->mfunction_v2
.call
,
712 type
->mfunction_v2
.class_type
,
713 type
->mfunction_v2
.this_type
,
714 type
->mfunction_v2
.params
,
715 type
->mfunction_v2
.arglist
,
716 type
->mfunction_v2
.this_adjust
);
720 printf("\t%x => Modifier V1 type:%x modif:%x\n",
721 curr_type
, type
->modifier_v1
.type
, type
->modifier_v1
.attribute
);
725 printf("\t%x => Modifier V2 type:%x modif:%x\n",
726 curr_type
, type
->modifier_v2
.type
, type
->modifier_v2
.attribute
);
729 case LF_METHODLIST_V1
:
731 const unsigned short* pattr
= (const unsigned short*)((const char*)type
+ 4);
733 printf("\t%x => Method list\n", curr_type
);
734 while ((const char*)pattr
< (const char*)type
+ type
->generic
.len
+ 2)
736 switch ((*pattr
>> 2) & 7)
739 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
740 get_attr(pattr
[0]), pattr
[1],
741 *(const unsigned*)(&pattr
[2]));
745 printf("\t\t\tattr:%s type:%x\n",
746 get_attr(pattr
[0]), pattr
[1]);
753 case LF_METHODLIST_V2
:
755 const unsigned* pattr
= (const unsigned*)((const char*)type
+ 4);
757 printf("\t%x => Method list\n", curr_type
);
758 while ((const char*)pattr
< (const char*)type
+ type
->generic
.len
+ 2)
760 switch ((*pattr
>> 2) & 7)
763 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
764 get_attr(pattr
[0]), pattr
[1], pattr
[2]);
768 printf("\t\t\tattr:%s type:%x\n",
769 get_attr(pattr
[0]), pattr
[1]);
778 int count
= *(const unsigned short*)((const char*)type
+ 4);
780 const char* ptr
= (const char*)type
+ 6;
781 const char* desc
[] = {"Near", "Far", "Thin", "Disp to outtermost",
782 "Pointer to metaclass", "Near32", "Far32"};
783 printf("\t%x => VT Shape #%d: ", curr_type
, count
);
786 if (((*ptr
<< shift
) & 0xF) <= 6)
787 printf("%s ", desc
[(*ptr
<< shift
) & 0xF]);
789 printf("%x ", (*ptr
<< shift
) & 0xF);
790 if (shift
== 0) shift
= 4; else {shift
= 0; ptr
++;}
797 printf("\t%x => Derived V1(#%u):", curr_type
, reftype
->derived_v1
.num
);
798 for (i
= 0; i
< reftype
->derived_v1
.num
; i
++)
800 printf(" %x", reftype
->derived_v1
.drvdcls
[i
]);
806 printf("\t%x => Derived V2(#%u):", curr_type
, reftype
->derived_v2
.num
);
807 for (j
= 0; j
< reftype
->derived_v2
.num
; j
++)
809 printf(" %x", reftype
->derived_v2
.drvdcls
[j
]);
815 printf(">>> Unsupported type-id %x for %x\n", type
->generic
.id
, curr_type
);
816 dump_data((const void*)type
, type
->generic
.len
+ 2, "");
821 int codeview_dump_types_from_offsets(const void* table
, const DWORD
* offsets
, unsigned num_types
)
825 for (i
= 0; i
< num_types
; i
++)
827 codeview_dump_one_type(0x1000 + i
,
828 (const union codeview_type
*)((const char*)table
+ offsets
[i
]));
834 int codeview_dump_types_from_block(const void* table
, unsigned long len
)
836 unsigned int curr_type
= 0x1000;
837 const unsigned char*ptr
= table
;
839 while (ptr
- (const unsigned char*)table
< len
)
841 const union codeview_type
* type
= (const union codeview_type
*)ptr
;
843 codeview_dump_one_type(curr_type
, type
);
845 ptr
+= (type
->generic
.len
+ 2 + 3) & ~3;
851 int codeview_dump_symbols(const void* root
, unsigned long size
)
855 char* curr_func
= NULL
;
858 * Loop over the different types of records and whenever we
859 * find something we are interested in, record it and move on.
861 for (i
= 0; i
< size
; i
+= length
)
863 const union codeview_symbol
* sym
= (const union codeview_symbol
*)((const char*)root
+ i
);
864 length
= sym
->generic
.len
+ 2;
865 if (!sym
->generic
.id
|| length
< 4) break;
866 switch (sym
->generic
.id
)
869 * Global and local data symbols. We don't associate these
870 * with any given source file.
874 printf("\tS-%s-Data V2 '%s' %04x:%08x type:%08x\n",
875 sym
->generic
.id
== S_GDATA_V2
? "Global" : "Local",
876 get_symbol_str(p_string(&sym
->data_v2
.p_name
)),
877 sym
->data_v2
.segment
, sym
->data_v2
.offset
, sym
->data_v2
.symtype
);
882 /* EPP case S_DATA_V3: */
883 printf("\tS-%s-Data V3 '%s' (%04x:%08x) type:%08x\n",
884 sym
->generic
.id
== S_GDATA_V3
? "Global" : "Local",
885 get_symbol_str(sym
->data_v3
.name
),
886 sym
->data_v3
.segment
, sym
->data_v3
.offset
,
887 sym
->data_v3
.symtype
);
891 printf("\tS-Public V2 '%s' %04x:%08x type:%08x\n",
892 get_symbol_str(p_string(&sym
->public_v2
.p_name
)),
893 sym
->public_v2
.segment
, sym
->public_v2
.offset
,
894 sym
->public_v2
.symtype
);
898 /* not completely sure of those two anyway */
901 printf("\tS-Public%s V3 '%s' %04x:%08x type:%08x\n",
902 sym
->generic
.id
== S_PUB_V3
? "" :
903 (sym
->generic
.id
== S_PUB_FUNC1_V3
? "<subkind1" : "<subkind2"),
904 get_symbol_str(sym
->public_v3
.name
),
905 sym
->public_v3
.segment
,
906 sym
->public_v3
.offset
, sym
->public_v3
.symtype
);
910 * Sort of like a global function, but it just points
911 * to a thunk, which is a stupid name for what amounts to
912 * a PLT slot in the normal jargon that everyone else uses.
915 printf("\tS-Thunk V1 '%s' (%04x:%08x#%x) type:%x\n",
916 p_string(&sym
->thunk_v1
.p_name
),
917 sym
->thunk_v1
.segment
, sym
->thunk_v1
.offset
,
918 sym
->thunk_v1
.thunk_len
, sym
->thunk_v1
.thtype
);
919 curr_func
= strdup(p_string(&sym
->thunk_v1
.p_name
));
923 printf("\tS-Thunk V3 '%s' (%04x:%08x#%x) type:%x\n",
925 sym
->thunk_v3
.segment
, sym
->thunk_v3
.offset
,
926 sym
->thunk_v3
.thunk_len
, sym
->thunk_v3
.thtype
);
927 curr_func
= strdup(sym
->thunk_v3
.name
);
930 /* Global and static functions */
933 printf("\tS-%s-Proc V1: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
934 sym
->generic
.id
== S_GPROC_V1
? "Global" : "-Local",
935 p_string(&sym
->proc_v1
.p_name
),
936 sym
->proc_v1
.segment
, sym
->proc_v1
.offset
,
937 sym
->proc_v1
.proc_len
, sym
->proc_v1
.proctype
,
939 printf("\t Debug: start=%08x end=%08x\n",
940 sym
->proc_v1
.debug_start
, sym
->proc_v1
.debug_end
);
943 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func
, nest_block
);
946 curr_func
= strdup(p_string(&sym
->proc_v1
.p_name
));
947 /* EPP unsigned int pparent; */
948 /* EPP unsigned int pend; */
949 /* EPP unsigned int next; */
954 printf("\tS-%s-Proc V2: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
955 sym
->generic
.id
== S_GPROC_V2
? "Global" : "-Local",
956 p_string(&sym
->proc_v2
.p_name
),
957 sym
->proc_v2
.segment
, sym
->proc_v2
.offset
,
958 sym
->proc_v2
.proc_len
, sym
->proc_v2
.proctype
,
960 printf("\t Debug: start=%08x end=%08x\n",
961 sym
->proc_v2
.debug_start
, sym
->proc_v2
.debug_end
);
964 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func
, nest_block
);
967 curr_func
= strdup(p_string(&sym
->proc_v2
.p_name
));
968 /* EPP unsigned int pparent; */
969 /* EPP unsigned int pend; */
970 /* EPP unsigned int next; */
975 printf("\tS-%s-Procedure V3 '%s' (%04x:%08x#%x) type:%x attr:%x\n",
976 sym
->generic
.id
== S_GPROC_V3
? "Global" : "Local",
978 sym
->proc_v3
.segment
, sym
->proc_v3
.offset
,
979 sym
->proc_v3
.proc_len
, sym
->proc_v3
.proctype
,
981 printf("\t Debug: start=%08x end=%08x\n",
982 sym
->proc_v3
.debug_start
, sym
->proc_v3
.debug_end
);
985 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func
, nest_block
);
988 curr_func
= strdup(sym
->proc_v3
.name
);
989 /* EPP unsigned int pparent; */
990 /* EPP unsigned int pend; */
991 /* EPP unsigned int next; */
994 /* Function parameters and stack variables */
996 printf("\tS-BP-relative V1: '%s' @%d type:%x (%s)\n",
997 p_string(&sym
->stack_v1
.p_name
),
998 sym
->stack_v1
.offset
, sym
->stack_v1
.symtype
, curr_func
);
1002 printf("\tS-BP-relative V2: '%s' @%d type:%x (%s)\n",
1003 p_string(&sym
->stack_v2
.p_name
),
1004 sym
->stack_v2
.offset
, sym
->stack_v2
.symtype
, curr_func
);
1008 printf("\tS-BP-relative V3: '%s' @%d type:%x (in %s)\n",
1009 sym
->stack_v3
.name
, sym
->stack_v3
.offset
,
1010 sym
->stack_v3
.symtype
, curr_func
);
1013 case S_BPREL_XXXX_V3
:
1014 printf("\tS-BP-relative XXXX V3: '%s' @%d type:%x unkn:%x (in %s)\n",
1015 sym
->stack_xxxx_v3
.name
, sym
->stack_xxxx_v3
.offset
,
1016 sym
->stack_xxxx_v3
.symtype
, sym
->stack_xxxx_v3
.unknown
, curr_func
);
1020 printf("\tS-Register V1 '%s' in %s type:%x register:%x\n",
1021 p_string(&sym
->register_v1
.p_name
),
1022 curr_func
, sym
->register_v1
.reg
, sym
->register_v1
.type
);
1026 printf("\tS-Register V2 '%s' in %s type:%x register:%x\n",
1027 p_string(&sym
->register_v2
.p_name
),
1028 curr_func
, sym
->register_v2
.reg
, sym
->register_v2
.type
);
1032 printf("\tS-Register V3 '%s' in %s type:%x register:%x\n",
1033 sym
->register_v3
.name
,
1034 curr_func
, sym
->register_v3
.reg
, sym
->register_v3
.type
);
1038 printf("\tS-Block V1 '%s' in '%s' (%04x:%08x#%08x)\n",
1039 p_string(&sym
->block_v1
.p_name
),
1041 sym
->block_v1
.segment
, sym
->block_v1
.offset
,
1042 sym
->block_v1
.length
);
1047 printf("\tS-Block V3 '%s' in '%s' (%04x:%08x#%08x) parent:%u end:%x\n",
1048 sym
->block_v3
.name
, curr_func
,
1049 sym
->block_v3
.segment
, sym
->block_v3
.offset
, sym
->block_v3
.length
,
1050 sym
->block_v3
.parent
, sym
->block_v3
.end
);
1054 /* Additional function information */
1056 printf("\tFunction info V2 unk1:%x unk2:%x unk3:%x unk4:%x unk5:%x unk6:%x flags:%04x unk7:%x\n",
1057 sym
->func_info_v2
.unknown1
,
1058 sym
->func_info_v2
.unknown2
,
1059 sym
->func_info_v2
.unknown3
,
1060 sym
->func_info_v2
.unknown4
,
1061 sym
->func_info_v2
.unknown5
,
1062 sym
->func_info_v2
.unknown6
,
1063 sym
->func_info_v2
.flags
,
1064 sym
->func_info_v2
.unknown7
);
1067 case S_SECUCOOKIE_V3
:
1068 printf("\tSecurity Cookie V3 @%d unk:%x\n",
1069 sym
->security_cookie_v3
.offset
, sym
->security_cookie_v3
.unknown
);
1076 printf("\tS-End-Of block (%u)\n", nest_block
);
1080 printf("\tS-End-Of %s\n", curr_func
);
1086 case S_COMPILAND_V1
:
1088 const char* machine
;
1091 switch (sym
->compiland_v1
.unknown
& 0xFF)
1093 case 0x00: machine
= "Intel 8080"; break;
1094 case 0x01: machine
= "Intel 8086"; break;
1095 case 0x02: machine
= "Intel 80286"; break;
1096 case 0x03: machine
= "Intel 80386"; break;
1097 case 0x04: machine
= "Intel 80486"; break;
1098 case 0x05: machine
= "Intel Pentium"; break;
1099 case 0x10: machine
= "MIPS R4000"; break;
1102 static char tmp
[16];
1103 sprintf(tmp
, "machine=%x", sym
->compiland_v1
.unknown
& 0xFF);
1108 switch ((sym
->compiland_v1
.unknown
>> 8) & 0xFF)
1110 case 0x00: lang
= "C"; break;
1111 case 0x01: lang
= "C++"; break;
1112 case 0x02: lang
= "Fortran"; break;
1113 case 0x03: lang
= "Masm"; break;
1114 case 0x04: lang
= "Pascal"; break;
1115 case 0x05: lang
= "Basic"; break;
1116 case 0x06: lang
= "Cobol"; break;
1119 static char tmp
[16];
1120 sprintf(tmp
, "language=%x", (sym
->compiland_v1
.unknown
>> 8) & 0xFF);
1126 printf("\tS-Compiland V1 '%s' %s %s unk:%x\n",
1127 p_string(&sym
->compiland_v1
.p_name
), machine
, lang
,
1128 sym
->compiland_v1
.unknown
>> 16);
1132 case S_COMPILAND_V2
:
1133 printf("\tS-Compiland V2 '%s'\n",
1134 p_string(&sym
->compiland_v2
.p_name
));
1135 dump_data((const void*)sym
, sym
->generic
.len
+ 2, " ");
1137 const char* ptr
= sym
->compiland_v2
.p_name
.name
+ sym
->compiland_v2
.p_name
.namelen
;
1140 printf("\t\t%s => ", ptr
); ptr
+= strlen(ptr
) + 1;
1141 printf("%s\n", ptr
); ptr
+= strlen(ptr
) + 1;
1146 case S_COMPILAND_V3
:
1147 printf("\tS-Compiland V3 '%s' unknown:%x\n",
1148 sym
->compiland_v3
.name
, sym
->compiland_v3
.unknown
);
1152 printf("\tS-ObjName V1 sig:%.4s '%s'\n",
1153 sym
->objname_v1
.signature
, p_string(&sym
->objname_v1
.p_name
));
1157 printf("\tS-Label V1 '%s' in '%s' (%04x:%08x)\n",
1158 p_string(&sym
->label_v1
.p_name
),
1159 curr_func
, sym
->label_v1
.segment
, sym
->label_v1
.offset
);
1163 printf("\tS-Label V3 '%s' in '%s' (%04x:%08x) flag:%x\n",
1164 sym
->label_v3
.name
, curr_func
, sym
->label_v3
.segment
,
1165 sym
->label_v3
.offset
, sym
->label_v3
.flags
);
1171 union full_value fv
;
1173 vlen
= full_numeric_leaf(&fv
, &sym
->constant_v2
.cvalue
);
1174 printf("\tS-Constant V2 '%s' = 0x%x%08x type:%x\n",
1175 p_string(PSTRING(&sym
->constant_v2
.cvalue
, vlen
)),
1176 (unsigned)(fv
.llu
>> 32), (unsigned)fv
.llu
, sym
->constant_v2
.type
);
1183 union full_value fv
;
1185 vlen
= full_numeric_leaf(&fv
, &sym
->constant_v3
.cvalue
);
1186 printf("\tS-Constant V3 '%s' = 0x%x%08x type:%x\n",
1187 (const char*)&sym
->constant_v3
.cvalue
+ vlen
,
1188 (unsigned)(fv
.llu
>> 32), (unsigned)fv
.llu
, sym
->constant_v3
.type
);
1193 printf("\tS-Udt V1 '%s': type:0x%x\n",
1194 p_string(&sym
->udt_v1
.p_name
), sym
->udt_v1
.type
);
1198 printf("\tS-Udt V2 '%s': type:0x%x\n",
1199 p_string(&sym
->udt_v2
.p_name
), sym
->udt_v2
.type
);
1203 printf("\tS-Udt V3 '%s': type:0x%x\n",
1204 sym
->udt_v3
.name
, sym
->udt_v3
.type
);
1207 * These are special, in that they are always followed by an
1208 * additional length-prefixed string which is *not* included
1209 * into the symbol length count. We need to skip it.
1212 printf("\tS-Procref V1 "); goto doaref
;
1214 printf("\tS-Dataref V1 "); goto doaref
;
1216 printf("\tS-L-Procref V1 "); goto doaref
;
1219 const struct p_string
* pname
;
1221 pname
= PSTRING(sym
, length
);
1222 length
+= (pname
->namelen
+ 1 + 3) & ~3;
1223 printf("\t%08x %08x %08x '%s'\n",
1224 *(((const DWORD
*)sym
) + 1), *(((const DWORD
*)sym
) + 2), *(((const DWORD
*)sym
) + 3),
1228 case S_MSTOOL_V3
: /* info about tool used to create CU */
1230 const unsigned short* ptr
= ((const unsigned short*)sym
) + 2;
1232 const char* x2
= (const char*)&ptr
[9];
1233 /* FIXME: what are all those values for ? */
1234 printf("\tTool V3 unk=%04x%04x%04x front=%d.%d.%d.0 back=%d.%d.%d.0 %s\n",
1235 ptr
[0], ptr
[1], ptr
[2], ptr
[3], ptr
[4], ptr
[5], ptr
[6], ptr
[7],
1237 while (*(x1
= x2
+ strlen(x2
) + 1))
1239 x2
= x1
+ strlen(x1
) + 1;
1241 printf("\t\t%s: %s\n", x1
, x2
);
1246 case S_MSTOOLINFO_V3
:
1248 const unsigned short* ptr
= ((const unsigned short*)sym
) + 2;
1250 printf("\tTool info V3: unk=%04x%04x%04x front=%d.%d.%d.%d back=%d.%d.%d.%d %s\n",
1251 ptr
[0], ptr
[1], ptr
[2],
1252 ptr
[3], ptr
[4], ptr
[5], ptr
[6],
1253 ptr
[7], ptr
[8], ptr
[9], ptr
[10],
1254 (const char*)(ptr
+ 11));
1258 case S_MSTOOLENV_V3
:
1260 const char* x1
= (const char*)sym
+ 4 + 1;
1263 printf("\tTool conf V3\n");
1266 x2
= x1
+ strlen(x1
) + 1;
1268 printf("\t\t%s: %s\n", x1
, x2
);
1269 x1
= x2
+ strlen(x2
) + 1;
1275 /* simply skip it */
1279 printf("\tSSearch V1: (%04x:%08x)\n",
1280 sym
->ssearch_v1
.segment
, sym
->ssearch_v1
.offset
);
1284 printf("\tSSection Info: seg=%04x ?=%04x rva=%08x size=%08x attr=%08x %s\n",
1285 *(unsigned short*)((const char*)sym
+ 4),
1286 *(unsigned short*)((const char*)sym
+ 6),
1287 *(unsigned*)((const char*)sym
+ 8),
1288 *(unsigned*)((const char*)sym
+ 12),
1289 *(unsigned*)((const char*)sym
+ 16),
1290 (const char*)sym
+ 20);
1293 case S_SUBSECTINFO_V3
:
1294 printf("\tSSubSection Info: addr=%04x:%08x size=%08x attr=%08x %s\n",
1295 *(unsigned short*)((const char*)sym
+ 16),
1296 *(unsigned*)((const char*)sym
+ 12),
1297 *(unsigned*)((const char*)sym
+ 4),
1298 *(unsigned*)((const char*)sym
+ 8),
1299 (const char*)sym
+ 18);
1302 case S_ENTRYPOINT_V3
:
1303 printf("\tSEntryPoint: id=%x '%s'\n",
1304 *(unsigned*)((const char*)sym
+ 4), (const char*)sym
+ 8);
1308 printf(">>> Unsupported symbol-id %x sz=%d\n", sym
->generic
.id
, sym
->generic
.len
+ 2);
1309 dump_data((const void*)sym
, sym
->generic
.len
+ 2, " ");
1315 void codeview_dump_linetab(const char* linetab
, DWORD size
, BOOL pascal_str
, const char* pfx
)
1317 const char* ptr
= linetab
;
1318 int nfile
, nseg
, nline
;
1320 const unsigned int* filetab
;
1321 const unsigned int* lt_ptr
;
1322 const struct startend
* start
;
1324 nfile
= *(const short*)linetab
;
1325 filetab
= (const unsigned int*)(linetab
+ 2 * sizeof(short));
1326 printf("%s%d files with %d ???\n", pfx
, nfile
, *(const short*)(linetab
+ sizeof(short)));
1328 for (i
= 0; i
< nfile
; i
++)
1330 ptr
= linetab
+ filetab
[i
];
1331 nseg
= *(const short*)ptr
;
1332 ptr
+= 2 * sizeof(short);
1333 lt_ptr
= (const unsigned int*)ptr
;
1334 start
= (const struct startend
*)(lt_ptr
+ nseg
);
1337 * Now snarf the filename for all of the segments for this file.
1341 char filename
[MAX_PATH
];
1342 const struct p_string
* p_fn
;
1344 p_fn
= (const struct p_string
*)(start
+ nseg
);
1345 memset(filename
, 0, sizeof(filename
));
1346 memcpy(filename
, p_fn
->name
, p_fn
->namelen
);
1347 printf("%slines for file #%d/%d %s %d\n", pfx
, i
, nfile
, filename
, nseg
);
1350 printf("%slines for file #%d/%d %s %d\n", pfx
, i
, nfile
, (const char*)(start
+ nseg
), nseg
);
1352 for (j
= 0; j
< nseg
; j
++)
1354 ptr
= linetab
+ *lt_ptr
++;
1355 nline
= *(const short*)(ptr
+ 2);
1356 printf("%s %04x:%08x-%08x #%d\n",
1357 pfx
, *(const short*)(ptr
+ 0), start
[j
].start
, start
[j
].end
, nline
);
1359 for (k
= 0; k
< nline
; k
++)
1361 printf("%s %x %d\n",
1362 pfx
, ((const unsigned int*)ptr
)[k
],
1363 ((const unsigned short*)((const unsigned int*)ptr
+ nline
))[k
]);
1369 void codeview_dump_linetab2(const char* linetab
, DWORD size
, const char* strimage
, DWORD strsize
, const char* pfx
)
1373 const struct codeview_linetab2_block
* lbh
;
1374 const struct codeview_linetab2_file
* fd
;
1376 if (*(const DWORD
*)linetab
!= 0x000000f4) return;
1377 offset
= *((const DWORD
*)linetab
+ 1);
1378 lbh
= (const struct codeview_linetab2_block
*)(linetab
+ 8 + offset
);
1379 while ((const char*)lbh
< linetab
+ size
)
1381 if (lbh
->header
!= 0x000000f2)
1382 /* FIXME: should also check that whole lbh fits in linetab + size */
1384 /* printf("%sblock end %x\n", pfx, lbh->header); */
1387 printf("%sblock from %04x:%08x #%x (%x lines)\n",
1388 pfx
, lbh
->seg
, lbh
->start
, lbh
->size
, lbh
->nlines
);
1389 fd
= (const struct codeview_linetab2_file
*)(linetab
+ 8 + lbh
->file_offset
);
1390 printf("%s md5=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
1391 pfx
, fd
->md5
[ 0], fd
->md5
[ 1], fd
->md5
[ 2], fd
->md5
[ 3],
1392 fd
->md5
[ 4], fd
->md5
[ 5], fd
->md5
[ 6], fd
->md5
[ 7],
1393 fd
->md5
[ 8], fd
->md5
[ 9], fd
->md5
[10], fd
->md5
[11],
1394 fd
->md5
[12], fd
->md5
[13], fd
->md5
[14], fd
->md5
[15]);
1395 /* FIXME: should check that string is within strimage + strsize */
1396 printf("%s file=%s\n", pfx
, strimage
? strimage
+ fd
->offset
: "--none--");
1397 for (i
= 0; i
< lbh
->nlines
; i
++)
1399 printf("%s offset=%08x line=%d\n", pfx
, lbh
->l
[i
].offset
, lbh
->l
[i
].lineno
^ 0x80000000);
1401 lbh
= (const struct codeview_linetab2_block
*)((const char*)lbh
+ 8 + lbh
->size_of_block
);