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