mshtml: Fixed events tests on IE9.
[wine] / tools / winedump / pdb.c
1 /*
2  *      PDB 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 struct pdb_reader
50 {
51     union
52     {
53         struct
54         {
55             const struct PDB_JG_HEADER* header;
56             const struct PDB_JG_TOC*    toc;
57             const struct PDB_JG_ROOT*   root;
58         } jg;
59         struct
60         {
61             const struct PDB_DS_HEADER* header;
62             const struct PDB_DS_TOC*    toc;
63             const struct PDB_DS_ROOT*   root;
64         } ds;
65     } u;
66     void*       (*read_file)(struct pdb_reader*, DWORD);
67     DWORD       file_used[1024];
68 };
69
70 static void* pdb_jg_read(const struct PDB_JG_HEADER* pdb, const WORD* block_list, int size)
71 {
72     int                 i, nBlocks;
73     BYTE*               buffer;
74
75     if (!size) return NULL;
76
77     nBlocks = (size + pdb->block_size - 1) / pdb->block_size;
78     buffer = malloc(nBlocks * pdb->block_size);
79
80     for (i = 0; i < nBlocks; i++)
81         memcpy(buffer + i * pdb->block_size,
82                (const char*)pdb + block_list[i] * pdb->block_size, pdb->block_size);
83
84     return buffer;
85 }
86
87 static void* pdb_jg_read_file(struct pdb_reader* reader, DWORD file_nr)
88 {
89     const WORD*         block_list;
90     DWORD               i;
91
92     if (!reader->u.jg.toc || file_nr >= reader->u.jg.toc->num_files) return NULL;
93
94     reader->file_used[file_nr / 32] |= 1 << (file_nr % 32);
95     if (reader->u.jg.toc->file[file_nr].size == 0 ||
96         reader->u.jg.toc->file[file_nr].size == 0xFFFFFFFF)
97         return NULL;
98     block_list = (const WORD*) &reader->u.jg.toc->file[reader->u.jg.toc->num_files];
99     for (i = 0; i < file_nr; i++)
100         block_list += (reader->u.jg.toc->file[i].size +
101                        reader->u.jg.header->block_size - 1) / reader->u.jg.header->block_size;
102
103     return pdb_jg_read(reader->u.jg.header, block_list,
104                        reader->u.jg.toc->file[file_nr].size);
105 }
106
107 static void pdb_jg_init(struct pdb_reader* reader)
108 {
109     reader->u.jg.header = PRD(0, sizeof(struct PDB_JG_HEADER));
110     reader->read_file = pdb_jg_read_file;
111     reader->u.jg.toc = pdb_jg_read(reader->u.jg.header, 
112                                    reader->u.jg.header->toc_block,
113                                    reader->u.jg.header->toc.size);
114     memset(reader->file_used, 0, sizeof(reader->file_used));
115 }
116
117 static DWORD    pdb_get_num_files(const struct pdb_reader* reader)
118 {
119     if (reader->read_file == pdb_jg_read_file)
120         return reader->u.jg.toc->num_files;
121     else
122         return reader->u.ds.toc->num_files;
123 }
124
125 static DWORD    pdb_get_file_size(const struct pdb_reader* reader, unsigned idx)
126 {
127     if (reader->read_file == pdb_jg_read_file)
128         return reader->u.jg.toc->file[idx].size;
129     else
130         return reader->u.ds.toc->file_size[idx];
131 }
132
133 static void pdb_exit(struct pdb_reader* reader)
134 {
135 #if 1
136     unsigned            i;
137     unsigned char*      file;
138     DWORD               size;
139
140     for (i = 0; i < pdb_get_num_files(reader); i++)
141     {
142         if (reader->file_used[i / 32] & (1 << (i % 32))) continue;
143
144         file = reader->read_file(reader, i);
145         if (!file) continue;
146
147         size = pdb_get_file_size(reader, i);
148
149         printf("File --unused-- #%d (%x)\n", i, size);
150         dump_data(file, size, "    ");
151         free(file);
152     }
153 #endif
154     if (reader->read_file == pdb_jg_read_file)
155     {
156         free((char*)reader->u.jg.root);
157         free((char*)reader->u.jg.toc);
158     }
159     else
160     {
161         free((char*)reader->u.ds.root);
162         free((char*)reader->u.ds.toc);
163     }
164 }
165
166 static unsigned get_stream_by_name(struct pdb_reader* reader, const char* name)
167 {
168     DWORD*      pdw;
169     DWORD*      ok_bits;
170     DWORD       cbstr, count;
171     DWORD       string_idx, stream_idx;
172     unsigned    i;
173     const char* str;
174
175     if (reader->read_file == pdb_jg_read_file)
176     {
177         str = &reader->u.jg.root->names[0];
178         cbstr = reader->u.jg.root->cbNames;
179     }
180     else
181     {
182         str = &reader->u.ds.root->names[0];
183         cbstr = reader->u.ds.root->cbNames;
184     }
185
186     pdw = (DWORD*)(str + cbstr);
187     pdw++; /* number of ok entries */
188     count = *pdw++;
189
190     /* bitfield: first dword is len (in dword), then data */
191     ok_bits = pdw;
192     pdw += *ok_bits++ + 1;
193     if (*pdw++ != 0)
194     {
195         printf("unexpected value\n");
196         return -1;
197     }
198
199     for (i = 0; i < count; i++)
200     {
201         if (ok_bits[i / 32] & (1 << (i % 32)))
202         {
203             string_idx = *pdw++;
204             stream_idx = *pdw++;
205             if (!strcmp(name, &str[string_idx])) return stream_idx;
206         }
207     }
208     return -1;
209 }
210
211 static void *read_string_table(struct pdb_reader* reader)
212 {
213     unsigned    stream_idx;
214     void*       ret;
215
216     stream_idx = get_stream_by_name(reader, "/names");
217     if (stream_idx == -1) return NULL;
218     ret = reader->read_file(reader, stream_idx);
219     if (ret && *(const DWORD*)ret == 0xeffeeffe) return ret;
220     printf("wrong header %x expecting 0xeffeeffe\n", *(const DWORD*)ret);
221     free( ret );
222     return NULL;
223 }
224
225 static void pdb_dump_symbols(struct pdb_reader* reader, PDB_STREAM_INDEXES* sidx)
226 {
227     PDB_SYMBOLS*    symbols;
228     unsigned char*  modimage;
229     const char*     file;
230     char*           filesimage;
231     DWORD           filessize = 0;
232
233     sidx->FPO = sidx->unk0 = sidx->unk1 = sidx->unk2 = sidx->unk3 = sidx->segments =
234         sidx->unk4 = sidx->unk5 = sidx->unk6 = sidx->FPO_EXT = sidx->unk7 = -1;
235
236     symbols = reader->read_file(reader, 3);
237     if (!symbols) return;
238
239     switch (symbols->version)
240     {
241     case 0:            /* VC 4.0 */
242     case 19960307:     /* VC 5.0 */
243     case 19970606:     /* VC 6.0 */
244     case 19990903:     /* VC 7.0 */
245         break;
246     default:
247         printf("-Unknown symbol info version %d\n", symbols->version);
248     }
249     printf("Symbols:\n"
250            "\tsignature:       %08x\n"
251            "\tversion:         %u\n"
252            "\tunknown:         %08x\n"
253            "\thash1_file:      %08x\n"
254            "\thash2_file:      %08x\n"
255            "\tgsym_file:       %04x\n"
256            "\tunknown1:        %04x\n"
257            "\tmodule_size:     %08x\n"
258            "\toffset_size:     %08x\n"
259            "\thash_size:       %08x\n"
260            "\tsrc_module_size: %08x\n"
261            "\tpdbimport_size:  %08x\n"
262            "\tresvd0:          %08x\n"
263            "\tstream_idx_size: %08x\n"
264            "\tunknown2_size:   %08x\n"
265            "\tresvd3:          %04x\n"
266            "\tmachine:         %s\n"
267            "\tresvd[4]         %08x\n",
268            symbols->signature,
269            symbols->version,
270            symbols->unknown,
271            symbols->hash1_file,
272            symbols->hash2_file,
273            symbols->gsym_file,
274            symbols->unknown1,
275            symbols->module_size,
276            symbols->offset_size,
277            symbols->hash_size,
278            symbols->srcmodule_size,
279            symbols->pdbimport_size,
280            symbols->resvd0,
281            symbols->stream_index_size,
282            symbols->unknown2_size,
283            symbols->resvd3,
284            get_machine_str( symbols->machine ),
285            symbols->resvd4);
286
287     if (symbols->offset_size)
288     {
289         const BYTE*                 src;
290
291         printf("\t----------offsets------------\n");
292         src = (const BYTE*)((const char*)symbols + sizeof(PDB_SYMBOLS) + symbols->module_size);
293         dump_data(src, symbols->offset_size, "    ");
294     }
295
296     if (!(filesimage = read_string_table(reader))) printf("string table not found\n");
297     else filessize = *(const DWORD*)(filesimage + 8);
298
299     if (symbols->srcmodule_size)
300     {
301         const PDB_SYMBOL_SOURCE*src;
302         int                     i, j, cfile;
303         const WORD*             indx;
304         const DWORD*            offset;
305         const char*             start_cstr;
306         const char*             cstr;
307
308         printf("\t----------src module------------\n");
309         src = (const PDB_SYMBOL_SOURCE*)((const char*)symbols + sizeof(PDB_SYMBOLS) + 
310                                          symbols->module_size + symbols->offset_size + symbols->hash_size);
311         printf("\tSource Modules\n"
312                "\t\tnModules:         %u\n"
313                "\t\tnSrcFiles:        %u\n",
314                src->nModules, src->nSrcFiles);
315
316         /* usage of table seems to be as follows:
317          * two arrays of WORD (src->nModules as size)
318          *  - first array contains index into files for "module" compilation
319          *    (module = compilation unit ??)
320          *  - second array contains the number of source files in module
321          *    an array of DWORD (src->nSrcFiles as size)
322          *  - contains offset (in following string table) of the source file name
323          *    a string table
324          *  - each string is a pascal string (ie. with its length as first BYTE) or
325          *    0-terminated string (depending on version)
326          */
327         indx = &src->table[src->nModules];
328         offset = (const DWORD*)&src->table[2 * src->nModules];
329         cstr = (const char*)&src->table[2 * (src->nModules + src->nSrcFiles)];
330         start_cstr = cstr;
331
332         for (i = cfile = 0; i < src->nModules; i++)
333         {
334             printf("\t\tModule[%2d]:\n", i);
335             cfile = src->table[i];
336             for (j = cfile; j < src->nSrcFiles && j < cfile + indx[i]; j++)
337             {
338                 /* FIXME: in some cases, it's a p_string but WHEN ? */
339                 if (cstr + offset[j] >= (const char*)start_cstr /* wrap around */ &&
340                     cstr + offset[j] < (const char*)src + symbols->srcmodule_size)
341                     printf("\t\t\tSource file: %s\n", cstr + offset[j]);
342                 else
343                     printf("\t\t\tSource file: <<out of bounds>>\n");
344             }
345         }
346     }
347     if (symbols->pdbimport_size)
348     {
349         const PDB_SYMBOL_IMPORT*  imp;
350         const char* first;
351         const char* last;
352         const char* ptr;
353
354         printf("\t------------import--------------\n");
355         imp = (const PDB_SYMBOL_IMPORT*)((const char*)symbols + sizeof(PDB_SYMBOLS) + 
356                                          symbols->module_size + symbols->offset_size + 
357                                          symbols->hash_size + symbols->srcmodule_size);
358         first = (const char*)imp;
359         last = (const char*)imp + symbols->pdbimport_size;
360         while (imp < (const PDB_SYMBOL_IMPORT*)last)
361         {
362             ptr = (const char*)imp + sizeof(*imp) + strlen(imp->filename);
363             printf("\tImport: %lx\n"
364                    "\t\tUnknown1:      %08x\n"
365                    "\t\tUnknown2:      %08x\n"
366                    "\t\tTimeDateStamp: %08x\n"
367                    "\t\tAge:           %08u\n"
368                    "\t\tfile1:         %s\n"
369                    "\t\tfile2:         %s\n",
370                    (ULONG_PTR)((const char*)imp - (const char*)first),
371                    imp->unknown1,
372                    imp->unknown2,
373                    imp->TimeDateStamp,
374                    imp->Age,
375                    imp->filename,
376                    ptr);
377             imp = (const PDB_SYMBOL_IMPORT*)(first + ((ptr - first + strlen(ptr) + 1 + 3) & ~3));
378         }
379     }
380     if (symbols->stream_index_size)
381     {
382         printf("\t------------stream indexes--------------\n");
383         switch (symbols->stream_index_size)
384         {
385         case sizeof(PDB_STREAM_INDEXES_OLD):
386             /* PDB_STREAM_INDEXES is a superset of PDB_STREAM_INDEX_OLD
387              * FIXME: to be confirmed when all fields are fully understood
388              */
389             memcpy(sidx,
390                    (const char*)symbols + sizeof(PDB_SYMBOLS) + symbols->module_size +
391                    symbols->offset_size + symbols->hash_size + symbols->srcmodule_size +
392                    symbols->pdbimport_size + symbols->unknown2_size,
393                    sizeof(PDB_STREAM_INDEXES_OLD));
394             printf("\tFPO:                  %04x\n"
395                    "\t?:                    %04x\n"
396                    "\t?:                    %04x\n"
397                    "\t?:                    %04x\n"
398                    "\t?:                    %04x\n"
399                    "\tSegments:             %04x\n",
400                    sidx->FPO, sidx->unk0, sidx->unk1, sidx->unk2, sidx->unk3,
401                    sidx->segments);
402             break;
403         case sizeof(PDB_STREAM_INDEXES):
404             memcpy(sidx,
405                    (const char*)symbols + sizeof(PDB_SYMBOLS) + symbols->module_size +
406                    symbols->offset_size + symbols->hash_size + symbols->srcmodule_size +
407                    symbols->pdbimport_size + symbols->unknown2_size,
408                    sizeof(*sidx));
409             printf("\tFPO:                  %04x\n"
410                    "\t?:                    %04x\n"
411                    "\t?:                    %04x\n"
412                    "\t?:                    %04x\n"
413                    "\t?:                    %04x\n"
414                    "\tSegments:             %04x\n"
415                    "\t?:                    %04x\n"
416                    "\t?:                    %04x\n"
417                    "\t?:                    %04x\n"
418                    "\tFPO-ext:              %04x\n"
419                    "\t?:                    %04x\n",
420                    sidx->FPO, sidx->unk0, sidx->unk1, sidx->unk2, sidx->unk3,
421                    sidx->segments, sidx->unk4, sidx->unk5, sidx->unk6, sidx->FPO_EXT,
422                    sidx->unk7);
423             break;
424         default:
425             printf("unexpected size for stream index %d\n", symbols->stream_index_size);
426             break;
427         }
428     }
429
430     /* Read global symbol table */
431     modimage = reader->read_file(reader, symbols->gsym_file);
432     if (modimage)
433     {
434         printf("\t------------globals-------------\n"); 
435         codeview_dump_symbols(modimage, pdb_get_file_size(reader, symbols->gsym_file));
436         free(modimage);
437     }
438
439     /* Read per-module symbol / linenumber tables */
440     file = (const char*)symbols + sizeof(PDB_SYMBOLS);
441     while (file - (const char*)symbols < sizeof(PDB_SYMBOLS) + symbols->module_size)
442     {
443         int file_nr, symbol_size, lineno_size;
444         const char* file_name;
445             
446         if (symbols->version < 19970000)
447         {
448             const PDB_SYMBOL_FILE*      sym_file = (const PDB_SYMBOL_FILE*) file;
449             file_nr     = sym_file->file;
450             file_name   = sym_file->filename;
451             symbol_size = sym_file->symbol_size;
452             lineno_size = sym_file->lineno_size;
453             printf("\t--------symbol file----------- %s\n", file_name);
454             printf("\tgot symbol_file\n"
455                    "\t\tunknown1:   %08x\n"
456                    "\t\trange\n"
457                    "\t\t\tsegment:         %04x\n"
458                    "\t\t\tpad1:            %04x\n"
459                    "\t\t\toffset:          %08x\n"
460                    "\t\t\tsize:            %08x\n"
461                    "\t\t\tcharacteristics: %08x\n"
462                    "\t\t\tindex:           %04x\n"
463                    "\t\t\tpad2:            %04x\n"
464                    "\t\tflag:       %04x\n"
465                    "\t\tfile:       %04x\n"
466                    "\t\tsymb size:  %08x\n"
467                    "\t\tline size:  %08x\n"
468                    "\t\tunknown2:   %08x\n"
469                    "\t\tnSrcFiles:  %08x\n"
470                    "\t\tattribute:  %08x\n",
471                    sym_file->unknown1,
472                    sym_file->range.segment,
473                    sym_file->range.pad1,
474                    sym_file->range.offset,
475                    sym_file->range.size,
476                    sym_file->range.characteristics,
477                    sym_file->range.index,
478                    sym_file->range.pad2,
479                    sym_file->flag,
480                    sym_file->file,
481                    sym_file->symbol_size,
482                    sym_file->lineno_size,
483                    sym_file->unknown2,
484                    sym_file->nSrcFiles,
485                    sym_file->attribute);
486         }
487         else
488         {
489             const PDB_SYMBOL_FILE_EX*   sym_file = (const PDB_SYMBOL_FILE_EX*) file;
490             file_nr     = sym_file->file;
491             file_name   = sym_file->filename;
492             symbol_size = sym_file->symbol_size;
493             lineno_size = sym_file->lineno_size;
494             printf("\t--------symbol file----------- %s\n", file_name);
495             printf("\t\tunknown1:   %08x\n"
496                    "\t\trange\n"
497                    "\t\t\tsegment:         %04x\n"
498                    "\t\t\tpad1:            %04x\n"
499                    "\t\t\toffset:          %08x\n"
500                    "\t\t\tsize:            %08x\n"
501                    "\t\t\tcharacteristics: %08x\n"
502                    "\t\t\tindex:           %04x\n"
503                    "\t\t\tpad2:            %04x\n"
504                    "\t\t\ttimestamp:       %08x\n"
505                    "\t\t\tunknown:         %08x\n"
506                    "\t\tflag:       %04x\n"
507                    "\t\tfile:       %04x\n"
508                    "\t\tsymb size:  %08x\n"
509                    "\t\tline size:  %08x\n"
510                    "\t\tunknown2:   %08x\n"
511                    "\t\tnSrcFiles:  %08x\n"
512                    "\t\tattribute:  %08x\n"
513                    "\t\treserved/0: %08x\n"
514                    "\t\treserved/1: %08x\n",
515                    sym_file->unknown1,
516                    sym_file->range.segment,
517                    sym_file->range.pad1,
518                    sym_file->range.offset,
519                    sym_file->range.size,
520                    sym_file->range.characteristics,
521                    sym_file->range.index,
522                    sym_file->range.pad2,
523                    sym_file->range.timestamp,
524                    sym_file->range.unknown,
525                    sym_file->flag,
526                    sym_file->file,
527                    sym_file->symbol_size,
528                    sym_file->lineno_size,
529                    sym_file->unknown2,
530                    sym_file->nSrcFiles,
531                    sym_file->attribute,
532                    sym_file->reserved[0],
533                    sym_file->reserved[1]);
534         }
535         modimage = reader->read_file(reader, file_nr);
536         if (modimage)
537         {
538             int total_size = pdb_get_file_size(reader, file_nr);
539
540             if (symbol_size)
541                 codeview_dump_symbols((const char*)modimage + sizeof(DWORD), symbol_size);
542
543             /* line number info */
544             if (lineno_size)
545                 codeview_dump_linetab((const char*)modimage + symbol_size, lineno_size, TRUE, "        ");
546             /* anyway, lineno_size doesn't see to really be the size of the line number information, and
547              * it's not clear yet when to call for linetab2...
548              */
549             codeview_dump_linetab2((const char*)modimage + symbol_size + lineno_size,
550                                    total_size - (symbol_size + lineno_size),
551                                    filesimage ? filesimage + 12 : NULL, filessize, "        ");
552             /* what's that part ??? */
553             if (0)
554                 dump_data(modimage + symbol_size + lineno_size, total_size - (symbol_size + lineno_size), "    ");
555             free(modimage);
556         }
557
558         file_name += strlen(file_name) + 1;
559         file = (char*)((DWORD_PTR)(file_name + strlen(file_name) + 1 + 3) & ~3);
560     }
561     free(symbols);
562     free(filesimage);
563 }
564
565 static void pdb_dump_types(struct pdb_reader* reader)
566 {
567     PDB_TYPES*  types = NULL;
568
569     types = reader->read_file(reader, 2);
570
571     switch (types->version)
572     {
573     case 19950410:      /* VC 4.0 */
574     case 19951122:
575     case 19961031:      /* VC 5.0 / 6.0 */
576     case 19990903:      /* VC 7.0 */
577     case 20040203:      /* VC 8.0 */
578         break;
579     default:
580         printf("-Unknown type info version %d\n", types->version);
581     }
582
583     /* Read type table */
584     printf("Types:\n"
585            "\tversion:        %u\n"
586            "\ttype_offset:    %08x\n"
587            "\tfirst_index:    %x\n"
588            "\tlast_index:     %x\n"
589            "\ttype_size:      %x\n"
590            "\tfile:           %x\n"
591            "\tpad:            %x\n"
592            "\thash_size:      %x\n"
593            "\thash_base:      %x\n"
594            "\thash_offset:    %x\n"
595            "\thash_len:       %x\n"
596            "\tsearch_offset:  %x\n"
597            "\tsearch_len:     %x\n"
598            "\tunknown_offset: %x\n"
599            "\tunknown_len:    %x\n",
600            types->version,
601            types->type_offset,
602            types->first_index,
603            types->last_index,
604            types->type_size,
605            types->file,
606            types->pad,
607            types->hash_size,
608            types->hash_base,
609            types->hash_offset,
610            types->hash_len,
611            types->search_offset,
612            types->search_len,
613            types->unknown_offset,
614            types->unknown_len);
615     codeview_dump_types_from_block((const char*)types + types->type_offset, types->type_size);
616     free(types);
617 }
618
619 static void pdb_dump_fpo(struct pdb_reader* reader, unsigned stream_idx)
620 {
621     FPO_DATA*           fpo;
622     unsigned            i, size;
623     const char*         frame_type[4] = {"Fpo", "Trap", "Tss", "NonFpo"};
624
625     if (stream_idx == (WORD)-1) return;
626     fpo = reader->read_file(reader, stream_idx);
627     size = pdb_get_file_size(reader, stream_idx);
628     if (fpo && (size % sizeof(*fpo)) == 0)
629     {
630         size /= sizeof(*fpo);
631         printf("FPO data:\n\t   Start   Length #loc #pmt #prolog #reg frame  SEH /BP\n");
632         for (i = 0; i < size; i++)
633         {
634             printf("\t%08x %08x %4d %4d %7d %4d %6s  %c   %c\n",
635                    fpo[i].ulOffStart, fpo[i].cbProcSize, fpo[i].cdwLocals, fpo[i].cdwParams,
636                    fpo[i].cbProlog, fpo[i].cbRegs, frame_type[fpo[i].cbFrame],
637                    fpo[i].fHasSEH ? 'Y' : 'N', fpo[i].fUseBP ? 'Y' : 'N');
638         }
639     }
640     free(fpo);
641 }
642
643 static void pdb_dump_fpo_ext(struct pdb_reader* reader, unsigned stream_idx)
644 {
645     PDB_FPO_DATA*       fpoext;
646     unsigned            i, size, strsize;
647     char*               strbase;
648
649     if (stream_idx == (WORD)-1) return;
650     strbase = read_string_table(reader);
651     if (!strbase) return;
652
653     strsize = *(const DWORD*)(strbase + 8);
654     fpoext = reader->read_file(reader, stream_idx);
655     size = pdb_get_file_size(reader, stream_idx);
656     if (fpoext && (size % sizeof(*fpoext)) == 0)
657     {
658         size /= sizeof(*fpoext);
659         printf("FPO data (extended):\n"
660                "\t   Start   Length   Locals   Params MaxStack Prolog #SavedRegs    Flags Command\n");
661         for (i = 0; i < size; i++)
662         {
663             printf("\t%08x %08x %8x %8x %8x %6x   %8x %08x %s\n",
664                    fpoext[i].start, fpoext[i].func_size, fpoext[i].locals_size, fpoext[i].params_size,
665                    fpoext[i].maxstack_size, fpoext[i].prolog_size, fpoext[i].savedregs_size, fpoext[i].flags,
666                    fpoext[i].str_offset < strsize ? strbase + 12 + fpoext[i].str_offset : "<out of bounds>");
667         }
668     }
669     free(fpoext);
670     free(strbase);
671 }
672
673 static void pdb_dump_segments(struct pdb_reader* reader, unsigned stream_idx)
674 {
675     const char* segs;
676     DWORD       size;
677     const char* ptr;
678
679     if (stream_idx == (WORD)-1) return;
680     segs = reader->read_file(reader, stream_idx);
681
682     if (segs)
683     {
684         size = pdb_get_file_size(reader, stream_idx);
685         for (ptr = segs; ptr < segs + size; )
686         {
687             printf("Segment %s\n", ptr);
688             ptr += (strlen(ptr) + 1 + 3) & ~3;
689             printf("\tdword[0]: %08x\n", *(DWORD*)ptr); ptr += 4;
690             printf("\tdword[1]: %08x\n", *(DWORD*)ptr); ptr += 4;
691             printf("\tdword[2]: %08x\n", *(DWORD*)ptr); ptr += 4;
692             printf("\tdword[3]: %08x\n", *(DWORD*)ptr); ptr += 4;
693             printf("\tdword[4]: %08x\n", *(DWORD*)ptr); ptr += 4;
694             printf("\tdword[5]: %08x\n", *(DWORD*)ptr); ptr += 4;
695             printf("\tdword[6]: %08x\n", *(DWORD*)ptr); ptr += 4;
696             printf("\tdword[7]: %08x\n", *(DWORD*)ptr); ptr += 4;
697         }
698         free((char*)segs);
699     } else printf("nosdfsdffd\n");
700 }
701
702 static const char       pdb2[] = "Microsoft C/C++ program database 2.00";
703
704 static void pdb_jg_dump(void)
705 {
706     struct pdb_reader   reader;
707
708     /*
709      * Read in TOC and well-known files
710      */
711     pdb_jg_init(&reader);
712     printf("Header (JG):\n"
713            "\tident:      %.*s\n"
714            "\tsignature:  %08x\n"
715            "\tblock_size: %08x\n"
716            "\tfree_list:  %04x\n"
717            "\ttotal_alloc:%04x\n",
718            (int)sizeof(pdb2) - 1, reader.u.jg.header->ident,
719            reader.u.jg.header->signature,
720            reader.u.jg.header->block_size,
721            reader.u.jg.header->free_list,
722            reader.u.jg.header->total_alloc);
723
724     reader.u.jg.root = reader.read_file(&reader, 1);
725     if (reader.u.jg.root)
726     {
727         DWORD*          pdw;
728         DWORD*          ok_bits;
729         DWORD           numok, count;
730         unsigned        i;
731         PDB_STREAM_INDEXES sidx;
732
733         printf("Root:\n"
734                "\tVersion:       %u\n"
735                "\tTimeDateStamp: %08x\n"
736                "\tAge:           %08x\n"
737                "\tnames:         %d\n",
738                reader.u.jg.root->Version,
739                reader.u.jg.root->TimeDateStamp,
740                reader.u.jg.root->Age,
741                (unsigned)reader.u.jg.root->cbNames);
742
743         pdw = (DWORD*)(&reader.u.jg.root->names[0] + reader.u.jg.root->cbNames);
744         numok = *pdw++;
745         count = *pdw++;
746         printf("\tStreams directory:\n"
747                "\t\tok:        %08x\n"
748                "\t\tcount:     %08x\n"
749                "\t\ttable:\n",
750                numok, count);
751
752         /* bitfield: first dword is len (in dword), then data */
753         ok_bits = pdw;
754         pdw += *ok_bits++ + 1;
755         if (*pdw++ != 0)
756         {
757             printf("unexpected value\n");
758             return;
759         }
760
761         for (i = 0; i < count; i++)
762         {
763             if (ok_bits[i / 32] & (1 << (i % 32)))
764             {
765                 DWORD string_idx, stream_idx;
766                 string_idx = *pdw++;
767                 stream_idx = *pdw++;
768                 printf("\t\t\t%2d) %-20s => %x\n", i, &reader.u.jg.root->names[string_idx], stream_idx);
769                 numok--;
770             }
771         }
772         if (numok) printf(">>> unmatched present field with found\n");
773
774         /* Check for unknown versions */
775         switch (reader.u.jg.root->Version)
776         {
777         case 19950623:      /* VC 4.0 */
778         case 19950814:
779         case 19960307:      /* VC 5.0 */
780         case 19970604:      /* VC 6.0 */
781             break;
782         default:
783             printf("-Unknown root block version %d\n", reader.u.jg.root->Version);
784         }
785         pdb_dump_types(&reader);
786         pdb_dump_symbols(&reader, &sidx);
787         pdb_dump_fpo(&reader, sidx.FPO);
788         pdb_dump_segments(&reader, sidx.segments);
789     }
790     else printf("-Unable to get root\n");
791
792     pdb_exit(&reader);
793 }
794
795 static void* pdb_ds_read(const struct PDB_DS_HEADER* header, const DWORD* block_list, int size)
796 {
797     int                 i, nBlocks;
798     BYTE*               buffer;
799
800     if (!size) return NULL;
801
802     nBlocks = (size + header->block_size - 1) / header->block_size;
803     buffer = malloc(nBlocks * header->block_size);
804
805     for (i = 0; i < nBlocks; i++)
806         memcpy(buffer + i * header->block_size,
807                (const char*)header + block_list[i] * header->block_size, header->block_size);
808
809     return buffer;
810 }
811
812 static void* pdb_ds_read_file(struct pdb_reader* reader, DWORD file_number)
813 {
814     const DWORD*        block_list;
815     DWORD               i;
816
817     if (!reader->u.ds.toc || file_number >= reader->u.ds.toc->num_files) return NULL;
818
819     reader->file_used[file_number / 32] |= 1 << (file_number % 32);
820     if (reader->u.ds.toc->file_size[file_number] == 0 ||
821         reader->u.ds.toc->file_size[file_number] == 0xFFFFFFFF)
822         return NULL;
823     block_list = reader->u.ds.toc->file_size + reader->u.ds.toc->num_files;
824     for (i = 0; i < file_number; i++)
825         block_list += (reader->u.ds.toc->file_size[i] + reader->u.ds.header->block_size - 1) /
826             reader->u.ds.header->block_size;
827
828     return pdb_ds_read(reader->u.ds.header, block_list, reader->u.ds.toc->file_size[file_number]);
829 }
830
831 static BOOL pdb_ds_init(struct pdb_reader* reader)
832 {
833     reader->u.ds.header = PRD(0, sizeof(*reader->u.ds.header));
834     if (!reader->u.ds.header) return FALSE;
835     reader->read_file = pdb_ds_read_file;
836     reader->u.ds.toc = pdb_ds_read(reader->u.ds.header, 
837                                    (const DWORD*)((const char*)reader->u.ds.header + reader->u.ds.header->toc_page * reader->u.ds.header->block_size),
838                                    reader->u.ds.header->toc_size);
839     memset(reader->file_used, 0, sizeof(reader->file_used));
840     return TRUE;
841 }
842
843 static const char       pdb7[] = "Microsoft C/C++ MSF 7.00";
844
845 static void pdb_ds_dump(void)
846 {
847     struct pdb_reader   reader;
848
849     pdb_ds_init(&reader);
850     printf("Header (DS)\n"
851            "\tsignature:        %.*s\n"
852            "\tblock_size:       %08x\n"
853            "\tunknown1:         %08x\n"
854            "\tnum_pages:        %08x\n"
855            "\ttoc_size:         %08x\n"
856            "\tunknown2:         %08x\n"
857            "\ttoc_page:         %08x\n",
858            (int)sizeof(pdb7) - 1, reader.u.ds.header->signature,
859            reader.u.ds.header->block_size,
860            reader.u.ds.header->unknown1,
861            reader.u.ds.header->num_pages,
862            reader.u.ds.header->toc_size,
863            reader.u.ds.header->unknown2,
864            reader.u.ds.header->toc_page);
865
866     /* files:
867      *  0: JG says old toc pages, I'd say free pages (tbc, low prio)
868      *  1: root structure
869      *  2: types
870      *  3: modules
871      * other known streams:
872      * - string table: it's index is in the stream table from ROOT object under "/names"
873      * those streams get their indexes out of the PDB_STREAM_INDEXES object
874      * - FPO data
875      * - segments
876      * - extended FPO data
877      */
878     reader.u.ds.root = reader.read_file(&reader, 1);
879     if (reader.u.ds.root)
880     {
881         DWORD*          pdw;
882         DWORD*          ok_bits;
883         DWORD           numok, count;
884         unsigned        i;
885         PDB_STREAM_INDEXES sidx;
886
887         printf("Root:\n"
888                "\tVersion:              %u\n"
889                "\tTimeDateStamp:        %08x\n"
890                "\tAge:                  %08x\n"
891                "\tguid                  %s\n"
892                "\tcbNames:              %08x\n",
893                reader.u.ds.root->Version,
894                reader.u.ds.root->TimeDateStamp,
895                reader.u.ds.root->Age,
896                get_guid_str(&reader.u.ds.root->guid),
897                reader.u.ds.root->cbNames);
898         pdw = (DWORD*)(&reader.u.ds.root->names[0] + reader.u.ds.root->cbNames);
899         numok = *pdw++;
900         count = *pdw++;
901         printf("\tStreams directory:\n"
902                "\t\tok:        %08x\n"
903                "\t\tcount:     %08x\n"
904                "\t\ttable:\n",
905                numok, count);
906
907         /* bitfield: first dword is len (in dword), then data */
908         ok_bits = pdw;
909         pdw += *ok_bits++ + 1;
910         if (*pdw++ != 0)
911         {
912             printf("unexpected value\n");
913             return;
914         }
915
916         for (i = 0; i < count; i++)
917         {
918             if (ok_bits[i / 32] & (1 << (i % 32)))
919             {
920                 DWORD string_idx, stream_idx;
921                 string_idx = *pdw++;
922                 stream_idx = *pdw++;
923                 printf("\t\t\t%2d) %-20s => %x\n", i, &reader.u.ds.root->names[string_idx], stream_idx);
924                 numok--;
925             }
926         }
927         if (numok) printf(">>> unmatched present field with found\n");
928
929         pdb_dump_types(&reader);
930         pdb_dump_symbols(&reader, &sidx);
931         pdb_dump_fpo(&reader, sidx.FPO);
932         pdb_dump_fpo_ext(&reader, sidx.FPO_EXT);
933         pdb_dump_segments(&reader, sidx.segments);
934     }
935     else printf("-Unable to get root\n");
936
937     pdb_exit(&reader);
938 }
939
940 enum FileSig get_kind_pdb(void)
941 {
942     const char* head;
943
944     head = PRD(0, sizeof(pdb2) - 1);
945     if (head && !memcmp(head, pdb2, sizeof(pdb2) - 1))
946         return SIG_PDB;
947     head = PRD(0, sizeof(pdb7) - 1);
948     if (head && !memcmp(head, pdb7, sizeof(pdb7) - 1))
949         return SIG_PDB;
950     return SIG_UNKNOWN;
951 }
952
953 void pdb_dump(void)
954 {
955     const char* head;
956
957 /*    init_types(); */
958     head = PRD(0, sizeof(pdb2) - 1);
959     if (head && !memcmp(head, pdb2, sizeof(pdb2) - 1))
960     {
961         pdb_jg_dump();
962         return;
963     }
964     head = PRD(0, sizeof(pdb7) - 1);
965     if (head && !memcmp(head, pdb7, sizeof(pdb7) - 1))
966     {
967         pdb_ds_dump();
968         return;
969     }
970     printf("Unrecognized header %s\n", head);
971 }