winedump: Print detailed information about class/struct properties.
[wine] / tools / winedump / msc.c
1 /*
2  *      MS debug info dumping utility
3  *
4  *      Copyright 2006 Eric Pouech
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
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>
41
42 #define NONAMELESSUNION
43 #define NONAMELESSSTRUCT
44 #include "windef.h"
45 #include "winbase.h"
46 #include "winedump.h"
47 #include "wine/mscvpdb.h"
48
49 #define PSTRING(adr, ofs) \
50     ((const struct p_string*)((const char*)(adr) + (ofs)))
51
52 static const char* p_string(const struct p_string* s)
53 {
54     static char tmp[256 + 1];
55     memcpy(tmp, s->name, s->namelen);
56     tmp[s->namelen] = '\0';
57     return tmp;
58 }
59
60 union full_value
61 {
62     int                 i;
63     long long unsigned  llu;
64 };
65
66 static int full_numeric_leaf(union full_value* fv, const unsigned short int* leaf)
67 {
68     unsigned short int type = *leaf++;
69     int length = 2;
70
71     if (type < LF_NUMERIC)
72     {
73         fv->i = type;
74     }
75     else
76     {
77         switch (type)
78         {
79         case LF_CHAR:
80             length += 1;
81             fv->i = *(const char*)leaf;
82             break;
83
84         case LF_SHORT:
85             length += 2;
86             fv->i = *(const short*)leaf;
87             break;
88
89         case LF_USHORT:
90             length += 2;
91             fv->i = *(const unsigned short*)leaf;
92             break;
93
94         case LF_LONG:
95             length += 4;
96             fv->i = *(const int*)leaf;
97             break;
98
99         case LF_ULONG:
100             length += 4;
101             fv->i = *(const unsigned int*)leaf;
102             break;
103
104         case LF_QUADWORD:
105             length += 8;
106             fv->llu = *(const long long int*)leaf;
107             break;
108
109         case LF_UQUADWORD:
110             length += 8;
111             fv->llu = *(const long long unsigned int*)leaf;
112             break;
113
114         case LF_REAL32:
115             length += 4;
116             printf(">>> unsupported leaf value %04x\n", type);
117             fv->i = 0;    /* FIXME */
118             break;
119
120         case LF_REAL48:
121             length += 6;
122             fv->i = 0;    /* FIXME */
123             printf(">>> unsupported leaf value %04x\n", type);
124             break;
125
126         case LF_REAL64:
127             length += 8;
128             fv->i = 0;    /* FIXME */
129             printf(">>> unsupported leaf value %04x\n", type);
130             break;
131
132         case LF_REAL80:
133             length += 10;
134             fv->i = 0;    /* FIXME */
135             printf(">>> unsupported leaf value %04x\n", type);
136             break;
137
138         case LF_REAL128:
139             length += 16;
140             fv->i = 0;    /* FIXME */
141             printf(">>> unsupported leaf value %04x\n", type);
142             break;
143
144         case LF_COMPLEX32:
145             length += 4;
146             fv->i = 0;    /* FIXME */
147             printf(">>> unsupported leaf value %04x\n", type);
148             break;
149
150         case LF_COMPLEX64:
151             length += 8;
152             fv->i = 0;    /* FIXME */
153             printf(">>> unsupported leaf value %04x\n", type);
154             break;
155
156         case LF_COMPLEX80:
157             length += 10;
158             fv->i = 0;    /* FIXME */
159             printf(">>> unsupported leaf value %04x\n", type);
160             break;
161
162         case LF_COMPLEX128:
163             length += 16;
164             fv->i = 0;    /* FIXME */
165             printf(">>> unsupported leaf value %04x\n", type);
166             break;
167
168         case LF_VARSTRING:
169             length += 2 + *leaf;
170             fv->i = 0;    /* FIXME */
171             printf(">>> unsupported leaf value %04x\n", type);
172             break;
173
174         default:
175             printf(">>> Unsupported numeric leaf-id %04x\n", type);
176             fv->i = 0;
177             break;
178         }
179     }
180     return length;
181 }
182
183 static int numeric_leaf(int* value, const unsigned short int* leaf)
184 {
185     union full_value fv;
186     int len = len = full_numeric_leaf(&fv, leaf);
187
188     *value = fv.i;
189     return len;
190 }
191
192 static const char* get_attr(unsigned attr)
193 {
194     static char tmp[256];
195
196     switch (attr & 3)
197     {
198     case 0: strcpy(tmp, ""); break;
199     case 1: strcpy(tmp, "private "); break;
200     case 2: strcpy(tmp, "protected "); break;
201     case 3: strcpy(tmp, "public "); break;
202     }
203     switch ((attr >> 2) & 7)
204     {
205     case 0: strcat(tmp, ""); break;
206     case 1: strcat(tmp, "virtual "); break;
207     case 2: strcat(tmp, "static "); break;
208     case 3: strcat(tmp, "friend "); break;
209     case 4: strcat(tmp, "introducing virtual "); break;
210     case 5: strcat(tmp, "pure virtual "); break;
211     case 6: strcat(tmp, "pure introducing virtual "); break;
212     case 7: strcat(tmp, "reserved "); break;
213     }
214     if ((attr >> 5) & 1) strcat(tmp, "pseudo ");
215     if ((attr >> 6) & 1) strcat(tmp, "no-inherit ");
216     if ((attr >> 7) & 1) strcat(tmp, "no-construct ");
217     return tmp;
218 }
219
220 static const char* get_property(unsigned prop)
221 {
222     static char tmp[1024];
223     unsigned    pos = 0;
224
225     if (!prop) return "none";
226 #define X(s) {if (pos) tmp[pos++] = ';'; strcpy(tmp + pos, s); pos += strlen(s);}
227     if (prop & 0x0001) X("packed");
228     if (prop & 0x0002) X("w/{cd}tor");
229     if (prop & 0x0004) X("w/overloaded-ops");
230     if (prop & 0x0008) X("nested-class");
231     if (prop & 0x0010) X("has-nested-classes");
232     if (prop & 0x0020) X("w/overloaded-assign");
233     if (prop & 0x0040) X("w/casting-methods");
234     if (prop & 0x0080) X("forward");
235     if (prop & 0x0100) X("scoped");
236 #undef X
237
238     if (prop & ~0x01FF) pos += sprintf(tmp, "unk%x", prop & ~0x01FF);
239     else tmp[pos] = '\0';
240     assert(pos < sizeof(tmp));
241
242     return tmp;
243 }
244
245 static void do_field(const unsigned char* start, const unsigned char* end)
246 {
247     /*
248      * A 'field list' is a CodeView-specific data type which doesn't
249      * directly correspond to any high-level data type.  It is used
250      * to hold the collection of members of a struct, class, union
251      * or enum type.  The actual definition of that type will follow
252      * later, and refer to the field list definition record.
253      *
254      * As we don't have a field list type ourselves, we look ahead
255      * in the field list to try to find out whether this field list
256      * will be used for an enum or struct type, and create a dummy
257      * type of the corresponding sort.  Later on, the definition of
258      * the 'real' type will copy the member / enumeration data.
259      */
260     const unsigned char*        ptr = start;
261     const char*                 cstr;
262     const struct p_string*      pstr;
263     int leaf_len, value;
264
265     while (ptr < end)
266     {
267         const union codeview_fieldtype* fieldtype = (const union codeview_fieldtype*)ptr;
268
269         if (*ptr >= 0xf0)       /* LF_PAD... */
270         {
271             ptr +=* ptr & 0x0f;
272             continue;
273         }
274
275         switch (fieldtype->generic.id)
276         {
277         case LF_ENUMERATE_V1:
278             leaf_len = numeric_leaf(&value, &fieldtype->enumerate_v1.value);
279             pstr = PSTRING(&fieldtype->enumerate_v1.value, leaf_len);
280             printf("\t\tEnumerate V1: '%s' value:%d\n",
281                    p_string(pstr), value);
282             ptr += 2 + 2 + leaf_len + 1 + pstr->namelen;
283             break;
284
285         case LF_ENUMERATE_V3:
286             leaf_len = numeric_leaf(&value, &fieldtype->enumerate_v3.value);
287             cstr = (const char*)&fieldtype->enumerate_v3.value + leaf_len;
288             printf("\t\tEnumerate V3: '%s' value:%d\n",
289                    cstr, value);
290             ptr += 2 + 2 + leaf_len + strlen(cstr) + 1;
291             break;
292
293         case LF_MEMBER_V1:
294             leaf_len = numeric_leaf(&value, &fieldtype->member_v1.offset);
295             pstr = PSTRING(&fieldtype->member_v1.offset, leaf_len);
296             printf("\t\tMember V1: '%s' type:%x attr:%s @%d\n",
297                    p_string(pstr), fieldtype->member_v1.type,
298                    get_attr(fieldtype->member_v1.attribute), value);
299             ptr += 2 + 2 + 2 + leaf_len + 1 + pstr->namelen;
300             break;
301
302         case LF_MEMBER_V2:
303             leaf_len = numeric_leaf(&value, &fieldtype->member_v2.offset);
304             pstr = PSTRING(&fieldtype->member_v2.offset, leaf_len);
305             printf("\t\tMember V2: '%s' type:%x attr:%s @%d\n",
306                    p_string(pstr), fieldtype->member_v2.type,
307                    get_attr(fieldtype->member_v2.attribute), value);
308             ptr += 2 + 2 + 4 + leaf_len + 1 + pstr->namelen;
309             break;
310
311         case LF_MEMBER_V3:
312             leaf_len = numeric_leaf(&value, &fieldtype->member_v3.offset);
313             cstr = (const char*)&fieldtype->member_v3.offset + leaf_len;
314             printf("\t\tMember V3: '%s' type:%x attr:%s @%d\n",
315                    cstr, fieldtype->member_v3.type, 
316                    get_attr(fieldtype->member_v3.attribute), value);
317             ptr += 2 + 2 + 4 + leaf_len + strlen(cstr) + 1;
318             break;
319
320         case LF_ONEMETHOD_V1:
321             switch ((fieldtype->onemethod_v1.attribute >> 2) & 7)
322             {
323             case 4: case 6:
324                 printf("\t\tVirtual-method V1: '%s' attr:%s type:%x vtable_offset:%u\n",
325                        p_string(&fieldtype->onemethod_virt_v1.p_name),
326                        get_attr(fieldtype->onemethod_virt_v1.attribute),
327                        fieldtype->onemethod_virt_v1.type,
328                        fieldtype->onemethod_virt_v1.vtab_offset);
329                 ptr += 2 + 2 + 2 + 4 + (1 + fieldtype->onemethod_virt_v1.p_name.namelen);
330                 break;
331
332             default:
333                 printf("\t\tMethod V1: '%s' attr:%s type:%x\n",
334                        p_string(&fieldtype->onemethod_v1.p_name),
335                        get_attr(fieldtype->onemethod_v1.attribute),
336                        fieldtype->onemethod_v1.type);
337                 ptr += 2 + 2 + 2 + (1 + fieldtype->onemethod_v1.p_name.namelen);
338                 break;
339             }
340             break;
341
342         case LF_ONEMETHOD_V2:
343             switch ((fieldtype->onemethod_v2.attribute >> 2) & 7)
344             {
345             case 4: case 6:
346                 printf("\t\tVirtual-method V2: '%s' attr:%s type:%x vtable_offset:%u\n",
347                        p_string(&fieldtype->onemethod_virt_v2.p_name),
348                        get_attr(fieldtype->onemethod_virt_v2.attribute),
349                        fieldtype->onemethod_virt_v2.type,
350                        fieldtype->onemethod_virt_v2.vtab_offset);
351                 ptr += 2 + 2 + 4 + 4 + (1 + fieldtype->onemethod_virt_v2.p_name.namelen);
352                 break;
353
354             default:
355                 printf("\t\tMethod V2: '%s' attr:%s type:%x\n",
356                        p_string(&fieldtype->onemethod_v2.p_name),
357                        get_attr(fieldtype->onemethod_v2.attribute),
358                        fieldtype->onemethod_v2.type);
359                 ptr += 2 + 2 + 4 + (1 + fieldtype->onemethod_v2.p_name.namelen);
360                 break;
361             }
362             break;
363
364         case LF_ONEMETHOD_V3:
365             switch ((fieldtype->onemethod_v3.attribute >> 2) & 7)
366             {
367             case 4: case 6:
368                 printf("\t\tVirtual-method V3: '%s' attr:%s type:%x vtable_offset:%u\n",
369                        fieldtype->onemethod_virt_v3.name,
370                        get_attr(fieldtype->onemethod_virt_v3.attribute),
371                        fieldtype->onemethod_virt_v3.type,
372                        fieldtype->onemethod_virt_v3.vtab_offset);
373                 ptr += 2 + 2 + 4 + 4 + (strlen(fieldtype->onemethod_virt_v3.name) + 1);
374                 break;
375
376             default:
377                 printf("\t\tMethod V3: '%s' attr:%s type:%x\n",
378                        fieldtype->onemethod_v3.name,
379                        get_attr(fieldtype->onemethod_v3.attribute),
380                        fieldtype->onemethod_v3.type);
381                 ptr += 2 + 2 + 4 + (strlen(fieldtype->onemethod_v3.name) + 1);
382                 break;
383             }
384             break;
385
386         case LF_METHOD_V1:
387             printf("\t\tMethod V1: '%s' overloaded=#%d method-list=%x\n",
388                    p_string(&fieldtype->method_v1.p_name),
389                    fieldtype->method_v1.count, fieldtype->method_v1.mlist);
390             ptr += 2 + 2 + 2 + (1 + fieldtype->method_v1.p_name.namelen);
391             break;
392
393         case LF_METHOD_V2:
394             printf("\t\tMethod V2: '%s' overloaded=#%d method-list=%x\n",
395                    p_string(&fieldtype->method_v2.p_name),
396                    fieldtype->method_v2.count, fieldtype->method_v2.mlist);
397             ptr += 2 + 2 + 4 + (1 + fieldtype->method_v2.p_name.namelen);
398             break;
399
400         case LF_METHOD_V3:
401             printf("\t\tMethod V3: '%s' overloaded=#%d method-list=%x\n",
402                    fieldtype->method_v3.name,
403                    fieldtype->method_v3.count, fieldtype->method_v3.mlist);
404             ptr += 2 + 2 + 4 + (strlen(fieldtype->method_v3.name) + 1);
405             break;
406
407         case LF_STMEMBER_V1:
408             printf("\t\tStatic member V1: '%s' attr:%s type:%x\n",
409                    p_string(&fieldtype->stmember_v1.p_name),
410                    get_attr(fieldtype->stmember_v1.attribute),
411                    fieldtype->stmember_v1.type);
412             ptr += 2 + 2 + 2 + (1 + fieldtype->stmember_v1.p_name.namelen);
413             break;
414
415         case LF_STMEMBER_V2:
416             printf("\t\tStatic member V2: '%s' attr:%s type:%x\n",
417                    p_string(&fieldtype->stmember_v2.p_name),
418                    get_attr(fieldtype->stmember_v2.attribute),
419                    fieldtype->stmember_v2.type);
420             ptr += 2 + 2 + 4 + (1 + fieldtype->stmember_v2.p_name.namelen);
421             break;
422
423         case LF_STMEMBER_V3:
424             printf("\t\tStatic member V3: '%s' attr:%s type:%x\n",
425                    fieldtype->stmember_v3.name,
426                    get_attr(fieldtype->stmember_v3.attribute),
427                    fieldtype->stmember_v3.type);
428             ptr += 2 + 2 + 4 + (strlen(fieldtype->stmember_v3.name) + 1);
429             break;
430
431         case LF_FRIENDFCN_V1:
432             printf("\t\tFriend function V1: '%s' type:%x\n",
433                    p_string(&fieldtype->friendfcn_v1.p_name),
434                    fieldtype->friendfcn_v1.type);
435             break;
436
437         case LF_FRIENDFCN_V2:
438             printf("\t\tFriend function V2: '%s' type:%x\n",
439                    p_string(&fieldtype->friendfcn_v2.p_name),
440                    fieldtype->friendfcn_v2.type);
441             break;
442
443 #if 0
444         case LF_FRIENDFCN_V3:
445             printf("\t\tFriend function V3: '%s' type:%x\n",
446                    fieldtype->friendfcn_v3.name,
447                    fieldtype->friendfcn_v3.type);
448             break;
449 #endif
450
451         case LF_BCLASS_V1:
452             leaf_len = numeric_leaf(&value, &fieldtype->bclass_v1.offset);
453             printf("\t\tBase class V1: type:%x attr:%s @%d\n",
454                    fieldtype->bclass_v1.type, 
455                    get_attr(fieldtype->bclass_v1.attribute), value);
456             ptr += 2 + 2 + 2 + leaf_len;
457             break;
458
459         case LF_BCLASS_V2:
460             leaf_len = numeric_leaf(&value, &fieldtype->bclass_v2.offset);
461             printf("\t\tBase class V2: type:%x attr:%s @%d\n",
462                    fieldtype->bclass_v2.type, 
463                    get_attr(fieldtype->bclass_v2.attribute), value);
464             ptr += 2 + 2 + 4 + leaf_len;
465             break;
466
467         case LF_VBCLASS_V1:
468         case LF_IVBCLASS_V1:
469             leaf_len = numeric_leaf(&value, &fieldtype->vbclass_v1.vbpoff);
470             printf("\t\t%sirtual base class V1: type:%x (ptr:%x) attr:%s vbpoff:%d ",
471                    (fieldtype->generic.id == LF_VBCLASS_V2) ? "V" : "Indirect v",
472                    fieldtype->vbclass_v1.btype, fieldtype->vbclass_v1.vbtype,
473                    get_attr(fieldtype->vbclass_v1.attribute), value);
474             ptr += 2 + 2 + 2 + 2 + leaf_len;
475             leaf_len = numeric_leaf(&value, (const unsigned short*)ptr);
476             printf("vboff:%d\n", value);
477             ptr += leaf_len;
478             break;
479
480         case LF_VBCLASS_V2:
481         case LF_IVBCLASS_V2:
482             leaf_len = numeric_leaf(&value, &fieldtype->vbclass_v1.vbpoff);
483             printf("\t\t%sirtual base class V2: type:%x (ptr:%x) attr:%s vbpoff:%d ",
484                    (fieldtype->generic.id == LF_VBCLASS_V2) ? "V" : "Indirect v",
485                    fieldtype->vbclass_v2.btype, fieldtype->vbclass_v2.vbtype,
486                    get_attr(fieldtype->vbclass_v2.attribute), value);
487             ptr += 2 + 2 + 4 + 4 + leaf_len;
488             leaf_len = numeric_leaf(&value, (const unsigned short*)ptr);
489             printf("vboff:%d\n", value);
490             ptr += leaf_len;
491             break;
492
493         case LF_FRIENDCLS_V1:
494             printf("\t\tFriend class V1: type:%x\n", fieldtype->friendcls_v1.type);
495             break;
496
497         case LF_FRIENDCLS_V2:
498             printf("\t\tFriend class V2: type:%x\n", fieldtype->friendcls_v2.type);
499             break;
500
501         case LF_NESTTYPE_V1:
502             printf("\t\tNested type V1: '%s' type:%x\n",
503                    p_string(&fieldtype->nesttype_v1.p_name),
504                    fieldtype->nesttype_v1.type);
505             ptr += 2 + 2 + (1 + fieldtype->nesttype_v1.p_name.namelen);
506             break;
507
508         case LF_NESTTYPE_V2:
509             printf("\t\tNested type V2: '%s' pad0:%u type:%x\n",
510                    p_string(&fieldtype->nesttype_v2.p_name),
511                    fieldtype->nesttype_v2._pad0, fieldtype->nesttype_v2.type);
512             ptr += 2 + 2 + 4 + (1 + fieldtype->nesttype_v2.p_name.namelen);
513             break;
514
515         case LF_NESTTYPE_V3:
516             printf("\t\tNested type V3: '%s' pad0:%u type:%x\n",
517                    fieldtype->nesttype_v3.name,
518                    fieldtype->nesttype_v3._pad0, fieldtype->nesttype_v3.type);
519             ptr += 2 + 2 + 4 + (strlen(fieldtype->nesttype_v3.name) + 1);
520             break;
521
522         case LF_VFUNCTAB_V1:
523             printf("\t\tVirtual function table V1: type:%x\n",
524                    fieldtype->vfunctab_v1.type);
525             ptr += 2 + 2;
526             break;
527
528         case LF_VFUNCTAB_V2:
529             printf("\t\tVirtual function table V2: type:%x\n",
530                    fieldtype->vfunctab_v2.type);
531             ptr += 2 + 2 + 4;
532             break;
533
534         case LF_VFUNCOFF_V1:
535             printf("\t\tVirtual function table offset V1: type:%x offset:%x\n",
536                    fieldtype->vfuncoff_v1.type, fieldtype->vfuncoff_v1.offset);
537             break;
538
539         case LF_VFUNCOFF_V2:
540             printf("\t\tVirtual function table offset V2: type:%x offset:%x\n",
541                    fieldtype->vfuncoff_v2.type, fieldtype->vfuncoff_v2.offset);
542             break;
543
544         default:
545             printf(">>> Unsupported field-id %x\n", fieldtype->generic.id);
546             dump_data((const void*)fieldtype, 0x30, "\t");
547             break;
548         }
549     }
550 }
551
552 static void codeview_dump_one_type(unsigned curr_type, const union codeview_type* type)
553 {
554     const union codeview_reftype* reftype = (const union codeview_reftype*)type;
555     int                 i, leaf_len, value;
556     unsigned int        j;
557     const char*         str;
558
559     switch (type->generic.id)
560     {
561     case LF_POINTER_V1:
562         printf("\t%x => Pointer V1 to type:%x\n",
563                curr_type, type->pointer_v1.datatype);
564         break;
565     case LF_POINTER_V2:
566         printf("\t%x => Pointer V2 to type:%x\n",
567                curr_type, type->pointer_v2.datatype);
568         break;
569     case LF_ARRAY_V1:
570         leaf_len = numeric_leaf(&value, &type->array_v1.arrlen);
571         printf("\t%x => Array V1-'%s'[%u type:%x] type:%x\n",
572                curr_type, p_string(PSTRING(&type->array_v1.arrlen, leaf_len)),
573                value, type->array_v1.idxtype, type->array_v1.elemtype);
574         break;
575     case LF_ARRAY_V2:
576         leaf_len = numeric_leaf(&value, &type->array_v2.arrlen);
577         printf("\t%x => Array V2-'%s'[%u type:%x] type:%x\n",
578                curr_type, p_string(PSTRING(&type->array_v2.arrlen, leaf_len)),
579                value, type->array_v2.idxtype, type->array_v2.elemtype);
580         break;
581     case LF_ARRAY_V3:
582         leaf_len = numeric_leaf(&value, &type->array_v3.arrlen);
583         str = (const char*)&type->array_v3.arrlen + leaf_len;
584         printf("\t%x => Array V3-'%s'[%u type:%x] type:%x\n",
585                curr_type, str, value,
586                type->array_v3.idxtype, type->array_v3.elemtype);
587         break;
588
589     /* a bitfields is a CodeView specific data type which represent a bitfield
590      * in a structure or a class. For now, we store it in a SymTag-like type
591      * (so that the rest of the process is seamless), but check at udt inclusion
592      * type for its presence
593      */
594     case LF_BITFIELD_V1:
595         printf("\t%x => Bitfield V1:%x offset:%u #bits:%u\n",
596                curr_type, reftype->bitfield_v1.type, reftype->bitfield_v1.bitoff,
597                reftype->bitfield_v1.nbits);
598         break;
599
600     case LF_BITFIELD_V2:
601         printf("\t%x => Bitfield V2:%x offset:%u #bits:%u\n",
602                curr_type, reftype->bitfield_v2.type, reftype->bitfield_v2.bitoff,
603                reftype->bitfield_v2.nbits);
604         break;
605
606     case LF_FIELDLIST_V1:
607     case LF_FIELDLIST_V2:
608         printf("\t%x => Fieldlist\n", curr_type);
609         do_field(reftype->fieldlist.list, (const BYTE*)type + reftype->generic.len + 2);
610         break;
611
612     case LF_STRUCTURE_V1:
613     case LF_CLASS_V1:
614         leaf_len = numeric_leaf(&value, &type->struct_v1.structlen);
615         printf("\t%x => %s V1 '%s' elts:%u property:%s fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
616                curr_type, type->generic.id == LF_CLASS_V1 ? "Class" : "Struct",
617                p_string(PSTRING(&type->struct_v1.structlen, leaf_len)),
618                type->struct_v1.n_element, get_property(type->struct_v1.property),
619                type->struct_v1.fieldlist, type->struct_v1.derived,
620                type->struct_v1.vshape, value);
621         break;
622
623     case LF_STRUCTURE_V2:
624     case LF_CLASS_V2:
625         leaf_len = numeric_leaf(&value, &type->struct_v2.structlen);
626         printf("\t%x => %s V2 '%s' elts:%u property:%s\n"
627                "                fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
628                curr_type, type->generic.id == LF_CLASS_V2 ? "Class" : "Struct",
629                p_string(PSTRING(&type->struct_v2.structlen, leaf_len)),
630                type->struct_v2.n_element, get_property(type->struct_v2.property),
631                type->struct_v2.fieldlist, type->struct_v2.derived,
632                type->struct_v2.vshape, value);
633         break;
634
635     case LF_STRUCTURE_V3:
636     case LF_CLASS_V3:
637         leaf_len = numeric_leaf(&value, &type->struct_v3.structlen);
638         str = (const char*)&type->struct_v3.structlen + leaf_len;
639         printf("\t%x => %s V3 '%s' elts:%u property:%s\n"
640                "                fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
641                curr_type, type->generic.id == LF_CLASS_V3 ? "Class" : "Struct",
642                str, type->struct_v3.n_element, get_property(type->struct_v3.property),
643                type->struct_v3.fieldlist, type->struct_v3.derived,
644                type->struct_v3.vshape, value);
645         break;
646
647     case LF_UNION_V1:
648         leaf_len = numeric_leaf(&value, &type->union_v1.un_len);
649         printf("\t%x => Union V1 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
650                curr_type, p_string(PSTRING(&type->union_v1.un_len, leaf_len)),
651                type->union_v1.count, get_property(type->union_v1.property),
652                type->union_v1.fieldlist, value);
653         break;
654
655     case LF_UNION_V2:
656         leaf_len = numeric_leaf(&value, &type->union_v2.un_len);
657         printf("\t%x => Union V2 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
658                curr_type, p_string(PSTRING(&type->union_v2.un_len, leaf_len)),
659                type->union_v2.count, get_property(type->union_v2.property),
660                type->union_v2.fieldlist, value);
661         break;
662
663     case LF_UNION_V3:
664         leaf_len = numeric_leaf(&value, &type->union_v3.un_len);
665         str = (const char*)&type->union_v3.un_len + leaf_len;
666         printf("\t%x => Union V3 '%s' count:%u property:%s fieldlist-type:%x size:%u\n",
667                curr_type, str, type->union_v3.count,
668                get_property(type->union_v3.property),
669                type->union_v3.fieldlist, value);
670         break;
671
672     case LF_ENUM_V1:
673         printf("\t%x => Enum V1 '%s' type:%x field-type:%x count:%u property:%s\n",
674                curr_type, p_string(&type->enumeration_v1.p_name),
675                type->enumeration_v1.type,
676                type->enumeration_v1.fieldlist,
677                type->enumeration_v1.count,
678                get_property(type->enumeration_v1.property));
679         break;
680
681     case LF_ENUM_V2:
682         printf("\t%x => Enum V2 '%s' type:%x field-type:%x count:%u property:%s\n",
683                curr_type, p_string(&type->enumeration_v2.p_name),
684                type->enumeration_v2.type,
685                type->enumeration_v2.fieldlist,
686                type->enumeration_v2.count,
687                get_property(type->enumeration_v2.property));
688         break;
689
690     case LF_ENUM_V3:
691         printf("\t%x => Enum V3 '%s' type:%x field-type:%x count:%u property:%s\n",
692                curr_type, type->enumeration_v3.name,
693                type->enumeration_v3.type,
694                type->enumeration_v3.fieldlist,
695                type->enumeration_v3.count,
696                get_property(type->enumeration_v3.property));
697         break;
698
699     case LF_ARGLIST_V1:
700         printf("\t%x => Arglist V1(#%u):", curr_type, reftype->arglist_v1.num);
701         for (i = 0; i < reftype->arglist_v1.num; i++)
702         {
703             printf(" %x", reftype->arglist_v1.args[i]);
704         }
705         printf("\n");
706         break;
707
708     case LF_ARGLIST_V2:
709         printf("\t%x => Arglist V2(#%u):", curr_type, reftype->arglist_v2.num);
710         for (j = 0; j < reftype->arglist_v2.num; j++)
711         {
712             printf("\t %x", reftype->arglist_v2.args[j]);
713         }
714         printf("\t\n");
715         break;
716
717     case LF_PROCEDURE_V1:
718         /* FIXME: unknown could be the calling convention for the proc */
719         printf("\t%x => Procedure V1 ret_type:%x call:%x (#%u args_type:%x)\n",
720                curr_type, type->procedure_v1.rvtype,
721                type->procedure_v1.call, type->procedure_v1.params,
722                type->procedure_v1.arglist);
723         break;
724
725     case LF_PROCEDURE_V2:
726         printf("\t%x => Procedure V2 ret_type:%x unk:%x (#%u args_type:%x)\n",
727                curr_type, type->procedure_v2.rvtype,
728                type->procedure_v2.call, type->procedure_v2.params,
729                type->procedure_v2.arglist);
730         break;
731
732     case LF_MFUNCTION_V2:
733         printf("\t%x => MFunction V2 ret-type:%x call:%x class-type:%x this-type:%x\n"
734                "\t\t#args:%x args-type:%x this_adjust:%x\n",
735                curr_type,
736                type->mfunction_v2.rvtype,
737                type->mfunction_v2.call,
738                type->mfunction_v2.class_type,
739                type->mfunction_v2.this_type,
740                type->mfunction_v2.params,
741                type->mfunction_v2.arglist,
742                type->mfunction_v2.this_adjust);
743         break;
744
745     case LF_MODIFIER_V1:
746         printf("\t%x => Modifier V1 type:%x modif:%x\n",
747                curr_type, type->modifier_v1.type, type->modifier_v1.attribute);
748         break;
749
750     case LF_MODIFIER_V2:
751         printf("\t%x => Modifier V2 type:%x modif:%x\n",
752                curr_type, type->modifier_v2.type, type->modifier_v2.attribute);
753         break;
754
755     case LF_METHODLIST_V1:
756         {
757             const unsigned short* pattr = (const unsigned short*)((const char*)type + 4);
758
759             printf("\t%x => Method list\n", curr_type);
760             while ((const char*)pattr < (const char*)type + type->generic.len + 2)
761             {
762                 switch ((*pattr >> 2) & 7)
763                 {
764                 case 4: case 6:
765                     printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
766                            get_attr(pattr[0]), pattr[1],
767                            *(const unsigned*)(&pattr[2]));
768                     pattr += 3;
769                     break;
770                 default:
771                     printf("\t\t\tattr:%s type:%x\n",
772                            get_attr(pattr[0]), pattr[1]);
773                     pattr += 2;
774                 }
775             }
776         }
777         break;
778
779     case LF_METHODLIST_V2:
780         {
781             const unsigned* pattr = (const unsigned*)((const char*)type + 4);
782
783             printf("\t%x => Method list\n", curr_type);
784             while ((const char*)pattr < (const char*)type + type->generic.len + 2)
785             {
786                 switch ((*pattr >> 2) & 7)
787                 {
788                 case 4: case 6:
789                     printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
790                            get_attr(pattr[0]), pattr[1], 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;
797                 }
798             }
799         }
800         break;
801
802     case LF_VTSHAPE_V1:
803         {
804             int count = *(const unsigned short*)((const char*)type + 4);
805             int shift = 0;
806             const char* ptr = (const char*)type + 6;
807             const char* desc[] = {"Near", "Far", "Thin", "Disp to outtermost",
808                                   "Pointer to metaclass", "Near32", "Far32"};
809             printf("\t%x => VT Shape #%d: ", curr_type, count);
810             while (count--)
811             {
812                 if (((*ptr << shift) & 0xF) <= 6)
813                     printf("%s ", desc[(*ptr << shift) & 0xF]);
814                 else
815                     printf("%x ", (*ptr << shift) & 0xF);
816                 if (shift == 0) shift = 4; else {shift = 0; ptr++;}
817             }
818             printf("\n");
819         }
820         break;
821
822     case LF_DERIVED_V1:
823         printf("\t%x => Derived V1(#%u):", curr_type, reftype->derived_v1.num);
824         for (i = 0; i < reftype->derived_v1.num; i++)
825         {
826             printf(" %x", reftype->derived_v1.drvdcls[i]);
827         }
828         printf("\n");
829         break;
830
831     case LF_DERIVED_V2:
832         printf("\t%x => Derived V2(#%u):", curr_type, reftype->derived_v2.num);
833         for (j = 0; j < reftype->derived_v2.num; j++)
834         {
835             printf(" %x", reftype->derived_v2.drvdcls[j]);
836         }
837         printf("\n");
838         break;
839
840     default:
841         printf(">>> Unsupported type-id %x for %x\n", type->generic.id, curr_type);
842         dump_data((const void*)type, type->generic.len + 2, "");
843         break;
844     }
845 }
846
847 int codeview_dump_types_from_offsets(const void* table, const DWORD* offsets, unsigned num_types)
848 {
849     unsigned long i;
850
851     for (i = 0; i < num_types; i++)
852     {
853         codeview_dump_one_type(0x1000 + i,
854                                (const union codeview_type*)((const char*)table + offsets[i]));
855     }
856
857     return TRUE;
858 }
859
860 int codeview_dump_types_from_block(const void* table, unsigned long len)
861 {
862     unsigned int        curr_type = 0x1000;
863     const unsigned char*ptr = table;
864
865     while (ptr - (const unsigned char*)table < len)
866     {
867         const union codeview_type* type = (const union codeview_type*)ptr;
868
869         codeview_dump_one_type(curr_type, type);
870         curr_type++;
871         ptr += (type->generic.len + 2 + 3) & ~3;
872     }
873
874     return TRUE;
875 }
876
877 int codeview_dump_symbols(const void* root, unsigned long size)
878 {
879     unsigned int i;
880     int          length;
881     char*        curr_func = NULL;
882     int          nest_block = 0;
883     /*
884      * Loop over the different types of records and whenever we
885      * find something we are interested in, record it and move on.
886      */
887     for (i = 0; i < size; i += length)
888     {
889         const union codeview_symbol* sym = (const union codeview_symbol*)((const char*)root + i);
890         length = sym->generic.len + 2;
891         if (!sym->generic.id || length < 4) break;
892         switch (sym->generic.id)
893         {
894         /*
895          * Global and local data symbols.  We don't associate these
896          * with any given source file.
897          */
898         case S_GDATA_V2:
899         case S_LDATA_V2:
900             printf("\tS-%s-Data V2 '%s' %04x:%08x type:%08x\n",
901                    sym->generic.id == S_GDATA_V2 ? "Global" : "Local",
902                    get_symbol_str(p_string(&sym->data_v2.p_name)),
903                    sym->data_v2.segment, sym->data_v2.offset, sym->data_v2.symtype);
904             break;
905
906         case S_LDATA_V3:
907         case S_GDATA_V3:
908 /* EPP         case S_DATA_V3: */
909             printf("\tS-%s-Data V3 '%s' (%04x:%08x) type:%08x\n",
910                    sym->generic.id == S_GDATA_V3 ? "Global" : "Local",
911                    get_symbol_str(sym->data_v3.name),
912                    sym->data_v3.segment, sym->data_v3.offset,
913                    sym->data_v3.symtype);
914             break;
915
916         case S_PUB_V2:
917             printf("\tS-Public V2 '%s' %04x:%08x type:%08x\n",
918                    get_symbol_str(p_string(&sym->public_v2.p_name)),
919                    sym->public_v2.segment, sym->public_v2.offset,
920                    sym->public_v2.symtype);
921             break;
922
923         case S_PUB_V3:
924         /* not completely sure of those two anyway */
925         case S_PUB_FUNC1_V3:
926         case S_PUB_FUNC2_V3:
927             printf("\tS-Public%s V3 '%s' %04x:%08x type:%08x\n",
928                    sym->generic.id == S_PUB_V3 ? "" :
929                                       (sym->generic.id == S_PUB_FUNC1_V3 ? "<subkind1" : "<subkind2"),
930                    get_symbol_str(sym->public_v3.name),
931                    sym->public_v3.segment,
932                    sym->public_v3.offset, sym->public_v3.symtype);
933             break;
934
935         /*
936          * Sort of like a global function, but it just points
937          * to a thunk, which is a stupid name for what amounts to
938          * a PLT slot in the normal jargon that everyone else uses.
939          */
940         case S_THUNK_V1:
941             printf("\tS-Thunk V1 '%s' (%04x:%08x#%x) type:%x\n", 
942                    p_string(&sym->thunk_v1.p_name),
943                    sym->thunk_v1.segment, sym->thunk_v1.offset,
944                    sym->thunk_v1.thunk_len, sym->thunk_v1.thtype);
945             curr_func = strdup(p_string(&sym->thunk_v1.p_name));
946             break;
947
948         case S_THUNK_V3:
949             printf("\tS-Thunk V3 '%s' (%04x:%08x#%x) type:%x\n", 
950                    sym->thunk_v3.name,
951                    sym->thunk_v3.segment, sym->thunk_v3.offset,
952                    sym->thunk_v3.thunk_len, sym->thunk_v3.thtype);
953             curr_func = strdup(sym->thunk_v3.name);
954             break;
955
956         /* Global and static functions */
957         case S_GPROC_V1:
958         case S_LPROC_V1:
959             printf("\tS-%s-Proc V1: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
960                    sym->generic.id == S_GPROC_V1 ? "Global" : "-Local",
961                    p_string(&sym->proc_v1.p_name),
962                    sym->proc_v1.segment, sym->proc_v1.offset,
963                    sym->proc_v1.proc_len, sym->proc_v1.proctype,
964                    sym->proc_v1.flags);
965             printf("\t  Debug: start=%08x end=%08x\n",
966                    sym->proc_v1.debug_start, sym->proc_v1.debug_end);
967             if (nest_block)
968             {
969                 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
970                 nest_block = 0;
971             }
972             curr_func = strdup(p_string(&sym->proc_v1.p_name));
973 /* EPP  unsigned int    pparent; */
974 /* EPP  unsigned int    pend; */
975 /* EPP  unsigned int    next; */
976             break;
977
978         case S_GPROC_V2:
979         case S_LPROC_V2:
980             printf("\tS-%s-Proc V2: '%s' (%04x:%08x#%x) type:%x attr:%x\n",
981                    sym->generic.id == S_GPROC_V2 ? "Global" : "-Local",
982                    p_string(&sym->proc_v2.p_name),
983                    sym->proc_v2.segment, sym->proc_v2.offset,
984                    sym->proc_v2.proc_len, sym->proc_v2.proctype,
985                    sym->proc_v2.flags);
986             printf("\t  Debug: start=%08x end=%08x\n",
987                    sym->proc_v2.debug_start, sym->proc_v2.debug_end);
988             if (nest_block)
989             {
990                 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
991                 nest_block = 0;
992             }
993             curr_func = strdup(p_string(&sym->proc_v2.p_name));
994 /* EPP  unsigned int    pparent; */
995 /* EPP  unsigned int    pend; */
996 /* EPP  unsigned int    next; */
997             break;
998
999         case S_LPROC_V3:
1000         case S_GPROC_V3:
1001             printf("\tS-%s-Procedure V3 '%s' (%04x:%08x#%x) type:%x attr:%x\n",
1002                    sym->generic.id == S_GPROC_V3 ? "Global" : "Local",
1003                    sym->proc_v3.name,
1004                    sym->proc_v3.segment, sym->proc_v3.offset,
1005                    sym->proc_v3.proc_len, sym->proc_v3.proctype,
1006                    sym->proc_v3.flags);
1007             printf("\t  Debug: start=%08x end=%08x\n",
1008                    sym->proc_v3.debug_start, sym->proc_v3.debug_end);
1009             if (nest_block)
1010             {
1011                 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
1012                 nest_block = 0;
1013             }
1014             curr_func = strdup(sym->proc_v3.name);
1015 /* EPP  unsigned int    pparent; */
1016 /* EPP  unsigned int    pend; */
1017 /* EPP  unsigned int    next; */
1018             break;
1019
1020         /* Function parameters and stack variables */
1021         case S_BPREL_V1:
1022             printf("\tS-BP-relative V1: '%s' @%d type:%x (%s)\n", 
1023                    p_string(&sym->stack_v1.p_name),
1024                    sym->stack_v1.offset, sym->stack_v1.symtype, curr_func);
1025             break;
1026
1027         case S_BPREL_V2:
1028             printf("\tS-BP-relative V2: '%s' @%d type:%x (%s)\n", 
1029                    p_string(&sym->stack_v2.p_name),
1030                    sym->stack_v2.offset, sym->stack_v2.symtype, curr_func);
1031             break;
1032
1033         case S_BPREL_V3:
1034             printf("\tS-BP-relative V3: '%s' @%d type:%x (in %s)\n", 
1035                    sym->stack_v3.name, sym->stack_v3.offset,
1036                    sym->stack_v3.symtype, curr_func);
1037             break;
1038
1039         case S_BPREL_XXXX_V3:
1040             printf("\tS-BP-relative XXXX V3: '%s' @%d type:%x unkn:%x (in %s)\n",
1041                    sym->stack_xxxx_v3.name, sym->stack_xxxx_v3.offset,
1042                    sym->stack_xxxx_v3.symtype, sym->stack_xxxx_v3.unknown, curr_func);
1043             break;
1044
1045         case S_REGISTER_V1:
1046             printf("\tS-Register V1 '%s' in %s type:%x register:%x\n",
1047                    p_string(&sym->register_v1.p_name),
1048                    curr_func, sym->register_v1.reg, sym->register_v1.type);
1049             break;
1050
1051         case S_REGISTER_V2:
1052             printf("\tS-Register V2 '%s' in %s type:%x register:%x\n",
1053                    p_string(&sym->register_v2.p_name),
1054                    curr_func, sym->register_v2.reg, sym->register_v2.type);
1055             break;
1056
1057         case S_REGISTER_V3:
1058             printf("\tS-Register V3 '%s' in %s type:%x register:%x\n",
1059                    sym->register_v3.name,
1060                    curr_func, sym->register_v3.reg, sym->register_v3.type);
1061             break;
1062
1063         case S_BLOCK_V1:
1064             printf("\tS-Block V1 '%s' in '%s' (%04x:%08x#%08x)\n",
1065                    p_string(&sym->block_v1.p_name),
1066                    curr_func, 
1067                    sym->block_v1.segment, sym->block_v1.offset,
1068                    sym->block_v1.length);
1069             nest_block++;
1070             break;
1071
1072         case S_BLOCK_V3:
1073             printf("\tS-Block V3 '%s' in '%s' (%04x:%08x#%08x) parent:%u end:%x\n",
1074                    sym->block_v3.name, curr_func, 
1075                    sym->block_v3.segment, sym->block_v3.offset, sym->block_v3.length,
1076                    sym->block_v3.parent, sym->block_v3.end);
1077             nest_block++;
1078             break;
1079
1080         /* Additional function information */
1081         case S_FUNCINFO_V2:
1082             printf("\tFunction info V2 unk1:%x unk2:%x unk3:%x unk4:%x unk5:%x unk6:%x flags:%04x unk7:%x\n",
1083                    sym->func_info_v2.unknown1,
1084                    sym->func_info_v2.unknown2,
1085                    sym->func_info_v2.unknown3,
1086                    sym->func_info_v2.unknown4,
1087                    sym->func_info_v2.unknown5,
1088                    sym->func_info_v2.unknown6,
1089                    sym->func_info_v2.flags,
1090                    sym->func_info_v2.unknown7);
1091             break;
1092
1093         case S_SECUCOOKIE_V3:
1094             printf("\tSecurity Cookie V3 @%d unk:%x\n",
1095                    sym->security_cookie_v3.offset, sym->security_cookie_v3.unknown);
1096             break;
1097
1098         case S_END_V1:
1099             if (nest_block)
1100             {
1101                 nest_block--;
1102                 printf("\tS-End-Of block (%u)\n", nest_block);
1103             }
1104             else
1105             {
1106                 printf("\tS-End-Of %s\n", curr_func);
1107                 free(curr_func);
1108                 curr_func = NULL;
1109             }
1110             break;
1111
1112         case S_COMPILAND_V1:
1113             {
1114                 const char*     machine;
1115                 const char*     lang;
1116
1117                 switch (sym->compiland_v1.unknown & 0xFF)
1118                 {
1119                 case 0x00:      machine = "Intel 8080"; break;
1120                 case 0x01:      machine = "Intel 8086"; break;
1121                 case 0x02:      machine = "Intel 80286"; break;
1122                 case 0x03:      machine = "Intel 80386"; break;
1123                 case 0x04:      machine = "Intel 80486"; break;
1124                 case 0x05:      machine = "Intel Pentium"; break;
1125                 case 0x10:      machine = "MIPS R4000"; break;
1126                 default:
1127                     {
1128                         static char tmp[16];
1129                         sprintf(tmp, "machine=%x", sym->compiland_v1.unknown & 0xFF);
1130                         machine = tmp;
1131                     }
1132                     break;
1133                 }
1134                 switch ((sym->compiland_v1.unknown >> 8) & 0xFF)
1135                 {
1136                 case 0x00:      lang = "C"; break;
1137                 case 0x01:      lang = "C++"; break;
1138                 case 0x02:      lang = "Fortran"; break;
1139                 case 0x03:      lang = "Masm"; break;
1140                 case 0x04:      lang = "Pascal"; break;
1141                 case 0x05:      lang = "Basic"; break;
1142                 case 0x06:      lang = "Cobol"; break;
1143                 default:
1144                     {
1145                         static char tmp[16];
1146                         sprintf(tmp, "language=%x", (sym->compiland_v1.unknown >> 8) & 0xFF);
1147                         lang = tmp;
1148                     }
1149                     break;
1150                 }
1151
1152                 printf("\tS-Compiland V1 '%s' %s %s unk:%x\n",
1153                        p_string(&sym->compiland_v1.p_name), machine, lang,
1154                        sym->compiland_v1.unknown >> 16);
1155             }
1156             break;
1157
1158         case S_COMPILAND_V2:
1159             printf("\tS-Compiland V2 '%s'\n",
1160                    p_string(&sym->compiland_v2.p_name));
1161             dump_data((const void*)sym, sym->generic.len + 2, "  ");
1162             {
1163                 const char* ptr = sym->compiland_v2.p_name.name + sym->compiland_v2.p_name.namelen;
1164                 while (*ptr)
1165                 {
1166                     printf("\t\t%s => ", ptr); ptr += strlen(ptr) + 1;
1167                     printf("%s\n", ptr); ptr += strlen(ptr) + 1;
1168                 }
1169             }
1170             break;
1171
1172         case S_COMPILAND_V3:
1173             printf("\tS-Compiland V3 '%s' unknown:%x\n",
1174                    sym->compiland_v3.name, sym->compiland_v3.unknown);
1175             break;
1176
1177         case S_OBJNAME_V1:
1178             printf("\tS-ObjName V1 sig:%.4s '%s'\n",
1179                    sym->objname_v1.signature, p_string(&sym->objname_v1.p_name));
1180             break;
1181
1182         case S_LABEL_V1:
1183             printf("\tS-Label V1 '%s' in '%s' (%04x:%08x)\n", 
1184                    p_string(&sym->label_v1.p_name),     
1185                    curr_func, sym->label_v1.segment, sym->label_v1.offset);
1186             break;
1187
1188         case S_LABEL_V3:
1189             printf("\tS-Label V3 '%s' in '%s' (%04x:%08x) flag:%x\n", 
1190                    sym->label_v3.name, curr_func, sym->label_v3.segment,
1191                    sym->label_v3.offset, sym->label_v3.flags);
1192             break;
1193
1194         case S_CONSTANT_V2:
1195             {
1196                 int             vlen;
1197                 union full_value fv;
1198
1199                 vlen = full_numeric_leaf(&fv, &sym->constant_v2.cvalue);
1200                 printf("\tS-Constant V2 '%s' = 0x%x%08x type:%x\n",
1201                        p_string(PSTRING(&sym->constant_v2.cvalue, vlen)),
1202                        (unsigned)(fv.llu >> 32), (unsigned)fv.llu, sym->constant_v2.type);
1203             }
1204             break;
1205
1206         case S_CONSTANT_V3:
1207             {
1208                 int             vlen;
1209                 union full_value fv;
1210
1211                 vlen = full_numeric_leaf(&fv, &sym->constant_v3.cvalue);
1212                 printf("\tS-Constant V3 '%s' =  0x%x%08x type:%x\n",
1213                        (const char*)&sym->constant_v3.cvalue + vlen,
1214                        (unsigned)(fv.llu >> 32), (unsigned)fv.llu, sym->constant_v3.type);
1215             }
1216             break;
1217
1218         case S_UDT_V1:
1219             printf("\tS-Udt V1 '%s': type:0x%x\n", 
1220                    p_string(&sym->udt_v1.p_name), sym->udt_v1.type);
1221             break;
1222
1223         case S_UDT_V2:
1224             printf("\tS-Udt V2 '%s': type:0x%x\n", 
1225                    p_string(&sym->udt_v2.p_name), sym->udt_v2.type);
1226             break;
1227
1228         case S_UDT_V3:
1229             printf("\tS-Udt V3 '%s': type:0x%x\n",
1230                    sym->udt_v3.name, sym->udt_v3.type);
1231             break;
1232         /*
1233          * These are special, in that they are always followed by an
1234          * additional length-prefixed string which is *not* included
1235          * into the symbol length count.  We need to skip it.
1236          */
1237         case S_PROCREF_V1:
1238             printf("\tS-Procref V1 "); goto doaref;
1239         case S_DATAREF_V1:
1240             printf("\tS-Dataref V1 "); goto doaref;
1241         case S_LPROCREF_V1:
1242             printf("\tS-L-Procref V1 "); goto doaref;
1243         doaref:
1244             {
1245                 const struct p_string* pname;
1246
1247                 pname = PSTRING(sym, length);
1248                 length += (pname->namelen + 1 + 3) & ~3;
1249                 printf("\t%08x %08x %08x '%s'\n",
1250                        *(((const DWORD*)sym) + 1), *(((const DWORD*)sym) + 2), *(((const DWORD*)sym) + 3),
1251                        p_string(pname));
1252             }
1253             break;
1254         case S_MSTOOL_V3:    /* info about tool used to create CU */
1255             {
1256                 const unsigned short*   ptr = ((const unsigned short*)sym) + 2;
1257                 const char*             x1;
1258                 const char*             x2 = (const char*)&ptr[9];
1259                 /* FIXME: what are all those values for ? */
1260                 printf("\tTool V3 unk=%04x%04x%04x front=%d.%d.%d.0 back=%d.%d.%d.0 %s\n",
1261                        ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
1262                        ptr[8], x2);
1263                 while (*(x1 = x2 + strlen(x2) + 1))
1264                 {
1265                     x2 = x1 + strlen(x1) + 1;
1266                     if (!*x2) break;
1267                     printf("\t\t%s: %s\n", x1, x2);
1268                 }
1269             }
1270             break;
1271
1272         case S_MSTOOLINFO_V3:
1273             {
1274                 const unsigned short*   ptr = ((const unsigned short*)sym) + 2;
1275
1276                 printf("\tTool info V3: unk=%04x%04x%04x front=%d.%d.%d.%d back=%d.%d.%d.%d %s\n",
1277                        ptr[0], ptr[1], ptr[2],
1278                        ptr[3], ptr[4], ptr[5], ptr[6],
1279                        ptr[7], ptr[8], ptr[9], ptr[10],
1280                        (const char*)(ptr + 11));
1281             }
1282             break;
1283
1284         case S_MSTOOLENV_V3:
1285             {
1286                 const char*             x1 = (const char*)sym + 4 + 1;
1287                 const char*             x2;
1288
1289                 printf("\tTool conf V3\n");
1290                 while (*x1)
1291                 {
1292                     x2 = x1 + strlen(x1) + 1;
1293                     if (!*x2) break;
1294                     printf("\t\t%s: %s\n", x1, x2);
1295                     x1 = x2 + strlen(x2) + 1;
1296                 }
1297             }
1298             break;
1299
1300         case S_ALIGN_V1:
1301             /* simply skip it */
1302             break;
1303
1304         case S_SSEARCH_V1:
1305             printf("\tSSearch V1: (%04x:%08x)\n",
1306                    sym->ssearch_v1.segment, sym->ssearch_v1.offset);
1307             break;
1308
1309         case S_SECTINFO_V3:
1310             printf("\tSSection Info: seg=%04x ?=%04x rva=%08x size=%08x attr=%08x %s\n",
1311                    *(unsigned short*)((const char*)sym + 4),
1312                    *(unsigned short*)((const char*)sym + 6),
1313                    *(unsigned*)((const char*)sym + 8),
1314                    *(unsigned*)((const char*)sym + 12),
1315                    *(unsigned*)((const char*)sym + 16),
1316                    (const char*)sym + 20);
1317             break;
1318
1319         case S_SUBSECTINFO_V3:
1320             printf("\tSSubSection Info: addr=%04x:%08x size=%08x attr=%08x %s\n",
1321                    *(unsigned short*)((const char*)sym + 16),
1322                    *(unsigned*)((const char*)sym + 12),
1323                    *(unsigned*)((const char*)sym + 4),
1324                    *(unsigned*)((const char*)sym + 8),
1325                    (const char*)sym + 18);
1326             break;
1327
1328         case S_ENTRYPOINT_V3:
1329             printf("\tSEntryPoint: id=%x '%s'\n",
1330                    *(unsigned*)((const char*)sym + 4), (const char*)sym + 8);
1331             break;
1332
1333         default:
1334             printf(">>> Unsupported symbol-id %x sz=%d\n", sym->generic.id, sym->generic.len + 2);
1335             dump_data((const void*)sym, sym->generic.len + 2, "  ");
1336         }
1337     }
1338     return 0;
1339 }
1340
1341 void codeview_dump_linetab(const char* linetab, DWORD size, BOOL pascal_str, const char* pfx)
1342 {
1343     const char*                 ptr = linetab;
1344     int                         nfile, nseg, nline;
1345     int                         i, j, k;
1346     const unsigned int*         filetab;
1347     const unsigned int*         lt_ptr;
1348     const struct startend*      start;
1349
1350     nfile = *(const short*)linetab;
1351     filetab = (const unsigned int*)(linetab + 2 * sizeof(short));
1352     printf("%s%d files with %d ???\n", pfx, nfile, *(const short*)(linetab + sizeof(short)));
1353
1354     for (i = 0; i < nfile; i++)
1355     {
1356         ptr = linetab + filetab[i];
1357         nseg = *(const short*)ptr;
1358         ptr += 2 * sizeof(short);
1359         lt_ptr = (const unsigned int*)ptr;
1360         start = (const struct startend*)(lt_ptr + nseg);
1361
1362         /*
1363          * Now snarf the filename for all of the segments for this file.
1364          */
1365         if (pascal_str)
1366         {
1367             char                        filename[MAX_PATH];
1368             const struct p_string*      p_fn;
1369
1370             p_fn = (const struct p_string*)(start + nseg);
1371             memset(filename, 0, sizeof(filename));
1372             memcpy(filename, p_fn->name, p_fn->namelen);
1373             printf("%slines for file #%d/%d %s %d\n", pfx, i, nfile, filename, nseg);
1374         }
1375         else
1376             printf("%slines for file #%d/%d %s %d\n", pfx, i, nfile, (const char*)(start + nseg), nseg);
1377
1378         for (j = 0; j < nseg; j++)
1379         {
1380             ptr = linetab + *lt_ptr++;
1381             nline = *(const short*)(ptr + 2);
1382             printf("%s  %04x:%08x-%08x #%d\n",
1383                    pfx, *(const short*)(ptr + 0), start[j].start, start[j].end, nline);
1384             ptr += 4;
1385             for (k = 0; k < nline; k++)
1386             {
1387                 printf("%s    %x %d\n",
1388                        pfx, ((const unsigned int*)ptr)[k],
1389                        ((const unsigned short*)((const unsigned int*)ptr + nline))[k]);
1390             }
1391         }
1392     }
1393 }
1394
1395 void codeview_dump_linetab2(const char* linetab, DWORD size, const char* strimage, DWORD strsize, const char* pfx)
1396 {
1397     DWORD       offset;
1398     unsigned    i;
1399     const struct codeview_linetab2_block* lbh;
1400     const struct codeview_linetab2_file* fd;
1401
1402     if (*(const DWORD*)linetab != 0x000000f4) return;
1403     offset = *((const DWORD*)linetab + 1);
1404     lbh = (const struct codeview_linetab2_block*)(linetab + 8 + offset);
1405     while ((const char*)lbh < linetab + size)
1406     {
1407         if (lbh->header != 0x000000f2)
1408         /* FIXME: should also check that whole lbh fits in linetab + size */
1409         {
1410             /* printf("%sblock end %x\n", pfx, lbh->header); */
1411             break;
1412         }
1413         printf("%sblock from %04x:%08x #%x (%x lines)\n",
1414                pfx, lbh->seg, lbh->start, lbh->size, lbh->nlines);
1415         fd = (const struct codeview_linetab2_file*)(linetab + 8 + lbh->file_offset);
1416         printf("%s  md5=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
1417                pfx, fd->md5[ 0], fd->md5[ 1], fd->md5[ 2], fd->md5[ 3],
1418                fd->md5[ 4], fd->md5[ 5], fd->md5[ 6], fd->md5[ 7],
1419                fd->md5[ 8], fd->md5[ 9], fd->md5[10], fd->md5[11],
1420                fd->md5[12], fd->md5[13], fd->md5[14], fd->md5[15]);
1421         /* FIXME: should check that string is within strimage + strsize */
1422         printf("%s  file=%s\n", pfx, strimage ? strimage + fd->offset : "--none--");
1423         for (i = 0; i < lbh->nlines; i++)
1424         {
1425             printf("%s  offset=%08x line=%d\n", pfx, lbh->l[i].offset, lbh->l[i].lineno ^ 0x80000000);
1426         }
1427         lbh = (const struct codeview_linetab2_block*)((const char*)lbh + 8 + lbh->size_of_block);
1428     }
1429 }