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