crypt32: Implement CryptBinaryToStringW(HEXRAW).
[wine.git] / tools / winedump / msc.c
blob6843f899b16c249ebbb1ba3ead3b2455421c2421
1 /*
2 * MS debug info dumping utility
4 * Copyright 2006 Eric Pouech
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <time.h>
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34 #ifdef HAVE_SYS_STAT_H
35 # include <sys/stat.h>
36 #endif
37 #ifdef HAVE_SYS_MMAN_H
38 #include <sys/mman.h>
39 #endif
40 #include <fcntl.h>
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winedump.h"
45 #include "wine/mscvpdb.h"
47 #define PSTRING(adr, ofs) \
48 ((const struct p_string*)((const char*)(adr) + (ofs)))
50 static const char* p_string(const struct p_string* s)
52 static char tmp[256 + 1];
53 memcpy(tmp, s->name, s->namelen);
54 tmp[s->namelen] = '\0';
55 return tmp;
58 struct full_value
60 enum {fv_integer, fv_longlong} type;
61 union
63 int i;
64 long long unsigned llu;
65 } v;
68 static int full_numeric_leaf(struct full_value* fv, const unsigned short int* leaf)
70 unsigned short int type = *leaf++;
71 int length = 2;
73 fv->type = fv_integer;
74 if (type < LF_NUMERIC)
76 fv->v.i = type;
78 else
80 switch (type)
82 case LF_CHAR:
83 length += 1;
84 fv->v.i = *(const char*)leaf;
85 break;
87 case LF_SHORT:
88 length += 2;
89 fv->v.i = *(const short*)leaf;
90 break;
92 case LF_USHORT:
93 length += 2;
94 fv->v.i = *leaf;
95 break;
97 case LF_LONG:
98 length += 4;
99 fv->v.i = *(const int*)leaf;
100 break;
102 case LF_ULONG:
103 length += 4;
104 fv->v.i = *(const unsigned int*)leaf;
105 break;
107 case LF_QUADWORD:
108 length += 8;
109 fv->type = fv_longlong;
110 fv->v.llu = *(const long long int*)leaf;
111 break;
113 case LF_UQUADWORD:
114 length += 8;
115 fv->type = fv_longlong;
116 fv->v.llu = *(const long long unsigned int*)leaf;
117 break;
119 case LF_REAL32:
120 length += 4;
121 printf(">>> unsupported leaf value %04x\n", type);
122 fv->v.i = 0; /* FIXME */
123 break;
125 case LF_REAL48:
126 length += 6;
127 fv->v.i = 0; /* FIXME */
128 printf(">>> unsupported leaf value %04x\n", type);
129 break;
131 case LF_REAL64:
132 length += 8;
133 fv->v.i = 0; /* FIXME */
134 printf(">>> unsupported leaf value %04x\n", type);
135 break;
137 case LF_REAL80:
138 length += 10;
139 fv->v.i = 0; /* FIXME */
140 printf(">>> unsupported leaf value %04x\n", type);
141 break;
143 case LF_REAL128:
144 length += 16;
145 fv->v.i = 0; /* FIXME */
146 printf(">>> unsupported leaf value %04x\n", type);
147 break;
149 case LF_COMPLEX32:
150 length += 4;
151 fv->v.i = 0; /* FIXME */
152 printf(">>> unsupported leaf value %04x\n", type);
153 break;
155 case LF_COMPLEX64:
156 length += 8;
157 fv->v.i = 0; /* FIXME */
158 printf(">>> unsupported leaf value %04x\n", type);
159 break;
161 case LF_COMPLEX80:
162 length += 10;
163 fv->v.i = 0; /* FIXME */
164 printf(">>> unsupported leaf value %04x\n", type);
165 break;
167 case LF_COMPLEX128:
168 length += 16;
169 fv->v.i = 0; /* FIXME */
170 printf(">>> unsupported leaf value %04x\n", type);
171 break;
173 case LF_VARSTRING:
174 length += 2 + *leaf;
175 fv->v.i = 0; /* FIXME */
176 printf(">>> unsupported leaf value %04x\n", type);
177 break;
179 default:
180 printf(">>> Unsupported numeric leaf-id %04x\n", type);
181 fv->v.i = 0;
182 break;
185 return length;
188 static const char* full_value_string(const struct full_value* fv)
190 static char tmp[128];
192 switch (fv->type)
194 case fv_integer: sprintf(tmp, "0x%x", fv->v.i); break;
195 case fv_longlong: sprintf(tmp, "0x%x%08x", (unsigned)(fv->v.llu >> 32), (unsigned)fv->v.llu); break;
197 return tmp;
200 static int numeric_leaf(int* value, const unsigned short int* leaf)
202 struct full_value fv;
203 int len = full_numeric_leaf(&fv, leaf);
205 switch (fv.type)
207 case fv_integer: *value = fv.v.i; break;
208 case fv_longlong: *value = (unsigned)fv.v.llu; printf("bad conversion\n"); break;
209 default: assert( 0 ); *value = 0;
211 return len;
214 static const char* get_attr(unsigned attr)
216 static char tmp[256];
218 switch (attr & 3)
220 case 0: strcpy(tmp, ""); break;
221 case 1: strcpy(tmp, "private "); break;
222 case 2: strcpy(tmp, "protected "); break;
223 case 3: strcpy(tmp, "public "); break;
225 switch ((attr >> 2) & 7)
227 case 0: strcat(tmp, ""); break;
228 case 1: strcat(tmp, "virtual "); break;
229 case 2: strcat(tmp, "static "); break;
230 case 3: strcat(tmp, "friend "); break;
231 case 4: strcat(tmp, "introducing virtual "); break;
232 case 5: strcat(tmp, "pure virtual "); break;
233 case 6: strcat(tmp, "pure introducing virtual "); break;
234 case 7: strcat(tmp, "reserved "); break;
236 if ((attr >> 5) & 1) strcat(tmp, "pseudo ");
237 if ((attr >> 6) & 1) strcat(tmp, "no-inherit ");
238 if ((attr >> 7) & 1) strcat(tmp, "no-construct ");
239 return tmp;
242 static const char* get_property(unsigned prop)
244 static char tmp[1024];
245 unsigned pos = 0;
247 if (!prop) return "none";
248 #define X(s) {if (pos) tmp[pos++] = ';'; strcpy(tmp + pos, s); pos += strlen(s);}
249 if (prop & 0x0001) X("packed");
250 if (prop & 0x0002) X("w/{cd}tor");
251 if (prop & 0x0004) X("w/overloaded-ops");
252 if (prop & 0x0008) X("nested-class");
253 if (prop & 0x0010) X("has-nested-classes");
254 if (prop & 0x0020) X("w/overloaded-assign");
255 if (prop & 0x0040) X("w/casting-methods");
256 if (prop & 0x0080) X("forward");
257 if (prop & 0x0100) X("scoped");
258 #undef X
260 if (prop & ~0x01FF) pos += sprintf(tmp, "unk%x", prop & ~0x01FF);
261 else tmp[pos] = '\0';
262 assert(pos < sizeof(tmp));
264 return tmp;
267 static void do_field(const unsigned char* start, const unsigned char* end)
270 * A 'field list' is a CodeView-specific data type which doesn't
271 * directly correspond to any high-level data type. It is used
272 * to hold the collection of members of a struct, class, union
273 * or enum type. The actual definition of that type will follow
274 * later, and refer to the field list definition record.
276 * As we don't have a field list type ourselves, we look ahead
277 * in the field list to try to find out whether this field list
278 * will be used for an enum or struct type, and create a dummy
279 * type of the corresponding sort. Later on, the definition of
280 * the 'real' type will copy the member / enumeration data.
282 const unsigned char* ptr = start;
283 const char* cstr;
284 const struct p_string* pstr;
285 int leaf_len, value;
287 while (ptr < end)
289 const union codeview_fieldtype* fieldtype = (const union codeview_fieldtype*)ptr;
291 if (*ptr >= 0xf0) /* LF_PAD... */
293 ptr +=* ptr & 0x0f;
294 continue;
297 switch (fieldtype->generic.id)
299 case LF_ENUMERATE_V1:
300 leaf_len = numeric_leaf(&value, &fieldtype->enumerate_v1.value);
301 pstr = PSTRING(&fieldtype->enumerate_v1.value, leaf_len);
302 printf("\t\tEnumerate V1: '%s' value:%d\n",
303 p_string(pstr), value);
304 ptr += 2 + 2 + leaf_len + 1 + pstr->namelen;
305 break;
307 case LF_ENUMERATE_V3:
308 leaf_len = numeric_leaf(&value, &fieldtype->enumerate_v3.value);
309 cstr = (const char*)&fieldtype->enumerate_v3.value + leaf_len;
310 printf("\t\tEnumerate V3: '%s' value:%d\n",
311 cstr, value);
312 ptr += 2 + 2 + leaf_len + strlen(cstr) + 1;
313 break;
315 case LF_MEMBER_V1:
316 leaf_len = numeric_leaf(&value, &fieldtype->member_v1.offset);
317 pstr = PSTRING(&fieldtype->member_v1.offset, leaf_len);
318 printf("\t\tMember V1: '%s' type:%x attr:%s @%d\n",
319 p_string(pstr), fieldtype->member_v1.type,
320 get_attr(fieldtype->member_v1.attribute), value);
321 ptr += 2 + 2 + 2 + leaf_len + 1 + pstr->namelen;
322 break;
324 case LF_MEMBER_V2:
325 leaf_len = numeric_leaf(&value, &fieldtype->member_v2.offset);
326 pstr = PSTRING(&fieldtype->member_v2.offset, leaf_len);
327 printf("\t\tMember V2: '%s' type:%x attr:%s @%d\n",
328 p_string(pstr), fieldtype->member_v2.type,
329 get_attr(fieldtype->member_v2.attribute), value);
330 ptr += 2 + 2 + 4 + leaf_len + 1 + pstr->namelen;
331 break;
333 case LF_MEMBER_V3:
334 leaf_len = numeric_leaf(&value, &fieldtype->member_v3.offset);
335 cstr = (const char*)&fieldtype->member_v3.offset + leaf_len;
336 printf("\t\tMember V3: '%s' type:%x attr:%s @%d\n",
337 cstr, fieldtype->member_v3.type,
338 get_attr(fieldtype->member_v3.attribute), value);
339 ptr += 2 + 2 + 4 + leaf_len + strlen(cstr) + 1;
340 break;
342 case LF_ONEMETHOD_V1:
343 switch ((fieldtype->onemethod_v1.attribute >> 2) & 7)
345 case 4: case 6:
346 printf("\t\tVirtual-method V1: '%s' attr:%s type:%x vtable_offset:%u\n",
347 p_string(&fieldtype->onemethod_virt_v1.p_name),
348 get_attr(fieldtype->onemethod_virt_v1.attribute),
349 fieldtype->onemethod_virt_v1.type,
350 fieldtype->onemethod_virt_v1.vtab_offset);
351 ptr += 2 + 2 + 2 + 4 + (1 + fieldtype->onemethod_virt_v1.p_name.namelen);
352 break;
354 default:
355 printf("\t\tMethod V1: '%s' attr:%s type:%x\n",
356 p_string(&fieldtype->onemethod_v1.p_name),
357 get_attr(fieldtype->onemethod_v1.attribute),
358 fieldtype->onemethod_v1.type);
359 ptr += 2 + 2 + 2 + (1 + fieldtype->onemethod_v1.p_name.namelen);
360 break;
362 break;
364 case LF_ONEMETHOD_V2:
365 switch ((fieldtype->onemethod_v2.attribute >> 2) & 7)
367 case 4: case 6:
368 printf("\t\tVirtual-method V2: '%s' attr:%s type:%x vtable_offset:%u\n",
369 p_string(&fieldtype->onemethod_virt_v2.p_name),
370 get_attr(fieldtype->onemethod_virt_v2.attribute),
371 fieldtype->onemethod_virt_v2.type,
372 fieldtype->onemethod_virt_v2.vtab_offset);
373 ptr += 2 + 2 + 4 + 4 + (1 + fieldtype->onemethod_virt_v2.p_name.namelen);
374 break;
376 default:
377 printf("\t\tMethod V2: '%s' attr:%s type:%x\n",
378 p_string(&fieldtype->onemethod_v2.p_name),
379 get_attr(fieldtype->onemethod_v2.attribute),
380 fieldtype->onemethod_v2.type);
381 ptr += 2 + 2 + 4 + (1 + fieldtype->onemethod_v2.p_name.namelen);
382 break;
384 break;
386 case LF_ONEMETHOD_V3:
387 switch ((fieldtype->onemethod_v3.attribute >> 2) & 7)
389 case 4: case 6:
390 printf("\t\tVirtual-method V3: '%s' attr:%s type:%x vtable_offset:%u\n",
391 fieldtype->onemethod_virt_v3.name,
392 get_attr(fieldtype->onemethod_virt_v3.attribute),
393 fieldtype->onemethod_virt_v3.type,
394 fieldtype->onemethod_virt_v3.vtab_offset);
395 ptr += 2 + 2 + 4 + 4 + (strlen(fieldtype->onemethod_virt_v3.name) + 1);
396 break;
398 default:
399 printf("\t\tMethod V3: '%s' attr:%s type:%x\n",
400 fieldtype->onemethod_v3.name,
401 get_attr(fieldtype->onemethod_v3.attribute),
402 fieldtype->onemethod_v3.type);
403 ptr += 2 + 2 + 4 + (strlen(fieldtype->onemethod_v3.name) + 1);
404 break;
406 break;
408 case LF_METHOD_V1:
409 printf("\t\tMethod V1: '%s' overloaded=#%d method-list=%x\n",
410 p_string(&fieldtype->method_v1.p_name),
411 fieldtype->method_v1.count, fieldtype->method_v1.mlist);
412 ptr += 2 + 2 + 2 + (1 + fieldtype->method_v1.p_name.namelen);
413 break;
415 case LF_METHOD_V2:
416 printf("\t\tMethod V2: '%s' overloaded=#%d method-list=%x\n",
417 p_string(&fieldtype->method_v2.p_name),
418 fieldtype->method_v2.count, fieldtype->method_v2.mlist);
419 ptr += 2 + 2 + 4 + (1 + fieldtype->method_v2.p_name.namelen);
420 break;
422 case LF_METHOD_V3:
423 printf("\t\tMethod V3: '%s' overloaded=#%d method-list=%x\n",
424 fieldtype->method_v3.name,
425 fieldtype->method_v3.count, fieldtype->method_v3.mlist);
426 ptr += 2 + 2 + 4 + (strlen(fieldtype->method_v3.name) + 1);
427 break;
429 case LF_STMEMBER_V1:
430 printf("\t\tStatic member V1: '%s' attr:%s type:%x\n",
431 p_string(&fieldtype->stmember_v1.p_name),
432 get_attr(fieldtype->stmember_v1.attribute),
433 fieldtype->stmember_v1.type);
434 ptr += 2 + 2 + 2 + (1 + fieldtype->stmember_v1.p_name.namelen);
435 break;
437 case LF_STMEMBER_V2:
438 printf("\t\tStatic member V2: '%s' attr:%s type:%x\n",
439 p_string(&fieldtype->stmember_v2.p_name),
440 get_attr(fieldtype->stmember_v2.attribute),
441 fieldtype->stmember_v2.type);
442 ptr += 2 + 2 + 4 + (1 + fieldtype->stmember_v2.p_name.namelen);
443 break;
445 case LF_STMEMBER_V3:
446 printf("\t\tStatic member V3: '%s' attr:%s type:%x\n",
447 fieldtype->stmember_v3.name,
448 get_attr(fieldtype->stmember_v3.attribute),
449 fieldtype->stmember_v3.type);
450 ptr += 2 + 2 + 4 + (strlen(fieldtype->stmember_v3.name) + 1);
451 break;
453 case LF_FRIENDFCN_V1:
454 printf("\t\tFriend function V1: '%s' type:%x\n",
455 p_string(&fieldtype->friendfcn_v1.p_name),
456 fieldtype->friendfcn_v1.type);
457 break;
459 case LF_FRIENDFCN_V2:
460 printf("\t\tFriend function V2: '%s' type:%x\n",
461 p_string(&fieldtype->friendfcn_v2.p_name),
462 fieldtype->friendfcn_v2.type);
463 break;
465 #if 0
466 case LF_FRIENDFCN_V3:
467 printf("\t\tFriend function V3: '%s' type:%x\n",
468 fieldtype->friendfcn_v3.name,
469 fieldtype->friendfcn_v3.type);
470 break;
471 #endif
473 case LF_BCLASS_V1:
474 leaf_len = numeric_leaf(&value, &fieldtype->bclass_v1.offset);
475 printf("\t\tBase class V1: type:%x attr:%s @%d\n",
476 fieldtype->bclass_v1.type,
477 get_attr(fieldtype->bclass_v1.attribute), value);
478 ptr += 2 + 2 + 2 + leaf_len;
479 break;
481 case LF_BCLASS_V2:
482 leaf_len = numeric_leaf(&value, &fieldtype->bclass_v2.offset);
483 printf("\t\tBase class V2: type:%x attr:%s @%d\n",
484 fieldtype->bclass_v2.type,
485 get_attr(fieldtype->bclass_v2.attribute), value);
486 ptr += 2 + 2 + 4 + leaf_len;
487 break;
489 case LF_VBCLASS_V1:
490 case LF_IVBCLASS_V1:
491 leaf_len = numeric_leaf(&value, &fieldtype->vbclass_v1.vbpoff);
492 printf("\t\t%sirtual base class V1: type:%x (ptr:%x) attr:%s vbpoff:%d ",
493 (fieldtype->generic.id == LF_VBCLASS_V2) ? "V" : "Indirect v",
494 fieldtype->vbclass_v1.btype, fieldtype->vbclass_v1.vbtype,
495 get_attr(fieldtype->vbclass_v1.attribute), value);
496 ptr += 2 + 2 + 2 + 2 + leaf_len;
497 leaf_len = numeric_leaf(&value, (const unsigned short*)ptr);
498 printf("vboff:%d\n", value);
499 ptr += leaf_len;
500 break;
502 case LF_VBCLASS_V2:
503 case LF_IVBCLASS_V2:
504 leaf_len = numeric_leaf(&value, &fieldtype->vbclass_v1.vbpoff);
505 printf("\t\t%sirtual base class V2: type:%x (ptr:%x) attr:%s vbpoff:%d ",
506 (fieldtype->generic.id == LF_VBCLASS_V2) ? "V" : "Indirect v",
507 fieldtype->vbclass_v2.btype, fieldtype->vbclass_v2.vbtype,
508 get_attr(fieldtype->vbclass_v2.attribute), value);
509 ptr += 2 + 2 + 4 + 4 + leaf_len;
510 leaf_len = numeric_leaf(&value, (const unsigned short*)ptr);
511 printf("vboff:%d\n", value);
512 ptr += leaf_len;
513 break;
515 case LF_FRIENDCLS_V1:
516 printf("\t\tFriend class V1: type:%x\n", fieldtype->friendcls_v1.type);
517 break;
519 case LF_FRIENDCLS_V2:
520 printf("\t\tFriend class V2: type:%x\n", fieldtype->friendcls_v2.type);
521 break;
523 case LF_NESTTYPE_V1:
524 printf("\t\tNested type V1: '%s' type:%x\n",
525 p_string(&fieldtype->nesttype_v1.p_name),
526 fieldtype->nesttype_v1.type);
527 ptr += 2 + 2 + (1 + fieldtype->nesttype_v1.p_name.namelen);
528 break;
530 case LF_NESTTYPE_V2:
531 printf("\t\tNested type V2: '%s' pad0:%u type:%x\n",
532 p_string(&fieldtype->nesttype_v2.p_name),
533 fieldtype->nesttype_v2._pad0, fieldtype->nesttype_v2.type);
534 ptr += 2 + 2 + 4 + (1 + fieldtype->nesttype_v2.p_name.namelen);
535 break;
537 case LF_NESTTYPE_V3:
538 printf("\t\tNested type V3: '%s' pad0:%u type:%x\n",
539 fieldtype->nesttype_v3.name,
540 fieldtype->nesttype_v3._pad0, fieldtype->nesttype_v3.type);
541 ptr += 2 + 2 + 4 + (strlen(fieldtype->nesttype_v3.name) + 1);
542 break;
544 case LF_VFUNCTAB_V1:
545 printf("\t\tVirtual function table V1: type:%x\n",
546 fieldtype->vfunctab_v1.type);
547 ptr += 2 + 2;
548 break;
550 case LF_VFUNCTAB_V2:
551 printf("\t\tVirtual function table V2: type:%x\n",
552 fieldtype->vfunctab_v2.type);
553 ptr += 2 + 2 + 4;
554 break;
556 case LF_VFUNCOFF_V1:
557 printf("\t\tVirtual function table offset V1: type:%x offset:%x\n",
558 fieldtype->vfuncoff_v1.type, fieldtype->vfuncoff_v1.offset);
559 break;
561 case LF_VFUNCOFF_V2:
562 printf("\t\tVirtual function table offset V2: type:%x offset:%x\n",
563 fieldtype->vfuncoff_v2.type, fieldtype->vfuncoff_v2.offset);
564 break;
566 default:
567 printf(">>> Unsupported field-id %x\n", fieldtype->generic.id);
568 dump_data((const void*)fieldtype, 0x30, "\t");
569 break;
574 static void codeview_dump_one_type(unsigned curr_type, const union codeview_type* type)
576 const union codeview_reftype* reftype = (const union codeview_reftype*)type;
577 int i, leaf_len, value;
578 unsigned int j;
579 const char* str;
581 switch (type->generic.id)
583 case LF_POINTER_V1:
584 printf("\t%x => Pointer V1 to type:%x\n",
585 curr_type, type->pointer_v1.datatype);
586 break;
587 case LF_POINTER_V2:
588 printf("\t%x => Pointer V2 to type:%x\n",
589 curr_type, type->pointer_v2.datatype);
590 break;
591 case LF_ARRAY_V1:
592 leaf_len = numeric_leaf(&value, &type->array_v1.arrlen);
593 printf("\t%x => Array V1-'%s'[%u type:%x] type:%x\n",
594 curr_type, p_string(PSTRING(&type->array_v1.arrlen, leaf_len)),
595 value, type->array_v1.idxtype, type->array_v1.elemtype);
596 break;
597 case LF_ARRAY_V2:
598 leaf_len = numeric_leaf(&value, &type->array_v2.arrlen);
599 printf("\t%x => Array V2-'%s'[%u type:%x] type:%x\n",
600 curr_type, p_string(PSTRING(&type->array_v2.arrlen, leaf_len)),
601 value, type->array_v2.idxtype, type->array_v2.elemtype);
602 break;
603 case LF_ARRAY_V3:
604 leaf_len = numeric_leaf(&value, &type->array_v3.arrlen);
605 str = (const char*)&type->array_v3.arrlen + leaf_len;
606 printf("\t%x => Array V3-'%s'[%u type:%x] type:%x\n",
607 curr_type, str, value,
608 type->array_v3.idxtype, type->array_v3.elemtype);
609 break;
611 /* a bitfields is a CodeView specific data type which represent a bitfield
612 * in a structure or a class. For now, we store it in a SymTag-like type
613 * (so that the rest of the process is seamless), but check at udt inclusion
614 * type for its presence
616 case LF_BITFIELD_V1:
617 printf("\t%x => Bitfield V1:%x offset:%u #bits:%u\n",
618 curr_type, reftype->bitfield_v1.type, reftype->bitfield_v1.bitoff,
619 reftype->bitfield_v1.nbits);
620 break;
622 case LF_BITFIELD_V2:
623 printf("\t%x => Bitfield V2:%x offset:%u #bits:%u\n",
624 curr_type, reftype->bitfield_v2.type, reftype->bitfield_v2.bitoff,
625 reftype->bitfield_v2.nbits);
626 break;
628 case LF_FIELDLIST_V1:
629 case LF_FIELDLIST_V2:
630 printf("\t%x => Fieldlist\n", curr_type);
631 do_field(reftype->fieldlist.list, (const BYTE*)type + reftype->generic.len + 2);
632 break;
634 case LF_STRUCTURE_V1:
635 case LF_CLASS_V1:
636 leaf_len = numeric_leaf(&value, &type->struct_v1.structlen);
637 printf("\t%x => %s V1 '%s' elts:%u property:%s fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
638 curr_type, type->generic.id == LF_CLASS_V1 ? "Class" : "Struct",
639 p_string(PSTRING(&type->struct_v1.structlen, leaf_len)),
640 type->struct_v1.n_element, get_property(type->struct_v1.property),
641 type->struct_v1.fieldlist, type->struct_v1.derived,
642 type->struct_v1.vshape, value);
643 break;
645 case LF_STRUCTURE_V2:
646 case LF_CLASS_V2:
647 leaf_len = numeric_leaf(&value, &type->struct_v2.structlen);
648 printf("\t%x => %s V2 '%s' elts:%u property:%s\n"
649 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
650 curr_type, type->generic.id == LF_CLASS_V2 ? "Class" : "Struct",
651 p_string(PSTRING(&type->struct_v2.structlen, leaf_len)),
652 type->struct_v2.n_element, get_property(type->struct_v2.property),
653 type->struct_v2.fieldlist, type->struct_v2.derived,
654 type->struct_v2.vshape, value);
655 break;
657 case LF_STRUCTURE_V3:
658 case LF_CLASS_V3:
659 leaf_len = numeric_leaf(&value, &type->struct_v3.structlen);
660 str = (const char*)&type->struct_v3.structlen + leaf_len;
661 printf("\t%x => %s V3 '%s' elts:%u property:%s\n"
662 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
663 curr_type, type->generic.id == LF_CLASS_V3 ? "Class" : "Struct",
664 str, type->struct_v3.n_element, get_property(type->struct_v3.property),
665 type->struct_v3.fieldlist, type->struct_v3.derived,
666 type->struct_v3.vshape, value);
667 break;
669 case LF_UNION_V1:
670 leaf_len = numeric_leaf(&value, &type->union_v1.un_len);
671 printf("\t%x => Union V1 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
672 curr_type, p_string(PSTRING(&type->union_v1.un_len, leaf_len)),
673 type->union_v1.count, get_property(type->union_v1.property),
674 type->union_v1.fieldlist, value);
675 break;
677 case LF_UNION_V2:
678 leaf_len = numeric_leaf(&value, &type->union_v2.un_len);
679 printf("\t%x => Union V2 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
680 curr_type, p_string(PSTRING(&type->union_v2.un_len, leaf_len)),
681 type->union_v2.count, get_property(type->union_v2.property),
682 type->union_v2.fieldlist, value);
683 break;
685 case LF_UNION_V3:
686 leaf_len = numeric_leaf(&value, &type->union_v3.un_len);
687 str = (const char*)&type->union_v3.un_len + leaf_len;
688 printf("\t%x => Union V3 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
689 curr_type, str, type->union_v3.count,
690 get_property(type->union_v3.property),
691 type->union_v3.fieldlist, value);
692 break;
694 case LF_ENUM_V1:
695 printf("\t%x => Enum V1 '%s' type:%x field-type:%x count:%u property:%s\n",
696 curr_type, p_string(&type->enumeration_v1.p_name),
697 type->enumeration_v1.type,
698 type->enumeration_v1.fieldlist,
699 type->enumeration_v1.count,
700 get_property(type->enumeration_v1.property));
701 break;
703 case LF_ENUM_V2:
704 printf("\t%x => Enum V2 '%s' type:%x field-type:%x count:%u property:%s\n",
705 curr_type, p_string(&type->enumeration_v2.p_name),
706 type->enumeration_v2.type,
707 type->enumeration_v2.fieldlist,
708 type->enumeration_v2.count,
709 get_property(type->enumeration_v2.property));
710 break;
712 case LF_ENUM_V3:
713 printf("\t%x => Enum V3 '%s' type:%x field-type:%x count:%u property:%s\n",
714 curr_type, type->enumeration_v3.name,
715 type->enumeration_v3.type,
716 type->enumeration_v3.fieldlist,
717 type->enumeration_v3.count,
718 get_property(type->enumeration_v3.property));
719 break;
721 case LF_ARGLIST_V1:
722 printf("\t%x => Arglist V1(#%u):", curr_type, reftype->arglist_v1.num);
723 for (i = 0; i < reftype->arglist_v1.num; i++)
725 printf(" %x", reftype->arglist_v1.args[i]);
727 printf("\n");
728 break;
730 case LF_ARGLIST_V2:
731 printf("\t%x => Arglist V2(#%u):", curr_type, reftype->arglist_v2.num);
732 for (j = 0; j < reftype->arglist_v2.num; j++)
734 printf("\t %x", reftype->arglist_v2.args[j]);
736 printf("\t\n");
737 break;
739 case LF_PROCEDURE_V1:
740 /* FIXME: unknown could be the calling convention for the proc */
741 printf("\t%x => Procedure V1 ret_type:%x call:%x (#%u args_type:%x)\n",
742 curr_type, type->procedure_v1.rvtype,
743 type->procedure_v1.call, type->procedure_v1.params,
744 type->procedure_v1.arglist);
745 break;
747 case LF_PROCEDURE_V2:
748 printf("\t%x => Procedure V2 ret_type:%x unk:%x (#%u args_type:%x)\n",
749 curr_type, type->procedure_v2.rvtype,
750 type->procedure_v2.call, type->procedure_v2.params,
751 type->procedure_v2.arglist);
752 break;
754 case LF_MFUNCTION_V2:
755 printf("\t%x => MFunction V2 ret-type:%x call:%x class-type:%x this-type:%x\n"
756 "\t\t#args:%x args-type:%x this_adjust:%x\n",
757 curr_type,
758 type->mfunction_v2.rvtype,
759 type->mfunction_v2.call,
760 type->mfunction_v2.class_type,
761 type->mfunction_v2.this_type,
762 type->mfunction_v2.params,
763 type->mfunction_v2.arglist,
764 type->mfunction_v2.this_adjust);
765 break;
767 case LF_MODIFIER_V1:
768 printf("\t%x => Modifier V1 type:%x modif:%x\n",
769 curr_type, type->modifier_v1.type, type->modifier_v1.attribute);
770 break;
772 case LF_MODIFIER_V2:
773 printf("\t%x => Modifier V2 type:%x modif:%x\n",
774 curr_type, type->modifier_v2.type, type->modifier_v2.attribute);
775 break;
777 case LF_METHODLIST_V1:
779 const unsigned short* pattr = (const unsigned short*)((const char*)type + 4);
781 printf("\t%x => Method list\n", curr_type);
782 while ((const char*)pattr < (const char*)type + type->generic.len + 2)
784 switch ((*pattr >> 2) & 7)
786 case 4: case 6:
787 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
788 get_attr(pattr[0]), pattr[1],
789 *(const unsigned*)(&pattr[2]));
790 pattr += 3;
791 break;
792 default:
793 printf("\t\t\tattr:%s type:%x\n",
794 get_attr(pattr[0]), pattr[1]);
795 pattr += 2;
799 break;
801 case LF_METHODLIST_V2:
803 const unsigned* pattr = (const unsigned*)((const char*)type + 4);
805 printf("\t%x => Method list\n", curr_type);
806 while ((const char*)pattr < (const char*)type + type->generic.len + 2)
808 switch ((*pattr >> 2) & 7)
810 case 4: case 6:
811 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
812 get_attr(pattr[0]), pattr[1], pattr[2]);
813 pattr += 3;
814 break;
815 default:
816 printf("\t\t\tattr:%s type:%x\n",
817 get_attr(pattr[0]), pattr[1]);
818 pattr += 2;
822 break;
824 case LF_VTSHAPE_V1:
826 int count = *(const unsigned short*)((const char*)type + 4);
827 int shift = 0;
828 const char* ptr = (const char*)type + 6;
829 const char* desc[] = {"Near", "Far", "Thin", "Disp to outermost",
830 "Pointer to metaclass", "Near32", "Far32"};
831 printf("\t%x => VT Shape #%d: ", curr_type, count);
832 while (count--)
834 if (((*ptr << shift) & 0xF) <= 6)
835 printf("%s ", desc[(*ptr << shift) & 0xF]);
836 else
837 printf("%x ", (*ptr << shift) & 0xF);
838 if (shift == 0) shift = 4; else {shift = 0; ptr++;}
840 printf("\n");
842 break;
844 case LF_DERIVED_V1:
845 printf("\t%x => Derived V1(#%u):", curr_type, reftype->derived_v1.num);
846 for (i = 0; i < reftype->derived_v1.num; i++)
848 printf(" %x", reftype->derived_v1.drvdcls[i]);
850 printf("\n");
851 break;
853 case LF_DERIVED_V2:
854 printf("\t%x => Derived V2(#%u):", curr_type, reftype->derived_v2.num);
855 for (j = 0; j < reftype->derived_v2.num; j++)
857 printf(" %x", reftype->derived_v2.drvdcls[j]);
859 printf("\n");
860 break;
862 default:
863 printf(">>> Unsupported type-id %x for %x\n", type->generic.id, curr_type);
864 dump_data((const void*)type, type->generic.len + 2, "");
865 break;
869 BOOL codeview_dump_types_from_offsets(const void* table, const DWORD* offsets, unsigned num_types)
871 unsigned long i;
873 for (i = 0; i < num_types; i++)
875 codeview_dump_one_type(0x1000 + i,
876 (const union codeview_type*)((const char*)table + offsets[i]));
879 return TRUE;
882 BOOL codeview_dump_types_from_block(const void* table, unsigned long len)
884 unsigned int curr_type = 0x1000;
885 const unsigned char*ptr = table;
887 while (ptr - (const unsigned char*)table < len)
889 const union codeview_type* type = (const union codeview_type*)ptr;
891 codeview_dump_one_type(curr_type, type);
892 curr_type++;
893 ptr += (type->generic.len + 2 + 3) & ~3;
896 return TRUE;
899 BOOL codeview_dump_symbols(const void* root, unsigned long size)
901 unsigned int i;
902 int length;
903 char* curr_func = NULL;
904 int nest_block = 0;
906 * Loop over the different types of records and whenever we
907 * find something we are interested in, record it and move on.
909 for (i = 0; i < size; i += length)
911 const union codeview_symbol* sym = (const union codeview_symbol*)((const char*)root + i);
912 length = sym->generic.len + 2;
913 if (!sym->generic.id || length < 4) break;
914 switch (sym->generic.id)
917 * Global and local data symbols. We don't associate these
918 * with any given source file.
920 case S_GDATA_V2:
921 case S_LDATA_V2:
922 printf("\tS-%s-Data V2 '%s' %04x:%08x type:%08x\n",
923 sym->generic.id == S_GDATA_V2 ? "Global" : "Local",
924 get_symbol_str(p_string(&sym->data_v2.p_name)),
925 sym->data_v2.segment, sym->data_v2.offset, sym->data_v2.symtype);
926 break;
928 case S_LDATA_V3:
929 case S_GDATA_V3:
930 /* EPP case S_DATA_V3: */
931 printf("\tS-%s-Data V3 '%s' (%04x:%08x) type:%08x\n",
932 sym->generic.id == S_GDATA_V3 ? "Global" : "Local",
933 get_symbol_str(sym->data_v3.name),
934 sym->data_v3.segment, sym->data_v3.offset,
935 sym->data_v3.symtype);
936 break;
938 case S_PUB_V2:
939 printf("\tS-Public V2 '%s' %04x:%08x type:%08x\n",
940 get_symbol_str(p_string(&sym->public_v2.p_name)),
941 sym->public_v2.segment, sym->public_v2.offset,
942 sym->public_v2.symtype);
943 break;
945 case S_PUB_V3:
946 /* not completely sure of those two anyway */
947 case S_PUB_FUNC1_V3:
948 case S_PUB_FUNC2_V3:
949 printf("\tS-Public%s V3 '%s' %04x:%08x type:%08x\n",
950 sym->generic.id == S_PUB_V3 ? "" :
951 (sym->generic.id == S_PUB_FUNC1_V3 ? "<subkind1" : "<subkind2"),
952 get_symbol_str(sym->public_v3.name),
953 sym->public_v3.segment,
954 sym->public_v3.offset, sym->public_v3.symtype);
955 break;
958 * Sort of like a global function, but it just points
959 * to a thunk, which is a stupid name for what amounts to
960 * a PLT slot in the normal jargon that everyone else uses.
962 case S_THUNK_V1:
963 printf("\tS-Thunk V1 '%s' (%04x:%08x#%x) type:%x\n",
964 p_string(&sym->thunk_v1.p_name),
965 sym->thunk_v1.segment, sym->thunk_v1.offset,
966 sym->thunk_v1.thunk_len, sym->thunk_v1.thtype);
967 curr_func = strdup(p_string(&sym->thunk_v1.p_name));
968 break;
970 case S_THUNK_V3:
971 printf("\tS-Thunk V3 '%s' (%04x:%08x#%x) type:%x\n",
972 sym->thunk_v3.name,
973 sym->thunk_v3.segment, sym->thunk_v3.offset,
974 sym->thunk_v3.thunk_len, sym->thunk_v3.thtype);
975 curr_func = strdup(sym->thunk_v3.name);
976 break;
978 /* Global and static functions */
979 case S_GPROC_V1:
980 case S_LPROC_V1:
981 printf("\tS-%s-Proc V1: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
982 sym->generic.id == S_GPROC_V1 ? "Global" : "-Local",
983 p_string(&sym->proc_v1.p_name),
984 sym->proc_v1.segment, sym->proc_v1.offset,
985 sym->proc_v1.proc_len, sym->proc_v1.proctype,
986 sym->proc_v1.flags);
987 printf("\t Debug: start=%08x end=%08x\n",
988 sym->proc_v1.debug_start, sym->proc_v1.debug_end);
989 if (nest_block)
991 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
992 nest_block = 0;
994 curr_func = strdup(p_string(&sym->proc_v1.p_name));
995 /* EPP unsigned int pparent; */
996 /* EPP unsigned int pend; */
997 /* EPP unsigned int next; */
998 break;
1000 case S_GPROC_V2:
1001 case S_LPROC_V2:
1002 printf("\tS-%s-Proc V2: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
1003 sym->generic.id == S_GPROC_V2 ? "Global" : "-Local",
1004 p_string(&sym->proc_v2.p_name),
1005 sym->proc_v2.segment, sym->proc_v2.offset,
1006 sym->proc_v2.proc_len, sym->proc_v2.proctype,
1007 sym->proc_v2.flags);
1008 printf("\t Debug: start=%08x end=%08x\n",
1009 sym->proc_v2.debug_start, sym->proc_v2.debug_end);
1010 if (nest_block)
1012 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
1013 nest_block = 0;
1015 curr_func = strdup(p_string(&sym->proc_v2.p_name));
1016 /* EPP unsigned int pparent; */
1017 /* EPP unsigned int pend; */
1018 /* EPP unsigned int next; */
1019 break;
1021 case S_LPROC_V3:
1022 case S_GPROC_V3:
1023 printf("\tS-%s-Procedure V3 '%s' (%04x:%08x#%x) type:%x attr:%x\n",
1024 sym->generic.id == S_GPROC_V3 ? "Global" : "Local",
1025 sym->proc_v3.name,
1026 sym->proc_v3.segment, sym->proc_v3.offset,
1027 sym->proc_v3.proc_len, sym->proc_v3.proctype,
1028 sym->proc_v3.flags);
1029 printf("\t Debug: start=%08x end=%08x\n",
1030 sym->proc_v3.debug_start, sym->proc_v3.debug_end);
1031 if (nest_block)
1033 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
1034 nest_block = 0;
1036 curr_func = strdup(sym->proc_v3.name);
1037 /* EPP unsigned int pparent; */
1038 /* EPP unsigned int pend; */
1039 /* EPP unsigned int next; */
1040 break;
1042 /* Function parameters and stack variables */
1043 case S_BPREL_V1:
1044 printf("\tS-BP-relative V1: '%s' @%d type:%x (%s)\n",
1045 p_string(&sym->stack_v1.p_name),
1046 sym->stack_v1.offset, sym->stack_v1.symtype, curr_func);
1047 break;
1049 case S_BPREL_V2:
1050 printf("\tS-BP-relative V2: '%s' @%d type:%x (%s)\n",
1051 p_string(&sym->stack_v2.p_name),
1052 sym->stack_v2.offset, sym->stack_v2.symtype, curr_func);
1053 break;
1055 case S_BPREL_V3:
1056 printf("\tS-BP-relative V3: '%s' @%d type:%x (in %s)\n",
1057 sym->stack_v3.name, sym->stack_v3.offset,
1058 sym->stack_v3.symtype, curr_func);
1059 break;
1061 case S_REGREL_V3:
1062 printf("\tS-Reg-relative V3: '%s' @%d type:%x reg:%x (in %s)\n",
1063 sym->regrel_v3.name, sym->regrel_v3.offset,
1064 sym->regrel_v3.symtype, sym->regrel_v3.reg, curr_func);
1065 break;
1067 case S_REGISTER_V1:
1068 printf("\tS-Register V1 '%s' in %s type:%x register:%x\n",
1069 p_string(&sym->register_v1.p_name),
1070 curr_func, sym->register_v1.reg, sym->register_v1.type);
1071 break;
1073 case S_REGISTER_V2:
1074 printf("\tS-Register V2 '%s' in %s type:%x register:%x\n",
1075 p_string(&sym->register_v2.p_name),
1076 curr_func, sym->register_v2.reg, sym->register_v2.type);
1077 break;
1079 case S_REGISTER_V3:
1080 printf("\tS-Register V3 '%s' in %s type:%x register:%x\n",
1081 sym->register_v3.name,
1082 curr_func, sym->register_v3.reg, sym->register_v3.type);
1083 break;
1085 case S_BLOCK_V1:
1086 printf("\tS-Block V1 '%s' in '%s' (%04x:%08x#%08x)\n",
1087 p_string(&sym->block_v1.p_name),
1088 curr_func,
1089 sym->block_v1.segment, sym->block_v1.offset,
1090 sym->block_v1.length);
1091 nest_block++;
1092 break;
1094 case S_BLOCK_V3:
1095 printf("\tS-Block V3 '%s' in '%s' (%04x:%08x#%08x) parent:%u end:%x\n",
1096 sym->block_v3.name, curr_func,
1097 sym->block_v3.segment, sym->block_v3.offset, sym->block_v3.length,
1098 sym->block_v3.parent, sym->block_v3.end);
1099 nest_block++;
1100 break;
1102 /* Additional function information */
1103 case S_FRAMEINFO_V2:
1104 printf("\tS-Frame-Info V2: frame-size:%x unk2:%x unk3:%x saved-regs-sz:%x eh(%04x:%08x) flags:%08x\n",
1105 sym->frame_info_v2.sz_frame,
1106 sym->frame_info_v2.unknown2,
1107 sym->frame_info_v2.unknown3,
1108 sym->frame_info_v2.sz_saved_regs,
1109 sym->frame_info_v2.eh_sect,
1110 sym->frame_info_v2.eh_offset,
1111 sym->frame_info_v2.flags);
1112 break;
1114 case S_SECUCOOKIE_V3:
1115 printf("\tSecurity Cookie V3 @%d unk:%x\n",
1116 sym->security_cookie_v3.offset, sym->security_cookie_v3.unknown);
1117 break;
1119 case S_END_V1:
1120 if (nest_block)
1122 nest_block--;
1123 printf("\tS-End-Of block (%u)\n", nest_block);
1125 else
1127 printf("\tS-End-Of %s\n", curr_func);
1128 free(curr_func);
1129 curr_func = NULL;
1131 break;
1133 case S_COMPILAND_V1:
1135 const char* machine;
1136 const char* lang;
1138 switch (sym->compiland_v1.unknown & 0xFF)
1140 case 0x00: machine = "Intel 8080"; break;
1141 case 0x01: machine = "Intel 8086"; break;
1142 case 0x02: machine = "Intel 80286"; break;
1143 case 0x03: machine = "Intel 80386"; break;
1144 case 0x04: machine = "Intel 80486"; break;
1145 case 0x05: machine = "Intel Pentium"; break;
1146 case 0x10: machine = "MIPS R4000"; break;
1147 default:
1149 static char tmp[16];
1150 sprintf(tmp, "machine=%x", sym->compiland_v1.unknown & 0xFF);
1151 machine = tmp;
1153 break;
1155 switch ((sym->compiland_v1.unknown >> 8) & 0xFF)
1157 case 0x00: lang = "C"; break;
1158 case 0x01: lang = "C++"; break;
1159 case 0x02: lang = "Fortran"; break;
1160 case 0x03: lang = "Masm"; break;
1161 case 0x04: lang = "Pascal"; break;
1162 case 0x05: lang = "Basic"; break;
1163 case 0x06: lang = "Cobol"; break;
1164 default:
1166 static char tmp[16];
1167 sprintf(tmp, "language=%x", (sym->compiland_v1.unknown >> 8) & 0xFF);
1168 lang = tmp;
1170 break;
1173 printf("\tS-Compiland V1 '%s' %s %s unk:%x\n",
1174 p_string(&sym->compiland_v1.p_name), machine, lang,
1175 sym->compiland_v1.unknown >> 16);
1177 break;
1179 case S_COMPILAND_V2:
1180 printf("\tS-Compiland V2 '%s'\n",
1181 p_string(&sym->compiland_v2.p_name));
1182 dump_data((const void*)sym, sym->generic.len + 2, " ");
1184 const char* ptr = sym->compiland_v2.p_name.name + sym->compiland_v2.p_name.namelen;
1185 while (*ptr)
1187 printf("\t\t%s => ", ptr); ptr += strlen(ptr) + 1;
1188 printf("%s\n", ptr); ptr += strlen(ptr) + 1;
1191 break;
1193 case S_COMPILAND_V3:
1194 printf("\tS-Compiland V3 '%s' unknown:%x\n",
1195 sym->compiland_v3.name, sym->compiland_v3.unknown);
1196 break;
1198 case S_OBJNAME_V1:
1199 printf("\tS-ObjName V1 sig:%.4s '%s'\n",
1200 sym->objname_v1.signature, p_string(&sym->objname_v1.p_name));
1201 break;
1203 case S_LABEL_V1:
1204 printf("\tS-Label V1 '%s' in '%s' (%04x:%08x)\n",
1205 p_string(&sym->label_v1.p_name),
1206 curr_func, sym->label_v1.segment, sym->label_v1.offset);
1207 break;
1209 case S_LABEL_V3:
1210 printf("\tS-Label V3 '%s' in '%s' (%04x:%08x) flag:%x\n",
1211 sym->label_v3.name, curr_func, sym->label_v3.segment,
1212 sym->label_v3.offset, sym->label_v3.flags);
1213 break;
1215 case S_CONSTANT_V2:
1217 int vlen;
1218 struct full_value fv;
1220 vlen = full_numeric_leaf(&fv, &sym->constant_v2.cvalue);
1221 printf("\tS-Constant V2 '%s' = %s type:%x\n",
1222 p_string(PSTRING(&sym->constant_v2.cvalue, vlen)),
1223 full_value_string(&fv), sym->constant_v2.type);
1225 break;
1227 case S_CONSTANT_V3:
1229 int vlen;
1230 struct full_value fv;
1232 vlen = full_numeric_leaf(&fv, &sym->constant_v3.cvalue);
1233 printf("\tS-Constant V3 '%s' = %s type:%x\n",
1234 (const char*)&sym->constant_v3.cvalue + vlen,
1235 full_value_string(&fv), sym->constant_v3.type);
1237 break;
1239 case S_UDT_V1:
1240 printf("\tS-Udt V1 '%s': type:0x%x\n",
1241 p_string(&sym->udt_v1.p_name), sym->udt_v1.type);
1242 break;
1244 case S_UDT_V2:
1245 printf("\tS-Udt V2 '%s': type:0x%x\n",
1246 p_string(&sym->udt_v2.p_name), sym->udt_v2.type);
1247 break;
1249 case S_UDT_V3:
1250 printf("\tS-Udt V3 '%s': type:0x%x\n",
1251 sym->udt_v3.name, sym->udt_v3.type);
1252 break;
1254 * These are special, in that they are always followed by an
1255 * additional length-prefixed string which is *not* included
1256 * into the symbol length count. We need to skip it.
1258 case S_PROCREF_V1:
1259 printf("\tS-Procref V1 "); goto doaref;
1260 case S_DATAREF_V1:
1261 printf("\tS-Dataref V1 "); goto doaref;
1262 case S_LPROCREF_V1:
1263 printf("\tS-L-Procref V1 "); goto doaref;
1264 doaref:
1266 const struct p_string* pname;
1268 pname = PSTRING(sym, length);
1269 length += (pname->namelen + 1 + 3) & ~3;
1270 printf("\t%08x %08x %08x '%s'\n",
1271 *(((const DWORD*)sym) + 1), *(((const DWORD*)sym) + 2), *(((const DWORD*)sym) + 3),
1272 p_string(pname));
1274 break;
1275 case S_MSTOOL_V3: /* info about tool used to create CU */
1277 const unsigned short* ptr = ((const unsigned short*)sym) + 2;
1278 const char* x1;
1279 const char* x2 = (const char*)&ptr[9];
1280 /* FIXME: what are all those values for ? */
1281 printf("\tTool V3 unk=%04x%04x%04x front=%d.%d.%d.0 back=%d.%d.%d.0 %s\n",
1282 ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
1283 ptr[8], x2);
1284 while (*(x1 = x2 + strlen(x2) + 1))
1286 x2 = x1 + strlen(x1) + 1;
1287 if (!*x2) break;
1288 printf("\t\t%s: %s\n", x1, x2);
1291 break;
1293 case S_MSTOOLINFO_V3:
1295 const unsigned short* ptr = ((const unsigned short*)sym) + 2;
1297 printf("\tTool info V3: unk=%04x%04x%04x front=%d.%d.%d.%d back=%d.%d.%d.%d %s\n",
1298 ptr[0], ptr[1], ptr[2],
1299 ptr[3], ptr[4], ptr[5], ptr[6],
1300 ptr[7], ptr[8], ptr[9], ptr[10],
1301 (const char*)(ptr + 11));
1303 break;
1305 case S_MSTOOLENV_V3:
1307 const char* x1 = (const char*)sym + 4 + 1;
1308 const char* x2;
1310 printf("\tTool conf V3\n");
1311 while (*x1)
1313 x2 = x1 + strlen(x1) + 1;
1314 if (!*x2) break;
1315 printf("\t\t%s: %s\n", x1, x2);
1316 x1 = x2 + strlen(x2) + 1;
1319 break;
1321 case S_ALIGN_V1:
1322 /* simply skip it */
1323 break;
1325 case S_SSEARCH_V1:
1326 printf("\tSSearch V1: (%04x:%08x)\n",
1327 sym->ssearch_v1.segment, sym->ssearch_v1.offset);
1328 break;
1330 case S_SECTINFO_V3:
1331 printf("\tSSection Info: seg=%04x ?=%04x rva=%08x size=%08x attr=%08x %s\n",
1332 *(const unsigned short*)((const char*)sym + 4),
1333 *(const unsigned short*)((const char*)sym + 6),
1334 *(const unsigned*)((const char*)sym + 8),
1335 *(const unsigned*)((const char*)sym + 12),
1336 *(const unsigned*)((const char*)sym + 16),
1337 (const char*)sym + 20);
1338 break;
1340 case S_SUBSECTINFO_V3:
1341 printf("\tSSubSection Info: addr=%04x:%08x size=%08x attr=%08x %s\n",
1342 *(const unsigned short*)((const char*)sym + 16),
1343 *(const unsigned*)((const char*)sym + 12),
1344 *(const unsigned*)((const char*)sym + 4),
1345 *(const unsigned*)((const char*)sym + 8),
1346 (const char*)sym + 18);
1347 break;
1349 case S_ENTRYPOINT_V3:
1350 printf("\tSEntryPoint: id=%x '%s'\n",
1351 *(const unsigned*)((const char*)sym + 4), (const char*)sym + 8);
1352 break;
1354 case S_LTHREAD_V1:
1355 case S_GTHREAD_V1:
1356 printf("\tS-Thread %s Var V1 '%s' seg=%04x offset=%08x type=%x\n",
1357 sym->generic.id == S_LTHREAD_V1 ? "global" : "local",
1358 p_string(&sym->thread_v1.p_name),
1359 sym->thread_v1.segment, sym->thread_v1.offset, sym->thread_v1.symtype);
1360 break;
1362 case S_LTHREAD_V2:
1363 case S_GTHREAD_V2:
1364 printf("\tS-Thread %s Var V2 '%s' seg=%04x offset=%08x type=%x\n",
1365 sym->generic.id == S_LTHREAD_V2 ? "global" : "local",
1366 p_string(&sym->thread_v2.p_name),
1367 sym->thread_v2.segment, sym->thread_v2.offset, sym->thread_v2.symtype);
1368 break;
1370 case S_LTHREAD_V3:
1371 case S_GTHREAD_V3:
1372 printf("\tS-Thread %s Var V3 '%s' seg=%04x offset=%08x type=%x\n",
1373 sym->generic.id == S_LTHREAD_V3 ? "global" : "local", sym->thread_v3.name,
1374 sym->thread_v3.segment, sym->thread_v3.offset, sym->thread_v3.symtype);
1375 break;
1377 default:
1378 printf(">>> Unsupported symbol-id %x sz=%d\n", sym->generic.id, sym->generic.len + 2);
1379 dump_data((const void*)sym, sym->generic.len + 2, " ");
1382 return TRUE;
1385 void codeview_dump_linetab(const char* linetab, BOOL pascal_str, const char* pfx)
1387 const char* ptr = linetab;
1388 int nfile, nseg, nline;
1389 int i, j, k;
1390 const unsigned int* filetab;
1391 const unsigned int* lt_ptr;
1392 const struct startend* start;
1394 nfile = *(const short*)linetab;
1395 filetab = (const unsigned int*)(linetab + 2 * sizeof(short));
1396 printf("%s%d files with %d ???\n", pfx, nfile, *(const short*)(linetab + sizeof(short)));
1398 for (i = 0; i < nfile; i++)
1400 ptr = linetab + filetab[i];
1401 nseg = *(const short*)ptr;
1402 ptr += 2 * sizeof(short);
1403 lt_ptr = (const unsigned int*)ptr;
1404 start = (const struct startend*)(lt_ptr + nseg);
1407 * Now snarf the filename for all of the segments for this file.
1409 if (pascal_str)
1411 char filename[MAX_PATH];
1412 const struct p_string* p_fn;
1414 p_fn = (const struct p_string*)(start + nseg);
1415 memset(filename, 0, sizeof(filename));
1416 memcpy(filename, p_fn->name, p_fn->namelen);
1417 printf("%slines for file #%d/%d %s %d\n", pfx, i, nfile, filename, nseg);
1419 else
1420 printf("%slines for file #%d/%d %s %d\n", pfx, i, nfile, (const char*)(start + nseg), nseg);
1422 for (j = 0; j < nseg; j++)
1424 ptr = linetab + *lt_ptr++;
1425 nline = *(const short*)(ptr + 2);
1426 printf("%s %04x:%08x-%08x #%d\n",
1427 pfx, *(const short*)(ptr + 0), start[j].start, start[j].end, nline);
1428 ptr += 4;
1429 for (k = 0; k < nline; k++)
1431 printf("%s %x %d\n",
1432 pfx, ((const unsigned int*)ptr)[k],
1433 ((const unsigned short*)((const unsigned int*)ptr + nline))[k]);
1439 void codeview_dump_linetab2(const char* linetab, DWORD size, const char* strimage, DWORD strsize, const char* pfx)
1441 unsigned i;
1442 const struct codeview_linetab2* lt2;
1443 const struct codeview_linetab2* lt2_files = NULL;
1444 const struct codeview_lt2blk_lines* lines_blk;
1445 const struct codeview_linetab2_file*fd;
1447 /* locate LT2_FILES_BLOCK (if any) */
1448 lt2 = (const struct codeview_linetab2*)linetab;
1449 while ((const char*)(lt2 + 1) < linetab + size)
1451 if (lt2->header == LT2_FILES_BLOCK)
1453 lt2_files = lt2;
1454 break;
1456 lt2 = codeview_linetab2_next_block(lt2);
1458 if (!lt2_files)
1460 printf("%sNo LT2_FILES_BLOCK found\n", pfx);
1461 return;
1464 lt2 = (const struct codeview_linetab2*)linetab;
1465 while ((const char*)(lt2 + 1) < linetab + size)
1467 /* FIXME: should also check that whole lbh fits in linetab + size */
1468 switch (lt2->header)
1470 case LT2_LINES_BLOCK:
1471 lines_blk = (const struct codeview_lt2blk_lines*)lt2;
1472 printf("%sblock from %04x:%08x #%x (%x lines) fo=%x\n",
1473 pfx, lines_blk->seg, lines_blk->start, lines_blk->size,
1474 lines_blk->nlines, lines_blk->file_offset);
1475 /* FIXME: should check that file_offset is within the LT2_FILES_BLOCK we've seen */
1476 fd = (const struct codeview_linetab2_file*)((const char*)lt2_files + 8 + lines_blk->file_offset);
1477 printf("%s md5=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
1478 pfx, fd->md5[ 0], fd->md5[ 1], fd->md5[ 2], fd->md5[ 3],
1479 fd->md5[ 4], fd->md5[ 5], fd->md5[ 6], fd->md5[ 7],
1480 fd->md5[ 8], fd->md5[ 9], fd->md5[10], fd->md5[11],
1481 fd->md5[12], fd->md5[13], fd->md5[14], fd->md5[15]);
1482 /* FIXME: should check that string is within strimage + strsize */
1483 printf("%s file=%s\n", pfx, strimage ? strimage + fd->offset : "--none--");
1484 for (i = 0; i < lines_blk->nlines; i++)
1486 printf("%s offset=%08x line=%d\n",
1487 pfx, lines_blk->l[i].offset, lines_blk->l[i].lineno ^ 0x80000000);
1489 break;
1490 case LT2_FILES_BLOCK: /* skip */
1491 break;
1492 default:
1493 printf("%sblock end %x\n", pfx, lt2->header);
1494 lt2 = (const struct codeview_linetab2*)(linetab + size);
1495 continue;
1497 lt2 = codeview_linetab2_next_block(lt2);