msxml3: Implement IXMLDOMText_get_data.
[wine.git] / tools / winedump / msc.c
blob7fb77c45b4e532075de1aa8736c144edb1dec7f7
1 /*
2 * MS debug info dumping utility
4 * Copyright 2006 Eric Pouech
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <time.h>
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34 #ifdef HAVE_SYS_STAT_H
35 # include <sys/stat.h>
36 #endif
37 #ifdef HAVE_SYS_MMAN_H
38 #include <sys/mman.h>
39 #endif
40 #include <fcntl.h>
42 #define NONAMELESSUNION
43 #define NONAMELESSSTRUCT
44 #include "windef.h"
45 #include "winbase.h"
46 #include "winedump.h"
47 #include "wine/mscvpdb.h"
49 #define PSTRING(adr, ofs) \
50 ((const struct p_string*)((const char*)(adr) + (ofs)))
52 static const char* p_string(const struct p_string* s)
54 static char tmp[256 + 1];
55 memcpy(tmp, s->name, s->namelen);
56 tmp[s->namelen] = '\0';
57 return tmp;
60 static int numeric_leaf(int* value, const unsigned short int* leaf)
62 unsigned short int type = *leaf++;
63 int length = 2;
65 if (type < LF_NUMERIC)
67 *value = type;
69 else
71 switch (type)
73 case LF_CHAR:
74 length += 1;
75 *value = *(const char*)leaf;
76 break;
78 case LF_SHORT:
79 length += 2;
80 *value = *(const short*)leaf;
81 break;
83 case LF_USHORT:
84 length += 2;
85 *value = *(const unsigned short*)leaf;
86 break;
88 case LF_LONG:
89 length += 4;
90 *value = *(const int*)leaf;
91 break;
93 case LF_ULONG:
94 length += 4;
95 *value = *(const unsigned int*)leaf;
96 break;
98 case LF_QUADWORD:
99 case LF_UQUADWORD:
100 length += 8;
101 printf(">>> unsupported leaf value\n");
102 *value = 0; /* FIXME */
103 break;
105 case LF_REAL32:
106 length += 4;
107 printf(">>> unsupported leaf value\n");
108 *value = 0; /* FIXME */
109 break;
111 case LF_REAL48:
112 length += 6;
113 *value = 0; /* FIXME */
114 printf(">>> unsupported leaf value\n");
115 break;
117 case LF_REAL64:
118 length += 8;
119 *value = 0; /* FIXME */
120 printf(">>> unsupported leaf value\n");
121 break;
123 case LF_REAL80:
124 length += 10;
125 *value = 0; /* FIXME */
126 printf(">>> unsupported leaf value\n");
127 break;
129 case LF_REAL128:
130 length += 16;
131 *value = 0; /* FIXME */
132 printf(">>> unsupported leaf value\n");
133 break;
135 case LF_COMPLEX32:
136 length += 4;
137 *value = 0; /* FIXME */
138 printf(">>> unsupported leaf value\n");
139 break;
141 case LF_COMPLEX64:
142 length += 8;
143 *value = 0; /* FIXME */
144 printf(">>> unsupported leaf value\n");
145 break;
147 case LF_COMPLEX80:
148 length += 10;
149 *value = 0; /* FIXME */
150 printf(">>> unsupported leaf value\n");
151 break;
153 case LF_COMPLEX128:
154 length += 16;
155 *value = 0; /* FIXME */
156 printf(">>> unsupported leaf value\n");
157 break;
159 case LF_VARSTRING:
160 length += 2 + *leaf;
161 *value = 0; /* FIXME */
162 printf(">>> unsupported leaf value\n");
163 break;
165 default:
166 printf(">>> Unsupported numeric leaf-id %04x\n", type);
167 *value = 0;
168 break;
171 return length;
174 static const char* get_attr(unsigned attr)
176 static char tmp[256];
178 switch (attr & 3)
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;
185 switch ((attr >> 2) & 7)
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;
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;
202 static void do_field(const unsigned char* start, const unsigned char* end)
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.
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.
217 const unsigned char* ptr = start;
218 const char* cstr;
219 const struct p_string* pstr;
220 int leaf_len, value;
222 while (ptr < end)
224 const union codeview_fieldtype* fieldtype = (const union codeview_fieldtype*)ptr;
226 if (*ptr >= 0xf0) /* LF_PAD... */
228 ptr +=* ptr & 0x0f;
229 continue;
232 switch (fieldtype->generic.id)
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;
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;
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;
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;
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;
277 case LF_ONEMETHOD_V1:
278 switch ((fieldtype->onemethod_v1.attribute >> 2) & 7)
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;
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;
297 break;
299 case LF_ONEMETHOD_V2:
300 switch ((fieldtype->onemethod_v2.attribute >> 2) & 7)
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;
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;
319 break;
321 case LF_ONEMETHOD_V3:
322 switch ((fieldtype->onemethod_v3.attribute >> 2) & 7)
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;
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;
341 break;
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;
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;
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;
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;
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;
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;
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;
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;
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
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;
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;
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;
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;
450 case LF_FRIENDCLS_V1:
451 printf("\t\tFriend class V1: type:%x\n", fieldtype->friendcls_v1.type);
452 break;
454 case LF_FRIENDCLS_V2:
455 printf("\t\tFriend class V2: type:%x\n", fieldtype->friendcls_v2.type);
456 break;
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;
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;
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;
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;
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;
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;
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;
501 default:
502 printf(">>> Unsupported field-id %x\n", fieldtype->generic.id);
503 dump_data((const void*)fieldtype, 0x30, "\t");
504 break;
509 static void codeview_dump_one_type(unsigned curr_type, const union codeview_type* type)
511 const union codeview_reftype* reftype = (const union codeview_reftype*)type;
512 int i, leaf_len, value;
513 unsigned int j;
514 const char* str;
516 switch (type->generic.id)
518 case LF_POINTER_V1:
519 printf("\t%x => Pointer V1 to type:%x\n",
520 curr_type, type->pointer_v1.datatype);
521 break;
522 case LF_POINTER_V2:
523 printf("\t%x => Pointer V2 to type:%x\n",
524 curr_type, type->pointer_v2.datatype);
525 break;
526 case LF_ARRAY_V1:
527 leaf_len = numeric_leaf(&value, &type->array_v1.arrlen);
528 printf("\t%x => Array V1-'%s'[%u type:%x] type:%x\n",
529 curr_type, p_string(PSTRING(&type->array_v1.arrlen, leaf_len)),
530 value, type->array_v1.idxtype, type->array_v1.elemtype);
531 break;
532 case LF_ARRAY_V2:
533 leaf_len = numeric_leaf(&value, &type->array_v2.arrlen);
534 printf("\t%x => Array V2-'%s'[%u type:%x] type:%x\n",
535 curr_type, p_string(PSTRING(&type->array_v2.arrlen, leaf_len)),
536 value, type->array_v2.idxtype, type->array_v2.elemtype);
537 break;
538 case LF_ARRAY_V3:
539 leaf_len = numeric_leaf(&value, &type->array_v3.arrlen);
540 str = (const char*)&type->array_v3.arrlen + leaf_len;
541 printf("\t%x => Array V3-'%s'[%u type:%x] type:%x\n",
542 curr_type, str, value,
543 type->array_v3.idxtype, type->array_v3.elemtype);
544 break;
546 /* a bitfields is a CodeView specific data type which represent a bitfield
547 * in a structure or a class. For now, we store it in a SymTag-like type
548 * (so that the rest of the process is seamless), but check at udt inclusion
549 * type for its presence
551 case LF_BITFIELD_V1:
552 printf("\t%x => Bitfield V1:%x offset:%u #bits:%u\n",
553 curr_type, reftype->bitfield_v1.type, reftype->bitfield_v1.bitoff,
554 reftype->bitfield_v1.nbits);
555 break;
557 case LF_BITFIELD_V2:
558 printf("\t%x => Bitfield V2:%x offset:%u #bits:%u\n",
559 curr_type, reftype->bitfield_v2.type, reftype->bitfield_v2.bitoff,
560 reftype->bitfield_v2.nbits);
561 break;
563 case LF_FIELDLIST_V1:
564 case LF_FIELDLIST_V2:
565 printf("\t%x => Fieldlist\n", curr_type);
566 do_field(reftype->fieldlist.list, (const BYTE*)type + reftype->generic.len + 2);
567 break;
569 case LF_STRUCTURE_V1:
570 case LF_CLASS_V1:
571 leaf_len = numeric_leaf(&value, &type->struct_v1.structlen);
572 printf("\t%x => %s V1 '%s' elts:%u prop:%u fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
573 curr_type, type->generic.id == LF_CLASS_V1 ? "Class" : "Struct",
574 p_string(PSTRING(&type->struct_v1.structlen, leaf_len)),
575 type->struct_v1.n_element, type->struct_v1.property,
576 type->struct_v1.fieldlist, type->struct_v1.derived,
577 type->struct_v1.vshape, value);
578 break;
580 case LF_STRUCTURE_V2:
581 case LF_CLASS_V2:
582 leaf_len = numeric_leaf(&value, &type->struct_v2.structlen);
583 printf("\t%x => %s V2 '%s' elts:%u prop:%u\n"
584 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
585 curr_type, type->generic.id == LF_CLASS_V2 ? "Class" : "Struct",
586 p_string(PSTRING(&type->struct_v2.structlen, leaf_len)),
587 type->struct_v2.n_element, type->struct_v2.property,
588 type->struct_v2.fieldlist, type->struct_v2.derived,
589 type->struct_v2.vshape, value);
590 break;
592 case LF_STRUCTURE_V3:
593 case LF_CLASS_V3:
594 leaf_len = numeric_leaf(&value, &type->struct_v3.structlen);
595 str = (const char*)&type->struct_v3.structlen + leaf_len;
596 printf("\t%x => %s V3 '%s' elts:%u prop:%u\n"
597 " fieldlist-type:%x derived-type:%x vshape:%x size:%u\n",
598 curr_type, type->generic.id == LF_CLASS_V3 ? "Class" : "Struct",
599 str, type->struct_v3.n_element, type->struct_v3.property,
600 type->struct_v3.fieldlist, type->struct_v3.derived,
601 type->struct_v3.vshape, value);
602 break;
604 case LF_UNION_V1:
605 leaf_len = numeric_leaf(&value, &type->union_v1.un_len);
606 printf("\t%x => Union V1 '%s' count:%u prop:%u fieldlist-type:%x size:%u\n",
607 curr_type, p_string(PSTRING(&type->union_v1.un_len, leaf_len)),
608 type->union_v1.count, type->union_v1.property,
609 type->union_v1.fieldlist, value);
610 break;
612 case LF_UNION_V2:
613 leaf_len = numeric_leaf(&value, &type->union_v2.un_len);
614 printf("\t%x => Union V2 '%s' count:%u prop:%u fieldlist-type:%x size:%u\n",
615 curr_type, p_string(PSTRING(&type->union_v2.un_len, leaf_len)),
616 type->union_v2.count, type->union_v2.property,
617 type->union_v2.fieldlist, value);
618 break;
620 case LF_UNION_V3:
621 leaf_len = numeric_leaf(&value, &type->union_v3.un_len);
622 str = (const char*)&type->union_v3.un_len + leaf_len;
623 printf("\t%x => Union V3 '%s' count:%u prop:%u fieldlist-type:%x size:%u\n",
624 curr_type, str, type->union_v3.count,
625 type->union_v3.property, type->union_v3.fieldlist, value);
626 break;
628 case LF_ENUM_V1:
629 printf("\t%x => Enum V1 '%s' type:%x field-type:%x count:%u property:%x\n",
630 curr_type, p_string(&type->enumeration_v1.p_name),
631 type->enumeration_v1.type,
632 type->enumeration_v1.fieldlist,
633 type->enumeration_v1.count,
634 type->enumeration_v1.property);
635 break;
637 case LF_ENUM_V2:
638 printf("\t%x => Enum V2 '%s' type:%x field-type:%x count:%u property:%x\n",
639 curr_type, p_string(&type->enumeration_v2.p_name),
640 type->enumeration_v2.type,
641 type->enumeration_v2.fieldlist,
642 type->enumeration_v2.count,
643 type->enumeration_v2.property);
644 break;
646 case LF_ENUM_V3:
647 printf("\t%x => Enum V3 '%s' type:%x field-type:%x count:%u property:%x\n",
648 curr_type, type->enumeration_v3.name,
649 type->enumeration_v3.type,
650 type->enumeration_v3.fieldlist,
651 type->enumeration_v3.count,
652 type->enumeration_v3.property);
653 break;
655 case LF_ARGLIST_V1:
656 printf("\t%x => Arglist V1(#%u):", curr_type, reftype->arglist_v1.num);
657 for (i = 0; i < reftype->arglist_v1.num; i++)
659 printf(" %x", reftype->arglist_v1.args[i]);
661 printf("\n");
662 break;
664 case LF_ARGLIST_V2:
665 printf("\t%x => Arglist V2(#%u):", curr_type, reftype->arglist_v2.num);
666 for (j = 0; j < reftype->arglist_v2.num; j++)
668 printf("\t %x", reftype->arglist_v2.args[j]);
670 printf("\t\n");
671 break;
673 case LF_PROCEDURE_V1:
674 /* FIXME: unknown could be the calling convention for the proc */
675 printf("\t%x => Procedure V1 ret_type:%x call:%x (#%u args_type:%x)\n",
676 curr_type, type->procedure_v1.rvtype,
677 type->procedure_v1.call, type->procedure_v1.params,
678 type->procedure_v1.arglist);
679 break;
681 case LF_PROCEDURE_V2:
682 printf("\t%x => Procedure V2 ret_type:%x unk:%x (#%u args_type:%x)\n",
683 curr_type, type->procedure_v2.rvtype,
684 type->procedure_v2.call, type->procedure_v2.params,
685 type->procedure_v2.arglist);
686 break;
688 case LF_MFUNCTION_V2:
689 printf("\t%x => MFunction V2 ret-type:%x call:%x class-type:%x this-type:%x\n"
690 "\t\t#args:%x args-type:%x this_adjust:%x\n",
691 curr_type,
692 type->mfunction_v2.rvtype,
693 type->mfunction_v2.call,
694 type->mfunction_v2.class_type,
695 type->mfunction_v2.this_type,
696 type->mfunction_v2.params,
697 type->mfunction_v2.arglist,
698 type->mfunction_v2.this_adjust);
699 break;
701 case LF_MODIFIER_V1:
702 printf("\t%x => Modifier V1 type:%x modif:%x\n",
703 curr_type, type->modifier_v1.type, type->modifier_v1.attribute);
704 break;
706 case LF_MODIFIER_V2:
707 printf("\t%x => Modifier V2 type:%x modif:%x\n",
708 curr_type, type->modifier_v2.type, type->modifier_v2.attribute);
709 break;
711 case LF_METHODLIST_V1:
713 const unsigned short* pattr = (const unsigned short*)((const char*)type + 4);
715 printf("\t%x => Method list\n", curr_type);
716 while ((const char*)pattr < (const char*)type + type->generic.len + 2)
718 switch ((*pattr >> 2) & 7)
720 case 4: case 6:
721 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
722 get_attr(pattr[0]), pattr[1],
723 *(const unsigned*)(&pattr[2]));
724 pattr += 3;
725 break;
726 default:
727 printf("\t\t\tattr:%s type:%x\n",
728 get_attr(pattr[0]), pattr[1]);
729 pattr += 2;
733 break;
735 case LF_METHODLIST_V2:
737 const unsigned* pattr = (const unsigned*)((const char*)type + 4);
739 printf("\t%x => Method list\n", curr_type);
740 while ((const char*)pattr < (const char*)type + type->generic.len + 2)
742 switch ((*pattr >> 2) & 7)
744 case 4: case 6:
745 printf("\t\t\tattr:%s type:%x vtab-offset:%x\n",
746 get_attr(pattr[0]), pattr[1], pattr[2]);
747 pattr += 3;
748 break;
749 default:
750 printf("\t\t\tattr:%s type:%x\n",
751 get_attr(pattr[0]), pattr[1]);
752 pattr += 2;
756 break;
758 case LF_VTSHAPE_V1:
760 int count = *(const unsigned short*)((const char*)type + 4);
761 int shift = 0;
762 const char* ptr = (const char*)type + 6;
763 const char* desc[] = {"Near", "Far", "Thin", "Disp to outtermost",
764 "Pointer to metaclass", "Near32", "Far32"};
765 printf("\t%x => VT Shape #%d: ", curr_type, count);
766 while (count--)
768 if (((*ptr << shift) & 0xF) <= 6)
769 printf("%s ", desc[(*ptr << shift) & 0xF]);
770 else
771 printf("%x ", (*ptr << shift) & 0xF);
772 if (shift == 0) shift = 4; else {shift = 0; ptr++;}
774 printf("\n");
776 break;
778 case LF_DERIVED_V1:
779 printf("\t%x => Derived V1(#%u):", curr_type, reftype->derived_v1.num);
780 for (i = 0; i < reftype->derived_v1.num; i++)
782 printf(" %x", reftype->derived_v1.drvdcls[i]);
784 printf("\n");
785 break;
787 case LF_DERIVED_V2:
788 printf("\t%x => Derived V2(#%u):", curr_type, reftype->derived_v2.num);
789 for (j = 0; j < reftype->derived_v2.num; j++)
791 printf(" %x", reftype->derived_v2.drvdcls[j]);
793 printf("\n");
794 break;
796 default:
797 printf(">>> Unsupported type-id %x for %x\n", type->generic.id, curr_type);
798 dump_data((const void*)type, type->generic.len + 2, "");
799 break;
803 int codeview_dump_types_from_offsets(const void* table, const DWORD* offsets, unsigned num_types)
805 unsigned long i;
807 for (i = 0; i < num_types; i++)
809 codeview_dump_one_type(0x1000 + i,
810 (const union codeview_type*)((const char*)table + offsets[i]));
813 return TRUE;
816 int codeview_dump_types_from_block(const void* table, unsigned long len)
818 unsigned int curr_type = 0x1000;
819 const unsigned char*ptr = table;
821 while (ptr - (const unsigned char*)table < len)
823 const union codeview_type* type = (const union codeview_type*)ptr;
825 codeview_dump_one_type(curr_type, type);
826 curr_type++;
827 ptr += (type->generic.len + 2 + 3) & ~3;
830 return TRUE;
833 int codeview_dump_symbols(const void* root, unsigned long size)
835 unsigned int i;
836 int length;
837 char* curr_func = NULL;
838 int nest_block = 0;
840 * Loop over the different types of records and whenever we
841 * find something we are interested in, record it and move on.
843 for (i = 0; i < size; i += length)
845 const union codeview_symbol* sym = (const union codeview_symbol*)((const char*)root + i);
846 length = sym->generic.len + 2;
847 if (!sym->generic.id || length < 4) break;
848 switch (sym->generic.id)
851 * Global and local data symbols. We don't associate these
852 * with any given source file.
854 case S_GDATA_V2:
855 case S_LDATA_V2:
856 printf("\tS-%s-Data V2 '%s' %04x:%08x type:%08x\n",
857 sym->generic.id == S_GDATA_V2 ? "Global" : "Local",
858 get_symbol_str(p_string(&sym->data_v2.p_name)),
859 sym->data_v2.segment, sym->data_v2.offset, sym->data_v2.symtype);
860 break;
862 case S_LDATA_V3:
863 case S_GDATA_V3:
864 /* EPP case S_DATA_V3: */
865 printf("\tS-%s-Data V3 '%s' (%04x:%08x) type:%08x\n",
866 sym->generic.id == S_GDATA_V3 ? "Global" : "Local",
867 get_symbol_str(sym->data_v3.name),
868 sym->data_v3.segment, sym->data_v3.offset,
869 sym->data_v3.symtype);
870 break;
872 case S_PUB_V2:
873 printf("\tS-Public V2 '%s' %04x:%08x type:%08x\n",
874 get_symbol_str(p_string(&sym->public_v2.p_name)),
875 sym->public_v2.segment, sym->public_v2.offset,
876 sym->public_v2.symtype);
877 break;
879 case S_PUB_V3:
880 /* not completely sure of those two anyway */
881 case S_PUB_FUNC1_V3:
882 case S_PUB_FUNC2_V3:
883 printf("\tS-Public%s V3 '%s' %04x:%08x type:%08x\n",
884 sym->generic.id == S_PUB_V3 ? "" :
885 (sym->generic.id == S_PUB_FUNC1_V3 ? "<subkind1" : "<subkind2"),
886 get_symbol_str(sym->public_v3.name),
887 sym->public_v3.segment,
888 sym->public_v3.offset, sym->public_v3.symtype);
889 break;
892 * Sort of like a global function, but it just points
893 * to a thunk, which is a stupid name for what amounts to
894 * a PLT slot in the normal jargon that everyone else uses.
896 case S_THUNK_V1:
897 printf("\tS-Thunk V1 '%s' (%04x:%08x#%x) type:%x\n",
898 p_string(&sym->thunk_v1.p_name),
899 sym->thunk_v1.segment, sym->thunk_v1.offset,
900 sym->thunk_v1.thunk_len, sym->thunk_v1.thtype);
901 curr_func = strdup(p_string(&sym->thunk_v1.p_name));
902 break;
904 case S_THUNK_V3:
905 printf("\tS-Thunk V3 '%s' (%04x:%08x#%x) type:%x\n",
906 sym->thunk_v3.name,
907 sym->thunk_v3.segment, sym->thunk_v3.offset,
908 sym->thunk_v3.thunk_len, sym->thunk_v3.thtype);
909 curr_func = strdup(sym->thunk_v3.name);
910 break;
912 /* Global and static functions */
913 case S_GPROC_V1:
914 case S_LPROC_V1:
915 printf("\tS-%s-Proc V1: '%s' (%04x:%08x#%x) type:%x\n",
916 sym->generic.id == S_GPROC_V1 ? "Global" : "-Local",
917 p_string(&sym->proc_v1.p_name),
918 sym->proc_v1.segment, sym->proc_v1.offset,
919 sym->proc_v1.proc_len, sym->proc_v1.proctype);
920 if (nest_block)
922 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
923 nest_block = 0;
925 curr_func = strdup(p_string(&sym->proc_v1.p_name));
926 /* EPP unsigned int pparent; */
927 /* EPP unsigned int pend; */
928 /* EPP unsigned int next; */
929 /* EPP unsigned int debug_start; */
930 /* EPP unsigned int debug_end; */
931 /* EPP unsigned char flags; */
932 break;
934 case S_GPROC_V2:
935 case S_LPROC_V2:
936 printf("\tS-%s-Proc V2: '%s' (%04x:%08x#%x) type:%x\n",
937 sym->generic.id == S_GPROC_V2 ? "Global" : "-Local",
938 p_string(&sym->proc_v2.p_name),
939 sym->proc_v2.segment, sym->proc_v2.offset,
940 sym->proc_v2.proc_len, sym->proc_v2.proctype);
941 if (nest_block)
943 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
944 nest_block = 0;
946 curr_func = strdup(p_string(&sym->proc_v2.p_name));
947 /* EPP unsigned int pparent; */
948 /* EPP unsigned int pend; */
949 /* EPP unsigned int next; */
950 /* EPP unsigned int debug_start; */
951 /* EPP unsigned int debug_end; */
952 /* EPP unsigned char flags; */
953 break;
955 case S_LPROC_V3:
956 case S_GPROC_V3:
957 printf("\tS-%s-Procedure V3 '%s' (%04x:%08x#%x) type:%x\n",
958 sym->generic.id == S_GPROC_V3 ? "Global" : "Local",
959 sym->proc_v3.name,
960 sym->proc_v3.segment, sym->proc_v3.offset,
961 sym->proc_v3.proc_len, sym->proc_v3.proctype);
962 if (nest_block)
964 printf(">>> prev func '%s' still has nest_block %u count\n", curr_func, nest_block);
965 nest_block = 0;
967 curr_func = strdup(sym->proc_v3.name);
968 /* EPP unsigned int pparent; */
969 /* EPP unsigned int pend; */
970 /* EPP unsigned int next; */
971 /* EPP unsigned int debug_start; */
972 /* EPP unsigned int debug_end; */
973 /* EPP unsigned char flags; */
974 break;
976 /* Function parameters and stack variables */
977 case S_BPREL_V1:
978 printf("\tS-BP-relative V1: '%s' @%d type:%x (%s)\n",
979 p_string(&sym->stack_v1.p_name),
980 sym->stack_v1.offset, sym->stack_v1.symtype, curr_func);
981 break;
983 case S_BPREL_V2:
984 printf("\tS-BP-relative V2: '%s' @%d type:%x (%s)\n",
985 p_string(&sym->stack_v2.p_name),
986 sym->stack_v2.offset, sym->stack_v2.symtype, curr_func);
987 break;
989 case S_BPREL_V3:
990 printf("\tS-BP-relative V3: '%s' @%d type:%x (in %s)\n",
991 sym->stack_v3.name, sym->stack_v3.offset,
992 sym->stack_v3.symtype, curr_func);
993 break;
995 case S_BPREL_XXXX_V3:
996 printf("\tS-BP-relative XXXX V3: '%s' @%d type:%x unkn:%x (in %s)\n",
997 sym->stack_xxxx_v3.name, sym->stack_xxxx_v3.offset,
998 sym->stack_xxxx_v3.symtype, sym->stack_xxxx_v3.unknown, curr_func);
999 break;
1001 case S_REGISTER_V1:
1002 printf("\tS-Register V1 '%s' in %s type:%x register:%x\n",
1003 p_string(&sym->register_v1.p_name),
1004 curr_func, sym->register_v1.reg, sym->register_v1.type);
1005 break;
1007 case S_REGISTER_V2:
1008 printf("\tS-Register V2 '%s' in %s type:%x register:%x\n",
1009 p_string(&sym->register_v2.p_name),
1010 curr_func, sym->register_v2.reg, sym->register_v2.type);
1011 break;
1013 case S_REGISTER_V3:
1014 printf("\tS-Register V3 '%s' in %s type:%x register:%x\n",
1015 sym->register_v3.name,
1016 curr_func, sym->register_v3.reg, sym->register_v3.type);
1017 break;
1019 case S_BLOCK_V1:
1020 printf("\tS-Block V1 '%s' in '%s' (%04x:%08x#%08x)\n",
1021 p_string(&sym->block_v1.p_name),
1022 curr_func,
1023 sym->block_v1.segment, sym->block_v1.offset,
1024 sym->block_v1.length);
1025 nest_block++;
1026 break;
1028 case S_BLOCK_V3:
1029 printf("\tS-Block V3 '%s' in '%s' (%04x:%08x#%08x) parent:%u end:%x\n",
1030 sym->block_v3.name, curr_func,
1031 sym->block_v3.segment, sym->block_v3.offset, sym->block_v3.length,
1032 sym->block_v3.parent, sym->block_v3.end);
1033 nest_block++;
1034 break;
1036 case S_END_V1:
1037 if (nest_block)
1039 nest_block--;
1040 printf("\tS-End-Of block (%u)\n", nest_block);
1042 else
1044 printf("\tS-End-Of %s\n", curr_func);
1045 free(curr_func);
1046 curr_func = NULL;
1048 break;
1050 case S_COMPILAND_V1:
1052 const char* machine;
1053 const char* lang;
1055 switch (sym->compiland_v1.unknown & 0xFF)
1057 case 0x00: machine = "Intel 8080"; break;
1058 case 0x01: machine = "Intel 8086"; break;
1059 case 0x02: machine = "Intel 80286"; break;
1060 case 0x03: machine = "Intel 80386"; break;
1061 case 0x04: machine = "Intel 80486"; break;
1062 case 0x05: machine = "Intel Pentium"; break;
1063 case 0x10: machine = "MIPS R4000"; break;
1064 default:
1066 static char tmp[16];
1067 sprintf(tmp, "machine=%x", sym->compiland_v1.unknown & 0xFF);
1068 machine = tmp;
1070 break;
1072 switch ((sym->compiland_v1.unknown >> 8) & 0xFF)
1074 case 0x00: lang = "C"; break;
1075 case 0x01: lang = "C++"; break;
1076 case 0x02: lang = "Fortran"; break;
1077 case 0x03: lang = "Masm"; break;
1078 case 0x04: lang = "Pascal"; break;
1079 case 0x05: lang = "Basic"; break;
1080 case 0x06: lang = "Cobol"; break;
1081 default:
1083 static char tmp[16];
1084 sprintf(tmp, "language=%x", (sym->compiland_v1.unknown >> 8) & 0xFF);
1085 lang = tmp;
1087 break;
1090 printf("\tS-Compiland V1 '%s' %s %s unk:%x\n",
1091 p_string(&sym->compiland_v1.p_name), machine, lang,
1092 sym->compiland_v1.unknown >> 16);
1094 break;
1096 case S_COMPILAND_V2:
1097 printf("\tS-Compiland V2 '%s'\n",
1098 p_string(&sym->compiland_v2.p_name));
1099 dump_data((const void*)sym, sym->generic.len + 2, " ");
1101 const char* ptr = sym->compiland_v2.p_name.name + sym->compiland_v2.p_name.namelen;
1102 while (*ptr)
1104 printf("\t\t%s => ", ptr); ptr += strlen(ptr) + 1;
1105 printf("%s\n", ptr); ptr += strlen(ptr) + 1;
1108 break;
1110 case S_COMPILAND_V3:
1111 printf("\tS-Compiland V3 '%s' unknown:%x\n",
1112 sym->compiland_v3.name, sym->compiland_v3.unknown);
1113 break;
1115 case S_OBJNAME_V1:
1116 printf("\tS-ObjName V1 sig:%.4s '%s'\n",
1117 sym->objname_v1.signature, p_string(&sym->objname_v1.p_name));
1118 break;
1120 case S_LABEL_V1:
1121 printf("\tS-Label V1 '%s' in '%s' (%04x:%08x)\n",
1122 p_string(&sym->label_v1.p_name),
1123 curr_func, sym->label_v1.segment, sym->label_v1.offset);
1124 break;
1126 case S_LABEL_V3:
1127 printf("\tS-Label V3 '%s' in '%s' (%04x:%08x) flag:%x\n",
1128 sym->label_v3.name, curr_func, sym->label_v3.segment,
1129 sym->label_v3.offset, sym->label_v3.flags);
1130 break;
1132 case S_CONSTANT_V2:
1134 int val, vlen;
1136 vlen = numeric_leaf(&val, &sym->constant_v2.cvalue);
1137 printf("\tS-Constant V2 '%s' = %u type:%x\n",
1138 p_string(PSTRING(&sym->constant_v2.cvalue, vlen)),
1139 val, sym->constant_v2.type);
1141 break;
1143 case S_CONSTANT_V3:
1145 int val, vlen;
1147 vlen = numeric_leaf(&val, &sym->constant_v3.cvalue);
1148 printf("\tS-Constant V3 '%s' = %u type:%x\n",
1149 (const char*)&sym->constant_v3.cvalue + vlen,
1150 val, sym->constant_v3.type);
1152 break;
1154 case S_UDT_V1:
1155 printf("\tS-Udt V1 '%s': type:0x%x\n",
1156 p_string(&sym->udt_v1.p_name), sym->udt_v1.type);
1157 break;
1159 case S_UDT_V2:
1160 printf("\tS-Udt V2 '%s': type:0x%x\n",
1161 p_string(&sym->udt_v2.p_name), sym->udt_v2.type);
1162 break;
1164 case S_UDT_V3:
1165 printf("\tS-Udt V3 '%s': type:0x%x\n",
1166 sym->udt_v3.name, sym->udt_v3.type);
1167 break;
1169 * These are special, in that they are always followed by an
1170 * additional length-prefixed string which is *not* included
1171 * into the symbol length count. We need to skip it.
1173 case S_PROCREF_V1:
1174 printf("\tS-Procref V1 "); goto doaref;
1175 case S_DATAREF_V1:
1176 printf("\tS-Dataref V1 "); goto doaref;
1177 case S_LPROCREF_V1:
1178 printf("\tS-L-Procref V1 "); goto doaref;
1179 doaref:
1181 const struct p_string* pname;
1183 pname = PSTRING(sym, length);
1184 length += (pname->namelen + 1 + 3) & ~3;
1185 printf("\t%08x %08x %08x '%s'\n",
1186 *(((const DWORD*)sym) + 1), *(((const DWORD*)sym) + 2), *(((const DWORD*)sym) + 3),
1187 p_string(pname));
1189 break;
1190 case S_MSTOOL_V3: /* info about tool used to create CU */
1192 const unsigned short* ptr = ((const unsigned short*)sym) + 2;
1194 /* FIXME: what are all those values for ? */
1195 printf("\tTool V3 ??? %x-%x-%x-%x-%x-%x-%x-%x-%x %s\n",
1196 ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7],
1197 ptr[8], (const char*)(&ptr[9]));
1198 dump_data((const void*)sym, sym->generic.len + 2, "\t\t");
1200 break;
1202 case S_ALIGN_V1:
1203 /* simply skip it */
1204 break;
1206 case S_SSEARCH_V1:
1207 printf("\tSSearch V1: (%04x:%08x)\n",
1208 sym->ssearch_v1.segment, sym->ssearch_v1.offset);
1209 break;
1211 default:
1212 printf(">>> Unsupported symbol-id %x sz=%d\n", sym->generic.id, sym->generic.len + 2);
1213 dump_data((const void*)sym, sym->generic.len + 2, " ");
1216 return 0;