TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / tools / winedump / msc.c
blob5890b2926bc5db7ebabeb72d0214414853531a0a
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 = *(const unsigned short*)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;
210 return len;
213 static const char* get_attr(unsigned attr)
215 static char tmp[256];
217 switch (attr & 3)
219 case 0: strcpy(tmp, ""); break;
220 case 1: strcpy(tmp, "private "); break;
221 case 2: strcpy(tmp, "protected "); break;
222 case 3: strcpy(tmp, "public "); break;
224 switch ((attr >> 2) & 7)
226 case 0: strcat(tmp, ""); break;
227 case 1: strcat(tmp, "virtual "); break;
228 case 2: strcat(tmp, "static "); break;
229 case 3: strcat(tmp, "friend "); break;
230 case 4: strcat(tmp, "introducing virtual "); break;
231 case 5: strcat(tmp, "pure virtual "); break;
232 case 6: strcat(tmp, "pure introducing virtual "); break;
233 case 7: strcat(tmp, "reserved "); break;
235 if ((attr >> 5) & 1) strcat(tmp, "pseudo ");
236 if ((attr >> 6) & 1) strcat(tmp, "no-inherit ");
237 if ((attr >> 7) & 1) strcat(tmp, "no-construct ");
238 return tmp;
241 static const char* get_property(unsigned prop)
243 static char tmp[1024];
244 unsigned pos = 0;
246 if (!prop) return "none";
247 #define X(s) {if (pos) tmp[pos++] = ';'; strcpy(tmp + pos, s); pos += strlen(s);}
248 if (prop & 0x0001) X("packed");
249 if (prop & 0x0002) X("w/{cd}tor");
250 if (prop & 0x0004) X("w/overloaded-ops");
251 if (prop & 0x0008) X("nested-class");
252 if (prop & 0x0010) X("has-nested-classes");
253 if (prop & 0x0020) X("w/overloaded-assign");
254 if (prop & 0x0040) X("w/casting-methods");
255 if (prop & 0x0080) X("forward");
256 if (prop & 0x0100) X("scoped");
257 #undef X
259 if (prop & ~0x01FF) pos += sprintf(tmp, "unk%x", prop & ~0x01FF);
260 else tmp[pos] = '\0';
261 assert(pos < sizeof(tmp));
263 return tmp;
266 static void do_field(const unsigned char* start, const unsigned char* end)
269 * A 'field list' is a CodeView-specific data type which doesn't
270 * directly correspond to any high-level data type. It is used
271 * to hold the collection of members of a struct, class, union
272 * or enum type. The actual definition of that type will follow
273 * later, and refer to the field list definition record.
275 * As we don't have a field list type ourselves, we look ahead
276 * in the field list to try to find out whether this field list
277 * will be used for an enum or struct type, and create a dummy
278 * type of the corresponding sort. Later on, the definition of
279 * the 'real' type will copy the member / enumeration data.
281 const unsigned char* ptr = start;
282 const char* cstr;
283 const struct p_string* pstr;
284 int leaf_len, value;
286 while (ptr < end)
288 const union codeview_fieldtype* fieldtype = (const union codeview_fieldtype*)ptr;
290 if (*ptr >= 0xf0) /* LF_PAD... */
292 ptr +=* ptr & 0x0f;
293 continue;
296 switch (fieldtype->generic.id)
298 case LF_ENUMERATE_V1:
299 leaf_len = numeric_leaf(&value, &fieldtype->enumerate_v1.value);
300 pstr = PSTRING(&fieldtype->enumerate_v1.value, leaf_len);
301 printf("\t\tEnumerate V1: '%s' value:%d\n",
302 p_string(pstr), value);
303 ptr += 2 + 2 + leaf_len + 1 + pstr->namelen;
304 break;
306 case LF_ENUMERATE_V3:
307 leaf_len = numeric_leaf(&value, &fieldtype->enumerate_v3.value);
308 cstr = (const char*)&fieldtype->enumerate_v3.value + leaf_len;
309 printf("\t\tEnumerate V3: '%s' value:%d\n",
310 cstr, value);
311 ptr += 2 + 2 + leaf_len + strlen(cstr) + 1;
312 break;
314 case LF_MEMBER_V1:
315 leaf_len = numeric_leaf(&value, &fieldtype->member_v1.offset);
316 pstr = PSTRING(&fieldtype->member_v1.offset, leaf_len);
317 printf("\t\tMember V1: '%s' type:%x attr:%s @%d\n",
318 p_string(pstr), fieldtype->member_v1.type,
319 get_attr(fieldtype->member_v1.attribute), value);
320 ptr += 2 + 2 + 2 + leaf_len + 1 + pstr->namelen;
321 break;
323 case LF_MEMBER_V2:
324 leaf_len = numeric_leaf(&value, &fieldtype->member_v2.offset);
325 pstr = PSTRING(&fieldtype->member_v2.offset, leaf_len);
326 printf("\t\tMember V2: '%s' type:%x attr:%s @%d\n",
327 p_string(pstr), fieldtype->member_v2.type,
328 get_attr(fieldtype->member_v2.attribute), value);
329 ptr += 2 + 2 + 4 + leaf_len + 1 + pstr->namelen;
330 break;
332 case LF_MEMBER_V3:
333 leaf_len = numeric_leaf(&value, &fieldtype->member_v3.offset);
334 cstr = (const char*)&fieldtype->member_v3.offset + leaf_len;
335 printf("\t\tMember V3: '%s' type:%x attr:%s @%d\n",
336 cstr, fieldtype->member_v3.type,
337 get_attr(fieldtype->member_v3.attribute), value);
338 ptr += 2 + 2 + 4 + leaf_len + strlen(cstr) + 1;
339 break;
341 case LF_ONEMETHOD_V1:
342 switch ((fieldtype->onemethod_v1.attribute >> 2) & 7)
344 case 4: case 6:
345 printf("\t\tVirtual-method V1: '%s' attr:%s type:%x vtable_offset:%u\n",
346 p_string(&fieldtype->onemethod_virt_v1.p_name),
347 get_attr(fieldtype->onemethod_virt_v1.attribute),
348 fieldtype->onemethod_virt_v1.type,
349 fieldtype->onemethod_virt_v1.vtab_offset);
350 ptr += 2 + 2 + 2 + 4 + (1 + fieldtype->onemethod_virt_v1.p_name.namelen);
351 break;
353 default:
354 printf("\t\tMethod V1: '%s' attr:%s type:%x\n",
355 p_string(&fieldtype->onemethod_v1.p_name),
356 get_attr(fieldtype->onemethod_v1.attribute),
357 fieldtype->onemethod_v1.type);
358 ptr += 2 + 2 + 2 + (1 + fieldtype->onemethod_v1.p_name.namelen);
359 break;
361 break;
363 case LF_ONEMETHOD_V2:
364 switch ((fieldtype->onemethod_v2.attribute >> 2) & 7)
366 case 4: case 6:
367 printf("\t\tVirtual-method V2: '%s' attr:%s type:%x vtable_offset:%u\n",
368 p_string(&fieldtype->onemethod_virt_v2.p_name),
369 get_attr(fieldtype->onemethod_virt_v2.attribute),
370 fieldtype->onemethod_virt_v2.type,
371 fieldtype->onemethod_virt_v2.vtab_offset);
372 ptr += 2 + 2 + 4 + 4 + (1 + fieldtype->onemethod_virt_v2.p_name.namelen);
373 break;
375 default:
376 printf("\t\tMethod V2: '%s' attr:%s type:%x\n",
377 p_string(&fieldtype->onemethod_v2.p_name),
378 get_attr(fieldtype->onemethod_v2.attribute),
379 fieldtype->onemethod_v2.type);
380 ptr += 2 + 2 + 4 + (1 + fieldtype->onemethod_v2.p_name.namelen);
381 break;
383 break;
385 case LF_ONEMETHOD_V3:
386 switch ((fieldtype->onemethod_v3.attribute >> 2) & 7)
388 case 4: case 6:
389 printf("\t\tVirtual-method V3: '%s' attr:%s type:%x vtable_offset:%u\n",
390 fieldtype->onemethod_virt_v3.name,
391 get_attr(fieldtype->onemethod_virt_v3.attribute),
392 fieldtype->onemethod_virt_v3.type,
393 fieldtype->onemethod_virt_v3.vtab_offset);
394 ptr += 2 + 2 + 4 + 4 + (strlen(fieldtype->onemethod_virt_v3.name) + 1);
395 break;
397 default:
398 printf("\t\tMethod V3: '%s' attr:%s type:%x\n",
399 fieldtype->onemethod_v3.name,
400 get_attr(fieldtype->onemethod_v3.attribute),
401 fieldtype->onemethod_v3.type);
402 ptr += 2 + 2 + 4 + (strlen(fieldtype->onemethod_v3.name) + 1);
403 break;
405 break;
407 case LF_METHOD_V1:
408 printf("\t\tMethod V1: '%s' overloaded=#%d method-list=%x\n",
409 p_string(&fieldtype->method_v1.p_name),
410 fieldtype->method_v1.count, fieldtype->method_v1.mlist);
411 ptr += 2 + 2 + 2 + (1 + fieldtype->method_v1.p_name.namelen);
412 break;
414 case LF_METHOD_V2:
415 printf("\t\tMethod V2: '%s' overloaded=#%d method-list=%x\n",
416 p_string(&fieldtype->method_v2.p_name),
417 fieldtype->method_v2.count, fieldtype->method_v2.mlist);
418 ptr += 2 + 2 + 4 + (1 + fieldtype->method_v2.p_name.namelen);
419 break;
421 case LF_METHOD_V3:
422 printf("\t\tMethod V3: '%s' overloaded=#%d method-list=%x\n",
423 fieldtype->method_v3.name,
424 fieldtype->method_v3.count, fieldtype->method_v3.mlist);
425 ptr += 2 + 2 + 4 + (strlen(fieldtype->method_v3.name) + 1);
426 break;
428 case LF_STMEMBER_V1:
429 printf("\t\tStatic member V1: '%s' attr:%s type:%x\n",
430 p_string(&fieldtype->stmember_v1.p_name),
431 get_attr(fieldtype->stmember_v1.attribute),
432 fieldtype->stmember_v1.type);
433 ptr += 2 + 2 + 2 + (1 + fieldtype->stmember_v1.p_name.namelen);
434 break;
436 case LF_STMEMBER_V2:
437 printf("\t\tStatic member V2: '%s' attr:%s type:%x\n",
438 p_string(&fieldtype->stmember_v2.p_name),
439 get_attr(fieldtype->stmember_v2.attribute),
440 fieldtype->stmember_v2.type);
441 ptr += 2 + 2 + 4 + (1 + fieldtype->stmember_v2.p_name.namelen);
442 break;
444 case LF_STMEMBER_V3:
445 printf("\t\tStatic member V3: '%s' attr:%s type:%x\n",
446 fieldtype->stmember_v3.name,
447 get_attr(fieldtype->stmember_v3.attribute),
448 fieldtype->stmember_v3.type);
449 ptr += 2 + 2 + 4 + (strlen(fieldtype->stmember_v3.name) + 1);
450 break;
452 case LF_FRIENDFCN_V1:
453 printf("\t\tFriend function V1: '%s' type:%x\n",
454 p_string(&fieldtype->friendfcn_v1.p_name),
455 fieldtype->friendfcn_v1.type);
456 break;
458 case LF_FRIENDFCN_V2:
459 printf("\t\tFriend function V2: '%s' type:%x\n",
460 p_string(&fieldtype->friendfcn_v2.p_name),
461 fieldtype->friendfcn_v2.type);
462 break;
464 #if 0
465 case LF_FRIENDFCN_V3:
466 printf("\t\tFriend function V3: '%s' type:%x\n",
467 fieldtype->friendfcn_v3.name,
468 fieldtype->friendfcn_v3.type);
469 break;
470 #endif
472 case LF_BCLASS_V1:
473 leaf_len = numeric_leaf(&value, &fieldtype->bclass_v1.offset);
474 printf("\t\tBase class V1: type:%x attr:%s @%d\n",
475 fieldtype->bclass_v1.type,
476 get_attr(fieldtype->bclass_v1.attribute), value);
477 ptr += 2 + 2 + 2 + leaf_len;
478 break;
480 case LF_BCLASS_V2:
481 leaf_len = numeric_leaf(&value, &fieldtype->bclass_v2.offset);
482 printf("\t\tBase class V2: type:%x attr:%s @%d\n",
483 fieldtype->bclass_v2.type,
484 get_attr(fieldtype->bclass_v2.attribute), value);
485 ptr += 2 + 2 + 4 + leaf_len;
486 break;
488 case LF_VBCLASS_V1:
489 case LF_IVBCLASS_V1:
490 leaf_len = numeric_leaf(&value, &fieldtype->vbclass_v1.vbpoff);
491 printf("\t\t%sirtual base class V1: type:%x (ptr:%x) attr:%s vbpoff:%d ",
492 (fieldtype->generic.id == LF_VBCLASS_V2) ? "V" : "Indirect v",
493 fieldtype->vbclass_v1.btype, fieldtype->vbclass_v1.vbtype,
494 get_attr(fieldtype->vbclass_v1.attribute), value);
495 ptr += 2 + 2 + 2 + 2 + leaf_len;
496 leaf_len = numeric_leaf(&value, (const unsigned short*)ptr);
497 printf("vboff:%d\n", value);
498 ptr += leaf_len;
499 break;
501 case LF_VBCLASS_V2:
502 case LF_IVBCLASS_V2:
503 leaf_len = numeric_leaf(&value, &fieldtype->vbclass_v1.vbpoff);
504 printf("\t\t%sirtual base class V2: type:%x (ptr:%x) attr:%s vbpoff:%d ",
505 (fieldtype->generic.id == LF_VBCLASS_V2) ? "V" : "Indirect v",
506 fieldtype->vbclass_v2.btype, fieldtype->vbclass_v2.vbtype,
507 get_attr(fieldtype->vbclass_v2.attribute), value);
508 ptr += 2 + 2 + 4 + 4 + leaf_len;
509 leaf_len = numeric_leaf(&value, (const unsigned short*)ptr);
510 printf("vboff:%d\n", value);
511 ptr += leaf_len;
512 break;
514 case LF_FRIENDCLS_V1:
515 printf("\t\tFriend class V1: type:%x\n", fieldtype->friendcls_v1.type);
516 break;
518 case LF_FRIENDCLS_V2:
519 printf("\t\tFriend class V2: type:%x\n", fieldtype->friendcls_v2.type);
520 break;
522 case LF_NESTTYPE_V1:
523 printf("\t\tNested type V1: '%s' type:%x\n",
524 p_string(&fieldtype->nesttype_v1.p_name),
525 fieldtype->nesttype_v1.type);
526 ptr += 2 + 2 + (1 + fieldtype->nesttype_v1.p_name.namelen);
527 break;
529 case LF_NESTTYPE_V2:
530 printf("\t\tNested type V2: '%s' pad0:%u type:%x\n",
531 p_string(&fieldtype->nesttype_v2.p_name),
532 fieldtype->nesttype_v2._pad0, fieldtype->nesttype_v2.type);
533 ptr += 2 + 2 + 4 + (1 + fieldtype->nesttype_v2.p_name.namelen);
534 break;
536 case LF_NESTTYPE_V3:
537 printf("\t\tNested type V3: '%s' pad0:%u type:%x\n",
538 fieldtype->nesttype_v3.name,
539 fieldtype->nesttype_v3._pad0, fieldtype->nesttype_v3.type);
540 ptr += 2 + 2 + 4 + (strlen(fieldtype->nesttype_v3.name) + 1);
541 break;
543 case LF_VFUNCTAB_V1:
544 printf("\t\tVirtual function table V1: type:%x\n",
545 fieldtype->vfunctab_v1.type);
546 ptr += 2 + 2;
547 break;
549 case LF_VFUNCTAB_V2:
550 printf("\t\tVirtual function table V2: type:%x\n",
551 fieldtype->vfunctab_v2.type);
552 ptr += 2 + 2 + 4;
553 break;
555 case LF_VFUNCOFF_V1:
556 printf("\t\tVirtual function table offset V1: type:%x offset:%x\n",
557 fieldtype->vfuncoff_v1.type, fieldtype->vfuncoff_v1.offset);
558 break;
560 case LF_VFUNCOFF_V2:
561 printf("\t\tVirtual function table offset V2: type:%x offset:%x\n",
562 fieldtype->vfuncoff_v2.type, fieldtype->vfuncoff_v2.offset);
563 break;
565 default:
566 printf(">>> Unsupported field-id %x\n", fieldtype->generic.id);
567 dump_data((const void*)fieldtype, 0x30, "\t");
568 break;
573 static void codeview_dump_one_type(unsigned curr_type, const union codeview_type* type)
575 const union codeview_reftype* reftype = (const union codeview_reftype*)type;
576 int i, leaf_len, value;
577 unsigned int j;
578 const char* str;
580 switch (type->generic.id)
582 case LF_POINTER_V1:
583 printf("\t%x => Pointer V1 to type:%x\n",
584 curr_type, type->pointer_v1.datatype);
585 break;
586 case LF_POINTER_V2:
587 printf("\t%x => Pointer V2 to type:%x\n",
588 curr_type, type->pointer_v2.datatype);
589 break;
590 case LF_ARRAY_V1:
591 leaf_len = numeric_leaf(&value, &type->array_v1.arrlen);
592 printf("\t%x => Array V1-'%s'[%u type:%x] type:%x\n",
593 curr_type, p_string(PSTRING(&type->array_v1.arrlen, leaf_len)),
594 value, type->array_v1.idxtype, type->array_v1.elemtype);
595 break;
596 case LF_ARRAY_V2:
597 leaf_len = numeric_leaf(&value, &type->array_v2.arrlen);
598 printf("\t%x => Array V2-'%s'[%u type:%x] type:%x\n",
599 curr_type, p_string(PSTRING(&type->array_v2.arrlen, leaf_len)),
600 value, type->array_v2.idxtype, type->array_v2.elemtype);
601 break;
602 case LF_ARRAY_V3:
603 leaf_len = numeric_leaf(&value, &type->array_v3.arrlen);
604 str = (const char*)&type->array_v3.arrlen + leaf_len;
605 printf("\t%x => Array V3-'%s'[%u type:%x] type:%x\n",
606 curr_type, str, value,
607 type->array_v3.idxtype, type->array_v3.elemtype);
608 break;
610 /* a bitfields is a CodeView specific data type which represent a bitfield
611 * in a structure or a class. For now, we store it in a SymTag-like type
612 * (so that the rest of the process is seamless), but check at udt inclusion
613 * type for its presence
615 case LF_BITFIELD_V1:
616 printf("\t%x => Bitfield V1:%x offset:%u #bits:%u\n",
617 curr_type, reftype->bitfield_v1.type, reftype->bitfield_v1.bitoff,
618 reftype->bitfield_v1.nbits);
619 break;
621 case LF_BITFIELD_V2:
622 printf("\t%x => Bitfield V2:%x offset:%u #bits:%u\n",
623 curr_type, reftype->bitfield_v2.type, reftype->bitfield_v2.bitoff,
624 reftype->bitfield_v2.nbits);
625 break;
627 case LF_FIELDLIST_V1:
628 case LF_FIELDLIST_V2:
629 printf("\t%x => Fieldlist\n", curr_type);
630 do_field(reftype->fieldlist.list, (const BYTE*)type + reftype->generic.len + 2);
631 break;
633 case LF_STRUCTURE_V1:
634 case LF_CLASS_V1:
635 leaf_len = numeric_leaf(&value, &type->struct_v1.structlen);
636 printf("\t%x => %s V1 '%s' elts:%u property:%s fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
637 curr_type, type->generic.id == LF_CLASS_V1 ? "Class" : "Struct",
638 p_string(PSTRING(&type->struct_v1.structlen, leaf_len)),
639 type->struct_v1.n_element, get_property(type->struct_v1.property),
640 type->struct_v1.fieldlist, type->struct_v1.derived,
641 type->struct_v1.vshape, value);
642 break;
644 case LF_STRUCTURE_V2:
645 case LF_CLASS_V2:
646 leaf_len = numeric_leaf(&value, &type->struct_v2.structlen);
647 printf("\t%x => %s V2 '%s' elts:%u property:%s\n"
648 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
649 curr_type, type->generic.id == LF_CLASS_V2 ? "Class" : "Struct",
650 p_string(PSTRING(&type->struct_v2.structlen, leaf_len)),
651 type->struct_v2.n_element, get_property(type->struct_v2.property),
652 type->struct_v2.fieldlist, type->struct_v2.derived,
653 type->struct_v2.vshape, value);
654 break;
656 case LF_STRUCTURE_V3:
657 case LF_CLASS_V3:
658 leaf_len = numeric_leaf(&value, &type->struct_v3.structlen);
659 str = (const char*)&type->struct_v3.structlen + leaf_len;
660 printf("\t%x => %s V3 '%s' elts:%u property:%s\n"
661 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
662 curr_type, type->generic.id == LF_CLASS_V3 ? "Class" : "Struct",
663 str, type->struct_v3.n_element, get_property(type->struct_v3.property),
664 type->struct_v3.fieldlist, type->struct_v3.derived,
665 type->struct_v3.vshape, value);
666 break;
668 case LF_UNION_V1:
669 leaf_len = numeric_leaf(&value, &type->union_v1.un_len);
670 printf("\t%x => Union V1 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
671 curr_type, p_string(PSTRING(&type->union_v1.un_len, leaf_len)),
672 type->union_v1.count, get_property(type->union_v1.property),
673 type->union_v1.fieldlist, value);
674 break;
676 case LF_UNION_V2:
677 leaf_len = numeric_leaf(&value, &type->union_v2.un_len);
678 printf("\t%x => Union V2 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
679 curr_type, p_string(PSTRING(&type->union_v2.un_len, leaf_len)),
680 type->union_v2.count, get_property(type->union_v2.property),
681 type->union_v2.fieldlist, value);
682 break;
684 case LF_UNION_V3:
685 leaf_len = numeric_leaf(&value, &type->union_v3.un_len);
686 str = (const char*)&type->union_v3.un_len + leaf_len;
687 printf("\t%x => Union V3 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
688 curr_type, str, type->union_v3.count,
689 get_property(type->union_v3.property),
690 type->union_v3.fieldlist, value);
691 break;
693 case LF_ENUM_V1:
694 printf("\t%x => Enum V1 '%s' type:%x field-type:%x count:%u property:%s\n",
695 curr_type, p_string(&type->enumeration_v1.p_name),
696 type->enumeration_v1.type,
697 type->enumeration_v1.fieldlist,
698 type->enumeration_v1.count,
699 get_property(type->enumeration_v1.property));
700 break;
702 case LF_ENUM_V2:
703 printf("\t%x => Enum V2 '%s' type:%x field-type:%x count:%u property:%s\n",
704 curr_type, p_string(&type->enumeration_v2.p_name),
705 type->enumeration_v2.type,
706 type->enumeration_v2.fieldlist,
707 type->enumeration_v2.count,
708 get_property(type->enumeration_v2.property));
709 break;
711 case LF_ENUM_V3:
712 printf("\t%x => Enum V3 '%s' type:%x field-type:%x count:%u property:%s\n",
713 curr_type, type->enumeration_v3.name,
714 type->enumeration_v3.type,
715 type->enumeration_v3.fieldlist,
716 type->enumeration_v3.count,
717 get_property(type->enumeration_v3.property));
718 break;
720 case LF_ARGLIST_V1:
721 printf("\t%x => Arglist V1(#%u):", curr_type, reftype->arglist_v1.num);
722 for (i = 0; i < reftype->arglist_v1.num; i++)
724 printf(" %x", reftype->arglist_v1.args[i]);
726 printf("\n");
727 break;
729 case LF_ARGLIST_V2:
730 printf("\t%x => Arglist V2(#%u):", curr_type, reftype->arglist_v2.num);
731 for (j = 0; j < reftype->arglist_v2.num; j++)
733 printf("\t %x", reftype->arglist_v2.args[j]);
735 printf("\t\n");
736 break;
738 case LF_PROCEDURE_V1:
739 /* FIXME: unknown could be the calling convention for the proc */
740 printf("\t%x => Procedure V1 ret_type:%x call:%x (#%u args_type:%x)\n",
741 curr_type, type->procedure_v1.rvtype,
742 type->procedure_v1.call, type->procedure_v1.params,
743 type->procedure_v1.arglist);
744 break;
746 case LF_PROCEDURE_V2:
747 printf("\t%x => Procedure V2 ret_type:%x unk:%x (#%u args_type:%x)\n",
748 curr_type, type->procedure_v2.rvtype,
749 type->procedure_v2.call, type->procedure_v2.params,
750 type->procedure_v2.arglist);
751 break;
753 case LF_MFUNCTION_V2:
754 printf("\t%x => MFunction V2 ret-type:%x call:%x class-type:%x this-type:%x\n"
755 "\t\t#args:%x args-type:%x this_adjust:%x\n",
756 curr_type,
757 type->mfunction_v2.rvtype,
758 type->mfunction_v2.call,
759 type->mfunction_v2.class_type,
760 type->mfunction_v2.this_type,
761 type->mfunction_v2.params,
762 type->mfunction_v2.arglist,
763 type->mfunction_v2.this_adjust);
764 break;
766 case LF_MODIFIER_V1:
767 printf("\t%x => Modifier V1 type:%x modif:%x\n",
768 curr_type, type->modifier_v1.type, type->modifier_v1.attribute);
769 break;
771 case LF_MODIFIER_V2:
772 printf("\t%x => Modifier V2 type:%x modif:%x\n",
773 curr_type, type->modifier_v2.type, type->modifier_v2.attribute);
774 break;
776 case LF_METHODLIST_V1:
778 const unsigned short* pattr = (const unsigned short*)((const char*)type + 4);
780 printf("\t%x => Method list\n", curr_type);
781 while ((const char*)pattr < (const char*)type + type->generic.len + 2)
783 switch ((*pattr >> 2) & 7)
785 case 4: case 6:
786 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
787 get_attr(pattr[0]), pattr[1],
788 *(const unsigned*)(&pattr[2]));
789 pattr += 3;
790 break;
791 default:
792 printf("\t\t\tattr:%s type:%x\n",
793 get_attr(pattr[0]), pattr[1]);
794 pattr += 2;
798 break;
800 case LF_METHODLIST_V2:
802 const unsigned* pattr = (const unsigned*)((const char*)type + 4);
804 printf("\t%x => Method list\n", curr_type);
805 while ((const char*)pattr < (const char*)type + type->generic.len + 2)
807 switch ((*pattr >> 2) & 7)
809 case 4: case 6:
810 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
811 get_attr(pattr[0]), pattr[1], pattr[2]);
812 pattr += 3;
813 break;
814 default:
815 printf("\t\t\tattr:%s type:%x\n",
816 get_attr(pattr[0]), pattr[1]);
817 pattr += 2;
821 break;
823 case LF_VTSHAPE_V1:
825 int count = *(const unsigned short*)((const char*)type + 4);
826 int shift = 0;
827 const char* ptr = (const char*)type + 6;
828 const char* desc[] = {"Near", "Far", "Thin", "Disp to outtermost",
829 "Pointer to metaclass", "Near32", "Far32"};
830 printf("\t%x => VT Shape #%d: ", curr_type, count);
831 while (count--)
833 if (((*ptr << shift) & 0xF) <= 6)
834 printf("%s ", desc[(*ptr << shift) & 0xF]);
835 else
836 printf("%x ", (*ptr << shift) & 0xF);
837 if (shift == 0) shift = 4; else {shift = 0; ptr++;}
839 printf("\n");
841 break;
843 case LF_DERIVED_V1:
844 printf("\t%x => Derived V1(#%u):", curr_type, reftype->derived_v1.num);
845 for (i = 0; i < reftype->derived_v1.num; i++)
847 printf(" %x", reftype->derived_v1.drvdcls[i]);
849 printf("\n");
850 break;
852 case LF_DERIVED_V2:
853 printf("\t%x => Derived V2(#%u):", curr_type, reftype->derived_v2.num);
854 for (j = 0; j < reftype->derived_v2.num; j++)
856 printf(" %x", reftype->derived_v2.drvdcls[j]);
858 printf("\n");
859 break;
861 default:
862 printf(">>> Unsupported type-id %x for %x\n", type->generic.id, curr_type);
863 dump_data((const void*)type, type->generic.len + 2, "");
864 break;
868 BOOL codeview_dump_types_from_offsets(const void* table, const DWORD* offsets, unsigned num_types)
870 unsigned long i;
872 for (i = 0; i < num_types; i++)
874 codeview_dump_one_type(0x1000 + i,
875 (const union codeview_type*)((const char*)table + offsets[i]));
878 return TRUE;
881 BOOL codeview_dump_types_from_block(const void* table, unsigned long len)
883 unsigned int curr_type = 0x1000;
884 const unsigned char*ptr = table;
886 while (ptr - (const unsigned char*)table < len)
888 const union codeview_type* type = (const union codeview_type*)ptr;
890 codeview_dump_one_type(curr_type, type);
891 curr_type++;
892 ptr += (type->generic.len + 2 + 3) & ~3;
895 return TRUE;
898 BOOL codeview_dump_symbols(const void* root, unsigned long size)
900 unsigned int i;
901 int length;
902 char* curr_func = NULL;
903 int nest_block = 0;
905 * Loop over the different types of records and whenever we
906 * find something we are interested in, record it and move on.
908 for (i = 0; i < size; i += length)
910 const union codeview_symbol* sym = (const union codeview_symbol*)((const char*)root + i);
911 length = sym->generic.len + 2;
912 if (!sym->generic.id || length < 4) break;
913 switch (sym->generic.id)
916 * Global and local data symbols. We don't associate these
917 * with any given source file.
919 case S_GDATA_V2:
920 case S_LDATA_V2:
921 printf("\tS-%s-Data V2 '%s' %04x:%08x type:%08x\n",
922 sym->generic.id == S_GDATA_V2 ? "Global" : "Local",
923 get_symbol_str(p_string(&sym->data_v2.p_name)),
924 sym->data_v2.segment, sym->data_v2.offset, sym->data_v2.symtype);
925 break;
927 case S_LDATA_V3:
928 case S_GDATA_V3:
929 /* EPP case S_DATA_V3: */
930 printf("\tS-%s-Data V3 '%s' (%04x:%08x) type:%08x\n",
931 sym->generic.id == S_GDATA_V3 ? "Global" : "Local",
932 get_symbol_str(sym->data_v3.name),
933 sym->data_v3.segment, sym->data_v3.offset,
934 sym->data_v3.symtype);
935 break;
937 case S_PUB_V2:
938 printf("\tS-Public V2 '%s' %04x:%08x type:%08x\n",
939 get_symbol_str(p_string(&sym->public_v2.p_name)),
940 sym->public_v2.segment, sym->public_v2.offset,
941 sym->public_v2.symtype);
942 break;
944 case S_PUB_V3:
945 /* not completely sure of those two anyway */
946 case S_PUB_FUNC1_V3:
947 case S_PUB_FUNC2_V3:
948 printf("\tS-Public%s V3 '%s' %04x:%08x type:%08x\n",
949 sym->generic.id == S_PUB_V3 ? "" :
950 (sym->generic.id == S_PUB_FUNC1_V3 ? "<subkind1" : "<subkind2"),
951 get_symbol_str(sym->public_v3.name),
952 sym->public_v3.segment,
953 sym->public_v3.offset, sym->public_v3.symtype);
954 break;
957 * Sort of like a global function, but it just points
958 * to a thunk, which is a stupid name for what amounts to
959 * a PLT slot in the normal jargon that everyone else uses.
961 case S_THUNK_V1:
962 printf("\tS-Thunk V1 '%s' (%04x:%08x#%x) type:%x\n",
963 p_string(&sym->thunk_v1.p_name),
964 sym->thunk_v1.segment, sym->thunk_v1.offset,
965 sym->thunk_v1.thunk_len, sym->thunk_v1.thtype);
966 curr_func = strdup(p_string(&sym->thunk_v1.p_name));
967 break;
969 case S_THUNK_V3:
970 printf("\tS-Thunk V3 '%s' (%04x:%08x#%x) type:%x\n",
971 sym->thunk_v3.name,
972 sym->thunk_v3.segment, sym->thunk_v3.offset,
973 sym->thunk_v3.thunk_len, sym->thunk_v3.thtype);
974 curr_func = strdup(sym->thunk_v3.name);
975 break;
977 /* Global and static functions */
978 case S_GPROC_V1:
979 case S_LPROC_V1:
980 printf("\tS-%s-Proc V1: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
981 sym->generic.id == S_GPROC_V1 ? "Global" : "-Local",
982 p_string(&sym->proc_v1.p_name),
983 sym->proc_v1.segment, sym->proc_v1.offset,
984 sym->proc_v1.proc_len, sym->proc_v1.proctype,
985 sym->proc_v1.flags);
986 printf("\t Debug: start=%08x end=%08x\n",
987 sym->proc_v1.debug_start, sym->proc_v1.debug_end);
988 if (nest_block)
990 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
991 nest_block = 0;
993 curr_func = strdup(p_string(&sym->proc_v1.p_name));
994 /* EPP unsigned int pparent; */
995 /* EPP unsigned int pend; */
996 /* EPP unsigned int next; */
997 break;
999 case S_GPROC_V2:
1000 case S_LPROC_V2:
1001 printf("\tS-%s-Proc V2: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
1002 sym->generic.id == S_GPROC_V2 ? "Global" : "-Local",
1003 p_string(&sym->proc_v2.p_name),
1004 sym->proc_v2.segment, sym->proc_v2.offset,
1005 sym->proc_v2.proc_len, sym->proc_v2.proctype,
1006 sym->proc_v2.flags);
1007 printf("\t Debug: start=%08x end=%08x\n",
1008 sym->proc_v2.debug_start, sym->proc_v2.debug_end);
1009 if (nest_block)
1011 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
1012 nest_block = 0;
1014 curr_func = strdup(p_string(&sym->proc_v2.p_name));
1015 /* EPP unsigned int pparent; */
1016 /* EPP unsigned int pend; */
1017 /* EPP unsigned int next; */
1018 break;
1020 case S_LPROC_V3:
1021 case S_GPROC_V3:
1022 printf("\tS-%s-Procedure V3 '%s' (%04x:%08x#%x) type:%x attr:%x\n",
1023 sym->generic.id == S_GPROC_V3 ? "Global" : "Local",
1024 sym->proc_v3.name,
1025 sym->proc_v3.segment, sym->proc_v3.offset,
1026 sym->proc_v3.proc_len, sym->proc_v3.proctype,
1027 sym->proc_v3.flags);
1028 printf("\t Debug: start=%08x end=%08x\n",
1029 sym->proc_v3.debug_start, sym->proc_v3.debug_end);
1030 if (nest_block)
1032 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
1033 nest_block = 0;
1035 curr_func = strdup(sym->proc_v3.name);
1036 /* EPP unsigned int pparent; */
1037 /* EPP unsigned int pend; */
1038 /* EPP unsigned int next; */
1039 break;
1041 /* Function parameters and stack variables */
1042 case S_BPREL_V1:
1043 printf("\tS-BP-relative V1: '%s' @%d type:%x (%s)\n",
1044 p_string(&sym->stack_v1.p_name),
1045 sym->stack_v1.offset, sym->stack_v1.symtype, curr_func);
1046 break;
1048 case S_BPREL_V2:
1049 printf("\tS-BP-relative V2: '%s' @%d type:%x (%s)\n",
1050 p_string(&sym->stack_v2.p_name),
1051 sym->stack_v2.offset, sym->stack_v2.symtype, curr_func);
1052 break;
1054 case S_BPREL_V3:
1055 printf("\tS-BP-relative V3: '%s' @%d type:%x (in %s)\n",
1056 sym->stack_v3.name, sym->stack_v3.offset,
1057 sym->stack_v3.symtype, curr_func);
1058 break;
1060 case S_REGREL_V3:
1061 printf("\tS-Reg-relative V3: '%s' @%d type:%x reg:%x (in %s)\n",
1062 sym->regrel_v3.name, sym->regrel_v3.offset,
1063 sym->regrel_v3.symtype, sym->regrel_v3.reg, curr_func);
1064 break;
1066 case S_REGISTER_V1:
1067 printf("\tS-Register V1 '%s' in %s type:%x register:%x\n",
1068 p_string(&sym->register_v1.p_name),
1069 curr_func, sym->register_v1.reg, sym->register_v1.type);
1070 break;
1072 case S_REGISTER_V2:
1073 printf("\tS-Register V2 '%s' in %s type:%x register:%x\n",
1074 p_string(&sym->register_v2.p_name),
1075 curr_func, sym->register_v2.reg, sym->register_v2.type);
1076 break;
1078 case S_REGISTER_V3:
1079 printf("\tS-Register V3 '%s' in %s type:%x register:%x\n",
1080 sym->register_v3.name,
1081 curr_func, sym->register_v3.reg, sym->register_v3.type);
1082 break;
1084 case S_BLOCK_V1:
1085 printf("\tS-Block V1 '%s' in '%s' (%04x:%08x#%08x)\n",
1086 p_string(&sym->block_v1.p_name),
1087 curr_func,
1088 sym->block_v1.segment, sym->block_v1.offset,
1089 sym->block_v1.length);
1090 nest_block++;
1091 break;
1093 case S_BLOCK_V3:
1094 printf("\tS-Block V3 '%s' in '%s' (%04x:%08x#%08x) parent:%u end:%x\n",
1095 sym->block_v3.name, curr_func,
1096 sym->block_v3.segment, sym->block_v3.offset, sym->block_v3.length,
1097 sym->block_v3.parent, sym->block_v3.end);
1098 nest_block++;
1099 break;
1101 /* Additional function information */
1102 case S_FRAMEINFO_V2:
1103 printf("\tS-Frame-Info V2: frame-size:%x unk2:%x unk3:%x saved-regs-sz:%x eh(%04x:%08x) flags:%08x\n",
1104 sym->frame_info_v2.sz_frame,
1105 sym->frame_info_v2.unknown2,
1106 sym->frame_info_v2.unknown3,
1107 sym->frame_info_v2.sz_saved_regs,
1108 sym->frame_info_v2.eh_sect,
1109 sym->frame_info_v2.eh_offset,
1110 sym->frame_info_v2.flags);
1111 break;
1113 case S_SECUCOOKIE_V3:
1114 printf("\tSecurity Cookie V3 @%d unk:%x\n",
1115 sym->security_cookie_v3.offset, sym->security_cookie_v3.unknown);
1116 break;
1118 case S_END_V1:
1119 if (nest_block)
1121 nest_block--;
1122 printf("\tS-End-Of block (%u)\n", nest_block);
1124 else
1126 printf("\tS-End-Of %s\n", curr_func);
1127 free(curr_func);
1128 curr_func = NULL;
1130 break;
1132 case S_COMPILAND_V1:
1134 const char* machine;
1135 const char* lang;
1137 switch (sym->compiland_v1.unknown & 0xFF)
1139 case 0x00: machine = "Intel 8080"; break;
1140 case 0x01: machine = "Intel 8086"; break;
1141 case 0x02: machine = "Intel 80286"; break;
1142 case 0x03: machine = "Intel 80386"; break;
1143 case 0x04: machine = "Intel 80486"; break;
1144 case 0x05: machine = "Intel Pentium"; break;
1145 case 0x10: machine = "MIPS R4000"; break;
1146 default:
1148 static char tmp[16];
1149 sprintf(tmp, "machine=%x", sym->compiland_v1.unknown & 0xFF);
1150 machine = tmp;
1152 break;
1154 switch ((sym->compiland_v1.unknown >> 8) & 0xFF)
1156 case 0x00: lang = "C"; break;
1157 case 0x01: lang = "C++"; break;
1158 case 0x02: lang = "Fortran"; break;
1159 case 0x03: lang = "Masm"; break;
1160 case 0x04: lang = "Pascal"; break;
1161 case 0x05: lang = "Basic"; break;
1162 case 0x06: lang = "Cobol"; break;
1163 default:
1165 static char tmp[16];
1166 sprintf(tmp, "language=%x", (sym->compiland_v1.unknown >> 8) & 0xFF);
1167 lang = tmp;
1169 break;
1172 printf("\tS-Compiland V1 '%s' %s %s unk:%x\n",
1173 p_string(&sym->compiland_v1.p_name), machine, lang,
1174 sym->compiland_v1.unknown >> 16);
1176 break;
1178 case S_COMPILAND_V2:
1179 printf("\tS-Compiland V2 '%s'\n",
1180 p_string(&sym->compiland_v2.p_name));
1181 dump_data((const void*)sym, sym->generic.len + 2, " ");
1183 const char* ptr = sym->compiland_v2.p_name.name + sym->compiland_v2.p_name.namelen;
1184 while (*ptr)
1186 printf("\t\t%s => ", ptr); ptr += strlen(ptr) + 1;
1187 printf("%s\n", ptr); ptr += strlen(ptr) + 1;
1190 break;
1192 case S_COMPILAND_V3:
1193 printf("\tS-Compiland V3 '%s' unknown:%x\n",
1194 sym->compiland_v3.name, sym->compiland_v3.unknown);
1195 break;
1197 case S_OBJNAME_V1:
1198 printf("\tS-ObjName V1 sig:%.4s '%s'\n",
1199 sym->objname_v1.signature, p_string(&sym->objname_v1.p_name));
1200 break;
1202 case S_LABEL_V1:
1203 printf("\tS-Label V1 '%s' in '%s' (%04x:%08x)\n",
1204 p_string(&sym->label_v1.p_name),
1205 curr_func, sym->label_v1.segment, sym->label_v1.offset);
1206 break;
1208 case S_LABEL_V3:
1209 printf("\tS-Label V3 '%s' in '%s' (%04x:%08x) flag:%x\n",
1210 sym->label_v3.name, curr_func, sym->label_v3.segment,
1211 sym->label_v3.offset, sym->label_v3.flags);
1212 break;
1214 case S_CONSTANT_V2:
1216 int vlen;
1217 struct full_value fv;
1219 vlen = full_numeric_leaf(&fv, &sym->constant_v2.cvalue);
1220 printf("\tS-Constant V2 '%s' = %s type:%x\n",
1221 p_string(PSTRING(&sym->constant_v2.cvalue, vlen)),
1222 full_value_string(&fv), sym->constant_v2.type);
1224 break;
1226 case S_CONSTANT_V3:
1228 int vlen;
1229 struct full_value fv;
1231 vlen = full_numeric_leaf(&fv, &sym->constant_v3.cvalue);
1232 printf("\tS-Constant V3 '%s' = %s type:%x\n",
1233 (const char*)&sym->constant_v3.cvalue + vlen,
1234 full_value_string(&fv), sym->constant_v3.type);
1236 break;
1238 case S_UDT_V1:
1239 printf("\tS-Udt V1 '%s': type:0x%x\n",
1240 p_string(&sym->udt_v1.p_name), sym->udt_v1.type);
1241 break;
1243 case S_UDT_V2:
1244 printf("\tS-Udt V2 '%s': type:0x%x\n",
1245 p_string(&sym->udt_v2.p_name), sym->udt_v2.type);
1246 break;
1248 case S_UDT_V3:
1249 printf("\tS-Udt V3 '%s': type:0x%x\n",
1250 sym->udt_v3.name, sym->udt_v3.type);
1251 break;
1253 * These are special, in that they are always followed by an
1254 * additional length-prefixed string which is *not* included
1255 * into the symbol length count. We need to skip it.
1257 case S_PROCREF_V1:
1258 printf("\tS-Procref V1 "); goto doaref;
1259 case S_DATAREF_V1:
1260 printf("\tS-Dataref V1 "); goto doaref;
1261 case S_LPROCREF_V1:
1262 printf("\tS-L-Procref V1 "); goto doaref;
1263 doaref:
1265 const struct p_string* pname;
1267 pname = PSTRING(sym, length);
1268 length += (pname->namelen + 1 + 3) & ~3;
1269 printf("\t%08x %08x %08x '%s'\n",
1270 *(((const DWORD*)sym) + 1), *(((const DWORD*)sym) + 2), *(((const DWORD*)sym) + 3),
1271 p_string(pname));
1273 break;
1274 case S_MSTOOL_V3: /* info about tool used to create CU */
1276 const unsigned short* ptr = ((const unsigned short*)sym) + 2;
1277 const char* x1;
1278 const char* x2 = (const char*)&ptr[9];
1279 /* FIXME: what are all those values for ? */
1280 printf("\tTool V3 unk=%04x%04x%04x front=%d.%d.%d.0 back=%d.%d.%d.0 %s\n",
1281 ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
1282 ptr[8], x2);
1283 while (*(x1 = x2 + strlen(x2) + 1))
1285 x2 = x1 + strlen(x1) + 1;
1286 if (!*x2) break;
1287 printf("\t\t%s: %s\n", x1, x2);
1290 break;
1292 case S_MSTOOLINFO_V3:
1294 const unsigned short* ptr = ((const unsigned short*)sym) + 2;
1296 printf("\tTool info V3: unk=%04x%04x%04x front=%d.%d.%d.%d back=%d.%d.%d.%d %s\n",
1297 ptr[0], ptr[1], ptr[2],
1298 ptr[3], ptr[4], ptr[5], ptr[6],
1299 ptr[7], ptr[8], ptr[9], ptr[10],
1300 (const char*)(ptr + 11));
1302 break;
1304 case S_MSTOOLENV_V3:
1306 const char* x1 = (const char*)sym + 4 + 1;
1307 const char* x2;
1309 printf("\tTool conf V3\n");
1310 while (*x1)
1312 x2 = x1 + strlen(x1) + 1;
1313 if (!*x2) break;
1314 printf("\t\t%s: %s\n", x1, x2);
1315 x1 = x2 + strlen(x2) + 1;
1318 break;
1320 case S_ALIGN_V1:
1321 /* simply skip it */
1322 break;
1324 case S_SSEARCH_V1:
1325 printf("\tSSearch V1: (%04x:%08x)\n",
1326 sym->ssearch_v1.segment, sym->ssearch_v1.offset);
1327 break;
1329 case S_SECTINFO_V3:
1330 printf("\tSSection Info: seg=%04x ?=%04x rva=%08x size=%08x attr=%08x %s\n",
1331 *(const unsigned short*)((const char*)sym + 4),
1332 *(const unsigned short*)((const char*)sym + 6),
1333 *(const unsigned*)((const char*)sym + 8),
1334 *(const unsigned*)((const char*)sym + 12),
1335 *(const unsigned*)((const char*)sym + 16),
1336 (const char*)sym + 20);
1337 break;
1339 case S_SUBSECTINFO_V3:
1340 printf("\tSSubSection Info: addr=%04x:%08x size=%08x attr=%08x %s\n",
1341 *(const unsigned short*)((const char*)sym + 16),
1342 *(const unsigned*)((const char*)sym + 12),
1343 *(const unsigned*)((const char*)sym + 4),
1344 *(const unsigned*)((const char*)sym + 8),
1345 (const char*)sym + 18);
1346 break;
1348 case S_ENTRYPOINT_V3:
1349 printf("\tSEntryPoint: id=%x '%s'\n",
1350 *(const unsigned*)((const char*)sym + 4), (const char*)sym + 8);
1351 break;
1353 case S_LTHREAD_V1:
1354 case S_GTHREAD_V1:
1355 printf("\tS-Thread %s Var V1 '%s' seg=%04x offset=%08x type=%x\n",
1356 sym->generic.id == S_LTHREAD_V1 ? "global" : "local",
1357 p_string(&sym->thread_v1.p_name),
1358 sym->thread_v1.segment, sym->thread_v1.offset, sym->thread_v1.symtype);
1359 break;
1361 case S_LTHREAD_V2:
1362 case S_GTHREAD_V2:
1363 printf("\tS-Thread %s Var V2 '%s' seg=%04x offset=%08x type=%x\n",
1364 sym->generic.id == S_LTHREAD_V2 ? "global" : "local",
1365 p_string(&sym->thread_v2.p_name),
1366 sym->thread_v2.segment, sym->thread_v2.offset, sym->thread_v2.symtype);
1367 break;
1369 case S_LTHREAD_V3:
1370 case S_GTHREAD_V3:
1371 printf("\tS-Thread %s Var V3 '%s' seg=%04x offset=%08x type=%x\n",
1372 sym->generic.id == S_LTHREAD_V3 ? "global" : "local", sym->thread_v3.name,
1373 sym->thread_v3.segment, sym->thread_v3.offset, sym->thread_v3.symtype);
1374 break;
1376 default:
1377 printf(">>> Unsupported symbol-id %x sz=%d\n", sym->generic.id, sym->generic.len + 2);
1378 dump_data((const void*)sym, sym->generic.len + 2, " ");
1381 return TRUE;
1384 void codeview_dump_linetab(const char* linetab, BOOL pascal_str, const char* pfx)
1386 const char* ptr = linetab;
1387 int nfile, nseg, nline;
1388 int i, j, k;
1389 const unsigned int* filetab;
1390 const unsigned int* lt_ptr;
1391 const struct startend* start;
1393 nfile = *(const short*)linetab;
1394 filetab = (const unsigned int*)(linetab + 2 * sizeof(short));
1395 printf("%s%d files with %d ???\n", pfx, nfile, *(const short*)(linetab + sizeof(short)));
1397 for (i = 0; i < nfile; i++)
1399 ptr = linetab + filetab[i];
1400 nseg = *(const short*)ptr;
1401 ptr += 2 * sizeof(short);
1402 lt_ptr = (const unsigned int*)ptr;
1403 start = (const struct startend*)(lt_ptr + nseg);
1406 * Now snarf the filename for all of the segments for this file.
1408 if (pascal_str)
1410 char filename[MAX_PATH];
1411 const struct p_string* p_fn;
1413 p_fn = (const struct p_string*)(start + nseg);
1414 memset(filename, 0, sizeof(filename));
1415 memcpy(filename, p_fn->name, p_fn->namelen);
1416 printf("%slines for file #%d/%d %s %d\n", pfx, i, nfile, filename, nseg);
1418 else
1419 printf("%slines for file #%d/%d %s %d\n", pfx, i, nfile, (const char*)(start + nseg), nseg);
1421 for (j = 0; j < nseg; j++)
1423 ptr = linetab + *lt_ptr++;
1424 nline = *(const short*)(ptr + 2);
1425 printf("%s %04x:%08x-%08x #%d\n",
1426 pfx, *(const short*)(ptr + 0), start[j].start, start[j].end, nline);
1427 ptr += 4;
1428 for (k = 0; k < nline; k++)
1430 printf("%s %x %d\n",
1431 pfx, ((const unsigned int*)ptr)[k],
1432 ((const unsigned short*)((const unsigned int*)ptr + nline))[k]);
1438 void codeview_dump_linetab2(const char* linetab, DWORD size, const char* strimage, DWORD strsize, const char* pfx)
1440 unsigned i;
1441 const struct codeview_linetab2* lt2;
1442 const struct codeview_linetab2* lt2_files = NULL;
1443 const struct codeview_lt2blk_lines* lines_blk;
1444 const struct codeview_linetab2_file*fd;
1446 /* locate LT2_FILES_BLOCK (if any) */
1447 lt2 = (const struct codeview_linetab2*)linetab;
1448 while ((const char*)(lt2 + 1) < linetab + size)
1450 if (lt2->header == LT2_FILES_BLOCK)
1452 lt2_files = lt2;
1453 break;
1455 lt2 = codeview_linetab2_next_block(lt2);
1457 if (!lt2_files)
1459 printf("%sNo LT2_FILES_BLOCK found\n", pfx);
1460 return;
1463 lt2 = (const struct codeview_linetab2*)linetab;
1464 while ((const char*)(lt2 + 1) < linetab + size)
1466 /* FIXME: should also check that whole lbh fits in linetab + size */
1467 switch (lt2->header)
1469 case LT2_LINES_BLOCK:
1470 lines_blk = (const struct codeview_lt2blk_lines*)lt2;
1471 printf("%sblock from %04x:%08x #%x (%x lines) fo=%x\n",
1472 pfx, lines_blk->seg, lines_blk->start, lines_blk->size,
1473 lines_blk->nlines, lines_blk->file_offset);
1474 /* FIXME: should check that file_offset is within the LT2_FILES_BLOCK we've seen */
1475 fd = (const struct codeview_linetab2_file*)((const char*)lt2_files + 8 + lines_blk->file_offset);
1476 printf("%s md5=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
1477 pfx, fd->md5[ 0], fd->md5[ 1], fd->md5[ 2], fd->md5[ 3],
1478 fd->md5[ 4], fd->md5[ 5], fd->md5[ 6], fd->md5[ 7],
1479 fd->md5[ 8], fd->md5[ 9], fd->md5[10], fd->md5[11],
1480 fd->md5[12], fd->md5[13], fd->md5[14], fd->md5[15]);
1481 /* FIXME: should check that string is within strimage + strsize */
1482 printf("%s file=%s\n", pfx, strimage ? strimage + fd->offset : "--none--");
1483 for (i = 0; i < lines_blk->nlines; i++)
1485 printf("%s offset=%08x line=%d\n",
1486 pfx, lines_blk->l[i].offset, lines_blk->l[i].lineno ^ 0x80000000);
1488 break;
1489 case LT2_FILES_BLOCK: /* skip */
1490 break;
1491 default:
1492 printf("%sblock end %x\n", pfx, lt2->header);
1493 lt2 = (const struct codeview_linetab2*)((const char*)linetab + size);
1494 continue;
1496 lt2 = codeview_linetab2_next_block(lt2);