Release 1.2-rc6.
[wine/gsoc-2012-control.git] / tools / winedump / msc.c
blobccd4664e741105d1c4f603db66f5e3dd6e1116ef
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 #define NONAMELESSUNION
43 #define NONAMELESSSTRUCT
44 #include "windef.h"
45 #include "winbase.h"
46 #include "winedump.h"
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';
57 return tmp;
60 struct full_value
62 enum {fv_integer, fv_longlong} type;
63 union
65 int i;
66 long long unsigned llu;
67 } v;
70 static int full_numeric_leaf(struct full_value* fv, const unsigned short int* leaf)
72 unsigned short int type = *leaf++;
73 int length = 2;
75 fv->type = fv_integer;
76 if (type < LF_NUMERIC)
78 fv->v.i = type;
80 else
82 switch (type)
84 case LF_CHAR:
85 length += 1;
86 fv->v.i = *(const char*)leaf;
87 break;
89 case LF_SHORT:
90 length += 2;
91 fv->v.i = *(const short*)leaf;
92 break;
94 case LF_USHORT:
95 length += 2;
96 fv->v.i = *(const unsigned short*)leaf;
97 break;
99 case LF_LONG:
100 length += 4;
101 fv->v.i = *(const int*)leaf;
102 break;
104 case LF_ULONG:
105 length += 4;
106 fv->v.i = *(const unsigned int*)leaf;
107 break;
109 case LF_QUADWORD:
110 length += 8;
111 fv->type = fv_longlong;
112 fv->v.llu = *(const long long int*)leaf;
113 break;
115 case LF_UQUADWORD:
116 length += 8;
117 fv->type = fv_longlong;
118 fv->v.llu = *(const long long unsigned int*)leaf;
119 break;
121 case LF_REAL32:
122 length += 4;
123 printf(">>> unsupported leaf value %04x\n", type);
124 fv->v.i = 0; /* FIXME */
125 break;
127 case LF_REAL48:
128 length += 6;
129 fv->v.i = 0; /* FIXME */
130 printf(">>> unsupported leaf value %04x\n", type);
131 break;
133 case LF_REAL64:
134 length += 8;
135 fv->v.i = 0; /* FIXME */
136 printf(">>> unsupported leaf value %04x\n", type);
137 break;
139 case LF_REAL80:
140 length += 10;
141 fv->v.i = 0; /* FIXME */
142 printf(">>> unsupported leaf value %04x\n", type);
143 break;
145 case LF_REAL128:
146 length += 16;
147 fv->v.i = 0; /* FIXME */
148 printf(">>> unsupported leaf value %04x\n", type);
149 break;
151 case LF_COMPLEX32:
152 length += 4;
153 fv->v.i = 0; /* FIXME */
154 printf(">>> unsupported leaf value %04x\n", type);
155 break;
157 case LF_COMPLEX64:
158 length += 8;
159 fv->v.i = 0; /* FIXME */
160 printf(">>> unsupported leaf value %04x\n", type);
161 break;
163 case LF_COMPLEX80:
164 length += 10;
165 fv->v.i = 0; /* FIXME */
166 printf(">>> unsupported leaf value %04x\n", type);
167 break;
169 case LF_COMPLEX128:
170 length += 16;
171 fv->v.i = 0; /* FIXME */
172 printf(">>> unsupported leaf value %04x\n", type);
173 break;
175 case LF_VARSTRING:
176 length += 2 + *leaf;
177 fv->v.i = 0; /* FIXME */
178 printf(">>> unsupported leaf value %04x\n", type);
179 break;
181 default:
182 printf(">>> Unsupported numeric leaf-id %04x\n", type);
183 fv->v.i = 0;
184 break;
187 return length;
190 static const char* full_value_string(const struct full_value* fv)
192 static char tmp[128];
194 switch (fv->type)
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;
199 return tmp;
202 static int numeric_leaf(int* value, const unsigned short int* leaf)
204 struct full_value fv;
205 int len = len = full_numeric_leaf(&fv, leaf);
207 switch (fv.type)
209 case fv_integer: *value = fv.v.i; break;
210 case fv_longlong: *value = (unsigned)fv.v.llu; printf("bad conversion\n"); break;
212 return len;
215 static const char* get_attr(unsigned attr)
217 static char tmp[256];
219 switch (attr & 3)
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 ");
240 return tmp;
243 static const char* get_property(unsigned prop)
245 static char tmp[1024];
246 unsigned pos = 0;
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");
259 #undef X
261 if (prop & ~0x01FF) pos += sprintf(tmp, "unk%x", prop & ~0x01FF);
262 else tmp[pos] = '\0';
263 assert(pos < sizeof(tmp));
265 return 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;
284 const char* cstr;
285 const struct p_string* pstr;
286 int leaf_len, value;
288 while (ptr < end)
290 const union codeview_fieldtype* fieldtype = (const union codeview_fieldtype*)ptr;
292 if (*ptr >= 0xf0) /* LF_PAD... */
294 ptr +=* ptr & 0x0f;
295 continue;
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;
306 break;
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",
312 cstr, value);
313 ptr += 2 + 2 + leaf_len + strlen(cstr) + 1;
314 break;
316 case LF_MEMBER_V1:
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;
323 break;
325 case LF_MEMBER_V2:
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;
332 break;
334 case LF_MEMBER_V3:
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;
341 break;
343 case LF_ONEMETHOD_V1:
344 switch ((fieldtype->onemethod_v1.attribute >> 2) & 7)
346 case 4: case 6:
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);
353 break;
355 default:
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);
361 break;
363 break;
365 case LF_ONEMETHOD_V2:
366 switch ((fieldtype->onemethod_v2.attribute >> 2) & 7)
368 case 4: case 6:
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);
375 break;
377 default:
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);
383 break;
385 break;
387 case LF_ONEMETHOD_V3:
388 switch ((fieldtype->onemethod_v3.attribute >> 2) & 7)
390 case 4: case 6:
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);
397 break;
399 default:
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);
405 break;
407 break;
409 case LF_METHOD_V1:
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);
414 break;
416 case LF_METHOD_V2:
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);
421 break;
423 case LF_METHOD_V3:
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);
428 break;
430 case LF_STMEMBER_V1:
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);
436 break;
438 case LF_STMEMBER_V2:
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);
444 break;
446 case LF_STMEMBER_V3:
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);
452 break;
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);
458 break;
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);
464 break;
466 #if 0
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);
471 break;
472 #endif
474 case LF_BCLASS_V1:
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;
480 break;
482 case LF_BCLASS_V2:
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;
488 break;
490 case LF_VBCLASS_V1:
491 case LF_IVBCLASS_V1:
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);
500 ptr += leaf_len;
501 break;
503 case LF_VBCLASS_V2:
504 case LF_IVBCLASS_V2:
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);
513 ptr += leaf_len;
514 break;
516 case LF_FRIENDCLS_V1:
517 printf("\t\tFriend class V1: type:%x\n", fieldtype->friendcls_v1.type);
518 break;
520 case LF_FRIENDCLS_V2:
521 printf("\t\tFriend class V2: type:%x\n", fieldtype->friendcls_v2.type);
522 break;
524 case LF_NESTTYPE_V1:
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);
529 break;
531 case LF_NESTTYPE_V2:
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);
536 break;
538 case LF_NESTTYPE_V3:
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);
543 break;
545 case LF_VFUNCTAB_V1:
546 printf("\t\tVirtual function table V1: type:%x\n",
547 fieldtype->vfunctab_v1.type);
548 ptr += 2 + 2;
549 break;
551 case LF_VFUNCTAB_V2:
552 printf("\t\tVirtual function table V2: type:%x\n",
553 fieldtype->vfunctab_v2.type);
554 ptr += 2 + 2 + 4;
555 break;
557 case LF_VFUNCOFF_V1:
558 printf("\t\tVirtual function table offset V1: type:%x offset:%x\n",
559 fieldtype->vfuncoff_v1.type, fieldtype->vfuncoff_v1.offset);
560 break;
562 case LF_VFUNCOFF_V2:
563 printf("\t\tVirtual function table offset V2: type:%x offset:%x\n",
564 fieldtype->vfuncoff_v2.type, fieldtype->vfuncoff_v2.offset);
565 break;
567 default:
568 printf(">>> Unsupported field-id %x\n", fieldtype->generic.id);
569 dump_data((const void*)fieldtype, 0x30, "\t");
570 break;
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;
579 unsigned int j;
580 const char* str;
582 switch (type->generic.id)
584 case LF_POINTER_V1:
585 printf("\t%x => Pointer V1 to type:%x\n",
586 curr_type, type->pointer_v1.datatype);
587 break;
588 case LF_POINTER_V2:
589 printf("\t%x => Pointer V2 to type:%x\n",
590 curr_type, type->pointer_v2.datatype);
591 break;
592 case LF_ARRAY_V1:
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);
597 break;
598 case LF_ARRAY_V2:
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);
603 break;
604 case LF_ARRAY_V3:
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);
610 break;
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
617 case LF_BITFIELD_V1:
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);
621 break;
623 case LF_BITFIELD_V2:
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);
627 break;
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);
633 break;
635 case LF_STRUCTURE_V1:
636 case LF_CLASS_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);
644 break;
646 case LF_STRUCTURE_V2:
647 case LF_CLASS_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);
656 break;
658 case LF_STRUCTURE_V3:
659 case LF_CLASS_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);
668 break;
670 case LF_UNION_V1:
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);
676 break;
678 case LF_UNION_V2:
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);
684 break;
686 case LF_UNION_V3:
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);
693 break;
695 case LF_ENUM_V1:
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));
702 break;
704 case LF_ENUM_V2:
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));
711 break;
713 case LF_ENUM_V3:
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));
720 break;
722 case LF_ARGLIST_V1:
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]);
728 printf("\n");
729 break;
731 case LF_ARGLIST_V2:
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]);
737 printf("\t\n");
738 break;
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);
746 break;
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);
753 break;
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",
758 curr_type,
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);
766 break;
768 case LF_MODIFIER_V1:
769 printf("\t%x => Modifier V1 type:%x modif:%x\n",
770 curr_type, type->modifier_v1.type, type->modifier_v1.attribute);
771 break;
773 case LF_MODIFIER_V2:
774 printf("\t%x => Modifier V2 type:%x modif:%x\n",
775 curr_type, type->modifier_v2.type, type->modifier_v2.attribute);
776 break;
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)
787 case 4: case 6:
788 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
789 get_attr(pattr[0]), pattr[1],
790 *(const unsigned*)(&pattr[2]));
791 pattr += 3;
792 break;
793 default:
794 printf("\t\t\tattr:%s type:%x\n",
795 get_attr(pattr[0]), pattr[1]);
796 pattr += 2;
800 break;
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)
811 case 4: case 6:
812 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
813 get_attr(pattr[0]), pattr[1], pattr[2]);
814 pattr += 3;
815 break;
816 default:
817 printf("\t\t\tattr:%s type:%x\n",
818 get_attr(pattr[0]), pattr[1]);
819 pattr += 2;
823 break;
825 case LF_VTSHAPE_V1:
827 int count = *(const unsigned short*)((const char*)type + 4);
828 int shift = 0;
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);
833 while (count--)
835 if (((*ptr << shift) & 0xF) <= 6)
836 printf("%s ", desc[(*ptr << shift) & 0xF]);
837 else
838 printf("%x ", (*ptr << shift) & 0xF);
839 if (shift == 0) shift = 4; else {shift = 0; ptr++;}
841 printf("\n");
843 break;
845 case LF_DERIVED_V1:
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]);
851 printf("\n");
852 break;
854 case LF_DERIVED_V2:
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]);
860 printf("\n");
861 break;
863 default:
864 printf(">>> Unsupported type-id %x for %x\n", type->generic.id, curr_type);
865 dump_data((const void*)type, type->generic.len + 2, "");
866 break;
870 int codeview_dump_types_from_offsets(const void* table, const DWORD* offsets, unsigned num_types)
872 unsigned long i;
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]));
880 return TRUE;
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);
893 curr_type++;
894 ptr += (type->generic.len + 2 + 3) & ~3;
897 return TRUE;
900 int codeview_dump_symbols(const void* root, unsigned long size)
902 unsigned int i;
903 int length;
904 char* curr_func = NULL;
905 int nest_block = 0;
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.
921 case S_GDATA_V2:
922 case S_LDATA_V2:
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);
927 break;
929 case S_LDATA_V3:
930 case S_GDATA_V3:
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);
937 break;
939 case S_PUB_V2:
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);
944 break;
946 case S_PUB_V3:
947 /* not completely sure of those two anyway */
948 case S_PUB_FUNC1_V3:
949 case S_PUB_FUNC2_V3:
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);
956 break;
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.
963 case S_THUNK_V1:
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));
969 break;
971 case S_THUNK_V3:
972 printf("\tS-Thunk V3 '%s' (%04x:%08x#%x) type:%x\n",
973 sym->thunk_v3.name,
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);
977 break;
979 /* Global and static functions */
980 case S_GPROC_V1:
981 case S_LPROC_V1:
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,
987 sym->proc_v1.flags);
988 printf("\t Debug: start=%08x end=%08x\n",
989 sym->proc_v1.debug_start, sym->proc_v1.debug_end);
990 if (nest_block)
992 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
993 nest_block = 0;
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; */
999 break;
1001 case S_GPROC_V2:
1002 case S_LPROC_V2:
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);
1011 if (nest_block)
1013 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
1014 nest_block = 0;
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; */
1020 break;
1022 case S_LPROC_V3:
1023 case S_GPROC_V3:
1024 printf("\tS-%s-Procedure V3 '%s' (%04x:%08x#%x) type:%x attr:%x\n",
1025 sym->generic.id == S_GPROC_V3 ? "Global" : "Local",
1026 sym->proc_v3.name,
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);
1032 if (nest_block)
1034 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
1035 nest_block = 0;
1037 curr_func = strdup(sym->proc_v3.name);
1038 /* EPP unsigned int pparent; */
1039 /* EPP unsigned int pend; */
1040 /* EPP unsigned int next; */
1041 break;
1043 /* Function parameters and stack variables */
1044 case S_BPREL_V1:
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);
1048 break;
1050 case S_BPREL_V2:
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);
1054 break;
1056 case S_BPREL_V3:
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);
1060 break;
1062 case S_BPREL_XXXX_V3:
1063 printf("\tS-BP-relative XXXX V3: '%s' @%d type:%x unkn:%x (in %s)\n",
1064 sym->stack_xxxx_v3.name, sym->stack_xxxx_v3.offset,
1065 sym->stack_xxxx_v3.symtype, sym->stack_xxxx_v3.unknown, curr_func);
1066 break;
1068 case S_REGISTER_V1:
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);
1072 break;
1074 case S_REGISTER_V2:
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);
1078 break;
1080 case S_REGISTER_V3:
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);
1084 break;
1086 case S_BLOCK_V1:
1087 printf("\tS-Block V1 '%s' in '%s' (%04x:%08x#%08x)\n",
1088 p_string(&sym->block_v1.p_name),
1089 curr_func,
1090 sym->block_v1.segment, sym->block_v1.offset,
1091 sym->block_v1.length);
1092 nest_block++;
1093 break;
1095 case S_BLOCK_V3:
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);
1100 nest_block++;
1101 break;
1103 /* Additional function information */
1104 case S_FUNCINFO_V2:
1105 printf("\tFunction info V2 unk1:%x unk2:%x unk3:%x unk4:%x unk5:%x unk6:%x flags:%04x unk7:%x\n",
1106 sym->func_info_v2.unknown1,
1107 sym->func_info_v2.unknown2,
1108 sym->func_info_v2.unknown3,
1109 sym->func_info_v2.unknown4,
1110 sym->func_info_v2.unknown5,
1111 sym->func_info_v2.unknown6,
1112 sym->func_info_v2.flags,
1113 sym->func_info_v2.unknown7);
1114 break;
1116 case S_SECUCOOKIE_V3:
1117 printf("\tSecurity Cookie V3 @%d unk:%x\n",
1118 sym->security_cookie_v3.offset, sym->security_cookie_v3.unknown);
1119 break;
1121 case S_END_V1:
1122 if (nest_block)
1124 nest_block--;
1125 printf("\tS-End-Of block (%u)\n", nest_block);
1127 else
1129 printf("\tS-End-Of %s\n", curr_func);
1130 free(curr_func);
1131 curr_func = NULL;
1133 break;
1135 case S_COMPILAND_V1:
1137 const char* machine;
1138 const char* lang;
1140 switch (sym->compiland_v1.unknown & 0xFF)
1142 case 0x00: machine = "Intel 8080"; break;
1143 case 0x01: machine = "Intel 8086"; break;
1144 case 0x02: machine = "Intel 80286"; break;
1145 case 0x03: machine = "Intel 80386"; break;
1146 case 0x04: machine = "Intel 80486"; break;
1147 case 0x05: machine = "Intel Pentium"; break;
1148 case 0x10: machine = "MIPS R4000"; break;
1149 default:
1151 static char tmp[16];
1152 sprintf(tmp, "machine=%x", sym->compiland_v1.unknown & 0xFF);
1153 machine = tmp;
1155 break;
1157 switch ((sym->compiland_v1.unknown >> 8) & 0xFF)
1159 case 0x00: lang = "C"; break;
1160 case 0x01: lang = "C++"; break;
1161 case 0x02: lang = "Fortran"; break;
1162 case 0x03: lang = "Masm"; break;
1163 case 0x04: lang = "Pascal"; break;
1164 case 0x05: lang = "Basic"; break;
1165 case 0x06: lang = "Cobol"; break;
1166 default:
1168 static char tmp[16];
1169 sprintf(tmp, "language=%x", (sym->compiland_v1.unknown >> 8) & 0xFF);
1170 lang = tmp;
1172 break;
1175 printf("\tS-Compiland V1 '%s' %s %s unk:%x\n",
1176 p_string(&sym->compiland_v1.p_name), machine, lang,
1177 sym->compiland_v1.unknown >> 16);
1179 break;
1181 case S_COMPILAND_V2:
1182 printf("\tS-Compiland V2 '%s'\n",
1183 p_string(&sym->compiland_v2.p_name));
1184 dump_data((const void*)sym, sym->generic.len + 2, " ");
1186 const char* ptr = sym->compiland_v2.p_name.name + sym->compiland_v2.p_name.namelen;
1187 while (*ptr)
1189 printf("\t\t%s => ", ptr); ptr += strlen(ptr) + 1;
1190 printf("%s\n", ptr); ptr += strlen(ptr) + 1;
1193 break;
1195 case S_COMPILAND_V3:
1196 printf("\tS-Compiland V3 '%s' unknown:%x\n",
1197 sym->compiland_v3.name, sym->compiland_v3.unknown);
1198 break;
1200 case S_OBJNAME_V1:
1201 printf("\tS-ObjName V1 sig:%.4s '%s'\n",
1202 sym->objname_v1.signature, p_string(&sym->objname_v1.p_name));
1203 break;
1205 case S_LABEL_V1:
1206 printf("\tS-Label V1 '%s' in '%s' (%04x:%08x)\n",
1207 p_string(&sym->label_v1.p_name),
1208 curr_func, sym->label_v1.segment, sym->label_v1.offset);
1209 break;
1211 case S_LABEL_V3:
1212 printf("\tS-Label V3 '%s' in '%s' (%04x:%08x) flag:%x\n",
1213 sym->label_v3.name, curr_func, sym->label_v3.segment,
1214 sym->label_v3.offset, sym->label_v3.flags);
1215 break;
1217 case S_CONSTANT_V2:
1219 int vlen;
1220 struct full_value fv;
1222 vlen = full_numeric_leaf(&fv, &sym->constant_v2.cvalue);
1223 printf("\tS-Constant V2 '%s' = %s type:%x\n",
1224 p_string(PSTRING(&sym->constant_v2.cvalue, vlen)),
1225 full_value_string(&fv), sym->constant_v2.type);
1227 break;
1229 case S_CONSTANT_V3:
1231 int vlen;
1232 struct full_value fv;
1234 vlen = full_numeric_leaf(&fv, &sym->constant_v3.cvalue);
1235 printf("\tS-Constant V3 '%s' = %s type:%x\n",
1236 (const char*)&sym->constant_v3.cvalue + vlen,
1237 full_value_string(&fv), sym->constant_v3.type);
1239 break;
1241 case S_UDT_V1:
1242 printf("\tS-Udt V1 '%s': type:0x%x\n",
1243 p_string(&sym->udt_v1.p_name), sym->udt_v1.type);
1244 break;
1246 case S_UDT_V2:
1247 printf("\tS-Udt V2 '%s': type:0x%x\n",
1248 p_string(&sym->udt_v2.p_name), sym->udt_v2.type);
1249 break;
1251 case S_UDT_V3:
1252 printf("\tS-Udt V3 '%s': type:0x%x\n",
1253 sym->udt_v3.name, sym->udt_v3.type);
1254 break;
1256 * These are special, in that they are always followed by an
1257 * additional length-prefixed string which is *not* included
1258 * into the symbol length count. We need to skip it.
1260 case S_PROCREF_V1:
1261 printf("\tS-Procref V1 "); goto doaref;
1262 case S_DATAREF_V1:
1263 printf("\tS-Dataref V1 "); goto doaref;
1264 case S_LPROCREF_V1:
1265 printf("\tS-L-Procref V1 "); goto doaref;
1266 doaref:
1268 const struct p_string* pname;
1270 pname = PSTRING(sym, length);
1271 length += (pname->namelen + 1 + 3) & ~3;
1272 printf("\t%08x %08x %08x '%s'\n",
1273 *(((const DWORD*)sym) + 1), *(((const DWORD*)sym) + 2), *(((const DWORD*)sym) + 3),
1274 p_string(pname));
1276 break;
1277 case S_MSTOOL_V3: /* info about tool used to create CU */
1279 const unsigned short* ptr = ((const unsigned short*)sym) + 2;
1280 const char* x1;
1281 const char* x2 = (const char*)&ptr[9];
1282 /* FIXME: what are all those values for ? */
1283 printf("\tTool V3 unk=%04x%04x%04x front=%d.%d.%d.0 back=%d.%d.%d.0 %s\n",
1284 ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
1285 ptr[8], x2);
1286 while (*(x1 = x2 + strlen(x2) + 1))
1288 x2 = x1 + strlen(x1) + 1;
1289 if (!*x2) break;
1290 printf("\t\t%s: %s\n", x1, x2);
1293 break;
1295 case S_MSTOOLINFO_V3:
1297 const unsigned short* ptr = ((const unsigned short*)sym) + 2;
1299 printf("\tTool info V3: unk=%04x%04x%04x front=%d.%d.%d.%d back=%d.%d.%d.%d %s\n",
1300 ptr[0], ptr[1], ptr[2],
1301 ptr[3], ptr[4], ptr[5], ptr[6],
1302 ptr[7], ptr[8], ptr[9], ptr[10],
1303 (const char*)(ptr + 11));
1305 break;
1307 case S_MSTOOLENV_V3:
1309 const char* x1 = (const char*)sym + 4 + 1;
1310 const char* x2;
1312 printf("\tTool conf V3\n");
1313 while (*x1)
1315 x2 = x1 + strlen(x1) + 1;
1316 if (!*x2) break;
1317 printf("\t\t%s: %s\n", x1, x2);
1318 x1 = x2 + strlen(x2) + 1;
1321 break;
1323 case S_ALIGN_V1:
1324 /* simply skip it */
1325 break;
1327 case S_SSEARCH_V1:
1328 printf("\tSSearch V1: (%04x:%08x)\n",
1329 sym->ssearch_v1.segment, sym->ssearch_v1.offset);
1330 break;
1332 case S_SECTINFO_V3:
1333 printf("\tSSection Info: seg=%04x ?=%04x rva=%08x size=%08x attr=%08x %s\n",
1334 *(const unsigned short*)((const char*)sym + 4),
1335 *(const unsigned short*)((const char*)sym + 6),
1336 *(const unsigned*)((const char*)sym + 8),
1337 *(const unsigned*)((const char*)sym + 12),
1338 *(const unsigned*)((const char*)sym + 16),
1339 (const char*)sym + 20);
1340 break;
1342 case S_SUBSECTINFO_V3:
1343 printf("\tSSubSection Info: addr=%04x:%08x size=%08x attr=%08x %s\n",
1344 *(const unsigned short*)((const char*)sym + 16),
1345 *(const unsigned*)((const char*)sym + 12),
1346 *(const unsigned*)((const char*)sym + 4),
1347 *(const unsigned*)((const char*)sym + 8),
1348 (const char*)sym + 18);
1349 break;
1351 case S_ENTRYPOINT_V3:
1352 printf("\tSEntryPoint: id=%x '%s'\n",
1353 *(const unsigned*)((const char*)sym + 4), (const char*)sym + 8);
1354 break;
1356 default:
1357 printf(">>> Unsupported symbol-id %x sz=%d\n", sym->generic.id, sym->generic.len + 2);
1358 dump_data((const void*)sym, sym->generic.len + 2, " ");
1361 return 0;
1364 void codeview_dump_linetab(const char* linetab, DWORD size, BOOL pascal_str, const char* pfx)
1366 const char* ptr = linetab;
1367 int nfile, nseg, nline;
1368 int i, j, k;
1369 const unsigned int* filetab;
1370 const unsigned int* lt_ptr;
1371 const struct startend* start;
1373 nfile = *(const short*)linetab;
1374 filetab = (const unsigned int*)(linetab + 2 * sizeof(short));
1375 printf("%s%d files with %d ???\n", pfx, nfile, *(const short*)(linetab + sizeof(short)));
1377 for (i = 0; i < nfile; i++)
1379 ptr = linetab + filetab[i];
1380 nseg = *(const short*)ptr;
1381 ptr += 2 * sizeof(short);
1382 lt_ptr = (const unsigned int*)ptr;
1383 start = (const struct startend*)(lt_ptr + nseg);
1386 * Now snarf the filename for all of the segments for this file.
1388 if (pascal_str)
1390 char filename[MAX_PATH];
1391 const struct p_string* p_fn;
1393 p_fn = (const struct p_string*)(start + nseg);
1394 memset(filename, 0, sizeof(filename));
1395 memcpy(filename, p_fn->name, p_fn->namelen);
1396 printf("%slines for file #%d/%d %s %d\n", pfx, i, nfile, filename, nseg);
1398 else
1399 printf("%slines for file #%d/%d %s %d\n", pfx, i, nfile, (const char*)(start + nseg), nseg);
1401 for (j = 0; j < nseg; j++)
1403 ptr = linetab + *lt_ptr++;
1404 nline = *(const short*)(ptr + 2);
1405 printf("%s %04x:%08x-%08x #%d\n",
1406 pfx, *(const short*)(ptr + 0), start[j].start, start[j].end, nline);
1407 ptr += 4;
1408 for (k = 0; k < nline; k++)
1410 printf("%s %x %d\n",
1411 pfx, ((const unsigned int*)ptr)[k],
1412 ((const unsigned short*)((const unsigned int*)ptr + nline))[k]);
1418 void codeview_dump_linetab2(const char* linetab, DWORD size, const char* strimage, DWORD strsize, const char* pfx)
1420 unsigned i;
1421 const struct codeview_linetab2* lt2;
1422 const struct codeview_linetab2* lt2_files = NULL;
1423 const struct codeview_lt2blk_lines* lines_blk;
1424 const struct codeview_linetab2_file*fd;
1426 /* locate LT2_FILES_BLOCK (if any) */
1427 lt2 = (const struct codeview_linetab2*)linetab;
1428 while ((const char*)(lt2 + 1) < linetab + size)
1430 if (lt2->header == LT2_FILES_BLOCK)
1432 lt2_files = lt2;
1433 break;
1435 lt2 = codeview_linetab2_next_block(lt2);
1437 if (!lt2_files)
1439 printf("%sNo LT2_FILES_BLOCK found\n", pfx);
1440 return;
1443 lt2 = (const struct codeview_linetab2*)linetab;
1444 while ((const char*)(lt2 + 1) < linetab + size)
1446 /* FIXME: should also check that whole lbh fits in linetab + size */
1447 switch (lt2->header)
1449 case LT2_LINES_BLOCK:
1450 lines_blk = (const struct codeview_lt2blk_lines*)lt2;
1451 printf("%sblock from %04x:%08x #%x (%x lines) fo=%x\n",
1452 pfx, lines_blk->seg, lines_blk->start, lines_blk->size,
1453 lines_blk->nlines, lines_blk->file_offset);
1454 /* FIXME: should check that file_offset is within the LT2_FILES_BLOCK we've seen */
1455 fd = (const struct codeview_linetab2_file*)((const char*)lt2_files + 8 + lines_blk->file_offset);
1456 printf("%s md5=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
1457 pfx, fd->md5[ 0], fd->md5[ 1], fd->md5[ 2], fd->md5[ 3],
1458 fd->md5[ 4], fd->md5[ 5], fd->md5[ 6], fd->md5[ 7],
1459 fd->md5[ 8], fd->md5[ 9], fd->md5[10], fd->md5[11],
1460 fd->md5[12], fd->md5[13], fd->md5[14], fd->md5[15]);
1461 /* FIXME: should check that string is within strimage + strsize */
1462 printf("%s file=%s\n", pfx, strimage ? strimage + fd->offset : "--none--");
1463 for (i = 0; i < lines_blk->nlines; i++)
1465 printf("%s offset=%08x line=%d\n",
1466 pfx, lines_blk->l[i].offset, lines_blk->l[i].lineno ^ 0x80000000);
1468 break;
1469 case LT2_FILES_BLOCK: /* skip */
1470 break;
1471 default:
1472 printf("%sblock end %x\n", pfx, lt2->header);
1473 lt2 = (const struct codeview_linetab2*)((const char*)linetab + size);
1474 continue;
1476 lt2 = codeview_linetab2_next_block(lt2);