ntdll: Move some duplicated locale definitions to a common header.
[wine.git] / tools / winedump / pdb.c
blob7badc8a32e29b91c70f4b42e73b8635b0b6f1b0c
1 /*
2 * PDB 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"
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <time.h>
27 #include <fcntl.h>
29 #define NONAMELESSUNION
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winedump.h"
34 #include "wine/mscvpdb.h"
36 struct pdb_reader
38 union
40 struct
42 const struct PDB_JG_HEADER* header;
43 const struct PDB_JG_TOC* toc;
44 const struct PDB_JG_ROOT* root;
45 } jg;
46 struct
48 const struct PDB_DS_HEADER* header;
49 const struct PDB_DS_TOC* toc;
50 const struct PDB_DS_ROOT* root;
51 } ds;
52 } u;
53 void* (*read_file)(struct pdb_reader*, DWORD);
54 DWORD file_used[1024];
57 static inline BOOL has_file_been_read(struct pdb_reader* reader, unsigned file_nr)
59 return reader->file_used[file_nr / 32] & (1 << (file_nr % 32));
62 static inline void mark_file_been_read(struct pdb_reader* reader, unsigned file_nr)
64 reader->file_used[file_nr / 32] |= 1 << (file_nr % 32);
67 static inline void clear_file_been_read(struct pdb_reader* reader, unsigned file_nr)
69 reader->file_used[file_nr / 32] &= ~(1 << (file_nr % 32));
72 static void* pdb_jg_read(const struct PDB_JG_HEADER* pdb, const WORD* block_list, int size)
74 int i, nBlocks;
75 BYTE* buffer;
77 if (!size) return NULL;
79 nBlocks = (size + pdb->block_size - 1) / pdb->block_size;
80 buffer = xmalloc(nBlocks * pdb->block_size);
82 for (i = 0; i < nBlocks; i++)
83 memcpy(buffer + i * pdb->block_size,
84 (const char*)pdb + block_list[i] * pdb->block_size, pdb->block_size);
86 return buffer;
89 static void* pdb_jg_read_file(struct pdb_reader* reader, DWORD file_nr)
91 const WORD* block_list;
92 DWORD i;
94 if (!reader->u.jg.toc || file_nr >= reader->u.jg.toc->num_files) return NULL;
96 mark_file_been_read(reader, file_nr);
97 if (reader->u.jg.toc->file[file_nr].size == 0 ||
98 reader->u.jg.toc->file[file_nr].size == 0xFFFFFFFF)
99 return NULL;
100 block_list = (const WORD*) &reader->u.jg.toc->file[reader->u.jg.toc->num_files];
101 for (i = 0; i < file_nr; i++)
102 block_list += (reader->u.jg.toc->file[i].size +
103 reader->u.jg.header->block_size - 1) / reader->u.jg.header->block_size;
105 return pdb_jg_read(reader->u.jg.header, block_list,
106 reader->u.jg.toc->file[file_nr].size);
109 static void pdb_jg_init(struct pdb_reader* reader)
111 reader->u.jg.header = PRD(0, sizeof(struct PDB_JG_HEADER));
112 reader->read_file = pdb_jg_read_file;
113 reader->u.jg.toc = pdb_jg_read(reader->u.jg.header,
114 reader->u.jg.header->toc_block,
115 reader->u.jg.header->toc.size);
116 memset(reader->file_used, 0, sizeof(reader->file_used));
119 static DWORD pdb_get_num_files(const struct pdb_reader* reader)
121 if (reader->read_file == pdb_jg_read_file)
122 return reader->u.jg.toc->num_files;
123 else
124 return reader->u.ds.toc->num_files;
127 static DWORD pdb_get_file_size(const struct pdb_reader* reader, unsigned idx)
129 if (reader->read_file == pdb_jg_read_file)
130 return reader->u.jg.toc->file[idx].size;
131 else
132 return reader->u.ds.toc->file_size[idx];
135 static void pdb_exit(struct pdb_reader* reader)
137 unsigned i;
138 unsigned char* file;
139 DWORD size;
141 for (i = 0; i < pdb_get_num_files(reader); i++)
143 if (has_file_been_read(reader, i)) continue;
145 file = reader->read_file(reader, i);
146 if (!file) continue;
148 size = pdb_get_file_size(reader, i);
150 printf("File --unused-- #%d (%x)\n", i, size);
151 dump_data(file, size, " ");
152 free(file);
155 if (reader->read_file == pdb_jg_read_file)
157 free((char*)reader->u.jg.root);
158 free((char*)reader->u.jg.toc);
160 else
162 free((char*)reader->u.ds.root);
163 free((char*)reader->u.ds.toc);
167 static unsigned get_stream_by_name(struct pdb_reader* reader, const char* name)
169 DWORD* pdw;
170 DWORD* ok_bits;
171 DWORD cbstr, count;
172 DWORD string_idx, stream_idx;
173 unsigned i;
174 const char* str;
176 if (reader->read_file == pdb_jg_read_file)
178 str = reader->u.jg.root->names;
179 cbstr = reader->u.jg.root->cbNames;
181 else
183 str = reader->u.ds.root->names;
184 cbstr = reader->u.ds.root->cbNames;
187 pdw = (DWORD*)(str + cbstr);
188 pdw++; /* number of ok entries */
189 count = *pdw++;
191 /* bitfield: first dword is len (in dword), then data */
192 ok_bits = pdw;
193 pdw += *ok_bits++ + 1;
194 if (*pdw++ != 0)
196 printf("unexpected value\n");
197 return -1;
200 for (i = 0; i < count; i++)
202 if (ok_bits[i / 32] & (1 << (i % 32)))
204 string_idx = *pdw++;
205 stream_idx = *pdw++;
206 if (!strcmp(name, &str[string_idx])) return stream_idx;
209 return -1;
212 static void *read_string_table(struct pdb_reader* reader)
214 unsigned stream_idx;
215 void* ret;
217 stream_idx = get_stream_by_name(reader, "/names");
218 if (stream_idx == -1) return NULL;
219 ret = reader->read_file(reader, stream_idx);
220 if (!ret) return NULL;
221 if(*(const DWORD*)ret == 0xeffeeffe) return ret;
222 printf("wrong header %x expecting 0xeffeeffe\n", *(const DWORD*)ret);
223 free( ret );
224 return NULL;
227 static void dump_global_symbol(struct pdb_reader* reader, unsigned file)
229 void* global = NULL;
230 DWORD size;
232 global = reader->read_file(reader, file);
233 if (!global) return;
235 size = pdb_get_file_size(reader, file);
237 printf("Global symbols table:\n");
238 dump_data(global, size, "\t");
239 free(global);
242 static void dump_public_symbol(struct pdb_reader* reader, unsigned file)
244 void* public = NULL;
245 DWORD size;
247 public = reader->read_file(reader, file);
248 if (!public) return;
250 size = pdb_get_file_size(reader, file);
252 printf("Public symbols table:\n");
253 dump_data(public, size, "\t");
254 free(public);
257 static void pdb_dump_symbols(struct pdb_reader* reader, PDB_STREAM_INDEXES* sidx)
259 PDB_SYMBOLS* symbols;
260 unsigned char* modimage;
261 const char* file;
262 char* filesimage;
263 DWORD filessize = 0;
264 char tcver[32];
266 sidx->FPO = sidx->unk0 = sidx->unk1 = sidx->unk2 = sidx->unk3 = sidx->segments =
267 sidx->unk4 = sidx->unk5 = sidx->unk6 = sidx->FPO_EXT = sidx->unk7 = -1;
269 symbols = reader->read_file(reader, 3);
270 if (!symbols) return;
272 switch (symbols->version)
274 case 0: /* VC 4.0 */
275 case 19960307: /* VC 5.0 */
276 case 19970606: /* VC 6.0 */
277 case 19990903: /* VC 7.0 */
278 break;
279 default:
280 printf("-Unknown symbol info version %d\n", symbols->version);
282 if (symbols->flags & 0x8000) /* new */
283 sprintf(tcver, "%u.%u", (symbols->flags >> 8) & 0x7f, symbols->flags & 0xff);
284 else
285 sprintf(tcver, "old-%x", symbols->flags);
286 printf("Symbols:\n"
287 "\tsignature: %08x\n"
288 "\tversion: %u\n"
289 "\tage: %08x\n"
290 "\tglobal_file: %u\n"
291 "\tbuilder: %s\n"
292 "\tpublic_file: %u\n"
293 "\tbldVer: %u\n"
294 "\tgsym_file: %u\n"
295 "\trbldVer: %u\n"
296 "\tmodule_size: %08x\n"
297 "\toffset_size: %08x\n"
298 "\thash_size: %08x\n"
299 "\tsrc_module_size: %08x\n"
300 "\tpdbimport_size: %08x\n"
301 "\tresvd0: %08x\n"
302 "\tstream_idx_size: %08x\n"
303 "\tunknown2_size: %08x\n"
304 "\tresvd3: %04x\n"
305 "\tmachine: %s\n"
306 "\tresvd4 %08x\n",
307 symbols->signature,
308 symbols->version,
309 symbols->age,
310 symbols->global_file,
311 tcver, /* from symbols->flags */
312 symbols->public_file,
313 symbols->bldVer,
314 symbols->gsym_file,
315 symbols->rbldVer,
316 symbols->module_size,
317 symbols->offset_size,
318 symbols->hash_size,
319 symbols->srcmodule_size,
320 symbols->pdbimport_size,
321 symbols->resvd0,
322 symbols->stream_index_size,
323 symbols->unknown2_size,
324 symbols->resvd3,
325 get_machine_str( symbols->machine ),
326 symbols->resvd4);
328 if (symbols->offset_size)
330 const BYTE* src;
332 printf("\t----------offsets------------\n");
333 src = (const BYTE*)((const char*)symbols + sizeof(PDB_SYMBOLS) + symbols->module_size);
334 dump_data(src, symbols->offset_size, " ");
337 if (!(filesimage = read_string_table(reader))) printf("string table not found\n");
338 else filessize = *(const DWORD*)(filesimage + 8);
340 if (symbols->srcmodule_size)
342 const PDB_SYMBOL_SOURCE*src;
343 int i, j, cfile;
344 const WORD* indx;
345 const DWORD* offset;
346 const char* start_cstr;
347 const char* cstr;
349 printf("\t----------src module------------\n");
350 src = (const PDB_SYMBOL_SOURCE*)((const char*)symbols + sizeof(PDB_SYMBOLS) +
351 symbols->module_size + symbols->offset_size + symbols->hash_size);
352 printf("\tSource Modules\n"
353 "\t\tnModules: %u\n"
354 "\t\tnSrcFiles: %u\n",
355 src->nModules, src->nSrcFiles);
357 /* usage of table seems to be as follows:
358 * two arrays of WORD (src->nModules as size)
359 * - first array contains index into files for "module" compilation
360 * (module = compilation unit ??)
361 * - second array contains the number of source files in module
362 * an array of DWORD (src->nSrcFiles as size)
363 * - contains offset (in following string table) of the source file name
364 * a string table
365 * - each string is a pascal string (ie. with its length as first BYTE) or
366 * 0-terminated string (depending on version)
368 indx = &src->table[src->nModules];
369 offset = (const DWORD*)&src->table[2 * src->nModules];
370 cstr = (const char*)&src->table[2 * (src->nModules + src->nSrcFiles)];
371 start_cstr = cstr;
373 for (i = cfile = 0; i < src->nModules; i++)
375 printf("\t\tModule[%2d]:\n", i);
376 cfile = src->table[i];
377 for (j = cfile; j < src->nSrcFiles && j < cfile + indx[i]; j++)
379 /* FIXME: in some cases, it's a p_string but WHEN ? */
380 if (cstr + offset[j] >= start_cstr /* wrap around */ &&
381 cstr + offset[j] < (const char*)src + symbols->srcmodule_size)
382 printf("\t\t\tSource file: %s\n", cstr + offset[j]);
383 else
384 printf("\t\t\tSource file: <<out of bounds>>\n");
388 if (symbols->pdbimport_size)
390 const PDB_SYMBOL_IMPORT* imp;
391 const char* first;
392 const char* last;
393 const char* ptr;
395 printf("\t------------import--------------\n");
396 imp = (const PDB_SYMBOL_IMPORT*)((const char*)symbols + sizeof(PDB_SYMBOLS) +
397 symbols->module_size + symbols->offset_size +
398 symbols->hash_size + symbols->srcmodule_size);
399 first = (const char*)imp;
400 last = (const char*)imp + symbols->pdbimport_size;
401 while (imp < (const PDB_SYMBOL_IMPORT*)last)
403 ptr = (const char*)imp + sizeof(*imp) + strlen(imp->filename);
404 printf("\tImport: %lx\n"
405 "\t\tUnknown1: %08x\n"
406 "\t\tUnknown2: %08x\n"
407 "\t\tTimeDateStamp: %08x\n"
408 "\t\tAge: %08u\n"
409 "\t\tfile1: %s\n"
410 "\t\tfile2: %s\n",
411 (ULONG_PTR)((const char*)imp - first),
412 imp->unknown1,
413 imp->unknown2,
414 imp->TimeDateStamp,
415 imp->Age,
416 imp->filename,
417 ptr);
418 imp = (const PDB_SYMBOL_IMPORT*)(first + ((ptr - first + strlen(ptr) + 1 + 3) & ~3));
421 if (symbols->stream_index_size)
423 printf("\t------------stream indexes--------------\n");
424 switch (symbols->stream_index_size)
426 case sizeof(PDB_STREAM_INDEXES_OLD):
427 /* PDB_STREAM_INDEXES is a superset of PDB_STREAM_INDEX_OLD
428 * FIXME: to be confirmed when all fields are fully understood
430 memcpy(sidx,
431 (const char*)symbols + sizeof(PDB_SYMBOLS) + symbols->module_size +
432 symbols->offset_size + symbols->hash_size + symbols->srcmodule_size +
433 symbols->pdbimport_size + symbols->unknown2_size,
434 sizeof(PDB_STREAM_INDEXES_OLD));
435 printf("\tFPO: %04x\n"
436 "\t?: %04x\n"
437 "\t?: %04x\n"
438 "\t?: %04x\n"
439 "\t?: %04x\n"
440 "\tSegments: %04x\n",
441 sidx->FPO, sidx->unk0, sidx->unk1, sidx->unk2, sidx->unk3,
442 sidx->segments);
443 break;
444 case sizeof(PDB_STREAM_INDEXES):
445 memcpy(sidx,
446 (const char*)symbols + sizeof(PDB_SYMBOLS) + symbols->module_size +
447 symbols->offset_size + symbols->hash_size + symbols->srcmodule_size +
448 symbols->pdbimport_size + symbols->unknown2_size,
449 sizeof(*sidx));
450 printf("\tFPO: %04x\n"
451 "\t?: %04x\n"
452 "\t?: %04x\n"
453 "\t?: %04x\n"
454 "\t?: %04x\n"
455 "\tSegments: %04x\n"
456 "\t?: %04x\n"
457 "\t?: %04x\n"
458 "\t?: %04x\n"
459 "\tFPO-ext: %04x\n"
460 "\t?: %04x\n",
461 sidx->FPO, sidx->unk0, sidx->unk1, sidx->unk2, sidx->unk3,
462 sidx->segments, sidx->unk4, sidx->unk5, sidx->unk6, sidx->FPO_EXT,
463 sidx->unk7);
464 break;
465 default:
466 printf("unexpected size for stream index %d\n", symbols->stream_index_size);
467 break;
471 /* Read global symbol table */
472 modimage = reader->read_file(reader, symbols->gsym_file);
473 if (modimage)
475 printf("\t------------globals-------------\n");
476 codeview_dump_symbols(modimage, 0, pdb_get_file_size(reader, symbols->gsym_file));
477 free(modimage);
480 /* Read per-module symbol / linenumber tables */
481 file = (const char*)symbols + sizeof(PDB_SYMBOLS);
482 while (file - (const char*)symbols < sizeof(PDB_SYMBOLS) + symbols->module_size)
484 int file_nr, symbol_size, lineno_size, lineno2_size;
485 const char* file_name;
486 const char* lib_name;
488 if (symbols->version < 19970000)
490 const PDB_SYMBOL_FILE* sym_file = (const PDB_SYMBOL_FILE*) file;
491 file_nr = sym_file->file;
492 file_name = sym_file->filename;
493 lib_name = file_name + strlen(file_name) + 1;
494 symbol_size = sym_file->symbol_size;
495 lineno_size = sym_file->lineno_size;
496 lineno2_size = sym_file->lineno2_size;
497 printf("\t--------symbol file-----------\n");
498 printf("\tName: %s\n", file_name);
499 if (strcmp(file_name, lib_name)) printf("\tLibrary: %s\n", lib_name);
500 printf("\t\tunknown1: %08x\n"
501 "\t\trange\n"
502 "\t\t\tsegment: %04x\n"
503 "\t\t\tpad1: %04x\n"
504 "\t\t\toffset: %08x\n"
505 "\t\t\tsize: %08x\n"
506 "\t\t\tcharacteristics: %08x\n"
507 "\t\t\tindex: %04x\n"
508 "\t\t\tpad2: %04x\n"
509 "\t\tflag: %04x\n"
510 "\t\tfile: %04x\n"
511 "\t\tsymb size: %08x\n"
512 "\t\tline size: %08x\n"
513 "\t\tline2 size: %08x\n"
514 "\t\tnSrcFiles: %08x\n"
515 "\t\tattribute: %08x\n",
516 sym_file->unknown1,
517 sym_file->range.segment,
518 sym_file->range.pad1,
519 sym_file->range.offset,
520 sym_file->range.size,
521 sym_file->range.characteristics,
522 sym_file->range.index,
523 sym_file->range.pad2,
524 sym_file->flag,
525 sym_file->file,
526 sym_file->symbol_size,
527 sym_file->lineno_size,
528 sym_file->lineno2_size,
529 sym_file->nSrcFiles,
530 sym_file->attribute);
532 else
534 const PDB_SYMBOL_FILE_EX* sym_file = (const PDB_SYMBOL_FILE_EX*) file;
536 file_nr = sym_file->file;
537 file_name = sym_file->filename;
538 lib_name = file_name + strlen(file_name) + 1;
539 symbol_size = sym_file->symbol_size;
540 lineno_size = sym_file->lineno_size;
541 lineno2_size = sym_file->lineno2_size;
542 printf("\t--------symbol file-----------\n");
543 printf("\tName: %s\n", file_name);
544 if (strcmp(file_name, lib_name)) printf("\tLibrary: %s\n", lib_name);
545 printf("\t\tunknown1: %08x\n"
546 "\t\trange\n"
547 "\t\t\tsegment: %04x\n"
548 "\t\t\tpad1: %04x\n"
549 "\t\t\toffset: %08x\n"
550 "\t\t\tsize: %08x\n"
551 "\t\t\tcharacteristics: %08x\n"
552 "\t\t\tindex: %04x\n"
553 "\t\t\tpad2: %04x\n"
554 "\t\t\ttimestamp: %08x\n"
555 "\t\t\tunknown: %08x\n"
556 "\t\tflag: %04x\n"
557 "\t\tfile: %04x\n"
558 "\t\tsymb size: %08x\n"
559 "\t\tline size: %08x\n"
560 "\t\tline2 size: %08x\n"
561 "\t\tnSrcFiles: %08x\n"
562 "\t\tattribute: %08x\n"
563 "\t\treserved/0: %08x\n"
564 "\t\treserved/1: %08x\n",
565 sym_file->unknown1,
566 sym_file->range.segment,
567 sym_file->range.pad1,
568 sym_file->range.offset,
569 sym_file->range.size,
570 sym_file->range.characteristics,
571 sym_file->range.index,
572 sym_file->range.pad2,
573 sym_file->range.timestamp,
574 sym_file->range.unknown,
575 sym_file->flag,
576 sym_file->file,
577 sym_file->symbol_size,
578 sym_file->lineno_size,
579 sym_file->lineno2_size,
580 sym_file->nSrcFiles,
581 sym_file->attribute,
582 sym_file->reserved[0],
583 sym_file->reserved[1]);
585 modimage = reader->read_file(reader, file_nr);
586 if (modimage)
588 int total_size = pdb_get_file_size(reader, file_nr);
590 if (symbol_size)
591 codeview_dump_symbols((const char*)modimage, sizeof(DWORD), symbol_size);
593 /* line number info */
594 if (lineno_size)
595 codeview_dump_linetab((const char*)modimage + symbol_size, TRUE, " ");
596 else if (lineno2_size) /* actually, only one of the 2 lineno should be present */
597 codeview_dump_linetab2((const char*)modimage + symbol_size, lineno2_size,
598 filesimage ? filesimage + 12 : NULL, filessize, " ");
599 /* what's that part ??? */
600 if (0)
601 dump_data(modimage + symbol_size + lineno_size + lineno2_size,
602 total_size - (symbol_size + lineno_size + lineno2_size), " ");
603 free(modimage);
606 file = (char*)((DWORD_PTR)(lib_name + strlen(lib_name) + 1 + 3) & ~3);
608 dump_global_symbol(reader, symbols->global_file);
609 dump_public_symbol(reader, symbols->public_file);
610 free(symbols);
611 free(filesimage);
614 static void pdb_dump_types_hash(struct pdb_reader* reader, unsigned file, const char* strmname)
616 void* hash = NULL;
617 DWORD size;
619 hash = reader->read_file(reader, file);
620 if (!hash) return;
622 size = pdb_get_file_size(reader, file);
624 printf("Types (%s) hash:\n", strmname);
625 dump_data(hash, size, " ");
626 free(hash);
629 /* there are two 'type' related streams, but with different indexes... */
630 static void pdb_dump_types(struct pdb_reader* reader, unsigned strmidx, const char* strmname)
632 PDB_TYPES* types = NULL;
633 BOOL used = has_file_been_read(reader, strmidx);
635 if (pdb_get_file_size(reader, strmidx) < sizeof(*types))
637 if (strmidx == 2)
638 printf("-Too small type header\n");
639 return;
641 types = reader->read_file(reader, strmidx);
642 if (!types) return;
644 switch (types->version)
646 case 19950410: /* VC 4.0 */
647 case 19951122:
648 case 19961031: /* VC 5.0 / 6.0 */
649 case 19990903: /* VC 7.0 */
650 case 20040203: /* VC 8.0 */
651 break;
652 default:
653 /* IPI stream is not always present in older PDB files */
654 if (strmidx == 2)
655 printf("-Unknown type info version %d\n", types->version);
656 free(types);
657 if (used) clear_file_been_read(reader, strmidx);
658 return;
661 /* Read type table */
662 printf("Types (%s):\n"
663 "\tversion: %u\n"
664 "\ttype_offset: %08x\n"
665 "\tfirst_index: %x\n"
666 "\tlast_index: %x\n"
667 "\ttype_size: %x\n"
668 "\tfile: %x\n"
669 "\tpad: %x\n"
670 "\thash_size: %x\n"
671 "\thash_base: %x\n"
672 "\thash_offset: %x\n"
673 "\thash_len: %x\n"
674 "\tsearch_offset: %x\n"
675 "\tsearch_len: %x\n"
676 "\tunknown_offset: %x\n"
677 "\tunknown_len: %x\n",
678 strmname,
679 types->version,
680 types->type_offset,
681 types->first_index,
682 types->last_index,
683 types->type_size,
684 types->file,
685 types->pad,
686 types->hash_size,
687 types->hash_base,
688 types->hash_offset,
689 types->hash_len,
690 types->search_offset,
691 types->search_len,
692 types->unknown_offset,
693 types->unknown_len);
694 codeview_dump_types_from_block((const char*)types + types->type_offset, types->type_size);
695 pdb_dump_types_hash(reader, types->file, strmname);
696 free(types);
699 static void pdb_dump_fpo(struct pdb_reader* reader, unsigned stream_idx)
701 FPO_DATA* fpo;
702 unsigned i, size;
703 const char* frame_type[4] = {"Fpo", "Trap", "Tss", "NonFpo"};
705 if (stream_idx == (WORD)-1) return;
706 fpo = reader->read_file(reader, stream_idx);
707 size = pdb_get_file_size(reader, stream_idx);
708 if (fpo && (size % sizeof(*fpo)) == 0)
710 size /= sizeof(*fpo);
711 printf("FPO data:\n\t Start Length #loc #pmt #prolog #reg frame SEH /BP\n");
712 for (i = 0; i < size; i++)
714 printf("\t%08x %08x %4d %4d %7d %4d %6s %c %c\n",
715 fpo[i].ulOffStart, fpo[i].cbProcSize, fpo[i].cdwLocals, fpo[i].cdwParams,
716 fpo[i].cbProlog, fpo[i].cbRegs, frame_type[fpo[i].cbFrame],
717 fpo[i].fHasSEH ? 'Y' : 'N', fpo[i].fUseBP ? 'Y' : 'N');
720 free(fpo);
723 static void pdb_dump_fpo_ext(struct pdb_reader* reader, unsigned stream_idx)
725 PDB_FPO_DATA* fpoext;
726 unsigned i, size, strsize;
727 char* strbase;
729 if (stream_idx == (WORD)-1) return;
730 strbase = read_string_table(reader);
731 if (!strbase) return;
733 strsize = *(const DWORD*)(strbase + 8);
734 fpoext = reader->read_file(reader, stream_idx);
735 size = pdb_get_file_size(reader, stream_idx);
736 if (fpoext && (size % sizeof(*fpoext)) == 0)
738 size /= sizeof(*fpoext);
739 printf("FPO data (extended):\n"
740 "\t Start Length Locals Params MaxStack Prolog #SavedRegs Flags Command\n");
741 for (i = 0; i < size; i++)
743 printf("\t%08x %08x %8x %8x %8x %6x %8x %08x %s\n",
744 fpoext[i].start, fpoext[i].func_size, fpoext[i].locals_size, fpoext[i].params_size,
745 fpoext[i].maxstack_size, fpoext[i].prolog_size, fpoext[i].savedregs_size, fpoext[i].flags,
746 fpoext[i].str_offset < strsize ? strbase + 12 + fpoext[i].str_offset : "<out of bounds>");
749 free(fpoext);
750 free(strbase);
753 static void pdb_dump_segments(struct pdb_reader* reader, unsigned stream_idx)
755 const char* segs;
756 DWORD size;
757 const char* ptr;
759 if (stream_idx == (WORD)-1) return;
760 segs = reader->read_file(reader, stream_idx);
762 if (segs)
764 size = pdb_get_file_size(reader, stream_idx);
765 for (ptr = segs; ptr < segs + size; )
767 printf("Segment %s\n", ptr);
768 ptr += (strlen(ptr) + 1 + 3) & ~3;
769 printf("\tdword[0]: %08x\n", *(DWORD*)ptr); ptr += 4;
770 printf("\tdword[1]: %08x\n", *(DWORD*)ptr); ptr += 4;
771 printf("\tdword[2]: %08x\n", *(DWORD*)ptr); ptr += 4;
772 printf("\tdword[3]: %08x\n", *(DWORD*)ptr); ptr += 4;
773 printf("\tdword[4]: %08x\n", *(DWORD*)ptr); ptr += 4;
774 printf("\tdword[5]: %08x\n", *(DWORD*)ptr); ptr += 4;
775 printf("\tdword[6]: %08x\n", *(DWORD*)ptr); ptr += 4;
776 printf("\tdword[7]: %08x\n", *(DWORD*)ptr); ptr += 4;
778 free((char*)segs);
779 } else printf("nosdfsdffd\n");
782 static const char pdb2[] = "Microsoft C/C++ program database 2.00";
784 static void pdb_jg_dump(void)
786 struct pdb_reader reader;
789 * Read in TOC and well-known files
791 pdb_jg_init(&reader);
792 printf("Header (JG):\n"
793 "\tident: %.*s\n"
794 "\tsignature: %08x\n"
795 "\tblock_size: %08x\n"
796 "\tfree_list: %04x\n"
797 "\ttotal_alloc:%04x\n",
798 (int)sizeof(pdb2) - 1, reader.u.jg.header->ident,
799 reader.u.jg.header->signature,
800 reader.u.jg.header->block_size,
801 reader.u.jg.header->free_list,
802 reader.u.jg.header->total_alloc);
804 reader.u.jg.root = reader.read_file(&reader, 1);
805 if (reader.u.jg.root)
807 DWORD* pdw;
808 DWORD* ok_bits;
809 DWORD numok, count;
810 unsigned i;
811 PDB_STREAM_INDEXES sidx;
813 printf("Root:\n"
814 "\tVersion: %u\n"
815 "\tTimeDateStamp: %08x\n"
816 "\tAge: %08x\n"
817 "\tnames: %d\n",
818 reader.u.jg.root->Version,
819 reader.u.jg.root->TimeDateStamp,
820 reader.u.jg.root->Age,
821 (unsigned)reader.u.jg.root->cbNames);
823 pdw = (DWORD*)(reader.u.jg.root->names + reader.u.jg.root->cbNames);
824 numok = *pdw++;
825 count = *pdw++;
826 printf("\tStreams directory:\n"
827 "\t\tok: %08x\n"
828 "\t\tcount: %08x\n"
829 "\t\ttable:\n",
830 numok, count);
832 /* bitfield: first dword is len (in dword), then data */
833 ok_bits = pdw;
834 pdw += *ok_bits++ + 1;
835 if (*pdw++ != 0)
837 printf("unexpected value\n");
838 return;
841 for (i = 0; i < count; i++)
843 if (ok_bits[i / 32] & (1 << (i % 32)))
845 DWORD string_idx, stream_idx;
846 string_idx = *pdw++;
847 stream_idx = *pdw++;
848 printf("\t\t\t%2d) %-20s => %x\n", i, &reader.u.jg.root->names[string_idx], stream_idx);
849 numok--;
852 if (numok) printf(">>> unmatched present field with found\n");
854 /* Check for unknown versions */
855 switch (reader.u.jg.root->Version)
857 case 19950623: /* VC 4.0 */
858 case 19950814:
859 case 19960307: /* VC 5.0 */
860 case 19970604: /* VC 6.0 */
861 break;
862 default:
863 printf("-Unknown root block version %d\n", reader.u.jg.root->Version);
865 pdb_dump_types(&reader, 2, "TPI");
866 pdb_dump_types(&reader, 4, "IPI");
867 pdb_dump_symbols(&reader, &sidx);
868 pdb_dump_fpo(&reader, sidx.FPO);
869 pdb_dump_segments(&reader, sidx.segments);
871 else printf("-Unable to get root\n");
873 pdb_exit(&reader);
876 static void* pdb_ds_read(const struct PDB_DS_HEADER* header, const DWORD* block_list, int size)
878 int i, nBlocks;
879 BYTE* buffer;
881 if (!size) return NULL;
883 nBlocks = (size + header->block_size - 1) / header->block_size;
884 buffer = xmalloc(nBlocks * header->block_size);
886 for (i = 0; i < nBlocks; i++)
887 memcpy(buffer + i * header->block_size,
888 (const char*)header + block_list[i] * header->block_size, header->block_size);
890 return buffer;
893 static void* pdb_ds_read_file(struct pdb_reader* reader, DWORD file_number)
895 const DWORD* block_list;
896 DWORD i;
898 if (!reader->u.ds.toc || file_number >= reader->u.ds.toc->num_files) return NULL;
900 mark_file_been_read(reader, file_number);
901 if (reader->u.ds.toc->file_size[file_number] == 0 ||
902 reader->u.ds.toc->file_size[file_number] == 0xFFFFFFFF)
903 return NULL;
904 block_list = reader->u.ds.toc->file_size + reader->u.ds.toc->num_files;
905 for (i = 0; i < file_number; i++)
906 block_list += (reader->u.ds.toc->file_size[i] + reader->u.ds.header->block_size - 1) /
907 reader->u.ds.header->block_size;
909 return pdb_ds_read(reader->u.ds.header, block_list, reader->u.ds.toc->file_size[file_number]);
912 static BOOL pdb_ds_init(struct pdb_reader* reader)
914 reader->u.ds.header = PRD(0, sizeof(*reader->u.ds.header));
915 if (!reader->u.ds.header) return FALSE;
916 reader->read_file = pdb_ds_read_file;
917 reader->u.ds.toc = pdb_ds_read(reader->u.ds.header,
918 (const DWORD*)((const char*)reader->u.ds.header + reader->u.ds.header->toc_page * reader->u.ds.header->block_size),
919 reader->u.ds.header->toc_size);
920 memset(reader->file_used, 0, sizeof(reader->file_used));
921 return TRUE;
924 static const char pdb7[] = "Microsoft C/C++ MSF 7.00";
926 static void pdb_ds_dump(void)
928 struct pdb_reader reader;
930 pdb_ds_init(&reader);
931 printf("Header (DS)\n"
932 "\tsignature: %.*s\n"
933 "\tblock_size: %08x\n"
934 "\tunknown1: %08x\n"
935 "\tnum_pages: %08x\n"
936 "\ttoc_size: %08x\n"
937 "\tunknown2: %08x\n"
938 "\ttoc_page: %08x\n",
939 (int)sizeof(pdb7) - 1, reader.u.ds.header->signature,
940 reader.u.ds.header->block_size,
941 reader.u.ds.header->unknown1,
942 reader.u.ds.header->num_pages,
943 reader.u.ds.header->toc_size,
944 reader.u.ds.header->unknown2,
945 reader.u.ds.header->toc_page);
947 /* files with static indexes:
948 * 0: JG says old toc pages
949 * 1: root structure
950 * 2: types
951 * 3: modules
952 * 4: types (second stream)
953 * other known streams:
954 * - string table: its index is in the stream table from ROOT object under "/names"
955 * - type hash table: its index is in the types header (2 and 4)
956 * - global and public streams: from symbol stream header
957 * those streams get their indexes out of the PDB_STREAM_INDEXES object
958 * - FPO data
959 * - segments
960 * - extended FPO data
962 mark_file_been_read(&reader, 0); /* mark stream #0 as read */
963 reader.u.ds.root = reader.read_file(&reader, 1);
964 if (reader.u.ds.root)
966 DWORD* pdw;
967 DWORD* ok_bits;
968 DWORD numok, count;
969 unsigned i;
970 PDB_STREAM_INDEXES sidx;
972 printf("Root:\n"
973 "\tVersion: %u\n"
974 "\tTimeDateStamp: %08x\n"
975 "\tAge: %08x\n"
976 "\tguid %s\n"
977 "\tcbNames: %08x\n",
978 reader.u.ds.root->Version,
979 reader.u.ds.root->TimeDateStamp,
980 reader.u.ds.root->Age,
981 get_guid_str(&reader.u.ds.root->guid),
982 reader.u.ds.root->cbNames);
983 pdw = (DWORD*)(reader.u.ds.root->names + reader.u.ds.root->cbNames);
984 numok = *pdw++;
985 count = *pdw++;
986 printf("\tStreams directory:\n"
987 "\t\tok: %08x\n"
988 "\t\tcount: %08x\n"
989 "\t\ttable:\n",
990 numok, count);
992 /* bitfield: first dword is len (in dword), then data */
993 ok_bits = pdw;
994 pdw += *ok_bits++ + 1;
995 if (*pdw++ != 0)
997 printf("unexpected value\n");
998 return;
1001 for (i = 0; i < count; i++)
1003 if (ok_bits[i / 32] & (1 << (i % 32)))
1005 DWORD string_idx, stream_idx;
1006 string_idx = *pdw++;
1007 stream_idx = *pdw++;
1008 printf("\t\t\t%2d) %-20s => %x\n", i, &reader.u.ds.root->names[string_idx], stream_idx);
1009 numok--;
1012 if (numok) printf(">>> unmatched present field with found\n");
1014 pdb_dump_types(&reader, 2, "TPI");
1015 pdb_dump_types(&reader, 4, "IPI");
1016 pdb_dump_symbols(&reader, &sidx);
1017 pdb_dump_fpo(&reader, sidx.FPO);
1018 pdb_dump_fpo_ext(&reader, sidx.FPO_EXT);
1019 pdb_dump_segments(&reader, sidx.segments);
1021 else printf("-Unable to get root\n");
1023 pdb_exit(&reader);
1026 enum FileSig get_kind_pdb(void)
1028 const char* head;
1030 head = PRD(0, sizeof(pdb2) - 1);
1031 if (head && !memcmp(head, pdb2, sizeof(pdb2) - 1))
1032 return SIG_PDB;
1033 head = PRD(0, sizeof(pdb7) - 1);
1034 if (head && !memcmp(head, pdb7, sizeof(pdb7) - 1))
1035 return SIG_PDB;
1036 return SIG_UNKNOWN;
1039 void pdb_dump(void)
1041 const char* head;
1043 /* init_types(); */
1044 head = PRD(0, sizeof(pdb2) - 1);
1045 if (head && !memcmp(head, pdb2, sizeof(pdb2) - 1))
1047 pdb_jg_dump();
1048 return;
1050 head = PRD(0, sizeof(pdb7) - 1);
1051 if (head && !memcmp(head, pdb7, sizeof(pdb7) - 1))
1053 pdb_ds_dump();
1054 return;
1056 printf("Unrecognized header %s\n", head);