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