blob: 8b63e9562e65ceaa9e8fa8e7ced80a0f39816c63 [file] [log] [blame]
sewardjc8259b82009-04-22 22:42:10 +00001
2/*--------------------------------------------------------------------*/
3/*--- Reading of syms & debug info from PDB-format files. ---*/
4/*--- readpdb.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
10 Spring 2008:
11 derived from readelf.c and valgrind-20031012-wine/vg_symtab2.c
12 derived from wine-1.0/tools/winedump/pdb.c and msc.c
13
sewardjb3a1e4b2015-08-21 11:32:26 +000014 Copyright (C) 2000-2015 Julian Seward
sewardjc8259b82009-04-22 22:42:10 +000015 jseward@acm.org
16 Copyright 2006 Eric Pouech (winedump/pdb.c and msc.c)
17 GNU Lesser General Public License version 2.1 or later applies.
18 Copyright (C) 2008 BitWagon Software LLC
19
20 This program is free software; you can redistribute it and/or
21 modify it under the terms of the GNU General Public License as
22 published by the Free Software Foundation; either version 2 of the
23 License, or (at your option) any later version.
24
25 This program is distributed in the hope that it will be useful, but
26 WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 General Public License for more details.
29
30 You should have received a copy of the GNU General Public License
31 along with this program; if not, write to the Free Software
32 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
33 02111-1307, USA.
34
35 The GNU General Public License is contained in the file COPYING.
36*/
37
sewardj8eb8bab2015-07-21 14:44:28 +000038#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
njn8b68b642009-06-24 00:37:09 +000039
sewardjc8259b82009-04-22 22:42:10 +000040#include "pub_core_basics.h"
41#include "pub_core_debuginfo.h"
42#include "pub_core_vki.h" // VKI_PAGE_SIZE
43#include "pub_core_libcbase.h"
44#include "pub_core_libcassert.h"
sewardj13ac96d2010-02-12 12:12:39 +000045#include "pub_core_libcfile.h" // VG_(open), read, lseek, close
sewardjc8259b82009-04-22 22:42:10 +000046#include "pub_core_libcprint.h"
sewardj13ac96d2010-02-12 12:12:39 +000047#include "pub_core_libcproc.h" // VG_(getpid), system
sewardjc8259b82009-04-22 22:42:10 +000048#include "pub_core_options.h" // VG_(clo_verbosity)
49#include "pub_core_xarray.h" // keeps priv_storage.h happy
50#include "pub_core_redir.h"
51
52#include "priv_misc.h" /* dinfo_zalloc/free/strdup */
sewardj5d616df2013-07-02 08:07:15 +000053#include "priv_image.h"
sewardjc8259b82009-04-22 22:42:10 +000054#include "priv_d3basics.h"
55#include "priv_storage.h"
56#include "priv_readpdb.h" // self
57
58
59/*------------------------------------------------------------*/
60/*--- ---*/
61/*--- Biasing ---*/
62/*--- ---*/
63/*------------------------------------------------------------*/
64
sewardj54c45db2012-07-13 12:58:55 +000065/* There are just two simple ways of biasing in use here.
sewardjc8259b82009-04-22 22:42:10 +000066
sewardj54c45db2012-07-13 12:58:55 +000067 The CodeView debug info entries contain virtual addresses
68 relative to segment (here it is one PE section), which in
69 turn specifies its start as a VA relative to "image base".
sewardjc8259b82009-04-22 22:42:10 +000070
sewardj54c45db2012-07-13 12:58:55 +000071 The second type of debug info (FPOs) contain VAs relative
72 directly to the image base, without the segment indirection.
sewardjc8259b82009-04-22 22:42:10 +000073
sewardj54c45db2012-07-13 12:58:55 +000074 The original/preferred image base is set in the PE header,
75 but it can change as long as the file contains relocation
76 data. So everything is biased using the current image base,
77 which is the base AVMA passed by Wine.
sewardjc8259b82009-04-22 22:42:10 +000078
sewardj54c45db2012-07-13 12:58:55 +000079 The difference between the original image base and current
80 image base, which is what Wine sends here in the last
81 argument of VG_(di_notify_pdb_debuginfo), is not used.
sewardj6560f212010-01-30 13:36:37 +000082*/
sewardjc8259b82009-04-22 22:42:10 +000083
84/* This module leaks space; enable m_main's calling of
85 VG_(di_discard_ALL_debuginfo)() at shutdown and run with
86 --profile-heap=yes to see. The main culprit appears to be
87 di.readpe.pdr.1. I haven't bothered to chase it further. */
88
89
90/*------------------------------------------------------------*/
91/*--- ---*/
92/*--- PE/PDB definitions ---*/
93/*--- ---*/
94/*------------------------------------------------------------*/
95
96typedef UInt DWORD;
97typedef UShort WORD;
98typedef UChar BYTE;
99
100
101/* the following DOS and WINDOWS structures, defines and PE/PDB
102 * parsing code are copied or derived from the WINE
103 * project - http://www.winehq.com/
104 */
105
106/*
107 * File formats definitions
108 */
109#define OFFSET_OF(__c,__f) ((int)(((char*)&(((__c*)0)->__f))-((char*)0)))
110#define WIN32_PATH_MAX 256
111
112#pragma pack(2)
113typedef struct _IMAGE_DOS_HEADER {
114 unsigned short e_magic; /* 00: MZ Header signature */
115 unsigned short e_cblp; /* 02: Bytes on last page of file */
116 unsigned short e_cp; /* 04: Pages in file */
117 unsigned short e_crlc; /* 06: Relocations */
118 unsigned short e_cparhdr; /* 08: Size of header in paragraphs */
119 unsigned short e_minalloc; /* 0a: Minimum extra paragraphs needed */
120 unsigned short e_maxalloc; /* 0c: Maximum extra paragraphs needed */
121 unsigned short e_ss; /* 0e: Initial (relative) SS value */
122 unsigned short e_sp; /* 10: Initial SP value */
123 unsigned short e_csum; /* 12: Checksum */
124 unsigned short e_ip; /* 14: Initial IP value */
125 unsigned short e_cs; /* 16: Initial (relative) CS value */
126 unsigned short e_lfarlc; /* 18: File address of relocation table */
127 unsigned short e_ovno; /* 1a: Overlay number */
128 unsigned short e_res[4]; /* 1c: Reserved words */
129 unsigned short e_oemid; /* 24: OEM identifier (for e_oeminfo) */
130 unsigned short e_oeminfo; /* 26: OEM information; e_oemid specific */
131 unsigned short e_res2[10]; /* 28: Reserved words */
132 unsigned long e_lfanew; /* 3c: Offset to extended header */
133} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
134
135#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */
136#define IMAGE_OS2_SIGNATURE 0x454E /* NE */
137#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */
138#define IMAGE_OS2_SIGNATURE_LX 0x584C /* LX */
139#define IMAGE_VXD_SIGNATURE 0x454C /* LE */
140#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
141
142/* Subsystem Values */
143
144#define IMAGE_SUBSYSTEM_UNKNOWN 0
145#define IMAGE_SUBSYSTEM_NATIVE 1
146#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 /* Windows GUI subsystem */
147#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 /* Windows character subsystem*/
148#define IMAGE_SUBSYSTEM_OS2_CUI 5
149#define IMAGE_SUBSYSTEM_POSIX_CUI 7
150
151typedef struct _IMAGE_FILE_HEADER {
152 unsigned short Machine;
153 unsigned short NumberOfSections;
154 unsigned long TimeDateStamp;
155 unsigned long PointerToSymbolTable;
156 unsigned long NumberOfSymbols;
157 unsigned short SizeOfOptionalHeader;
158 unsigned short Characteristics;
159} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
160
161typedef struct _IMAGE_DATA_DIRECTORY {
162 unsigned long VirtualAddress;
163 unsigned long Size;
164} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
165
166#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
167
168typedef struct _IMAGE_OPTIONAL_HEADER {
169
170 /* Standard fields */
171
172 unsigned short Magic; /* 0x10b or 0x107 */ /* 0x00 */
173 unsigned char MajorLinkerVersion;
174 unsigned char MinorLinkerVersion;
175 unsigned long SizeOfCode;
176 unsigned long SizeOfInitializedData;
177 unsigned long SizeOfUninitializedData;
178 unsigned long AddressOfEntryPoint; /* 0x10 */
179 unsigned long BaseOfCode;
180 unsigned long BaseOfData;
181
182 /* NT additional fields */
183
184 unsigned long ImageBase;
185 unsigned long SectionAlignment; /* 0x20 */
186 unsigned long FileAlignment;
187 unsigned short MajorOperatingSystemVersion;
188 unsigned short MinorOperatingSystemVersion;
189 unsigned short MajorImageVersion;
190 unsigned short MinorImageVersion;
191 unsigned short MajorSubsystemVersion; /* 0x30 */
192 unsigned short MinorSubsystemVersion;
193 unsigned long Win32VersionValue;
194 unsigned long SizeOfImage;
195 unsigned long SizeOfHeaders;
196 unsigned long CheckSum; /* 0x40 */
197 unsigned short Subsystem;
198 unsigned short DllCharacteristics;
199 unsigned long SizeOfStackReserve;
200 unsigned long SizeOfStackCommit;
201 unsigned long SizeOfHeapReserve; /* 0x50 */
202 unsigned long SizeOfHeapCommit;
203 unsigned long LoaderFlags;
204 unsigned long NumberOfRvaAndSizes;
205 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; /* 0x60 */
206 /* 0xE0 */
207} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
208
209typedef struct _IMAGE_NT_HEADERS {
210 unsigned long Signature; /* "PE"\0\0 */ /* 0x00 */
211 IMAGE_FILE_HEADER FileHeader; /* 0x04 */
212 IMAGE_OPTIONAL_HEADER OptionalHeader; /* 0x18 */
213} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
214
215#define IMAGE_SIZEOF_SHORT_NAME 8
216
217typedef struct _IMAGE_SECTION_HEADER {
218 unsigned char Name[IMAGE_SIZEOF_SHORT_NAME];
219 union {
220 unsigned long PhysicalAddress;
221 unsigned long VirtualSize;
222 } Misc;
223 unsigned long VirtualAddress;
224 unsigned long SizeOfRawData;
225 unsigned long PointerToRawData;
226 unsigned long PointerToRelocations;
227 unsigned long PointerToLinenumbers;
228 unsigned short NumberOfRelocations;
229 unsigned short NumberOfLinenumbers;
230 unsigned long Characteristics;
231} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
232
233#define IMAGE_SIZEOF_SECTION_HEADER 40
234
235#define IMAGE_FIRST_SECTION(ntheader) \
236 ((PIMAGE_SECTION_HEADER)((LPunsigned char)&((PIMAGE_NT_HEADERS)(ntheader))->OptionalHeader + \
237 ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader))
238
239/* These defines are for the Characteristics bitfield. */
240/* #define IMAGE_SCN_TYPE_REG 0x00000000 - Reserved */
241/* #define IMAGE_SCN_TYPE_DSECT 0x00000001 - Reserved */
242/* #define IMAGE_SCN_TYPE_NOLOAD 0x00000002 - Reserved */
243/* #define IMAGE_SCN_TYPE_GROUP 0x00000004 - Reserved */
244/* #define IMAGE_SCN_TYPE_NO_PAD 0x00000008 - Reserved */
245/* #define IMAGE_SCN_TYPE_COPY 0x00000010 - Reserved */
246
247#define IMAGE_SCN_CNT_CODE 0x00000020
248#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
249#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
250
251#define IMAGE_SCN_LNK_OTHER 0x00000100
252#define IMAGE_SCN_LNK_INFO 0x00000200
253/* #define IMAGE_SCN_TYPE_OVER 0x00000400 - Reserved */
254#define IMAGE_SCN_LNK_REMOVE 0x00000800
255#define IMAGE_SCN_LNK_COMDAT 0x00001000
256
257/* 0x00002000 - Reserved */
258/* #define IMAGE_SCN_MEM_PROTECTED 0x00004000 - Obsolete */
259#define IMAGE_SCN_MEM_FARDATA 0x00008000
260
261/* #define IMAGE_SCN_MEM_SYSHEAP 0x00010000 - Obsolete */
262#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
263#define IMAGE_SCN_MEM_16BIT 0x00020000
264#define IMAGE_SCN_MEM_LOCKED 0x00040000
265#define IMAGE_SCN_MEM_PRELOAD 0x00080000
266
267#define IMAGE_SCN_ALIGN_1BYTES 0x00100000
268#define IMAGE_SCN_ALIGN_2BYTES 0x00200000
269#define IMAGE_SCN_ALIGN_4BYTES 0x00300000
270#define IMAGE_SCN_ALIGN_8BYTES 0x00400000
271#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default */
272#define IMAGE_SCN_ALIGN_32BYTES 0x00600000
273#define IMAGE_SCN_ALIGN_64BYTES 0x00700000
274/* 0x00800000 - Unused */
275
276#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000
277
278
279#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
280#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000
281#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000
282#define IMAGE_SCN_MEM_SHARED 0x10000000
283#define IMAGE_SCN_MEM_EXECUTE 0x20000000
284#define IMAGE_SCN_MEM_READ 0x40000000
285#define IMAGE_SCN_MEM_WRITE 0x80000000
286
287#pragma pack()
288
289typedef struct _GUID /* 16 bytes */
290{
291 unsigned int Data1;
292 unsigned short Data2;
293 unsigned short Data3;
294 unsigned char Data4[ 8 ];
295} GUID;
296
297/*========================================================================
298 * Process PDB file.
299 */
300
301#pragma pack(1)
302typedef struct _PDB_FILE
303{
304 unsigned long size;
305 unsigned long unknown;
306
307} PDB_FILE, *PPDB_FILE;
308
309// A .pdb file begins with a variable-length one-line text string
310// that ends in "\r\n\032". This is followed by a 4-byte "signature"
311// ("DS\0\0" for newer files, "JG\0\0" for older files), then
312// aligned up to a 4-byte boundary, then the struct below:
313struct PDB_JG_HEADER
314{
315 //char ident[40]; // "Microsoft C/C++ program database 2.00\r\n\032"
316 //unsigned long signature; // "JG\0\0"
317 unsigned int blocksize; // 0x400 typical; also 0x800, 0x1000
318 unsigned short freelist;
319 unsigned short total_alloc;
320 PDB_FILE toc;
321 unsigned short toc_block[ 1 ];
322};
323
324struct PDB_DS_HEADER
325{
326 //char signature[32]; // "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"
327 unsigned int block_size;
328 unsigned int unknown1;
329 unsigned int num_pages;
330 unsigned int toc_size;
331 unsigned int unknown2;
332 unsigned int toc_page;
333};
334
335struct PDB_JG_TOC
336{
337 unsigned int nFiles;
338 PDB_FILE file[ 1 ];
339
340};
341
342struct PDB_DS_TOC
343{
344 unsigned int num_files;
345 unsigned int file_size[1];
346};
347
348struct PDB_JG_ROOT
349{
350 unsigned int version;
351 unsigned int TimeDateStamp;
352 unsigned int age;
353 unsigned int cbNames;
354 char names[ 1 ];
355};
356
357struct PDB_DS_ROOT
358{
359 unsigned int version;
360 unsigned int TimeDateStamp;
361 unsigned int age;
362 GUID guid;
363 unsigned int cbNames;
364 char names[1];
365};
366
367typedef struct _PDB_TYPES_OLD
368{
369 unsigned long version;
370 unsigned short first_index;
371 unsigned short last_index;
372 unsigned long type_size;
373 unsigned short file;
374 unsigned short pad;
375
376} PDB_TYPES_OLD, *PPDB_TYPES_OLD;
377
378typedef struct _PDB_TYPES
379{
380 unsigned long version;
381 unsigned long type_offset;
382 unsigned long first_index;
383 unsigned long last_index;
384 unsigned long type_size;
385 unsigned short file;
386 unsigned short pad;
387 unsigned long hash_size;
388 unsigned long hash_base;
389 unsigned long hash_offset;
390 unsigned long hash_len;
391 unsigned long search_offset;
392 unsigned long search_len;
393 unsigned long unknown_offset;
394 unsigned long unknown_len;
395
396} PDB_TYPES, *PPDB_TYPES;
397
398typedef struct _PDB_SYMBOL_RANGE
399{
400 unsigned short segment;
401 unsigned short pad1;
402 unsigned long offset;
403 unsigned long size;
404 unsigned long characteristics;
405 unsigned short index;
406 unsigned short pad2;
407
408} PDB_SYMBOL_RANGE, *PPDB_SYMBOL_RANGE;
409
410typedef struct _PDB_SYMBOL_RANGE_EX
411{
412 unsigned short segment;
413 unsigned short pad1;
414 unsigned long offset;
415 unsigned long size;
416 unsigned long characteristics;
417 unsigned short index;
418 unsigned short pad2;
419 unsigned long timestamp;
420 unsigned long unknown;
421
422} PDB_SYMBOL_RANGE_EX, *PPDB_SYMBOL_RANGE_EX;
423
424typedef struct _PDB_SYMBOL_FILE
425{
426 unsigned long unknown1;
427 PDB_SYMBOL_RANGE range;
428 unsigned short flag;
429 unsigned short file;
430 unsigned long symbol_size;
431 unsigned long lineno_size;
432 unsigned long unknown2;
433 unsigned long nSrcFiles;
434 unsigned long attribute;
435 char filename[ 1 ];
436
437} PDB_SYMBOL_FILE, *PPDB_SYMBOL_FILE;
438
439typedef struct _PDB_SYMBOL_FILE_EX
440{
441 unsigned long unknown1;
442 PDB_SYMBOL_RANGE_EX range;
443 unsigned short flag;
444 unsigned short file;
445 unsigned long symbol_size;
446 unsigned long lineno_size;
447 unsigned long unknown2;
448 unsigned long nSrcFiles;
449 unsigned long attribute;
450 unsigned long reserved[ 2 ];
451 char filename[ 1 ];
452
453} PDB_SYMBOL_FILE_EX, *PPDB_SYMBOL_FILE_EX;
454
455typedef struct _PDB_SYMBOL_SOURCE
456{
457 unsigned short nModules;
458 unsigned short nSrcFiles;
459 unsigned short table[ 1 ];
460
461} PDB_SYMBOL_SOURCE, *PPDB_SYMBOL_SOURCE;
462
463typedef struct _PDB_SYMBOL_IMPORT
464{
465 unsigned long unknown1;
466 unsigned long unknown2;
467 unsigned long TimeDateStamp;
468 unsigned long nRequests;
469 char filename[ 1 ];
470
471} PDB_SYMBOL_IMPORT, *PPDB_SYMBOL_IMPORT;
472
473typedef struct _PDB_SYMBOLS_OLD
474{
475 unsigned short hash1_file;
476 unsigned short hash2_file;
477 unsigned short gsym_file;
478 unsigned short pad;
479 unsigned long module_size;
480 unsigned long offset_size;
481 unsigned long hash_size;
482 unsigned long srcmodule_size;
483
484} PDB_SYMBOLS_OLD, *PPDB_SYMBOLS_OLD;
485
486typedef struct _PDB_SYMBOLS
487{
488 unsigned long signature;
489 unsigned long version;
490 unsigned long unknown;
491 unsigned long hash1_file;
492 unsigned long hash2_file;
493 unsigned long gsym_file;
494 unsigned long module_size;
495 unsigned long offset_size;
496 unsigned long hash_size;
497 unsigned long srcmodule_size;
498 unsigned long pdbimport_size;
499 unsigned long resvd[ 5 ];
500
501} PDB_SYMBOLS, *PPDB_SYMBOLS;
502#pragma pack()
503
504/*========================================================================
505 * Process CodeView symbol information.
506 */
507
508/* from wine-1.0/include/wine/mscvpdb.h */
509
510struct p_string /* "Pascal string": prefixed by byte containing length */
511{
512 unsigned char namelen;
513 char name[1];
514};
515/* The other kind of "char name[1]" is a "C++ string" terminated by '\0'.
516 * "Name mangling" to encode type information often exceeds 255 bytes.
517 * Instead of using a 2-byte explicit length, they save one byte of space
518 * but incur a strlen(). This is justified by other code that wants
519 * a "C string" [terminated by '\0'] anyway.
520 */
521
522union codeview_symbol
523{
524 struct
525 {
526 short int len;
527 short int id;
528 } generic;
529
530 struct
531 {
532 short int len;
533 short int id;
534 unsigned int offset;
535 unsigned short segment;
536 unsigned short symtype;
537 struct p_string p_name;
538 } data_v1;
539
540 struct
541 {
542 short int len;
543 short int id;
544 unsigned int symtype;
545 unsigned int offset;
546 unsigned short segment;
547 struct p_string p_name;
548 } data_v2;
549
550 struct
551 {
552 short int len;
553 short int id;
554 unsigned int symtype;
555 unsigned int offset;
556 unsigned short segment;
557 char name[1]; /* terminated by '\0' */
558 } data_v3;
559
560 struct
561 {
562 short int len;
563 short int id;
564 unsigned int pparent;
565 unsigned int pend;
566 unsigned int next;
567 unsigned int offset;
568 unsigned short segment;
569 unsigned short thunk_len;
570 unsigned char thtype;
571 struct p_string p_name;
572 } thunk_v1;
573
574 struct
575 {
576 short int len;
577 short int id;
578 unsigned int pparent;
579 unsigned int pend;
580 unsigned int next;
581 unsigned int offset;
582 unsigned short segment;
583 unsigned short thunk_len;
584 unsigned char thtype;
585 char name[1]; /* terminated by '\0' */
586 } thunk_v3;
587
588 struct
589 {
590 short int len;
591 short int id;
592 unsigned int pparent;
593 unsigned int pend;
594 unsigned int next;
595 unsigned int proc_len;
596 unsigned int debug_start;
597 unsigned int debug_end;
598 unsigned int offset;
599 unsigned short segment;
600 unsigned short proctype;
601 unsigned char flags;
602 struct p_string p_name;
603 } proc_v1;
604
605 struct
606 {
607 short int len;
608 short int id;
609 unsigned int pparent;
610 unsigned int pend;
611 unsigned int next;
612 unsigned int proc_len;
613 unsigned int debug_start;
614 unsigned int debug_end;
615 unsigned int proctype;
616 unsigned int offset;
617 unsigned short segment;
618 unsigned char flags;
619 struct p_string p_name;
620 } proc_v2;
621
622 struct
623 {
624 short int len;
625 short int id;
626 unsigned int pparent;
627 unsigned int pend;
628 unsigned int next;
629 unsigned int proc_len;
630 unsigned int debug_start;
631 unsigned int debug_end;
632 unsigned int proctype;
633 unsigned int offset;
634 unsigned short segment;
635 unsigned char flags;
636 char name[1]; /* terminated by '\0' */
637 } proc_v3;
638
639 struct
640 {
641 short int len;
642 short int id;
643 unsigned int symtype;
644 unsigned int offset;
645 unsigned short segment;
646 struct p_string p_name;
647 } public_v2;
648
649 struct
650 {
651 short int len;
652 short int id;
653 unsigned int symtype;
654 unsigned int offset;
655 unsigned short segment;
656 char name[1]; /* terminated by '\0' */
657 } public_v3;
658
659 struct
660 {
661 short int len; /* Total length of this entry */
662 short int id; /* Always S_BPREL_V1 */
663 unsigned int offset; /* Stack offset relative to BP */
664 unsigned short symtype;
665 struct p_string p_name;
666 } stack_v1;
667
668 struct
669 {
670 short int len; /* Total length of this entry */
671 short int id; /* Always S_BPREL_V2 */
672 unsigned int offset; /* Stack offset relative to EBP */
673 unsigned int symtype;
674 struct p_string p_name;
675 } stack_v2;
676
677 struct
678 {
679 short int len; /* Total length of this entry */
680 short int id; /* Always S_BPREL_V3 */
681 int offset; /* Stack offset relative to BP */
682 unsigned int symtype;
683 char name[1]; /* terminated by '\0' */
684 } stack_v3;
685
686 struct
687 {
688 short int len; /* Total length of this entry */
689 short int id; /* Always S_BPREL_V3 */
690 int offset; /* Stack offset relative to BP */
691 unsigned int symtype;
692 unsigned short unknown;
693 char name[1]; /* terminated by '\0' */
694 } stack_xxxx_v3;
695
696 struct
697 {
698 short int len; /* Total length of this entry */
699 short int id; /* Always S_REGISTER */
700 unsigned short type;
701 unsigned short reg;
702 struct p_string p_name;
703 /* don't handle register tracking */
704 } register_v1;
705
706 struct
707 {
708 short int len; /* Total length of this entry */
709 short int id; /* Always S_REGISTER_V2 */
710 unsigned int type; /* check whether type & reg are correct */
711 unsigned short reg;
712 struct p_string p_name;
713 /* don't handle register tracking */
714 } register_v2;
715
716 struct
717 {
718 short int len; /* Total length of this entry */
719 short int id; /* Always S_REGISTER_V3 */
720 unsigned int type; /* check whether type & reg are correct */
721 unsigned short reg;
722 char name[1]; /* terminated by '\0' */
723 /* don't handle register tracking */
724 } register_v3;
725
726 struct
727 {
728 short int len;
729 short int id;
730 unsigned int parent;
731 unsigned int end;
732 unsigned int length;
733 unsigned int offset;
734 unsigned short segment;
735 struct p_string p_name;
736 } block_v1;
737
738 struct
739 {
740 short int len;
741 short int id;
742 unsigned int parent;
743 unsigned int end;
744 unsigned int length;
745 unsigned int offset;
746 unsigned short segment;
747 char name[1]; /* terminated by '\0' */
748 } block_v3;
749
750 struct
751 {
752 short int len;
753 short int id;
754 unsigned int offset;
755 unsigned short segment;
756 unsigned char flags;
757 struct p_string p_name;
758 } label_v1;
759
760 struct
761 {
762 short int len;
763 short int id;
764 unsigned int offset;
765 unsigned short segment;
766 unsigned char flags;
767 char name[1]; /* terminated by '\0' */
768 } label_v3;
769
770 struct
771 {
772 short int len;
773 short int id;
774 unsigned short type;
775 unsigned short cvalue; /* numeric leaf */
776#if 0
777 struct p_string p_name;
778#endif
779 } constant_v1;
780
781 struct
782 {
783 short int len;
784 short int id;
785 unsigned type;
786 unsigned short cvalue; /* numeric leaf */
787#if 0
788 struct p_string p_name;
789#endif
790 } constant_v2;
791
792 struct
793 {
794 short int len;
795 short int id;
796 unsigned type;
797 unsigned short cvalue;
798#if 0
799 char name[1]; /* terminated by '\0' */
800#endif
801 } constant_v3;
802
803 struct
804 {
805 short int len;
806 short int id;
807 unsigned short type;
808 struct p_string p_name;
809 } udt_v1;
810
811 struct
812 {
813 short int len;
814 short int id;
815 unsigned type;
816 struct p_string p_name;
817 } udt_v2;
818
819 struct
820 {
821 short int len;
822 short int id;
823 unsigned int type;
824 char name[1]; /* terminated by '\0' */
825 } udt_v3;
826
827 struct
828 {
829 short int len;
830 short int id;
831 char signature[4];
832 struct p_string p_name;
833 } objname_v1;
834
835 struct
836 {
837 short int len;
838 short int id;
839 unsigned int unknown;
840 struct p_string p_name;
841 } compiland_v1;
842
843 struct
844 {
845 short int len;
846 short int id;
847 unsigned unknown1[4];
848 unsigned short unknown2;
849 struct p_string p_name;
850 } compiland_v2;
851
852 struct
853 {
854 short int len;
855 short int id;
856 unsigned int unknown;
857 char name[1]; /* terminated by '\0' */
858 } compiland_v3;
859
860 struct
861 {
862 short int len;
863 short int id;
864 unsigned int offset;
865 unsigned short segment;
866 } ssearch_v1;
867};
868
869#define S_COMPILAND_V1 0x0001
870#define S_REGISTER_V1 0x0002
871#define S_CONSTANT_V1 0x0003
872#define S_UDT_V1 0x0004
873#define S_SSEARCH_V1 0x0005
874#define S_END_V1 0x0006
875#define S_SKIP_V1 0x0007
876#define S_CVRESERVE_V1 0x0008
877#define S_OBJNAME_V1 0x0009
878#define S_ENDARG_V1 0x000a
879#define S_COBOLUDT_V1 0x000b
880#define S_MANYREG_V1 0x000c
881#define S_RETURN_V1 0x000d
882#define S_ENTRYTHIS_V1 0x000e
883
884#define S_BPREL_V1 0x0200
885#define S_LDATA_V1 0x0201
886#define S_GDATA_V1 0x0202
887#define S_PUB_V1 0x0203
888#define S_LPROC_V1 0x0204
889#define S_GPROC_V1 0x0205
890#define S_THUNK_V1 0x0206
891#define S_BLOCK_V1 0x0207
892#define S_WITH_V1 0x0208
893#define S_LABEL_V1 0x0209
894#define S_CEXMODEL_V1 0x020a
895#define S_VFTPATH_V1 0x020b
896#define S_REGREL_V1 0x020c
897#define S_LTHREAD_V1 0x020d
898#define S_GTHREAD_V1 0x020e
899
900#define S_PROCREF_V1 0x0400
901#define S_DATAREF_V1 0x0401
902#define S_ALIGN_V1 0x0402
903#define S_LPROCREF_V1 0x0403
904
905#define S_REGISTER_V2 0x1001 /* Variants with new 32-bit type indices */
906#define S_CONSTANT_V2 0x1002
907#define S_UDT_V2 0x1003
908#define S_COBOLUDT_V2 0x1004
909#define S_MANYREG_V2 0x1005
910#define S_BPREL_V2 0x1006
911#define S_LDATA_V2 0x1007
912#define S_GDATA_V2 0x1008
913#define S_PUB_V2 0x1009
914#define S_LPROC_V2 0x100a
915#define S_GPROC_V2 0x100b
916#define S_VFTTABLE_V2 0x100c
917#define S_REGREL_V2 0x100d
918#define S_LTHREAD_V2 0x100e
919#define S_GTHREAD_V2 0x100f
920#if 0
921#define S_XXXXXXXXX_32 0x1012 /* seems linked to a function, content unknown */
922#endif
923#define S_COMPILAND_V2 0x1013
924
925#define S_COMPILAND_V3 0x1101
926#define S_THUNK_V3 0x1102
927#define S_BLOCK_V3 0x1103
928#define S_LABEL_V3 0x1105
929#define S_REGISTER_V3 0x1106
930#define S_CONSTANT_V3 0x1107
931#define S_UDT_V3 0x1108
932#define S_BPREL_V3 0x110B
933#define S_LDATA_V3 0x110C
934#define S_GDATA_V3 0x110D
935#define S_PUB_V3 0x110E
936#define S_LPROC_V3 0x110F
937#define S_GPROC_V3 0x1110
938#define S_BPREL_XXXX_V3 0x1111 /* not really understood, but looks like bprel... */
939#define S_MSTOOL_V3 0x1116 /* compiler command line options and build information */
940#define S_PUB_FUNC1_V3 0x1125 /* didn't get the difference between the two */
941#define S_PUB_FUNC2_V3 0x1127
942
943
944/*------------------------------------------------------------*/
945/*--- ---*/
946/*--- pdb-reading: bits and pieces ---*/
947/*--- ---*/
948/*------------------------------------------------------------*/
949
950struct pdb_reader
951{
florian518850b2014-10-22 22:25:30 +0000952 void* (*read_file)(const struct pdb_reader*, unsigned, unsigned *);
sewardjc8259b82009-04-22 22:42:10 +0000953 // JRS 2009-Apr-8: .uu_n_pdbimage is never used.
954 UChar* pdbimage; // image address
955 SizeT uu_n_pdbimage; // size
956 union {
957 struct {
958 struct PDB_JG_HEADER* header;
959 struct PDB_JG_TOC* toc;
sewardj4fc42702015-02-18 12:57:06 +0000960 struct PDB_JG_ROOT* root;
sewardjc8259b82009-04-22 22:42:10 +0000961 } jg;
962 struct {
963 struct PDB_DS_HEADER* header;
964 struct PDB_DS_TOC* toc;
sewardj4fc42702015-02-18 12:57:06 +0000965 struct PDB_DS_ROOT* root;
sewardjc8259b82009-04-22 22:42:10 +0000966 } ds;
967 } u;
968};
969
970
florian518850b2014-10-22 22:25:30 +0000971static void* pdb_ds_read( const struct pdb_reader* pdb,
972 const unsigned* block_list,
sewardjc8259b82009-04-22 22:42:10 +0000973 unsigned size )
974{
975 unsigned blocksize, nBlocks;
976 UChar* buffer;
977 UInt i;
978
979 if (!size) return NULL;
sewardj0418bd32010-07-22 22:36:43 +0000980 if (size > 512 * 1024 * 1024) {
sewardj3d0724b2015-02-18 15:38:25 +0000981 VG_(umsg)("LOAD_PDB_DEBUGINFO: pdb_ds_read: implausible size "
sewardj0418bd32010-07-22 22:36:43 +0000982 "(%u); skipping -- possible invalid .pdb file?\n", size);
983 return NULL;
984 }
sewardjc8259b82009-04-22 22:42:10 +0000985
986 blocksize = pdb->u.ds.header->block_size;
987 nBlocks = (size + blocksize - 1) / blocksize;
988 buffer = ML_(dinfo_zalloc)("di.readpe.pdr.1", nBlocks * blocksize);
989 for (i = 0; i < nBlocks; i++)
990 VG_(memcpy)( buffer + i * blocksize,
991 pdb->pdbimage + block_list[i] * blocksize,
992 blocksize );
993 return buffer;
994}
995
996
florian518850b2014-10-22 22:25:30 +0000997static void* pdb_jg_read( const struct pdb_reader* pdb,
998 const unsigned short* block_list,
sewardjc8259b82009-04-22 22:42:10 +0000999 int size )
1000{
1001 unsigned blocksize, nBlocks;
1002 UChar* buffer;
1003 UInt i;
1004 //VG_(printf)("pdb_read %p %p %d\n", pdb, block_list, size);
1005 if ( !size ) return NULL;
1006
1007 blocksize = pdb->u.jg.header->blocksize;
1008 nBlocks = (size + blocksize-1) / blocksize;
1009 buffer = ML_(dinfo_zalloc)("di.readpe.pjr.1", nBlocks * blocksize);
1010 for ( i = 0; i < nBlocks; i++ )
1011 VG_(memcpy)( buffer + i*blocksize,
1012 pdb->pdbimage + block_list[i]*blocksize, blocksize );
1013 return buffer;
1014}
1015
1016
florian1636d332012-11-15 04:27:04 +00001017static void* find_pdb_header( void* pdbimage,
sewardjc8259b82009-04-22 22:42:10 +00001018 unsigned* signature )
1019{
florian1636d332012-11-15 04:27:04 +00001020 static const HChar pdbtxt[]= "Microsoft C/C++";
1021 HChar* txteof = VG_(strchr)(pdbimage, '\032');
sewardjc8259b82009-04-22 22:42:10 +00001022 if (! txteof)
1023 return NULL;
1024 if (0!=VG_(strncmp)(pdbimage, pdbtxt, -1+ sizeof(pdbtxt)))
1025 return NULL;
1026
1027 *signature = *(unsigned*)(1+ txteof);
florian1636d332012-11-15 04:27:04 +00001028 HChar *img_addr = pdbimage; // so we can do address arithmetic
1029 return ((~3& (3+ (4+ 1+ (txteof - img_addr)))) + img_addr);
sewardjc8259b82009-04-22 22:42:10 +00001030}
1031
1032
florian518850b2014-10-22 22:25:30 +00001033static void* pdb_ds_read_file( const struct pdb_reader* reader,
sewardjc8259b82009-04-22 22:42:10 +00001034 unsigned file_number,
1035 unsigned* plength )
1036{
1037 unsigned i, *block_list;
1038 if (!reader->u.ds.toc || file_number >= reader->u.ds.toc->num_files)
1039 return NULL;
1040 if (reader->u.ds.toc->file_size[file_number] == 0
1041 || reader->u.ds.toc->file_size[file_number] == 0xFFFFFFFF)
1042 return NULL;
1043
1044 block_list
1045 = reader->u.ds.toc->file_size + reader->u.ds.toc->num_files;
1046 for (i = 0; i < file_number; i++)
1047 block_list += (reader->u.ds.toc->file_size[i]
1048 + reader->u.ds.header->block_size - 1)
1049 /
1050 reader->u.ds.header->block_size;
1051 if (plength)
1052 *plength = reader->u.ds.toc->file_size[file_number];
1053 return pdb_ds_read( reader, block_list,
1054 reader->u.ds.toc->file_size[file_number]);
1055}
1056
1057
florian518850b2014-10-22 22:25:30 +00001058static void* pdb_jg_read_file( const struct pdb_reader* pdb,
sewardjc8259b82009-04-22 22:42:10 +00001059 unsigned fileNr,
1060 unsigned *plength )
1061{
1062 //VG_(printf)("pdb_read_file %p %d\n", pdb, fileNr);
1063 unsigned blocksize = pdb->u.jg.header->blocksize;
1064 struct PDB_JG_TOC* toc = pdb->u.jg.toc;
1065 unsigned i;
1066 unsigned short* block_list;
1067
1068 if ( !toc || fileNr >= toc->nFiles )
1069 return NULL;
1070
1071 block_list
1072 = (unsigned short *) &toc->file[ toc->nFiles ];
1073 for ( i = 0; i < fileNr; i++ )
1074 block_list += (toc->file[i].size + blocksize-1) / blocksize;
1075
1076 if (plength)
1077 *plength = toc->file[fileNr].size;
1078 return pdb_jg_read( pdb, block_list, toc->file[fileNr].size );
1079}
1080
1081
1082static void pdb_ds_init( struct pdb_reader * reader,
1083 UChar* pdbimage,
1084 SizeT n_pdbimage )
1085{
1086 reader->read_file = pdb_ds_read_file;
1087 reader->pdbimage = pdbimage;
1088 reader->uu_n_pdbimage = n_pdbimage;
1089 reader->u.ds.toc
1090 = pdb_ds_read(
1091 reader,
1092 (unsigned*)(reader->u.ds.header->block_size
1093 * reader->u.ds.header->toc_page
1094 + reader->pdbimage),
1095 reader->u.ds.header->toc_size
1096 );
1097}
1098
1099
1100static void pdb_jg_init( struct pdb_reader* reader,
florian1636d332012-11-15 04:27:04 +00001101 void* pdbimage,
sewardjc8259b82009-04-22 22:42:10 +00001102 unsigned n_pdbimage )
1103{
1104 reader->read_file = pdb_jg_read_file;
1105 reader->pdbimage = pdbimage;
1106 reader->uu_n_pdbimage = n_pdbimage;
1107 reader->u.jg.toc = pdb_jg_read(reader,
1108 reader->u.jg.header->toc_block,
1109 reader->u.jg.header->toc.size);
1110}
1111
1112
sewardjc8259b82009-04-22 22:42:10 +00001113static
florian518850b2014-10-22 22:25:30 +00001114void pdb_check_root_version_and_timestamp( const HChar* pdbname,
sewardjc8259b82009-04-22 22:42:10 +00001115 ULong pdbmtime,
florianc6e5d762015-08-05 22:27:24 +00001116 UInt version,
sewardjc8259b82009-04-22 22:42:10 +00001117 UInt TimeDateStamp )
1118{
1119 switch ( version ) {
1120 case 19950623: /* VC 4.0 */
1121 case 19950814:
1122 case 19960307: /* VC 5.0 */
1123 case 19970604: /* VC 6.0 */
1124 case 20000404: /* VC 7.0 FIXME?? */
1125 break;
1126 default:
1127 if (VG_(clo_verbosity) > 1)
sewardj3d0724b2015-02-18 15:38:25 +00001128 VG_(umsg)("LOAD_PDB_DEBUGINFO: "
florianc6e5d762015-08-05 22:27:24 +00001129 "Unknown .pdb root block version %u\n", version );
sewardjc8259b82009-04-22 22:42:10 +00001130 }
1131 if ( TimeDateStamp != pdbmtime ) {
1132 if (VG_(clo_verbosity) > 1)
sewardj3d0724b2015-02-18 15:38:25 +00001133 VG_(umsg)("LOAD_PDB_DEBUGINFO: Wrong time stamp of .PDB file "
1134 "%s (0x%08x, 0x%08llx)\n",
1135 pdbname, TimeDateStamp, pdbmtime );
sewardjc8259b82009-04-22 22:42:10 +00001136 }
1137}
1138
1139
florian518850b2014-10-22 22:25:30 +00001140static DWORD pdb_get_file_size( const struct pdb_reader* reader, unsigned idx )
sewardjc8259b82009-04-22 22:42:10 +00001141{
1142 if (reader->read_file == pdb_jg_read_file)
1143 return reader->u.jg.toc->file[idx].size;
1144 else
1145 return reader->u.ds.toc->file_size[idx];
1146}
1147
1148
1149static void pdb_convert_types_header( PDB_TYPES *types, char* image )
1150{
1151 VG_(memset)( types, 0, sizeof(PDB_TYPES) );
1152 if ( !image )
1153 return;
1154 if ( *(unsigned long *)image < 19960000 ) { /* FIXME: correct version? */
1155 /* Old version of the types record header */
1156 PDB_TYPES_OLD *old = (PDB_TYPES_OLD *)image;
1157 types->version = old->version;
1158 types->type_offset = sizeof(PDB_TYPES_OLD);
1159 types->type_size = old->type_size;
1160 types->first_index = old->first_index;
1161 types->last_index = old->last_index;
1162 types->file = old->file;
1163 } else {
1164 /* New version of the types record header */
1165 *types = *(PDB_TYPES *)image;
1166 }
1167}
1168
1169
1170static void pdb_convert_symbols_header( PDB_SYMBOLS *symbols,
1171 int *header_size, char* image )
1172{
1173 VG_(memset)( symbols, 0, sizeof(PDB_SYMBOLS) );
1174 if ( !image )
1175 return;
1176 if ( *(unsigned long *)image != 0xffffffff ) {
1177 /* Old version of the symbols record header */
1178 PDB_SYMBOLS_OLD *old = (PDB_SYMBOLS_OLD *)image;
1179 symbols->version = 0;
1180 symbols->module_size = old->module_size;
1181 symbols->offset_size = old->offset_size;
1182 symbols->hash_size = old->hash_size;
1183 symbols->srcmodule_size = old->srcmodule_size;
1184 symbols->pdbimport_size = 0;
1185 symbols->hash1_file = old->hash1_file;
1186 symbols->hash2_file = old->hash2_file;
1187 symbols->gsym_file = old->gsym_file;
1188 *header_size = sizeof(PDB_SYMBOLS_OLD);
1189 } else {
1190 /* New version of the symbols record header */
1191 *symbols = *(PDB_SYMBOLS *)image;
1192 *header_size = sizeof(PDB_SYMBOLS);
1193 }
1194}
1195
1196
1197/*------------------------------------------------------------*/
1198/*--- ---*/
1199/*--- Main stuff: reading of symbol addresses ---*/
1200/*--- ---*/
1201/*------------------------------------------------------------*/
1202
sewardjc8259b82009-04-22 22:42:10 +00001203static ULong DEBUG_SnarfCodeView(
1204 DebugInfo* di,
sewardj54c45db2012-07-13 12:58:55 +00001205 PtrdiffT bias,
florian518850b2014-10-22 22:25:30 +00001206 const IMAGE_SECTION_HEADER* sectp,
1207 const void* root, /* FIXME: better name */
sewardjc8259b82009-04-22 22:42:10 +00001208 Int offset,
1209 Int size
1210 )
1211{
1212 Int i, length;
1213 DiSym vsym;
florian1ef70c62014-10-22 17:42:37 +00001214 const HChar* nmstr;
florian518850b2014-10-22 22:25:30 +00001215 HChar symname[4096 /*WIN32_PATH_MAX*/]; // FIXME: really ?
sewardjc8259b82009-04-22 22:42:10 +00001216
sewardj275f93d2010-01-26 13:26:41 +00001217 Bool debug = di->trace_symtab;
sewardjc8259b82009-04-22 22:42:10 +00001218 ULong n_syms_read = 0;
1219
1220 if (debug)
sewardj3d0724b2015-02-18 15:38:25 +00001221 VG_(umsg)("BEGIN SnarfCodeView addr=%p offset=%d length=%d\n",
1222 root, offset, size );
sewardjc8259b82009-04-22 22:42:10 +00001223
1224 VG_(memset)(&vsym, 0, sizeof(vsym)); /* avoid holes */
1225 /*
1226 * Loop over the different types of records and whenever we
1227 * find something we are interested in, record it and move on.
1228 */
1229 for ( i = offset; i < size; i += length )
1230 {
florian518850b2014-10-22 22:25:30 +00001231 const union codeview_symbol *sym =
1232 (const union codeview_symbol *)((const char *)root + i);
sewardjc8259b82009-04-22 22:42:10 +00001233
1234 length = sym->generic.len + 2;
1235
1236 //VG_(printf)("id=%x len=%d\n", sym->generic.id, length);
1237 switch ( sym->generic.id ) {
1238
1239 default:
1240 if (0) {
florianc6e5d762015-08-05 22:27:24 +00001241 const UInt *isym = (const UInt *)sym;
sewardjc8259b82009-04-22 22:42:10 +00001242 VG_(printf)("unknown id 0x%x len=0x%x at %p\n",
florianc6e5d762015-08-05 22:27:24 +00001243 (UInt)sym->generic.id, (UInt)sym->generic.len, sym);
sewardjc8259b82009-04-22 22:42:10 +00001244 VG_(printf)(" %8x %8x %8x %8x\n",
florian518850b2014-10-22 22:25:30 +00001245 isym[1], isym[2], isym[3], isym[4]);
sewardjc8259b82009-04-22 22:42:10 +00001246 VG_(printf)(" %8x %8x %8x %8x\n",
florian518850b2014-10-22 22:25:30 +00001247 isym[5], isym[6], isym[7], isym[8]);
sewardjc8259b82009-04-22 22:42:10 +00001248 }
1249 break;
1250 /*
1251 * Global and local data symbols. We don't associate these
1252 * with any given source file.
1253 */
1254 case S_GDATA_V1:
1255 case S_LDATA_V1:
1256 case S_PUB_V1:
1257 VG_(memcpy)(symname, sym->data_v1.p_name.name,
1258 sym->data_v1.p_name.namelen);
1259 symname[sym->data_v1.p_name.namelen] = '\0';
1260
1261 if (debug)
sewardj3d0724b2015-02-18 15:38:25 +00001262 VG_(umsg)(" Data %s\n", symname );
sewardjc8259b82009-04-22 22:42:10 +00001263
1264 if (0 /*VG_(needs).data_syms*/) {
1265 nmstr = ML_(addStr)(di, symname, sym->data_v1.p_name.namelen);
philippe4cace662014-08-13 21:25:45 +00001266 vsym.avmas.main = bias + sectp[sym->data_v1.segment-1].VirtualAddress
sewardja5cace02011-08-15 09:42:34 +00001267 + sym->data_v1.offset;
philippe4cace662014-08-13 21:25:45 +00001268 SET_TOCPTR_AVMA(vsym.avmas, 0);
sewardja5cace02011-08-15 09:42:34 +00001269 vsym.pri_name = nmstr;
1270 vsym.sec_names = NULL;
1271 vsym.size = sym->data_v1.p_name.namelen;
1272 // FIXME: .namelen is sizeof(.data) including .name[]
1273 vsym.isText = (sym->generic.id == S_PUB_V1);
1274 vsym.isIFunc = False;
sewardjc8259b82009-04-22 22:42:10 +00001275 ML_(addSym)( di, &vsym );
1276 n_syms_read++;
1277 }
1278 break;
1279 case S_GDATA_V2:
1280 case S_LDATA_V2:
1281 case S_PUB_V2: {
1282 Int const k = sym->data_v2.p_name.namelen;
1283 VG_(memcpy)(symname, sym->data_v2.p_name.name, k);
1284 symname[k] = '\0';
1285
1286 if (debug)
sewardj3d0724b2015-02-18 15:38:25 +00001287 VG_(umsg)(" S_GDATA_V2/S_LDATA_V2/S_PUB_V2 %s\n", symname );
sewardjc8259b82009-04-22 22:42:10 +00001288
1289 if (sym->generic.id==S_PUB_V2 /*VG_(needs).data_syms*/) {
1290 nmstr = ML_(addStr)(di, symname, k);
philippe4cace662014-08-13 21:25:45 +00001291 vsym.avmas.main = bias + sectp[sym->data_v2.segment-1].VirtualAddress
sewardja5cace02011-08-15 09:42:34 +00001292 + sym->data_v2.offset;
philippe4cace662014-08-13 21:25:45 +00001293 SET_TOCPTR_AVMA(vsym.avmas, 0);
sewardja5cace02011-08-15 09:42:34 +00001294 vsym.pri_name = nmstr;
1295 vsym.sec_names = NULL;
1296 vsym.size = 4000;
1297 // FIXME: data_v2.len is sizeof(.data),
1298 // not size of function!
1299 vsym.isText = !!(IMAGE_SCN_CNT_CODE
1300 & sectp[sym->data_v2.segment-1].Characteristics);
1301 vsym.isIFunc = False;
sewardjc8259b82009-04-22 22:42:10 +00001302 ML_(addSym)( di, &vsym );
1303 n_syms_read++;
1304 }
1305 break;
1306 }
1307 case S_PUB_V3:
1308 /* not completely sure of those two anyway */
1309 case S_PUB_FUNC1_V3:
1310 case S_PUB_FUNC2_V3: {
1311 Int k = sym->public_v3.len - (-1+ sizeof(sym->public_v3));
1312 if ((-1+ sizeof(symname)) < k)
1313 k = -1+ sizeof(symname);
1314 VG_(memcpy)(symname, sym->public_v3.name, k);
1315 symname[k] = '\0';
1316
1317 if (debug)
sewardj3d0724b2015-02-18 15:38:25 +00001318 VG_(umsg)(" S_PUB_FUNC1_V3/S_PUB_FUNC2_V3/S_PUB_V3 %s\n",
1319 symname );
sewardjc8259b82009-04-22 22:42:10 +00001320
1321 if (1 /*sym->generic.id==S_PUB_FUNC1_V3
1322 || sym->generic.id==S_PUB_FUNC2_V3*/) {
1323 nmstr = ML_(addStr)(di, symname, k);
philippe4cace662014-08-13 21:25:45 +00001324 vsym.avmas.main = bias + sectp[sym->public_v3.segment-1].VirtualAddress
sewardja5cace02011-08-15 09:42:34 +00001325 + sym->public_v3.offset;
philippe4cace662014-08-13 21:25:45 +00001326 SET_TOCPTR_AVMA(vsym.avmas, 0);
sewardja5cace02011-08-15 09:42:34 +00001327 vsym.pri_name = nmstr;
1328 vsym.sec_names = NULL;
1329 vsym.size = 4000;
1330 // FIXME: public_v3.len is not length of the
1331 // .text of the function
1332 vsym.isText = !!(IMAGE_SCN_CNT_CODE
1333 & sectp[sym->data_v2.segment-1].Characteristics);
1334 vsym.isIFunc = False;
sewardjc8259b82009-04-22 22:42:10 +00001335 ML_(addSym)( di, &vsym );
1336 n_syms_read++;
1337 }
1338 break;
1339 }
1340
1341 /*
1342 * Sort of like a global function, but it just points
1343 * to a thunk, which is a stupid name for what amounts to
1344 * a PLT slot in the normal jargon that everyone else uses.
1345 */
1346 case S_THUNK_V3:
1347 case S_THUNK_V1:
1348 /* valgrind ignores PLTs */ /* JRS: it does? */
1349 break;
1350
1351 /*
1352 * Global and static functions.
1353 */
1354 case S_GPROC_V1:
1355 case S_LPROC_V1:
1356 VG_(memcpy)(symname, sym->proc_v1.p_name.name,
1357 sym->proc_v1.p_name.namelen);
1358 symname[sym->proc_v1.p_name.namelen] = '\0';
1359 nmstr = ML_(addStr)(di, symname, sym->proc_v1.p_name.namelen);
philippe4cace662014-08-13 21:25:45 +00001360 vsym.avmas.main = bias + sectp[sym->proc_v1.segment-1].VirtualAddress
sewardja5cace02011-08-15 09:42:34 +00001361 + sym->proc_v1.offset;
philippe4cace662014-08-13 21:25:45 +00001362 SET_TOCPTR_AVMA(vsym.avmas, 0);
sewardja5cace02011-08-15 09:42:34 +00001363 vsym.pri_name = nmstr;
1364 vsym.sec_names = NULL;
1365 vsym.size = sym->proc_v1.proc_len;
1366 vsym.isText = True;
1367 vsym.isIFunc = False;
sewardjc8259b82009-04-22 22:42:10 +00001368 if (debug)
florianc6e5d762015-08-05 22:27:24 +00001369 VG_(umsg)(" Adding function %s addr=%#lx length=%u\n",
sewardj3d0724b2015-02-18 15:38:25 +00001370 symname, vsym.avmas.main, vsym.size );
sewardjc8259b82009-04-22 22:42:10 +00001371 ML_(addSym)( di, &vsym );
1372 n_syms_read++;
1373 break;
1374
1375 case S_GPROC_V2:
1376 case S_LPROC_V2:
1377 VG_(memcpy)(symname, sym->proc_v2.p_name.name,
1378 sym->proc_v2.p_name.namelen);
1379 symname[sym->proc_v2.p_name.namelen] = '\0';
1380 nmstr = ML_(addStr)(di, symname, sym->proc_v2.p_name.namelen);
philippe4cace662014-08-13 21:25:45 +00001381 vsym.avmas.main = bias + sectp[sym->proc_v2.segment-1].VirtualAddress
sewardja5cace02011-08-15 09:42:34 +00001382 + sym->proc_v2.offset;
philippe4cace662014-08-13 21:25:45 +00001383 SET_TOCPTR_AVMA(vsym.avmas, 0);
sewardja5cace02011-08-15 09:42:34 +00001384 vsym.pri_name = nmstr;
1385 vsym.sec_names = NULL;
1386 vsym.size = sym->proc_v2.proc_len;
1387 vsym.isText = True;
1388 vsym.isIFunc = False;
sewardjc8259b82009-04-22 22:42:10 +00001389 if (debug)
florianc6e5d762015-08-05 22:27:24 +00001390 VG_(umsg)(" Adding function %s addr=%#lx length=%u\n",
sewardj3d0724b2015-02-18 15:38:25 +00001391 symname, vsym.avmas.main, vsym.size );
sewardjc8259b82009-04-22 22:42:10 +00001392 ML_(addSym)( di, &vsym );
1393 n_syms_read++;
1394 break;
1395 case S_LPROC_V3:
1396 case S_GPROC_V3: {
1397 if (debug)
sewardj3d0724b2015-02-18 15:38:25 +00001398 VG_(umsg)(" S_LPROC_V3/S_GPROC_V3 %s\n", sym->proc_v3.name );
sewardjc8259b82009-04-22 22:42:10 +00001399
1400 if (1) {
1401 nmstr = ML_(addStr)(di, sym->proc_v3.name,
1402 VG_(strlen)(sym->proc_v3.name));
philippe4cace662014-08-13 21:25:45 +00001403 vsym.avmas.main = bias + sectp[sym->proc_v3.segment-1].VirtualAddress
sewardja5cace02011-08-15 09:42:34 +00001404 + sym->proc_v3.offset;
philippe4cace662014-08-13 21:25:45 +00001405 SET_TOCPTR_AVMA(vsym.avmas, 0);
sewardja5cace02011-08-15 09:42:34 +00001406 vsym.pri_name = nmstr;
1407 vsym.sec_names = NULL;
1408 vsym.size = sym->proc_v3.proc_len;
1409 vsym.isText = 1;
1410 vsym.isIFunc = False;
sewardjc8259b82009-04-22 22:42:10 +00001411 ML_(addSym)( di, &vsym );
1412 n_syms_read++;
1413 }
1414 break;
1415 }
1416 /* JRS: how is flow supposed to arrive at commented out code below? */
1417 //if (nest_block)
1418 //{
1419 // printf(">>> prev func '%s' still has nest_block %u count\n",
1420 // curr_func, nest_block);
1421 // nest_block = 0;
1422 //}
1423 //curr_func = strdup(sym->proc_v3.name);
1424 /* EPP unsigned int pparent; */
1425 /* EPP unsigned int pend; */
1426 /* EPP unsigned int next; */
1427 /* EPP unsigned int debug_start; */
1428 /* EPP unsigned int debug_end; */
1429 /* EPP unsigned char flags; */
1430 // break;
1431
1432
1433 /*
1434 * Function parameters and stack variables.
1435 */
1436 case S_BPREL_XXXX_V3:
1437 case S_BPREL_V3:
1438 case S_BPREL_V2:
1439 case S_BPREL_V1:
1440 /* ignored */
1441 break;
1442
1443 case S_LABEL_V3: // FIXME
1444 case S_LABEL_V1:
1445 break;
1446
1447 case S_SSEARCH_V1:
1448 case S_ALIGN_V1:
1449 case S_MSTOOL_V3:
1450 case S_UDT_V3:
1451 case S_UDT_V2:
1452 case S_UDT_V1:
1453 case S_CONSTANT_V3:
1454 case S_CONSTANT_V1:
1455 case S_OBJNAME_V1:
1456 case S_END_V1:
1457 case S_COMPILAND_V3:
1458 case S_COMPILAND_V2:
1459 case S_COMPILAND_V1:
1460 case S_BLOCK_V3:
1461 case S_BLOCK_V1:
1462 case S_REGISTER_V3:
1463 case S_REGISTER_V2:
1464 case S_REGISTER_V1:
1465 /* ignored */
1466 break;
1467
1468 /*
1469 * These are special, in that they are always followed by an
1470 * additional length-prefixed string which is *not* included
1471 * into the symbol length count. We need to skip it.
1472 */
1473 case S_PROCREF_V1:
1474 case S_DATAREF_V1:
1475 case S_LPROCREF_V1: {
florian518850b2014-10-22 22:25:30 +00001476 const unsigned char *name = (const unsigned char *)sym + length;
sewardjc8259b82009-04-22 22:42:10 +00001477 length += (*name + 1 + 3) & ~3;
1478 break;
1479 }
1480 } /* switch ( sym->generic.id ) */
1481
1482 } /* for ( i = offset; i < size; i += length ) */
1483
sewardj275f93d2010-01-26 13:26:41 +00001484 if (debug)
sewardj3d0724b2015-02-18 15:38:25 +00001485 VG_(umsg)("END SnarfCodeView addr=%p offset=%d length=%d\n",
1486 root, offset, size );
sewardjc8259b82009-04-22 22:42:10 +00001487 return n_syms_read;
1488}
1489
1490
1491/*------------------------------------------------------------*/
1492/*--- ---*/
1493/*--- Main stuff: reading of line number tables ---*/
1494/*--- ---*/
1495/*------------------------------------------------------------*/
1496
1497union any_size
1498{
1499 char const *c;
1500 short const *s;
1501 int const *i;
1502 unsigned int const *ui;
1503};
1504
1505struct startend
1506{
1507 unsigned int start;
1508 unsigned int end;
1509};
1510
1511static ULong DEBUG_SnarfLinetab(
1512 DebugInfo* di,
sewardj54c45db2012-07-13 12:58:55 +00001513 PtrdiffT bias,
florian518850b2014-10-22 22:25:30 +00001514 const IMAGE_SECTION_HEADER* sectp,
1515 const void* linetab,
sewardjc8259b82009-04-22 22:42:10 +00001516 Int size
1517 )
1518{
1519 //VG_(printf)("DEBUG_SnarfLinetab %p %p %p %d\n", di, sectp, linetab, size);
1520 Int file_segcount;
florian1636d332012-11-15 04:27:04 +00001521 HChar filename[WIN32_PATH_MAX];
florian3e798632012-11-24 19:41:54 +00001522 const UInt * filetab;
1523 const UChar * fn;
sewardjc8259b82009-04-22 22:42:10 +00001524 Int i;
1525 Int k;
florian3e798632012-11-24 19:41:54 +00001526 const UInt * lt_ptr;
sewardjc8259b82009-04-22 22:42:10 +00001527 Int nfile;
1528 Int nseg;
1529 union any_size pnt;
1530 union any_size pnt2;
florian3e798632012-11-24 19:41:54 +00001531 const struct startend * start;
sewardjc8259b82009-04-22 22:42:10 +00001532 Int this_seg;
1533
sewardj275f93d2010-01-26 13:26:41 +00001534 Bool debug = di->trace_symtab;
sewardjc8259b82009-04-22 22:42:10 +00001535 ULong n_lines_read = 0;
1536
sewardj275f93d2010-01-26 13:26:41 +00001537 if (debug)
sewardj3d0724b2015-02-18 15:38:25 +00001538 VG_(umsg)("BEGIN SnarfLineTab linetab=%p size=%d\n", linetab, size);
sewardj275f93d2010-01-26 13:26:41 +00001539
sewardjc8259b82009-04-22 22:42:10 +00001540 /*
1541 * Now get the important bits.
1542 */
1543 pnt.c = linetab;
1544 nfile = *pnt.s++;
1545 nseg = *pnt.s++;
1546
florian3e798632012-11-24 19:41:54 +00001547 filetab = pnt.ui;
sewardjc8259b82009-04-22 22:42:10 +00001548
1549 /*
1550 * Now count up the number of segments in the file.
1551 */
1552 nseg = 0;
1553 for (i = 0; i < nfile; i++) {
florian518850b2014-10-22 22:25:30 +00001554 pnt2.c = (const HChar *)linetab + filetab[i];
sewardjc8259b82009-04-22 22:42:10 +00001555 nseg += *pnt2.s;
1556 }
1557
1558 this_seg = 0;
1559 for (i = 0; i < nfile; i++) {
florian1ef70c62014-10-22 17:42:37 +00001560 const HChar *fnmstr;
1561 const HChar *dirstr;
philippe4b469102014-07-23 20:28:11 +00001562 UInt fnmdirstr_ix;
sewardjc8259b82009-04-22 22:42:10 +00001563
1564 /*
1565 * Get the pointer into the segment information.
1566 */
florian518850b2014-10-22 22:25:30 +00001567 pnt2.c = (const HChar *)linetab + filetab[i];
sewardjc8259b82009-04-22 22:42:10 +00001568 file_segcount = *pnt2.s;
1569
1570 pnt2.ui++;
florian3e798632012-11-24 19:41:54 +00001571 lt_ptr = pnt2.ui;
1572 start = (const struct startend *) (lt_ptr + file_segcount);
sewardjc8259b82009-04-22 22:42:10 +00001573
1574 /*
1575 * Now snarf the filename for all of the segments for this file.
1576 */
florian3e798632012-11-24 19:41:54 +00001577 fn = (const UChar*) (start + file_segcount);
sewardjc8259b82009-04-22 22:42:10 +00001578 /* fn now points at a Pascal-style string, that is, the first
1579 byte is the length, and the remaining up to 255 (presumably)
1580 are the contents. */
1581 vg_assert(WIN32_PATH_MAX >= 256);
1582 VG_(memset)(filename, 0, sizeof(filename));
1583 VG_(memcpy)(filename, fn + 1, *fn);
1584 vg_assert(filename[ sizeof(filename)-1 ] == 0);
1585 filename[(Int)*fn] = 0;
1586 fnmstr = VG_(strrchr)(filename, '\\');
1587 if (fnmstr == NULL)
1588 fnmstr = filename;
1589 else
1590 ++fnmstr;
1591 k = VG_(strlen)(fnmstr);
1592 dirstr = ML_(addStr)(di, filename, *fn - k);
1593 fnmstr = ML_(addStr)(di, fnmstr, k);
philippe4b469102014-07-23 20:28:11 +00001594 fnmdirstr_ix = ML_(addFnDn) (di, fnmstr, dirstr);
sewardjc8259b82009-04-22 22:42:10 +00001595
1596 for (k = 0; k < file_segcount; k++, this_seg++) {
1597 Int linecount;
1598 Int segno;
1599
florian518850b2014-10-22 22:25:30 +00001600 pnt2.c = (const HChar *)linetab + lt_ptr[k];
sewardjc8259b82009-04-22 22:42:10 +00001601
1602 segno = *pnt2.s++;
1603 linecount = *pnt2.s++;
1604
1605 if ( linecount > 0 ) {
1606 UInt j;
1607
1608 if (debug)
sewardj3d0724b2015-02-18 15:38:25 +00001609 VG_(umsg)(
sewardj275f93d2010-01-26 13:26:41 +00001610 " Adding %d lines for file %s segment %d addr=%#x end=%#x\n",
sewardjc8259b82009-04-22 22:42:10 +00001611 linecount, filename, segno, start[k].start, start[k].end );
1612
1613 for ( j = 0; j < linecount; j++ ) {
1614 Addr startaddr = bias + sectp[segno-1].VirtualAddress
1615 + pnt2.ui[j];
1616 Addr endaddr = bias + sectp[segno-1].VirtualAddress
1617 + ((j < (linecount - 1))
1618 ? pnt2.ui[j+1]
1619 : start[k].end);
1620 if (debug)
sewardj3d0724b2015-02-18 15:38:25 +00001621 VG_(umsg)(
sewardj275f93d2010-01-26 13:26:41 +00001622 " Adding line %d addr=%#lx end=%#lx\n",
sewardj3d0724b2015-02-18 15:38:25 +00001623 ((const unsigned short *)(pnt2.ui + linecount))[j],
1624 startaddr, endaddr );
sewardjc8259b82009-04-22 22:42:10 +00001625 ML_(addLineInfo)(
philippe59e1f3c2014-07-14 21:20:57 +00001626 di,
philippe4b469102014-07-23 20:28:11 +00001627 fnmdirstr_ix,
philippe59e1f3c2014-07-14 21:20:57 +00001628 startaddr, endaddr,
florian3e798632012-11-24 19:41:54 +00001629 ((const unsigned short *)(pnt2.ui + linecount))[j], j );
sewardjc8259b82009-04-22 22:42:10 +00001630 n_lines_read++;
1631 }
1632 }
1633 }
1634 }
1635
sewardj275f93d2010-01-26 13:26:41 +00001636 if (debug)
sewardj3d0724b2015-02-18 15:38:25 +00001637 VG_(umsg)("END SnarfLineTab linetab=%p size=%d\n",
1638 linetab, size );
sewardj275f93d2010-01-26 13:26:41 +00001639
sewardjc8259b82009-04-22 22:42:10 +00001640 return n_lines_read;
1641}
1642
1643
1644
1645/* there's a new line tab structure from MS Studio 2005 and after
1646 * it's made of:
1647 * DWORD 000000f4
1648 * DWORD lineblk_offset (counting bytes after this field)
1649 * an array of codeview_linetab2_file structures
1650 * an array (starting at <lineblk_offset>) of codeview_linetab2_block structures
1651 */
1652
florian518850b2014-10-22 22:25:30 +00001653typedef struct codeview_linetab2_file
sewardjc8259b82009-04-22 22:42:10 +00001654{
1655 DWORD offset; /* offset in string table for filename */
1656 WORD unk; /* always 0x0110... type of following
1657 information ??? */
1658 BYTE md5[16]; /* MD5 signature of file (signature on
1659 file's content or name ???) */
1660 WORD pad0; /* always 0 */
florian518850b2014-10-22 22:25:30 +00001661} codeview_linetab2_file;
sewardjc8259b82009-04-22 22:42:10 +00001662
florian518850b2014-10-22 22:25:30 +00001663typedef struct codeview_linetab2_block
sewardjc8259b82009-04-22 22:42:10 +00001664{
1665 DWORD header; /* 0x000000f2 */
1666 DWORD size_of_block; /* next block is at # bytes after this field */
1667 DWORD start; /* start address of function with line numbers */
1668 DWORD seg; /* segment of function with line numbers */
1669 DWORD size; /* size of function with line numbers */
1670 DWORD file_offset; /* offset for accessing corresponding
1671 codeview_linetab2_file */
1672 DWORD nlines; /* number of lines in this block */
1673 DWORD size_lines; /* number of bytes following for line
1674 number information */
1675 struct {
1676 DWORD offset; /* offset (from <seg>:<start>) for line number */
1677 DWORD lineno; /* the line number (OR:ed with
1678 0x80000000 why ???) */
1679 } l[1]; /* actually array of <nlines> */
florian518850b2014-10-22 22:25:30 +00001680} codeview_linetab2_block;
sewardjc8259b82009-04-22 22:42:10 +00001681
1682static ULong codeview_dump_linetab2(
1683 DebugInfo* di,
sewardj54c45db2012-07-13 12:58:55 +00001684 Addr bias,
florian518850b2014-10-22 22:25:30 +00001685 const IMAGE_SECTION_HEADER* sectp,
1686 const HChar* linetab,
sewardjc8259b82009-04-22 22:42:10 +00001687 DWORD size,
florian518850b2014-10-22 22:25:30 +00001688 const HChar* strimage,
sewardjc8259b82009-04-22 22:42:10 +00001689 DWORD strsize,
florian1636d332012-11-15 04:27:04 +00001690 const HChar* pfx
sewardjc8259b82009-04-22 22:42:10 +00001691 )
1692{
1693 DWORD offset;
1694 unsigned i;
florian518850b2014-10-22 22:25:30 +00001695 const codeview_linetab2_block* lbh;
1696 const codeview_linetab2_file* fd;
sewardjc8259b82009-04-22 22:42:10 +00001697
sewardj275f93d2010-01-26 13:26:41 +00001698 Bool debug = di->trace_symtab;
sewardjc8259b82009-04-22 22:42:10 +00001699 ULong n_line2s_read = 0;
1700
1701 if (*(const DWORD*)linetab != 0x000000f4)
1702 return 0;
florian518850b2014-10-22 22:25:30 +00001703 offset = *((const DWORD*)linetab + 1);
1704 lbh = (const codeview_linetab2_block*)(linetab + 8 + offset);
sewardjc8259b82009-04-22 22:42:10 +00001705
florian518850b2014-10-22 22:25:30 +00001706 while ((const HChar*)lbh < linetab + size) {
sewardjc8259b82009-04-22 22:42:10 +00001707
philippe4b469102014-07-23 20:28:11 +00001708 UInt filedirname_ix;
sewardjc8259b82009-04-22 22:42:10 +00001709 Addr svma_s, svma_e;
1710 if (lbh->header != 0x000000f2) {
1711 /* FIXME: should also check that whole lbh fits in linetab + size */
1712 if (debug)
1713 VG_(printf)("%sblock end %x\n", pfx, lbh->header);
1714 break;
1715 }
1716 if (debug)
1717 VG_(printf)("%sblock from %04x:%08x-%08x (size %u) (%u lines)\n",
1718 pfx, lbh->seg, lbh->start, lbh->start + lbh->size - 1,
1719 lbh->size, lbh->nlines);
florian518850b2014-10-22 22:25:30 +00001720 fd = (const codeview_linetab2_file*)(linetab + 8 + lbh->file_offset);
sewardjc8259b82009-04-22 22:42:10 +00001721 if (debug)
1722 VG_(printf)(
1723 "%s md5=%02x%02x%02x%02x%02x%02x%02x%02x"
1724 "%02x%02x%02x%02x%02x%02x%02x%02x\n",
1725 pfx, fd->md5[ 0], fd->md5[ 1], fd->md5[ 2], fd->md5[ 3],
1726 fd->md5[ 4], fd->md5[ 5], fd->md5[ 6], fd->md5[ 7],
1727 fd->md5[ 8], fd->md5[ 9], fd->md5[10], fd->md5[11],
1728 fd->md5[12], fd->md5[13], fd->md5[14], fd->md5[15] );
1729 /* FIXME: should check that string is within strimage + strsize */
sewardj4fc42702015-02-18 12:57:06 +00001730 const HChar* filename = NULL; // in ML_(addStr) space
1731 const HChar* dirname = NULL; // in ML_(addStr) space
sewardjc8259b82009-04-22 22:42:10 +00001732 if (strimage) {
sewardj4fc42702015-02-18 12:57:06 +00001733 const HChar* strI = strimage + fd->offset;
1734 /* Copy |strI| into mutable storage, temporarily, so we can put a zero
1735 byte in place of the last pathname separator. */
1736 HChar* strM = ML_(dinfo_strdup)("di.readpe.cdl2.1", strI);
1737 HChar* fname = VG_(strrchr)(strM, '\\');
1738 if (fname == NULL) {
1739 filename = ML_(addStr)(di, strM, -1);
sewardjc8259b82009-04-22 22:42:10 +00001740 dirname = NULL;
1741 } else {
sewardj4fc42702015-02-18 12:57:06 +00001742 *fname++ = '\0';
1743 filename = ML_(addStr)(di, fname, -1);
1744 dirname = ML_(addStr)(di, strM, -1);
sewardjc8259b82009-04-22 22:42:10 +00001745 }
sewardj4fc42702015-02-18 12:57:06 +00001746 ML_(dinfo_free)(strM);
sewardjc8259b82009-04-22 22:42:10 +00001747 } else {
1748 filename = ML_(addStr)(di, "???", -1);
1749 dirname = NULL;
1750 }
1751
1752 if (debug)
1753 VG_(printf)("%s file=%s\n", pfx, filename);
1754
philippe4b469102014-07-23 20:28:11 +00001755 filedirname_ix = ML_(addFnDn) (di, filename, dirname);
1756
sewardjc8259b82009-04-22 22:42:10 +00001757 for (i = 0; i < lbh->nlines; i++) {
1758 if (debug)
florianc6e5d762015-08-05 22:27:24 +00001759 VG_(printf)("%s offset=%08x line=%u\n",
sewardjc8259b82009-04-22 22:42:10 +00001760 pfx, lbh->l[i].offset, lbh->l[i].lineno ^ 0x80000000);
1761 }
1762
1763 if (lbh->nlines > 1) {
1764 for (i = 0; i < lbh->nlines-1; i++) {
sewardj54c45db2012-07-13 12:58:55 +00001765 svma_s = sectp[lbh->seg - 1].VirtualAddress + lbh->start
1766 + lbh->l[i].offset;
1767 svma_e = sectp[lbh->seg - 1].VirtualAddress + lbh->start
1768 + lbh->l[i+1].offset-1;
sewardjc8259b82009-04-22 22:42:10 +00001769 if (debug)
florianc6e5d762015-08-05 22:27:24 +00001770 VG_(printf)("%s line %u: %08lx to %08lx\n",
sewardjc8259b82009-04-22 22:42:10 +00001771 pfx, lbh->l[i].lineno ^ 0x80000000, svma_s, svma_e);
philippe59e1f3c2014-07-14 21:20:57 +00001772 ML_(addLineInfo)( di,
philippe4b469102014-07-23 20:28:11 +00001773 filedirname_ix,
sewardjc8259b82009-04-22 22:42:10 +00001774 bias + svma_s,
1775 bias + svma_e + 1,
1776 lbh->l[i].lineno ^ 0x80000000, 0 );
1777 n_line2s_read++;
1778 }
sewardj54c45db2012-07-13 12:58:55 +00001779 svma_s = sectp[lbh->seg - 1].VirtualAddress + lbh->start
1780 + lbh->l[ lbh->nlines-1].offset;
1781 svma_e = sectp[lbh->seg - 1].VirtualAddress + lbh->start
1782 + lbh->size - 1;
sewardjc8259b82009-04-22 22:42:10 +00001783 if (debug)
florianc6e5d762015-08-05 22:27:24 +00001784 VG_(printf)("%s line %u: %08lx to %08lx\n",
sewardjc8259b82009-04-22 22:42:10 +00001785 pfx, lbh->l[ lbh->nlines-1 ].lineno ^ 0x80000000,
1786 svma_s, svma_e);
philippe59e1f3c2014-07-14 21:20:57 +00001787 ML_(addLineInfo)( di,
philippe4b469102014-07-23 20:28:11 +00001788 filedirname_ix,
sewardjc8259b82009-04-22 22:42:10 +00001789 bias + svma_s,
1790 bias + svma_e + 1,
1791 lbh->l[lbh->nlines-1].lineno ^ 0x80000000, 0 );
1792 n_line2s_read++;
1793 }
1794
florian518850b2014-10-22 22:25:30 +00001795 lbh = (const codeview_linetab2_block*)
1796 ((const char*)lbh + 8 + lbh->size_of_block);
sewardjc8259b82009-04-22 22:42:10 +00001797 }
1798 return n_line2s_read;
1799}
1800
1801
1802/*------------------------------------------------------------*/
1803/*--- ---*/
1804/*--- Main stuff: pdb_dump ---*/
1805/*--- ---*/
1806/*------------------------------------------------------------*/
1807
florian6bd9dc12012-11-23 16:17:43 +00001808static Int cmp_FPO_DATA_for_canonicalisation ( const void* f1V,
1809 const void* f2V )
sewardj39ff6062010-01-30 13:07:08 +00001810{
1811 /* Cause FPO data to be sorted first in ascending order of range
1812 starts, and for entries with the same range start, with the
1813 shorter range (length) first. */
florian6bd9dc12012-11-23 16:17:43 +00001814 const FPO_DATA* f1 = f1V;
1815 const FPO_DATA* f2 = f2V;
sewardj39ff6062010-01-30 13:07:08 +00001816 if (f1->ulOffStart < f2->ulOffStart) return -1;
1817 if (f1->ulOffStart > f2->ulOffStart) return 1;
1818 if (f1->cbProcSize < f2->cbProcSize) return -1;
1819 if (f1->cbProcSize > f2->cbProcSize) return 1;
1820 return 0; /* identical in both start and length */
1821}
1822
sewardj4fc42702015-02-18 12:57:06 +00001823static unsigned get_stream_by_name(const struct pdb_reader* pdb, const char* name)
1824{
1825 const DWORD* pdw;
1826 const DWORD* ok_bits;
1827 DWORD cbstr, count;
1828 DWORD string_idx, stream_idx;
1829 unsigned i;
1830 const char* str;
1831
1832 if (pdb->read_file == pdb_jg_read_file)
1833 {
1834 str = pdb->u.jg.root->names;
1835 cbstr = pdb->u.jg.root->cbNames;
1836 }
1837 else
1838 {
1839 str = pdb->u.ds.root->names;
1840 cbstr = pdb->u.ds.root->cbNames;
1841 }
1842
1843 pdw = (const DWORD*)(str + cbstr);
1844 pdw++; /* number of ok entries */
1845 count = *pdw++;
1846
1847 /* bitfield: first dword is len (in dword), then data */
1848 ok_bits = pdw;
1849 pdw += *ok_bits++ + 1;
1850 if (*pdw++ != 0)
1851 {
sewardj3d0724b2015-02-18 15:38:25 +00001852 if (VG_(clo_verbosity) > 1)
1853 VG_(umsg)("LOAD_PDB_DEBUGINFO: "
1854 "get_stream_by_name: unexpected value\n");
sewardj4fc42702015-02-18 12:57:06 +00001855 return -1;
1856 }
1857
1858 for (i = 0; i < count; i++)
1859 {
1860 if (ok_bits[i / 32] & (1 << (i % 32)))
1861 {
1862 string_idx = *pdw++;
1863 stream_idx = *pdw++;
1864 if (!VG_(strcmp)(name, &str[string_idx])) return stream_idx;
1865 }
1866 }
1867 return -1;
1868}
1869
1870
1871static void *read_string_table(const struct pdb_reader* pdb)
1872{
1873 unsigned stream_idx;
1874 void* ret;
1875
1876 stream_idx = get_stream_by_name(pdb, "/names");
1877 if (stream_idx == -1) return NULL;
1878 ret = pdb->read_file(pdb, stream_idx,0);
sewardj3d0724b2015-02-18 15:38:25 +00001879 if (ret && *(const DWORD*)ret == 0xeffeeffe) {
1880 return ret;
1881 }
1882 if (VG_(clo_verbosity) > 1)
1883 VG_(umsg)("LOAD_PDB_DEBUGINFO: read_string_table: "
1884 "wrong header 0x%08x, expecting 0xeffeeffe\n",
1885 *(const DWORD*)ret);
sewardj4fc42702015-02-18 12:57:06 +00001886 ML_(dinfo_free)( ret );
1887 return NULL;
1888}
sewardj39ff6062010-01-30 13:07:08 +00001889
sewardjc8259b82009-04-22 22:42:10 +00001890/* JRS fixme: compare with version in current Wine sources */
florian518850b2014-10-22 22:25:30 +00001891static void pdb_dump( const struct pdb_reader* pdb,
sewardjc8259b82009-04-22 22:42:10 +00001892 DebugInfo* di,
sewardj54c45db2012-07-13 12:58:55 +00001893 Addr pe_avma,
1894 PtrdiffT pe_bias,
florian518850b2014-10-22 22:25:30 +00001895 const IMAGE_SECTION_HEADER* sectp_avma )
sewardjc8259b82009-04-22 22:42:10 +00001896{
1897 Int header_size;
1898
1899 PDB_TYPES types;
1900 PDB_SYMBOLS symbols;
1901 unsigned len_modimage;
1902 char *modimage;
florian518850b2014-10-22 22:25:30 +00001903 const char *file;
sewardjc8259b82009-04-22 22:42:10 +00001904
sewardj275f93d2010-01-26 13:26:41 +00001905 Bool debug = di->trace_symtab;
sewardjc8259b82009-04-22 22:42:10 +00001906
1907 ULong n_fpos_read = 0, n_syms_read = 0,
1908 n_lines_read = 0, n_line2s_read = 0;
1909
1910 // FIXME: symbols for bare indices 1,2,3,5 in .pdb file
1911
1912 char* types_image = pdb->read_file( pdb, 2, 0 );
1913 char* symbols_image = pdb->read_file( pdb, 3, 0 );
1914
1915 /* establish filesimage and filessize. These are only needed for
1916 reading linetab2 tables, as far as I can deduce from the Wine
1917 sources. */
sewardjc8ec65a2015-02-23 13:58:55 +00001918 DWORD filessize = 0;
1919 char* filesimage = read_string_table(pdb);
1920 if (filesimage) {
sewardj4fc42702015-02-18 12:57:06 +00001921 filessize = *(const DWORD*)(filesimage + 8);
sewardjc8ec65a2015-02-23 13:58:55 +00001922 } else {
1923 VG_(umsg)("LOAD_PDB_DEBUGINFO: pdb_dump: string table not found\n");
sewardj3d0724b2015-02-18 15:38:25 +00001924 }
sewardjc8259b82009-04-22 22:42:10 +00001925
sewardjc8259b82009-04-22 22:42:10 +00001926 /* Since we just use the FPO data without reformatting, at least
1927 do a basic sanity check on the struct layout. */
1928 vg_assert(sizeof(FPO_DATA) == 16);
1929 if (di->text_present) {
1930 /* only load FPO if there's text present (otherwise it's
1931 meaningless?) */
1932 unsigned sz = 0;
1933 di->fpo = pdb->read_file( pdb, 5, &sz );
sewardj39ff6062010-01-30 13:07:08 +00001934
1935 // FIXME: seems like the size can be a non-integral number
1936 // of FPO_DATAs. Force-align it (moronically). Perhaps this
1937 // signifies that we're not looking at a valid FPO table ..
1938 // who knows. Needs investigation.
1939 while (sz > 0 && (sz % sizeof(FPO_DATA)) != 0)
1940 sz--;
1941
sewardjc8259b82009-04-22 22:42:10 +00001942 di->fpo_size = sz;
sewardj39ff6062010-01-30 13:07:08 +00001943 if (0) VG_(printf)("FPO: got fpo_size %lu\n", (UWord)sz);
1944 vg_assert(0 == (di->fpo_size % sizeof(FPO_DATA)));
sewardj54c45db2012-07-13 12:58:55 +00001945 di->fpo_base_avma = pe_avma;
sewardjc8259b82009-04-22 22:42:10 +00001946 } else {
1947 vg_assert(di->fpo == NULL);
1948 vg_assert(di->fpo_size == 0);
1949 }
1950
sewardj39ff6062010-01-30 13:07:08 +00001951 // BEGIN clean up FPO data
1952 if (di->fpo && di->fpo_size > 0) {
1953 Word i, j;
1954 Bool anyChanges;
1955 Int itersAvail = 10;
1956
sewardjc8259b82009-04-22 22:42:10 +00001957 vg_assert(sizeof(di->fpo[0]) == 16);
1958 di->fpo_size /= sizeof(di->fpo[0]);
1959
sewardj39ff6062010-01-30 13:07:08 +00001960 // BEGIN FPO-data tidying-up loop
1961 do {
sewardjc8259b82009-04-22 22:42:10 +00001962
sewardj39ff6062010-01-30 13:07:08 +00001963 vg_assert(itersAvail >= 0); /* safety check -- don't loop forever */
1964 itersAvail--;
1965
1966 anyChanges = False;
1967
1968 /* First get them in ascending order of start point */
1969 VG_(ssort)( di->fpo, (SizeT)di->fpo_size, (SizeT)sizeof(FPO_DATA),
1970 cmp_FPO_DATA_for_canonicalisation );
1971 /* Get rid of any zero length entries */
1972 j = 0;
1973 for (i = 0; i < di->fpo_size; i++) {
1974 if (di->fpo[i].cbProcSize == 0) {
1975 anyChanges = True;
1976 continue;
1977 }
1978 di->fpo[j++] = di->fpo[i];
sewardjc8259b82009-04-22 22:42:10 +00001979 }
sewardj39ff6062010-01-30 13:07:08 +00001980 vg_assert(j >= 0 && j <= di->fpo_size);
1981 di->fpo_size = j;
1982
1983 /* Get rid of any dups */
1984 if (di->fpo_size > 1) {
1985 j = 1;
1986 for (i = 1; i < di->fpo_size; i++) {
1987 Bool dup
1988 = di->fpo[j-1].ulOffStart == di->fpo[i].ulOffStart
1989 && di->fpo[j-1].cbProcSize == di->fpo[i].cbProcSize;
1990 if (dup) {
1991 anyChanges = True;
1992 continue;
1993 }
1994 di->fpo[j++] = di->fpo[i];
1995 }
1996 vg_assert(j >= 0 && j <= di->fpo_size);
1997 di->fpo_size = j;
1998 }
1999
2000 /* Truncate any overlapping ranges */
2001 for (i = 1; i < di->fpo_size; i++) {
2002 vg_assert(di->fpo[i-1].ulOffStart <= di->fpo[i].ulOffStart);
2003 if (di->fpo[i-1].ulOffStart + di->fpo[i-1].cbProcSize
2004 > di->fpo[i].ulOffStart) {
2005 anyChanges = True;
2006 di->fpo[i-1].cbProcSize
2007 = di->fpo[i].ulOffStart - di->fpo[i-1].ulOffStart;
2008 }
2009 }
2010
2011 } while (anyChanges);
2012 // END FPO-data tidying-up loop
2013
2014 /* Should now be in ascending order, non overlapping, no zero ranges.
2015 Check this, get the min and max avmas, and bias the entries. */
2016 for (i = 0; i < di->fpo_size; i++) {
2017 vg_assert(di->fpo[i].cbProcSize > 0);
2018
2019 if (i > 0) {
2020 vg_assert(di->fpo[i-1].ulOffStart < di->fpo[i].ulOffStart);
2021 vg_assert(di->fpo[i-1].ulOffStart + di->fpo[i-1].cbProcSize
2022 <= di->fpo[i].ulOffStart);
2023 }
sewardjc8259b82009-04-22 22:42:10 +00002024 }
sewardj39ff6062010-01-30 13:07:08 +00002025
sewardjc8259b82009-04-22 22:42:10 +00002026 /* Now bias the table. This can't be done in the same pass as
2027 the sanity check, hence a second loop. */
2028 for (i = 0; i < di->fpo_size; i++) {
sewardj54c45db2012-07-13 12:58:55 +00002029 di->fpo[i].ulOffStart += pe_avma;
sewardj39ff6062010-01-30 13:07:08 +00002030 // make sure the biasing didn't royally screw up, by wrapping
2031 // the range around the end of the address space
2032 vg_assert(0xFFFFFFFF - di->fpo[i].ulOffStart /* "remaining space" */
2033 >= di->fpo[i].cbProcSize);
sewardjc8259b82009-04-22 22:42:10 +00002034 }
2035
sewardj39ff6062010-01-30 13:07:08 +00002036 /* Dump any entries which point outside the text segment and
2037 compute the min/max avma "hint" addresses. */
2038 Addr min_avma = ~(Addr)0;
2039 Addr max_avma = (Addr)0;
2040 vg_assert(di->text_present);
2041 j = 0;
2042 for (i = 0; i < di->fpo_size; i++) {
2043 if ((Addr)(di->fpo[i].ulOffStart) >= di->text_avma
2044 && (Addr)(di->fpo[i].ulOffStart + di->fpo[i].cbProcSize)
2045 <= di->text_avma + di->text_size) {
2046 /* Update min/max limits as we go along. */
2047 if (di->fpo[i].ulOffStart < min_avma)
2048 min_avma = di->fpo[i].ulOffStart;
2049 if (di->fpo[i].ulOffStart + di->fpo[i].cbProcSize - 1 > max_avma)
2050 max_avma = di->fpo[i].ulOffStart + di->fpo[i].cbProcSize - 1;
2051 /* Keep */
2052 di->fpo[j++] = di->fpo[i];
2053 if (0)
2054 VG_(printf)("FPO: keep text=[0x%lx,0x%lx) 0x%lx 0x%lx\n",
2055 di->text_avma, di->text_avma + di->text_size,
2056 (Addr)di->fpo[i].ulOffStart,
2057 (Addr)di->fpo[i].ulOffStart
2058 + (Addr)di->fpo[i].cbProcSize - 1);
2059 } else {
2060 if (0)
2061 VG_(printf)("FPO: SKIP text=[0x%lx,0x%lx) 0x%lx 0x%lx\n",
2062 di->text_avma, di->text_avma + di->text_size,
2063 (Addr)di->fpo[i].ulOffStart,
2064 (Addr)di->fpo[i].ulOffStart
2065 + (Addr)di->fpo[i].cbProcSize - 1);
2066 /* out of range; ignore */
2067 }
2068 }
sewardj6560f212010-01-30 13:36:37 +00002069 vg_assert(j >= 0 && j <= di->fpo_size);
sewardj39ff6062010-01-30 13:07:08 +00002070 di->fpo_size = j;
2071
sewardjc8259b82009-04-22 22:42:10 +00002072 /* And record min/max */
sewardjc8259b82009-04-22 22:42:10 +00002073 /* biasing shouldn't cause wraparound (?!) */
sewardj39ff6062010-01-30 13:07:08 +00002074 if (di->fpo_size > 0) {
2075 vg_assert(min_avma <= max_avma); /* should always hold */
2076 di->fpo_minavma = min_avma;
2077 di->fpo_maxavma = max_avma;
2078 } else {
2079 di->fpo_minavma = 0;
2080 di->fpo_maxavma = 0;
2081 }
sewardjc8259b82009-04-22 22:42:10 +00002082
2083 if (0) {
sewardj39ff6062010-01-30 13:07:08 +00002084 VG_(printf)("FPO: min/max avma %#lx %#lx\n",
sewardjc8259b82009-04-22 22:42:10 +00002085 di->fpo_minavma, di->fpo_maxavma);
2086 }
2087
2088 n_fpos_read += (ULong)di->fpo_size;
2089 }
sewardj39ff6062010-01-30 13:07:08 +00002090 // END clean up FPO data
sewardjc8259b82009-04-22 22:42:10 +00002091
2092 pdb_convert_types_header( &types, types_image );
2093 switch ( types.version ) {
2094 case 19950410: /* VC 4.0 */
2095 case 19951122:
2096 case 19961031: /* VC 5.0 / 6.0 */
2097 case 20040203: /* VC 7.0 FIXME?? */
2098 break;
2099 default:
2100 if (VG_(clo_verbosity) > 1)
sewardj3d0724b2015-02-18 15:38:25 +00002101 VG_(umsg)("LOAD_PDB_DEBUGINFO: "
florianc6e5d762015-08-05 22:27:24 +00002102 "Unknown .pdb type info version %lu\n", types.version );
sewardjc8259b82009-04-22 22:42:10 +00002103 }
2104
2105 header_size = 0;
2106 pdb_convert_symbols_header( &symbols, &header_size, symbols_image );
2107 switch ( symbols.version ) {
2108 case 0: /* VC 4.0 */
2109 case 19960307: /* VC 5.0 */
2110 case 19970606: /* VC 6.0 */
2111 case 19990903: /* VC 7.0 FIXME?? */
2112 break;
2113 default:
2114 if (VG_(clo_verbosity) > 1)
sewardj3d0724b2015-02-18 15:38:25 +00002115 VG_(umsg)("LOAD_PDB_DEBUGINFO: "
florianc6e5d762015-08-05 22:27:24 +00002116 "Unknown .pdb symbol info version %lu\n",
sewardj3d0724b2015-02-18 15:38:25 +00002117 symbols.version );
sewardjc8259b82009-04-22 22:42:10 +00002118 }
2119
2120 /*
2121 * Read global symbol table
2122 */
2123 modimage = pdb->read_file( pdb, symbols.gsym_file, &len_modimage );
2124 if (modimage) {
sewardj275f93d2010-01-26 13:26:41 +00002125 if (debug)
2126 VG_(umsg)("\n");
sewardjc8259b82009-04-22 22:42:10 +00002127 if (VG_(clo_verbosity) > 1)
sewardj3d0724b2015-02-18 15:38:25 +00002128 VG_(umsg)("LOAD_PDB_DEBUGINFO: Reading global symbols\n" );
sewardj54c45db2012-07-13 12:58:55 +00002129 DEBUG_SnarfCodeView( di, pe_avma, sectp_avma, modimage, 0, len_modimage );
florian518850b2014-10-22 22:25:30 +00002130 ML_(dinfo_free)( modimage );
sewardjc8259b82009-04-22 22:42:10 +00002131 }
2132
2133 /*
2134 * Read per-module symbol / linenumber tables
2135 */
2136 file = symbols_image + header_size;
2137 while ( file - symbols_image < header_size + symbols.module_size ) {
sewardjc7ffc942011-03-28 16:26:42 +00002138 int file_nr, /* file_index, */ symbol_size, lineno_size;
florian518850b2014-10-22 22:25:30 +00002139 const char *file_name;
sewardjc8259b82009-04-22 22:42:10 +00002140
2141 if ( symbols.version < 19970000 ) {
florian518850b2014-10-22 22:25:30 +00002142 const PDB_SYMBOL_FILE *sym_file = (const PDB_SYMBOL_FILE *) file;
sewardjc8259b82009-04-22 22:42:10 +00002143 file_nr = sym_file->file;
2144 file_name = sym_file->filename;
sewardjc7ffc942011-03-28 16:26:42 +00002145 /* file_index = sym_file->range.index; */ /* UNUSED */
sewardjc8259b82009-04-22 22:42:10 +00002146 symbol_size = sym_file->symbol_size;
2147 lineno_size = sym_file->lineno_size;
2148 } else {
florian518850b2014-10-22 22:25:30 +00002149 const PDB_SYMBOL_FILE_EX *sym_file = (const PDB_SYMBOL_FILE_EX *) file;
sewardjc8259b82009-04-22 22:42:10 +00002150 file_nr = sym_file->file;
2151 file_name = sym_file->filename;
sewardjc7ffc942011-03-28 16:26:42 +00002152 /* file_index = sym_file->range.index; */ /* UNUSED */
sewardjc8259b82009-04-22 22:42:10 +00002153 symbol_size = sym_file->symbol_size;
2154 lineno_size = sym_file->lineno_size;
2155 }
2156
2157 modimage = pdb->read_file( pdb, file_nr, 0 );
2158 if (modimage) {
2159 Int total_size;
2160 if (0) VG_(printf)("lineno_size %d symbol_size %d\n",
2161 lineno_size, symbol_size );
2162
2163 total_size = pdb_get_file_size(pdb, file_nr);
2164
2165 if (symbol_size) {
sewardj275f93d2010-01-26 13:26:41 +00002166 if (debug)
2167 VG_(umsg)("\n");
sewardjc8259b82009-04-22 22:42:10 +00002168 if (VG_(clo_verbosity) > 1)
sewardj3d0724b2015-02-18 15:38:25 +00002169 VG_(umsg)("LOAD_PDB_DEBUGINFO: Reading symbols for %s\n",
sewardj738856f2009-07-15 14:48:32 +00002170 file_name );
sewardjc8259b82009-04-22 22:42:10 +00002171 n_syms_read
sewardj54c45db2012-07-13 12:58:55 +00002172 += DEBUG_SnarfCodeView( di, pe_avma, sectp_avma, modimage,
sewardjc8259b82009-04-22 22:42:10 +00002173 sizeof(unsigned long),
2174 symbol_size );
2175 }
2176
2177 if (lineno_size) {
sewardj275f93d2010-01-26 13:26:41 +00002178 if (debug)
2179 VG_(umsg)("\n");
sewardjc8259b82009-04-22 22:42:10 +00002180 if (VG_(clo_verbosity) > 1)
sewardj3d0724b2015-02-18 15:38:25 +00002181 VG_(umsg)("LOAD_PDB_DEBUGINFO: "
2182 "Reading lines for %s\n", file_name );
sewardjc8259b82009-04-22 22:42:10 +00002183 n_lines_read
sewardj54c45db2012-07-13 12:58:55 +00002184 += DEBUG_SnarfLinetab( di, pe_avma, sectp_avma,
sewardjc8259b82009-04-22 22:42:10 +00002185 modimage + symbol_size, lineno_size );
2186 }
2187
2188 /* anyway, lineno_size doesn't see to really be the size of
2189 * the line number information, and it's not clear yet when
2190 * to call for linetab2...
2191 */
sewardjc8ec65a2015-02-23 13:58:55 +00002192 if (0) VG_(printf)("Reading lines for %s\n", file_name );
sewardjc8259b82009-04-22 22:42:10 +00002193 n_line2s_read
2194 += codeview_dump_linetab2(
sewardj54c45db2012-07-13 12:58:55 +00002195 di, pe_avma, sectp_avma,
florian1636d332012-11-15 04:27:04 +00002196 (HChar*)modimage + symbol_size + lineno_size,
sewardjc8259b82009-04-22 22:42:10 +00002197 total_size - (symbol_size + lineno_size),
2198 /* if filesimage is NULL, pass that directly onwards
2199 to codeview_dump_linetab2, so it knows not to
2200 poke around in there. */
2201 filesimage ? filesimage + 12 : NULL,
2202 filessize, " "
2203 );
2204
florian518850b2014-10-22 22:25:30 +00002205 ML_(dinfo_free)( modimage );
sewardjc8259b82009-04-22 22:42:10 +00002206 }
2207
2208 file_name += VG_(strlen)(file_name) + 1;
florian518850b2014-10-22 22:25:30 +00002209 file = (const char *)(
sewardjc8259b82009-04-22 22:42:10 +00002210 (unsigned long)(file_name
2211 + VG_(strlen)(file_name) + 1 + 3) & ~3 );
2212 }
2213
2214 /*
2215 * Cleanup
2216 */
2217 if ( symbols_image ) ML_(dinfo_free)( symbols_image );
2218 if ( types_image ) ML_(dinfo_free)( types_image );
2219 if ( pdb->u.jg.toc ) ML_(dinfo_free)( pdb->u.jg.toc );
2220
sewardj20728802010-02-12 12:19:36 +00002221 if (VG_(clo_verbosity) > 1) {
sewardj3d0724b2015-02-18 15:38:25 +00002222 VG_(dmsg)("LOAD_PDB_DEBUGINFO:"
2223 " # symbols read = %llu\n", n_syms_read );
2224 VG_(dmsg)("LOAD_PDB_DEBUGINFO:"
2225 " # lines read = %llu\n", n_lines_read );
2226 VG_(dmsg)("LOAD_PDB_DEBUGINFO:"
2227 " # line2s read = %llu\n", n_line2s_read );
2228 VG_(dmsg)("LOAD_PDB_DEBUGINFO:"
2229 " # fpos read = %llu\n", n_fpos_read );
sewardjc8259b82009-04-22 22:42:10 +00002230 }
2231}
2232
2233
2234/*------------------------------------------------------------*/
2235/*--- ---*/
2236/*--- TOP LEVEL for PDB reading ---*/
2237/*--- ---*/
2238/*------------------------------------------------------------*/
2239
sewardj13ac96d2010-02-12 12:12:39 +00002240/* Read line, symbol and unwind information from a PDB file.
2241*/
sewardjc8259b82009-04-22 22:42:10 +00002242Bool ML_(read_pdb_debug_info)(
2243 DebugInfo* di,
2244 Addr obj_avma,
sewardj54c45db2012-07-13 12:58:55 +00002245 PtrdiffT obj_bias,
sewardjc8259b82009-04-22 22:42:10 +00002246 void* pdbimage,
2247 SizeT n_pdbimage,
florian518850b2014-10-22 22:25:30 +00002248 const HChar* pdbname,
sewardjc8259b82009-04-22 22:42:10 +00002249 ULong pdbmtime
2250 )
2251{
2252 Char* pe_seg_avma;
2253 Int i;
2254 Addr mapped_avma, mapped_end_avma;
2255 unsigned signature;
2256 void* hdr;
2257 struct pdb_reader reader;
2258 IMAGE_DOS_HEADER* dos_avma;
2259 IMAGE_NT_HEADERS* ntheaders_avma;
2260 IMAGE_SECTION_HEADER* sectp_avma;
2261 IMAGE_SECTION_HEADER* pe_sechdr_avma;
2262
2263 if (VG_(clo_verbosity) > 1)
sewardj3d0724b2015-02-18 15:38:25 +00002264 VG_(umsg)("LOAD_PDB_DEBUGINFO: Processing PDB file %s\n", pdbname );
sewardjc8259b82009-04-22 22:42:10 +00002265
2266 dos_avma = (IMAGE_DOS_HEADER *)obj_avma;
2267 if (dos_avma->e_magic != IMAGE_DOS_SIGNATURE)
2268 return False;
2269
2270 ntheaders_avma
2271 = (IMAGE_NT_HEADERS *)((Char*)dos_avma + dos_avma->e_lfanew);
2272 if (ntheaders_avma->Signature != IMAGE_NT_SIGNATURE)
2273 return False;
2274
2275 sectp_avma
2276 = (IMAGE_SECTION_HEADER *)(
2277 (Char*)ntheaders_avma
2278 + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader)
2279 + ntheaders_avma->FileHeader.SizeOfOptionalHeader
2280 );
2281
2282 /* JRS: this seems like something of a hack. */
2283 di->soname = ML_(dinfo_strdup)("di.readpdb.rpdi.1", pdbname);
2284
2285 /* someone (ie WINE) is loading a Windows PE format object. we
2286 need to use its details to determine which area of memory is
2287 executable... */
2288 pe_seg_avma
2289 = (Char*)ntheaders_avma
2290 + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader)
2291 + ntheaders_avma->FileHeader.SizeOfOptionalHeader;
2292
sewardj54c45db2012-07-13 12:58:55 +00002293 /* Iterate over PE headers and fill our section mapping table. */
sewardjc8259b82009-04-22 22:42:10 +00002294 for ( i = 0;
2295 i < ntheaders_avma->FileHeader.NumberOfSections;
2296 i++, pe_seg_avma += sizeof(IMAGE_SECTION_HEADER) ) {
2297 pe_sechdr_avma = (IMAGE_SECTION_HEADER *)pe_seg_avma;
2298
sewardj54c45db2012-07-13 12:58:55 +00002299 if (VG_(clo_verbosity) > 1) {
2300 /* Copy name, it can be 8 chars and not NUL-terminated */
2301 char name[9];
2302 VG_(memcpy)(name, pe_sechdr_avma->Name, 8);
2303 name[8] = '\0';
sewardj3d0724b2015-02-18 15:38:25 +00002304 VG_(umsg)("LOAD_PDB_DEBUGINFO:"
2305 " Scanning PE section %ps at avma %#lx svma %#lx\n",
2306 name, obj_avma + pe_sechdr_avma->VirtualAddress,
2307 pe_sechdr_avma->VirtualAddress);
sewardj54c45db2012-07-13 12:58:55 +00002308 }
sewardjc8259b82009-04-22 22:42:10 +00002309
2310 if (pe_sechdr_avma->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
2311 continue;
2312
2313 mapped_avma = (Addr)obj_avma + pe_sechdr_avma->VirtualAddress;
2314 mapped_end_avma = mapped_avma + pe_sechdr_avma->Misc.VirtualSize;
sewardjc8259b82009-04-22 22:42:10 +00002315
florian518850b2014-10-22 22:25:30 +00002316 DebugInfoMapping map;
sewardj6b5625b2012-07-13 11:24:05 +00002317 map.avma = mapped_avma;
2318 map.size = pe_sechdr_avma->Misc.VirtualSize;
2319 map.foff = pe_sechdr_avma->PointerToRawData;
2320 map.ro = False;
2321
sewardjc8259b82009-04-22 22:42:10 +00002322 if (pe_sechdr_avma->Characteristics & IMAGE_SCN_CNT_CODE) {
tom368ef5d2009-07-01 11:59:20 +00002323 /* Ignore uninitialised code sections - if you have
2324 incremental linking enabled in Visual Studio then you will
2325 get a uninitialised code section called .textbss before
2326 the real text section and valgrind will compute the wrong
2327 avma value and hence the wrong bias. */
2328 if (!(pe_sechdr_avma->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)) {
sewardj6b5625b2012-07-13 11:24:05 +00002329 map.rx = True;
2330 map.rw = False;
2331 VG_(addToXA)(di->fsm.maps, &map);
sewardja5acac32011-09-20 21:59:50 +00002332 di->fsm.have_rx_map = True;
sewardj6b5625b2012-07-13 11:24:05 +00002333
tom368ef5d2009-07-01 11:59:20 +00002334 di->text_present = True;
sewardj6b5625b2012-07-13 11:24:05 +00002335 if (di->text_avma == 0) {
2336 di->text_svma = pe_sechdr_avma->VirtualAddress;
tom368ef5d2009-07-01 11:59:20 +00002337 di->text_avma = mapped_avma;
sewardj6b5625b2012-07-13 11:24:05 +00002338 di->text_size = pe_sechdr_avma->Misc.VirtualSize;
2339 } else {
2340 di->text_size = mapped_end_avma - di->text_avma;
tom368ef5d2009-07-01 11:59:20 +00002341 }
sewardjc8259b82009-04-22 22:42:10 +00002342 }
sewardjc8259b82009-04-22 22:42:10 +00002343 }
2344 else if (pe_sechdr_avma->Characteristics
2345 & IMAGE_SCN_CNT_INITIALIZED_DATA) {
sewardj6b5625b2012-07-13 11:24:05 +00002346 map.rx = False;
2347 map.rw = True;
2348 VG_(addToXA)(di->fsm.maps, &map);
sewardja5acac32011-09-20 21:59:50 +00002349 di->fsm.have_rw_map = True;
sewardj6b5625b2012-07-13 11:24:05 +00002350
sewardjc8259b82009-04-22 22:42:10 +00002351 di->data_present = True;
sewardj6b5625b2012-07-13 11:24:05 +00002352 if (di->data_avma == 0) {
sewardjc8259b82009-04-22 22:42:10 +00002353 di->data_avma = mapped_avma;
sewardj6b5625b2012-07-13 11:24:05 +00002354 di->data_size = pe_sechdr_avma->Misc.VirtualSize;
2355 } else {
2356 di->data_size = mapped_end_avma - di->data_avma;
sewardjc8259b82009-04-22 22:42:10 +00002357 }
sewardjc8259b82009-04-22 22:42:10 +00002358 }
2359 else if (pe_sechdr_avma->Characteristics
2360 & IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
2361 di->bss_present = True;
sewardj6b5625b2012-07-13 11:24:05 +00002362 if (di->bss_avma == 0) {
2363 di->bss_avma = mapped_avma;
2364 di->bss_size = pe_sechdr_avma->Misc.VirtualSize;
2365 } else {
2366 di->bss_size = mapped_end_avma - di->bss_avma;
sewardjc8259b82009-04-22 22:42:10 +00002367 }
2368 }
2369 }
2370
sewardja5acac32011-09-20 21:59:50 +00002371 if (di->fsm.have_rx_map && di->fsm.have_rw_map && !di->have_dinfo) {
2372 vg_assert(di->fsm.filename);
sewardjc8259b82009-04-22 22:42:10 +00002373 TRACE_SYMTAB("\n");
2374 TRACE_SYMTAB("------ start PE OBJECT with PDB INFO "
2375 "---------------------\n");
sewardja5acac32011-09-20 21:59:50 +00002376 TRACE_SYMTAB("------ name = %s\n", di->fsm.filename);
sewardjc8259b82009-04-22 22:42:10 +00002377 TRACE_SYMTAB("\n");
2378 }
2379
sewardj54c45db2012-07-13 12:58:55 +00002380 di->text_bias = obj_bias;
sewardjc8259b82009-04-22 22:42:10 +00002381
2382 if (VG_(clo_verbosity) > 1) {
sewardj6b5625b2012-07-13 11:24:05 +00002383 for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
florian518850b2014-10-22 22:25:30 +00002384 const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i);
sewardj6b5625b2012-07-13 11:24:05 +00002385 if (map->rx)
sewardj3d0724b2015-02-18 15:38:25 +00002386 VG_(dmsg)("LOAD_PDB_DEBUGINFO: "
sewardjda4bdf72015-08-18 07:54:22 +00002387 "rx_map: avma %#lx size %7lu foff %lld\n",
2388 map->avma, map->size, (Long)map->foff);
sewardj6b5625b2012-07-13 11:24:05 +00002389 }
2390 for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
florian518850b2014-10-22 22:25:30 +00002391 const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i);
sewardj6b5625b2012-07-13 11:24:05 +00002392 if (map->rw)
sewardj3d0724b2015-02-18 15:38:25 +00002393 VG_(dmsg)("LOAD_PDB_DEBUGINFO: "
sewardjda4bdf72015-08-18 07:54:22 +00002394 "rw_map: avma %#lx size %7lu foff %lld\n",
2395 map->avma, map->size, (Long)map->foff);
sewardj6b5625b2012-07-13 11:24:05 +00002396 }
sewardjc8259b82009-04-22 22:42:10 +00002397
sewardj3d0724b2015-02-18 15:38:25 +00002398 VG_(dmsg)("LOAD_PDB_DEBUGINFO: "
2399 " text: avma %#lx svma %#lx size %7lu bias %#lx\n",
2400 di->text_avma, di->text_svma,
florianc6e5d762015-08-05 22:27:24 +00002401 di->text_size, (UWord)di->text_bias);
sewardjc8259b82009-04-22 22:42:10 +00002402 }
2403
2404 /*
2405 * Read in TOC and well-known files
2406 */
2407 signature = 0;
2408 hdr = find_pdb_header( pdbimage, &signature );
2409 if (0==hdr)
2410 return False; /* JRS: significance? no pdb header? */
2411
2412 VG_(memset)(&reader, 0, sizeof(reader));
2413 reader.u.jg.header = hdr;
2414
2415 if (0==VG_(strncmp)((char const *)&signature, "DS\0\0", 4)) {
2416 struct PDB_DS_ROOT* root;
2417 pdb_ds_init( &reader, pdbimage, n_pdbimage );
2418 root = reader.read_file( &reader, 1, 0 );
sewardj4fc42702015-02-18 12:57:06 +00002419 reader.u.ds.root = root;
sewardjc8259b82009-04-22 22:42:10 +00002420 if (root) {
2421 pdb_check_root_version_and_timestamp(
2422 pdbname, pdbmtime, root->version, root->TimeDateStamp );
sewardjc8259b82009-04-22 22:42:10 +00002423 }
sewardj54c45db2012-07-13 12:58:55 +00002424 pdb_dump( &reader, di, obj_avma, obj_bias, sectp_avma );
sewardj4fc42702015-02-18 12:57:06 +00002425 if (root) {
2426 ML_(dinfo_free)( root );
2427 }
sewardjc8259b82009-04-22 22:42:10 +00002428 }
2429 else
2430 if (0==VG_(strncmp)((char const *)&signature, "JG\0\0", 4)) {
2431 struct PDB_JG_ROOT* root;
2432 pdb_jg_init( &reader, pdbimage, n_pdbimage );
2433 root = reader.read_file( &reader, 1, 0 );
sewardj4fc42702015-02-18 12:57:06 +00002434 reader.u.jg.root = root;
sewardjc8259b82009-04-22 22:42:10 +00002435 if (root) {
2436 pdb_check_root_version_and_timestamp(
2437 pdbname, pdbmtime, root->version, root->TimeDateStamp);
sewardjc8259b82009-04-22 22:42:10 +00002438 }
sewardj54c45db2012-07-13 12:58:55 +00002439 pdb_dump( &reader, di, obj_avma, obj_bias, sectp_avma );
sewardj4fc42702015-02-18 12:57:06 +00002440 if (root) {
2441 ML_(dinfo_free)( root );
2442 }
sewardjc8259b82009-04-22 22:42:10 +00002443 }
2444
2445 if (1) {
2446 TRACE_SYMTAB("\n------ Canonicalising the "
2447 "acquired info ------\n");
2448 /* prepare read data for use */
2449 ML_(canonicaliseTables)( di );
2450 /* notify m_redir about it */
2451 TRACE_SYMTAB("\n------ Notifying m_redir ------\n");
2452 VG_(redir_notify_new_DebugInfo)( di );
2453 /* Note that we succeeded */
2454 di->have_dinfo = True;
2455 } else {
2456 TRACE_SYMTAB("\n------ PE with PDB reading failed ------\n");
2457 /* Something went wrong (eg. bad ELF file). Should we delete
2458 this DebugInfo? No - it contains info on the rw/rx
2459 mappings, at least. */
2460 }
2461
2462 TRACE_SYMTAB("\n");
sewardja5acac32011-09-20 21:59:50 +00002463 TRACE_SYMTAB("------ name = %s\n", di->fsm.filename);
sewardjc8259b82009-04-22 22:42:10 +00002464 TRACE_SYMTAB("------ end PE OBJECT with PDB INFO "
2465 "--------------------\n");
2466 TRACE_SYMTAB("\n");
2467
2468 return True;
2469}
2470
sewardj13ac96d2010-02-12 12:12:39 +00002471
2472/* Examine a PE file to see if it states the path of an associated PDB
2473 file; if so return that. Caller must deallocate with
2474 ML_(dinfo_free).
2475*/
2476
florian518850b2014-10-22 22:25:30 +00002477HChar* ML_(find_name_of_pdb_file)( const HChar* pename )
sewardj13ac96d2010-02-12 12:12:39 +00002478{
2479 /* This is a giant kludge, of the kind "you did WTF?!?", but it
2480 works. */
2481 Bool do_cleanup = False;
florian87c8abb2014-11-09 16:15:23 +00002482 HChar tmpnameroot[50]; // large enough
2483 HChar tmpname[VG_(mkstemp_fullname_bufsz)(sizeof tmpnameroot - 1)];
sewardj13ac96d2010-02-12 12:12:39 +00002484 Int fd, r;
2485 HChar* res = NULL;
2486
2487 if (!pename)
2488 goto out;
2489
2490 fd = -1;
2491 VG_(memset)(tmpnameroot, 0, sizeof(tmpnameroot));
2492 VG_(sprintf)(tmpnameroot, "petmp%d", VG_(getpid)());
2493 VG_(memset)(tmpname, 0, sizeof(tmpname));
2494 fd = VG_(mkstemp)( tmpnameroot, tmpname );
2495 if (fd == -1) {
sewardj3d0724b2015-02-18 15:38:25 +00002496 VG_(umsg)("LOAD_PDB_DEBUGINFO: "
2497 "Find PDB file: Can't create temporary file %s\n", tmpname);
sewardj13ac96d2010-02-12 12:12:39 +00002498 goto out;
2499 }
2500 do_cleanup = True;
2501
2502 /* Make up the command to run, essentially:
sewardj04aae322015-02-17 13:46:26 +00002503 sh -c "strings (pename) | egrep '\.pdb$|\.PDB$' > (tmpname)"
sewardj13ac96d2010-02-12 12:12:39 +00002504 */
florian6bd9dc12012-11-23 16:17:43 +00002505 const HChar* sh = "/bin/sh";
florian0d77f502015-09-16 08:59:03 +00002506 const HChar* strings = "strings";
2507 const HChar* egrep = "grep -E";
sewardj13ac96d2010-02-12 12:12:39 +00002508
2509 /* (sh) -c "(strings) (pename) | (egrep) 'pdb' > (tmpname) */
2510 Int cmdlen = VG_(strlen)(strings) + VG_(strlen)(pename)
2511 + VG_(strlen)(egrep) + VG_(strlen)(tmpname)
2512 + 100/*misc*/;
2513 HChar* cmd = ML_(dinfo_zalloc)("di.readpe.fnopf.cmd", cmdlen);
sewardj04aae322015-02-17 13:46:26 +00002514 VG_(sprintf)(cmd, "%s -c \"%s '%s' | %s '\\.pdb$|\\.PDB$' >> %s\"",
sewardj13ac96d2010-02-12 12:12:39 +00002515 sh, strings, pename, egrep, tmpname);
2516 vg_assert(cmd[cmdlen-1] == 0);
2517 if (0) VG_(printf)("QQQQQQQQ: %s\n", cmd);
2518
2519 r = VG_(system)( cmd );
2520 if (r) {
sewardj3d0724b2015-02-18 15:38:25 +00002521 VG_(dmsg)("LOAD_PDB_DEBUGINFO: "
2522 "Find PDB file: Command failed:\n %s\n", cmd);
sewardj13ac96d2010-02-12 12:12:39 +00002523 goto out;
2524 }
2525
2526 /* Find out how big the file is, and get it aboard. */
2527 struct vg_stat stat_buf;
2528 VG_(memset)(&stat_buf, 0, sizeof(stat_buf));
2529
2530 SysRes sr = VG_(stat)(tmpname, &stat_buf);
2531 if (sr_isError(sr)) {
sewardj3d0724b2015-02-18 15:38:25 +00002532 VG_(umsg)("LOAD_PDB_DEBUGINFO: Find PDB file: can't stat %s\n", tmpname);
sewardj13ac96d2010-02-12 12:12:39 +00002533 goto out;
2534 }
2535
2536 Int szB = (Int)stat_buf.size;
2537 if (szB == 0) {
sewardj3d0724b2015-02-18 15:38:25 +00002538 VG_(umsg)("LOAD_PDB_DEBUGINFO: Find PDB file: %s is empty\n", tmpname);
sewardj13ac96d2010-02-12 12:12:39 +00002539 goto out;
2540 }
2541 /* 6 == strlen("X.pdb\n") */
2542 if (szB < 6 || szB > 1024/*let's say*/) {
sewardj3d0724b2015-02-18 15:38:25 +00002543 VG_(umsg)("LOAD_PDB_DEBUGINFO: Find PDB file: %s has implausible size %d\n",
sewardj13ac96d2010-02-12 12:12:39 +00002544 tmpname, szB);
2545 goto out;
2546 }
2547
2548 HChar* pdbname = ML_(dinfo_zalloc)("di.readpe.fnopf.pdbname", szB + 1);
sewardj13ac96d2010-02-12 12:12:39 +00002549 pdbname[szB] = 0;
2550
2551 Int nread = VG_(read)(fd, pdbname, szB);
2552 if (nread != szB) {
sewardj3d0724b2015-02-18 15:38:25 +00002553 VG_(umsg)("LOAD_PDB_DEBUGINFO: Find PDB file: read of %s failed\n", tmpname);
sewardj13ac96d2010-02-12 12:12:39 +00002554 goto out;
2555 }
2556 vg_assert(pdbname[szB] == 0);
2557
2558 /* Check we've got something remotely sane -- must have one dot and
2559 one \n in it, and the \n must be at the end */
2560 Bool saw_dot = False;
2561 Int saw_n_crs = 0;
2562 Int i;
2563 for (i = 0; pdbname[i]; i++) {
2564 if (pdbname[i] == '.') saw_dot = True;
2565 if (pdbname[i] == '\n') saw_n_crs++;
2566 }
2567 if (!saw_dot || saw_n_crs != 1 || pdbname[szB-1] != '\n') {
sewardj3d0724b2015-02-18 15:38:25 +00002568 VG_(umsg)("LOAD_PDB_DEBUGINFO: Find PDB file: can't make sense of: %s\n", pdbname);
sewardj13ac96d2010-02-12 12:12:39 +00002569 goto out;
2570 }
2571 /* Change the \n to a terminating zero, so we have a "normal" string */
2572 pdbname[szB-1] = 0;
2573
2574 if (0) VG_(printf)("QQQQQQQQ: got %s\n", pdbname);
2575
2576 res = pdbname;
2577 goto out;
2578
2579 out:
2580 if (do_cleanup) {
2581 VG_(close)(fd);
2582 VG_(unlink)( tmpname );
2583 }
2584 return res;
2585}
2586
sewardj8eb8bab2015-07-21 14:44:28 +00002587#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
sewardjc8259b82009-04-22 22:42:10 +00002588
2589/*--------------------------------------------------------------------*/
njn8b68b642009-06-24 00:37:09 +00002590/*--- end ---*/
sewardjc8259b82009-04-22 22:42:10 +00002591/*--------------------------------------------------------------------*/