VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/dbg/dbgmodcodeview.cpp@ 46936

Last change on this file since 46936 was 46936, checked in by vboxsync, 11 years ago

fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 104.7 KB
Line 
1/* $Id: dbgmodcodeview.cpp 46936 2013-07-03 13:28:53Z vboxsync $ */
2/** @file
3 * IPRT - Debug Module Reader For Microsoft CodeView and COFF.
4 *
5 * Based on the following documentation (plus guess work and googling):
6 *
7 * - "Tools Interface Standard (TIS) Formats Specification for Windows",
8 * dated February 1993, version 1.0.
9 *
10 * - "Visual C++ 5.0 Symbolic Debug Information Specification" chapter of
11 * SPECS.CHM from MSDN Library October 2001.
12 *
13 * - "High Level Languages Debug Table Documentation", aka HLLDBG.HTML, aka
14 * IBMHLL.HTML, last changed 1996-07-08.
15 *
16 * Testcases using RTLdrFlt:
17 * - VBoxPcBios.sym at 0xf0000.
18 * - NT4 kernel PE image (coff syms).
19 */
20
21/*
22 * Copyright (C) 2013 Oracle Corporation
23 *
24 * This file is part of VirtualBox Open Source Edition (OSE), as
25 * available from http://www.virtualbox.org. This file is free software;
26 * you can redistribute it and/or modify it under the terms of the GNU
27 * General Public License (GPL) as published by the Free Software
28 * Foundation, in version 2 as it comes in the "COPYING" file of the
29 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
30 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
31 *
32 * The contents of this file may alternatively be used under the terms
33 * of the Common Development and Distribution License Version 1.0
34 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
35 * VirtualBox OSE distribution, in which case the provisions of the
36 * CDDL are applicable instead of those of the GPL.
37 *
38 * You may elect to license modified versions of this file under the
39 * terms and conditions of either the GPL or the CDDL or both.
40 */
41
42
43/*******************************************************************************
44* Header Files *
45*******************************************************************************/
46#define LOG_GROUP RTLOGGROUP_DBG
47#include <iprt/dbg.h>
48#include "internal/iprt.h"
49
50#include <iprt/alloca.h>
51#include <iprt/asm.h>
52#include <iprt/assert.h>
53#include <iprt/err.h>
54#include <iprt/file.h>
55#include <iprt/log.h>
56#include <iprt/mem.h>
57#include <iprt/param.h>
58#include <iprt/path.h>
59#include <iprt/string.h>
60#include <iprt/strcache.h>
61#include "internal/dbgmod.h"
62#include "internal/ldrPE.h"
63#include "internal/magics.h"
64
65
66/*******************************************************************************
67* Structures and Typedefs *
68*******************************************************************************/
69/**
70 * CodeView Header. There are two of this, base header at the start of the debug
71 * information and a trailing header at the end.
72 */
73typedef struct RTCVHDR
74{
75 /** The magic ('NBxx'), see RTCVHDR_MAGIC_XXX. */
76 uint32_t u32Magic;
77 /**
78 * Base header: Subsection directory offset relative to this header (start).
79 * Trailing header: Offset of the base header relative to the end of the file.
80 *
81 * Called lfoBase, lfaBase, lfoDirectory, lfoDir and probably other things in
82 * the various specs/docs available. */
83 uint32_t off;
84} RTCVHDR;
85/** Pointer to a CodeView header. */
86typedef RTCVHDR *PRTCVHDR;
87
88/** @name CodeView magic values (RTCVHDR::u32Magic).
89 * @{ */
90/** CodeView from Visual C++ 5.0. Specified in the 2001 MSDN specs.chm file. */
91#define RTCVHDR_MAGIC_NB11 RT_MAKE_U32_FROM_U8('N', 'B', '1', '1')
92/** External PDB reference (often referred to as PDB 2.0). */
93#define RTCVHDR_MAGIC_NB10 RT_MAKE_U32_FROM_U8('N', 'B', '1', '0')
94/** CodeView v4.10, packed. Specified in the TIS document. */
95#define RTCVHDR_MAGIC_NB09 RT_MAKE_U32_FROM_U8('N', 'B', '0', '9')
96/** CodeView v4.00 thru v4.05. Specified in the TIS document? */
97#define RTCVHDR_MAGIC_NB08 RT_MAKE_U32_FROM_U8('N', 'B', '0', '8')
98/** Quick C for Windows 1.0 debug info. */
99#define RTCVHDR_MAGIC_NB07 RT_MAKE_U32_FROM_U8('N', 'B', '0', '7')
100/** Emitted by ILINK indicating incremental link. Comparable to NB05? */
101#define RTCVHDR_MAGIC_NB06 RT_MAKE_U32_FROM_U8('N', 'B', '0', '6')
102/** Emitted by LINK version 5.20 and later before packing. */
103#define RTCVHDR_MAGIC_NB05 RT_MAKE_U32_FROM_U8('N', 'B', '0', '5')
104/** Emitted by IBM ILINK for HLL (similar to NB02 in many ways). */
105#define RTCVHDR_MAGIC_NB04 RT_MAKE_U32_FROM_U8('N', 'B', '0', '4')
106/** Emitted by LINK version 5.10 (or similar OMF linkers), as shipped with
107 * Microsoft C v6.0 for example. More or less entirely 16-bit. */
108#define RTCVHDR_MAGIC_NB02 RT_MAKE_U32_FROM_U8('N', 'B', '0', '2')
109/* No idea what NB03 might have been. */
110/** AIX debugger format according to "IBM OS/2 16/32-bit Object Module Format
111 * (OMF) and Linear eXecutable Module Format (LX)" revision 10 (LXOMF.PDF). */
112#define RTCVHDR_MAGIC_NB01 RT_MAKE_U32_FROM_U8('N', 'B', '0', '1')
113/** Ancient CodeView format according to LXOMF.PDF. */
114#define RTCVHDR_MAGIC_NB00 RT_MAKE_U32_FROM_U8('N', 'B', '0', '0')
115/** @} */
116
117
118/** @name CV directory headers.
119 * @{ */
120
121/**
122 * Really old CV directory header used with NB00 and NB02.
123 *
124 * Uses 16-bit directory entires (RTCVDIRENT16).
125 */
126typedef struct RTCVDIRHDR16
127{
128 /** The number of directory entries. */
129 uint16_t cEntries;
130} RTCVDIRHDR16;
131/** Pointer to a old CV directory header. */
132typedef RTCVDIRHDR16 *PRTCVDIRHDR16;
133
134/**
135 * Simple 32-bit CV directory base header, used by NB04 (aka IBM HLL).
136 */
137typedef struct RTCVDIRHDR32
138{
139 /** The number of bytes of this header structure. */
140 uint16_t cbHdr;
141 /** The number of bytes per entry. */
142 uint16_t cbEntry;
143 /** The number of directory entries. */
144 uint32_t cEntries;
145} RTCVDIRHDR32;
146/** Pointer to a 32-bit CV directory header. */
147typedef RTCVDIRHDR32 *PRTCVDIRHDR32;
148
149/**
150 * Extended 32-bit CV directory header as specified in the TIS doc.
151 * The two extra fields seems to never have been assigned any official purpose.
152 */
153typedef struct RTCVDIRHDR32EX
154{
155 /** This starts the same way as the NB04 header. */
156 RTCVDIRHDR32 Core;
157 /** Tentatively decleared as the offset to the next directory generated by
158 * the incremental linker. Haven't seen this used yet. */
159 uint32_t offNextDir;
160 /** Flags, non defined apparently, so MBZ. */
161 uint32_t fFlags;
162} RTCVDIRHDR32EX;
163/** Pointer to an extended 32-bit CV directory header. */
164typedef RTCVDIRHDR32EX *PRTCVDIRHDR32EX;
165
166/** @} */
167
168
169/**
170 * 16-bit CV directory entry used with NB00 and NB02.
171 */
172typedef struct RTCVDIRENT16
173{
174 /** Subsection type (RTCVSST). */
175 uint16_t uSubSectType;
176 /** Which module (1-based, 0xffff is special). */
177 uint16_t iMod;
178 /** The lowe offset of this subsection relative to the base CV header. */
179 uint16_t offLow;
180 /** The high part of the subsection offset. */
181 uint16_t offHigh;
182 /** The size of the subsection. */
183 uint16_t cb;
184} RTCVDIRENT16;
185AssertCompileSize(RTCVDIRENT16, 10);
186/** Pointer to a 16-bit CV directory entry. */
187typedef RTCVDIRENT16 *PRTCVDIRENT16;
188
189
190/**
191 * 32-bit CV directory entry used starting with NB04.
192 */
193typedef struct RTCVDIRENT32
194{
195 /** Subsection type (RTCVSST). */
196 uint16_t uSubSectType;
197 /** Which module (1-based, 0xffff is special). */
198 uint16_t iMod;
199 /** The offset of this subsection relative to the base CV header. */
200 uint32_t off;
201 /** The size of the subsection. */
202 uint32_t cb;
203} RTCVDIRENT32;
204AssertCompileSize(RTCVDIRENT32, 12);
205/** Pointer to a 32-bit CV directory entry. */
206typedef RTCVDIRENT32 *PRTCVDIRENT32;
207/** Pointer to a const 32-bit CV directory entry. */
208typedef RTCVDIRENT32 const *PCRTCVDIRENT32;
209
210
211/**
212 * CodeView subsection types.
213 */
214typedef enum RTCVSST
215{
216 /** @name NB00, NB02 and NB04 subsection types.
217 * The actual format of each subsection varies between NB04 and the others,
218 * and it may further vary in NB04 depending on the module type.
219 * @{ */
220 kCvSst_OldModule = 0x101,
221 kCvSst_OldPublic,
222 kCvSst_OldTypes,
223 kCvSst_OldSymbols,
224 kCvSst_OldSrcLines,
225 kCvSst_OldLibraries,
226 kCvSst_OldImports,
227 kCvSst_OldCompacted,
228 kCvSst_OldSrcLnSeg = 0x109,
229 kCvSst_OldSrcLines3 = 0x10b,
230 /** @} */
231
232 /** @name NB09, NB11 (and possibly NB05, NB06, NB07, and NB08) subsection types.
233 * @{ */
234 kCvSst_Module = 0x120,
235 kCvSst_Types,
236 kCvSst_Public,
237 kCvSst_PublicSym,
238 kCvSst_Symbols,
239 kCvSst_AlignSym,
240 kCvSst_SrcLnSeg,
241 kCvSst_SrcModule,
242 kCvSst_Libraries,
243 kCvSst_GlobalSym,
244 kCvSst_GlobalPub,
245 kCvSst_GlobalTypes,
246 kCvSst_MPC,
247 kCvSst_SegMap,
248 kCvSst_SegName,
249 kCvSst_PreComp,
250 kCvSst_PreCompMap,
251 kCvSst_OffsetMap16,
252 kCvSst_OffsetMap32,
253 kCvSst_FileIndex = 0x133,
254 kCvSst_StaticSym
255 /** @} */
256} RTCVSST;
257/** Pointer to a CV subsection type value. */
258typedef RTCVSST *PRTCVSST;
259/** Pointer to a const CV subsection type value. */
260typedef RTCVSST const *PCRTCVSST;
261
262
263/**
264 * CV4 module segment info.
265 */
266typedef struct RTCVMODSEGINFO32
267{
268 /** The segment number. */
269 uint16_t iSeg;
270 /** Explicit padding. */
271 uint16_t u16Padding;
272 /** Offset into the segment. */
273 uint32_t off;
274 /** The size of the contribution. */
275 uint32_t cb;
276} RTCVMODSEGINFO32;
277typedef RTCVMODSEGINFO32 *PRTCVMODSEGINFO32;
278typedef RTCVMODSEGINFO32 const *PCRTCVMODSEGINFO32;
279
280
281/**
282 * CV4 segment map header.
283 */
284typedef struct RTCVSEGMAPHDR
285{
286 /** Number of segments descriptors in the table. */
287 uint16_t cSegs;
288 /** Number of logical segment descriptors. */
289 uint16_t cLogSegs;
290} RTCVSEGMAPHDR;
291/** Pointer to a CV4 segment map header. */
292typedef RTCVSEGMAPHDR *PRTCVSEGMAPHDR;
293/** Pointer to a const CV4 segment map header. */
294typedef RTCVSEGMAPHDR const *PCRTCVSEGMAPHDR;
295
296/**
297 * CV4 Segment map descriptor entry.
298 */
299typedef struct RTCVSEGMAPDESC
300{
301 /** Segment flags. */
302 uint16_t fFlags;
303 /** The overlay number. */
304 uint16_t iOverlay;
305 /** Group index into this segment descriptor array. 0 if not relevant.
306 * The group descriptors are found in the second half of the table. */
307 uint16_t iGroup;
308 /** Complicated. */
309 uint16_t iFrame;
310 /** Offset (byte) into the kCvSst_SegName table of the segment name, or
311 * 0xffff. */
312 uint16_t offSegName;
313 /** Offset (byte) into the kCvSst_SegName table of the class name, or 0xffff. */
314 uint16_t offClassName;
315 /** Offset into the physical segment. */
316 uint32_t off;
317 /** Size of segment. */
318 uint32_t cb;
319} RTCVSEGMAPDESC;
320/** Pointer to a segment map descriptor entry. */
321typedef RTCVSEGMAPDESC *PRTCVSEGMAPDESC;
322/** Pointer to a const segment map descriptor entry. */
323typedef RTCVSEGMAPDESC const *PCRTCVSEGMAPDESC;
324
325/** @name RTCVSEGMAPDESC_F_XXX - RTCVSEGMAPDESC::fFlags values.
326 * @{ */
327#define RTCVSEGMAPDESC_F_READ UINT16_C(0x0001)
328#define RTCVSEGMAPDESC_F_WRITE UINT16_C(0x0002)
329#define RTCVSEGMAPDESC_F_EXECUTE UINT16_C(0x0004)
330#define RTCVSEGMAPDESC_F_32BIT UINT16_C(0x0008)
331#define RTCVSEGMAPDESC_F_SEL UINT16_C(0x0100)
332#define RTCVSEGMAPDESC_F_ABS UINT16_C(0x0200)
333#define RTCVSEGMAPDESC_F_GROUP UINT16_C(0x1000)
334#define RTCVSEGMAPDESC_F_RESERVED UINT16_C(0xecf0)
335/** @} */
336
337/**
338 * CV4 segment map subsection.
339 */
340typedef struct RTCVSEGMAP
341{
342 /** The header. */
343 RTCVSEGMAPHDR Hdr;
344 /** Descriptor array. */
345 RTCVSEGMAPDESC aDescs[1];
346} RTCVSEGMAP;
347/** Pointer to a segment map subsection. */
348typedef RTCVSEGMAP *PRTCVSEGMAP;
349/** Pointer to a const segment map subsection. */
350typedef RTCVSEGMAP const *PCRTCVSEGMAP;
351
352
353/**
354 * Global symbol table header, used by kCvSst_GlobalSym and kCvSst_GlobalPub.
355 */
356typedef struct RTCVGLOBALSYMTABHDR
357{
358 /** The symbol hash function. */
359 uint16_t uSymHash;
360 /** The address hash function. */
361 uint16_t uAddrHash;
362 /** The amount of symbol information following immediately after the header. */
363 uint32_t cbSymbols;
364 /** The amount of symbol hash tables following the symbols. */
365 uint32_t cbSymHash;
366 /** The amount of address hash tables following the symbol hash tables. */
367 uint32_t cbAddrHash;
368} RTCVGLOBALSYMTABHDR;
369/** Pointer to a global symbol table header. */
370typedef RTCVGLOBALSYMTABHDR *PRTCVGLOBALSYMTABHDR;
371/** Pointer to a const global symbol table header. */
372typedef RTCVGLOBALSYMTABHDR const *PCRTCVGLOBALSYMTABHDR;
373
374
375typedef enum RTCVSYMTYPE
376{
377 /** @name Symbols that doesn't change with compilation model or target machine.
378 * @{ */
379 kCvSymType_Compile = 0x0001,
380 kCvSymType_Register,
381 kCvSymType_Constant,
382 kCvSymType_UDT,
383 kCvSymType_SSearch,
384 kCvSymType_End,
385 kCvSymType_Skip,
386 kCvSymType_CVReserve,
387 kCvSymType_ObjName,
388 kCvSymType_EndArg,
389 kCvSymType_CobolUDT,
390 kCvSymType_ManyReg,
391 kCvSymType_Return,
392 kCvSymType_EntryThis,
393 /** @} */
394
395 /** @name Symbols with 16:16 addresses.
396 * @{ */
397 kCvSymType_BpRel16 = 0x0100,
398 kCvSymType_LData16,
399 kCvSymType_GData16,
400 kCvSymType_Pub16,
401 kCvSymType_LProc16,
402 kCvSymType_GProc16,
403 kCvSymType_Thunk16,
404 kCvSymType_BLock16,
405 kCvSymType_With16,
406 kCvSymType_Label16,
407 kCvSymType_CExModel16,
408 kCvSymType_VftPath16,
409 kCvSymType_RegRel16,
410 /** @} */
411
412 /** @name Symbols with 16:32 addresses.
413 * @{ */
414 kCvSymType_BpRel32 = 0x0200,
415 kCvSymType_LData32,
416 kCvSymType_GData32,
417 kCvSymType_Pub32,
418 kCvSymType_LProc32,
419 kCvSymType_GProc32,
420 kCvSymType_Thunk32,
421 kCvSymType_Block32,
422 kCvSymType_With32,
423 kCvSymType_Label32,
424 kCvSymType_CExModel32,
425 kCvSymType_VftPath32,
426 kCvSymType_RegRel32,
427 kCvSymType_LThread32,
428 kCvSymType_GThread32,
429 /** @} */
430
431 /** @name Symbols for MIPS.
432 * @{ */
433 kCvSymType_LProcMips = 0x0300,
434 kCvSymType_GProcMips,
435 /** @} */
436
437 /** @name Symbols for Microsoft CodeView.
438 * @{ */
439 kCvSymType_ProcRef,
440 kCvSymType_DataRef,
441 kCvSymType_Align
442 /** @} */
443} RTCVSYMTYPE;
444typedef RTCVSYMTYPE *PRTCVSYMTYPE;
445typedef RTCVSYMTYPE const *PCRTCVSYMTYPE;
446
447
448/** The $$SYMBOL table signature for CV4. */
449#define RTCVSYMBOLS_SIGNATURE_CV4 UINT32_C(0x00000001)
450
451
452/**
453 * Directory sorting order.
454 */
455typedef enum RTCVDIRORDER
456{
457 RTCVDIRORDER_INVALID = 0,
458 /** Ordered by module. */
459 RTCVDIRORDER_BY_MOD,
460 /** Ordered by module, but 0 modules at the end. */
461 RTCVDIRORDER_BY_MOD_0,
462 /** Ordered by section, with global modules at the end. */
463 RTCVDIRORDER_BY_SST_MOD
464} RTCVDIRORDER;
465
466
467/**
468 * File type.
469 */
470typedef enum RTCVFILETYPE
471{
472 RTCVFILETYPE_INVALID = 0,
473 /** Executable image. */
474 RTCVFILETYPE_IMAGE,
475 /** A DBG-file with a IMAGE_SEPARATE_DEBUG_HEADER. */
476 RTCVFILETYPE_DBG,
477 /** A PDB file. */
478 RTCVFILETYPE_PDB,
479 /** Some other kind of file with CV at the end. */
480 RTCVFILETYPE_OTHER_AT_END,
481 /** The end of the valid values. */
482 RTCVFILETYPE_END,
483 /** Type blowup. */
484 RTCVFILETYPE_32BIT_HACK = 0x7fffffff
485} RTCVFILETYPE;
486
487
488/**
489 * CodeView debug info reader instance.
490 */
491typedef struct RTDBGMODCV
492{
493 /** Using a container for managing the debug info. */
494 RTDBGMOD hCnt;
495
496 /** @name Codeview details
497 * @{ */
498 /** The code view magic (used as format indicator). */
499 uint32_t u32CvMagic;
500 /** The offset of the CV debug info in the file. */
501 uint32_t offBase;
502 /** The size of the CV debug info. */
503 uint32_t cbDbgInfo;
504 /** The offset of the subsection directory (relative to offBase). */
505 uint32_t offDir;
506 /** The directory order. */
507 RTCVDIRORDER enmDirOrder;
508 /** @} */
509
510 /** @name COFF details.
511 * @{ */
512 /** Offset of the COFF header. */
513 uint32_t offCoffDbgInfo;
514 /** The size of the COFF debug info. */
515 uint32_t cbCoffDbgInfo;
516 /** The COFF debug info header. */
517 IMAGE_COFF_SYMBOLS_HEADER CoffHdr;
518 /** @} */
519
520 /** The file type. */
521 RTCVFILETYPE enmType;
522 /** The file handle (if external). */
523 RTFILE hFile;
524 /** Pointer to the module (no reference retained). */
525 PRTDBGMODINT pMod;
526
527 /** The image size, if we know it. This is 0 if we don't know it. */
528 uint32_t cbImage;
529
530 /** Indicates that we've loaded segments intot he container already. */
531 bool fHaveLoadedSegments;
532 /** Alternative address translation method for DOS frames. */
533 bool fHaveDosFrames;
534
535 /** @name Codeview Parsing state.
536 * @{ */
537 /** Number of directory entries. */
538 uint32_t cDirEnts;
539 /** The directory (converted to 32-bit). */
540 PRTCVDIRENT32 paDirEnts;
541 /** Current debugging style when parsing modules. */
542 uint16_t uCurStyle;
543 /** Current debugging style version (HLL only). */
544 uint16_t uCurStyleVer;
545
546 /** The segment map (if present). */
547 PRTCVSEGMAP pSegMap;
548 /** Segment names. */
549 char *pszzSegNames;
550 /** The size of the segment names. */
551 uint32_t cbSegNames;
552
553 /** @} */
554
555} RTDBGMODCV;
556/** Pointer to a codeview debug info reader instance. */
557typedef RTDBGMODCV *PRTDBGMODCV;
558/** Pointer to a const codeview debug info reader instance. */
559typedef RTDBGMODCV *PCRTDBGMODCV;
560
561
562
563/**
564 * Subsection callback.
565 *
566 * @returns IPRT status code.
567 * @param pThis The CodeView debug info reader instance.
568 * @param pvSubSect Pointer to the subsection data.
569 * @param cbSubSect The size of the subsection data.
570 * @param pDirEnt The directory entry.
571 */
572typedef DECLCALLBACK(int) FNDBGMODCVSUBSECTCALLBACK(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect,
573 PCRTCVDIRENT32 pDirEnt);
574/** Pointer to a subsection callback. */
575typedef FNDBGMODCVSUBSECTCALLBACK *PFNDBGMODCVSUBSECTCALLBACK;
576
577
578
579/*******************************************************************************
580* Defined Constants And Macros *
581*******************************************************************************/
582/** Light weight assert + return w/ fixed status code. */
583#define RTDBGMODCV_CHECK_RET_BF(a_Expr, a_LogArgs) \
584 do { \
585 if (!(a_Expr)) \
586 { \
587 Log(("RTDbgCv: Check failed on line %d: " #a_Expr "\n", __LINE__)); \
588 Log(a_LogArgs); \
589 /*return VERR_CV_BAD_FORMAT;*/ \
590 } \
591 } while (0)
592
593
594/** Light weight assert + return w/ fixed status code. */
595#define RTDBGMODCV_CHECK_NOMSG_RET_BF(a_Expr) \
596 do { \
597 if (!(a_Expr)) \
598 { \
599 Log(("RTDbgCv: Check failed on line %d: " #a_Expr "\n", __LINE__)); \
600 /*return VERR_CV_BAD_FORMAT;*/ \
601 } \
602 } while (0)
603
604
605
606
607
608/**
609 * Reads CodeView information.
610 *
611 * @returns IPRT status.
612 * @param pThis The CodeView reader instance.
613 * @param off The offset to start reading at, relative to the
614 * CodeView base header.
615 * @param pvBuf The buffer to read into.
616 * @param cb How many bytes to read.
617 */
618static int rtDbgModCvReadAt(PRTDBGMODCV pThis, uint32_t off, void *pvBuf, size_t cb)
619{
620 int rc;
621 if (pThis->hFile == NIL_RTFILE)
622 rc = pThis->pMod->pImgVt->pfnReadAt(pThis->pMod, UINT32_MAX, off + pThis->offBase, pvBuf, cb);
623 else
624 rc = RTFileReadAt(pThis->hFile, off + pThis->offBase, pvBuf, cb, NULL);
625 return rc;
626}
627
628
629/**
630 * Reads CodeView information into an allocated buffer.
631 *
632 * @returns IPRT status.
633 * @param pThis The CodeView reader instance.
634 * @param off The offset to start reading at, relative to the
635 * CodeView base header.
636 * @param ppvBuf Where to return the allocated buffer on success.
637 * @param cb How many bytes to read.
638 */
639static int rtDbgModCvReadAtAlloc(PRTDBGMODCV pThis, uint32_t off, void **ppvBuf, size_t cb)
640{
641 int rc;
642 void *pvBuf = *ppvBuf = RTMemAlloc(cb);
643 if (pvBuf)
644 {
645 if (pThis->hFile == NIL_RTFILE)
646 rc = pThis->pMod->pImgVt->pfnReadAt(pThis->pMod, UINT32_MAX, off + pThis->offBase, pvBuf, cb);
647 else
648 rc = RTFileReadAt(pThis->hFile, off + pThis->offBase, pvBuf, cb, NULL);
649 if (RT_SUCCESS(rc))
650 return VINF_SUCCESS;
651
652 RTMemFree(pvBuf);
653 *ppvBuf = NULL;
654 }
655 else
656 rc = VERR_NO_MEMORY;
657 return rc;
658}
659
660
661/**
662 * Gets a name string for a subsection type.
663 *
664 * @returns Section name (read only).
665 * @param uSubSectType The subsection type.
666 */
667static const char *rtDbgModCvGetSubSectionName(uint16_t uSubSectType)
668{
669 switch (uSubSectType)
670 {
671 case kCvSst_OldModule: return "sstOldModule";
672 case kCvSst_OldPublic: return "sstOldPublic";
673 case kCvSst_OldTypes: return "sstOldTypes";
674 case kCvSst_OldSymbols: return "sstOldSymbols";
675 case kCvSst_OldSrcLines: return "sstOldSrcLines";
676 case kCvSst_OldLibraries: return "sstOldLibraries";
677 case kCvSst_OldImports: return "sstOldImports";
678 case kCvSst_OldCompacted: return "sstOldCompacted";
679 case kCvSst_OldSrcLnSeg: return "sstOldSrcLnSeg";
680 case kCvSst_OldSrcLines3: return "sstOldSrcLines3";
681
682 case kCvSst_Module: return "sstModule";
683 case kCvSst_Types: return "sstTypes";
684 case kCvSst_Public: return "sstPublic";
685 case kCvSst_PublicSym: return "sstPublicSym";
686 case kCvSst_Symbols: return "sstSymbols";
687 case kCvSst_AlignSym: return "sstAlignSym";
688 case kCvSst_SrcLnSeg: return "sstSrcLnSeg";
689 case kCvSst_SrcModule: return "sstSrcModule";
690 case kCvSst_Libraries: return "sstLibraries";
691 case kCvSst_GlobalSym: return "sstGlobalSym";
692 case kCvSst_GlobalPub: return "sstGlobalPub";
693 case kCvSst_GlobalTypes: return "sstGlobalTypes";
694 case kCvSst_MPC: return "sstMPC";
695 case kCvSst_SegMap: return "sstSegMap";
696 case kCvSst_SegName: return "sstSegName";
697 case kCvSst_PreComp: return "sstPreComp";
698 case kCvSst_PreCompMap: return "sstPreCompMap";
699 case kCvSst_OffsetMap16: return "sstOffsetMap16";
700 case kCvSst_OffsetMap32: return "sstOffsetMap32";
701 case kCvSst_FileIndex: return "sstFileIndex";
702 case kCvSst_StaticSym: return "sstStaticSym";
703 }
704 static char s_sz[32];
705 RTStrPrintf(s_sz, sizeof(s_sz), "Unknown%#x", uSubSectType);
706 return s_sz;
707}
708
709
710/**
711 * Adds a symbol to the container.
712 *
713 * @returns IPRT status code
714 * @param pThis The CodeView debug info reader instance.
715 * @param iSeg Segment number.
716 * @param off Offset into the segment
717 * @param pchName The symbol name (not necessarily terminated).
718 * @param cchName The symbol name length.
719 * @param fFlags Flags reserved for future exploits, MBZ.
720 */
721static int rtDbgModCvAddSymbol(PRTDBGMODCV pThis, uint32_t iSeg, uint64_t off, const char *pchName,
722 uint8_t cchName, uint32_t fFlags)
723{
724 const char *pszName = RTStrCacheEnterN(g_hDbgModStrCache, pchName, cchName);
725 if (!pszName)
726 return VERR_NO_STR_MEMORY;
727#if 1
728 Log2(("CV Sym: %04x:%08x %.*s\n", iSeg, off, cchName, pchName));
729 if (iSeg == 0)
730 iSeg = RTDBGSEGIDX_ABS;
731 else if (pThis->pSegMap)
732 {
733 if (pThis->fHaveDosFrames)
734 {
735 if ( iSeg > pThis->pSegMap->Hdr.cSegs
736 || iSeg == 0)
737 {
738 Log(("Invalid segment index/offset %#06x:%08x for symbol %.*s\n", iSeg, off, cchName, pchName));
739 return VERR_CV_BAD_FORMAT;
740 }
741 if (off <= pThis->pSegMap->aDescs[iSeg - 1].cb + pThis->pSegMap->aDescs[iSeg - 1].off)
742 off -= pThis->pSegMap->aDescs[iSeg - 1].off;
743 else
744 {
745 /* Workaround for VGABIOS where _DATA symbols like vgafont8 are
746 reported in the VGAROM segment. */
747 uint64_t uAddrSym = off + ((uint32_t)pThis->pSegMap->aDescs[iSeg - 1].iFrame << 4);
748 uint16_t j = pThis->pSegMap->Hdr.cSegs;
749 while (j-- > 0)
750 {
751 uint64_t uAddrFirst = (uint64_t)pThis->pSegMap->aDescs[j].off
752 + ((uint32_t)pThis->pSegMap->aDescs[j].iFrame << 4);
753 if (uAddrSym - uAddrFirst < pThis->pSegMap->aDescs[j].cb)
754 {
755 Log(("CV addr fix: %04x:%08x -> %04x:%08x\n", iSeg, off, j + 1, uAddrSym - uAddrFirst));
756 off = uAddrSym - uAddrFirst;
757 iSeg = j + 1;
758 break;
759 }
760 }
761 if (j == UINT16_MAX)
762 {
763 Log(("Invalid segment index/offset %#06x:%08x for symbol %.*s [2]\n", iSeg, off, cchName, pchName));
764 return VERR_CV_BAD_FORMAT;
765 }
766 }
767 }
768 else
769 {
770 if ( iSeg > pThis->pSegMap->Hdr.cSegs
771 || iSeg == 0
772 || off > pThis->pSegMap->aDescs[iSeg - 1].cb)
773 {
774 Log(("Invalid segment index/offset %#06x:%08x for symbol %.*s\n", iSeg, off, cchName, pchName));
775 return VERR_CV_BAD_FORMAT;
776 }
777 off += pThis->pSegMap->aDescs[iSeg - 1].off;
778 }
779 if (pThis->pSegMap->aDescs[iSeg - 1].fFlags & RTCVSEGMAPDESC_F_ABS)
780 iSeg = RTDBGSEGIDX_ABS;
781 else
782 iSeg = pThis->pSegMap->aDescs[iSeg - 1].iGroup;
783 }
784
785 int rc = RTDbgModSymbolAdd(pThis->hCnt, pszName, iSeg, off, 0, 0 /*fFlags*/, NULL);
786 Log(("Symbol: %04x:%08x %.*s [%Rrc]\n", iSeg, off, cchName, pchName, rc));
787 if (rc == VERR_DBG_ADDRESS_CONFLICT || rc == VERR_DBG_DUPLICATE_SYMBOL)
788 rc = VINF_SUCCESS;
789 RTStrCacheRelease(g_hDbgModStrCache, pszName);
790 return rc;
791#else
792 Log(("Symbol: %04x:%08x %.*s\n", iSeg, off, cchName, pchName));
793 return VINF_SUCCESS;
794#endif
795}
796
797
798/**
799 * Parses a CV4 symbol table, adding symbols to the container.
800 *
801 * @returns IPRT status code
802 * @param pThis The CodeView debug info reader instance.
803 * @param pbSymTab The symbol table.
804 * @param cbSymTab The size of the symbol table.
805 * @param fFlags Flags reserved for future exploits, MBZ.
806 */
807static int rtDbgModCvSsProcessV4SymTab(PRTDBGMODCV pThis, void const *pvSymTab, size_t cbSymTab, uint32_t fFlags)
808{
809 int rc = VINF_SUCCESS;
810 RTCPTRUNION uCursor;
811 uCursor.pv = pvSymTab;
812
813 while (cbSymTab > 0 && RT_SUCCESS(rc))
814 {
815 uint8_t const * const pbRecStart = uCursor.pu8;
816 uint16_t cbRec = *uCursor.pu16++;
817 if (cbRec >= 2)
818 {
819 uint16_t uSymType = *uCursor.pu16++;
820
821 Log3((" %p: uSymType=%#06x LB %#x\n", pbRecStart - (uint8_t *)pvSymTab, uSymType, cbRec));
822 RTDBGMODCV_CHECK_RET_BF(cbRec >= 2 && cbRec <= cbSymTab, ("cbRec=%#x cbSymTab=%#x\n", cbRec, cbSymTab));
823
824 switch (uSymType)
825 {
826 case kCvSymType_LData16:
827 case kCvSymType_GData16:
828 case kCvSymType_Pub16:
829 {
830 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec > 2 + 2+2+2+1);
831 uint16_t off = *uCursor.pu16++;
832 uint16_t iSeg = *uCursor.pu16++;
833 /*uint16_t iType =*/ *uCursor.pu16++;
834 uint8_t cchName = *uCursor.pu8++;
835 RTDBGMODCV_CHECK_NOMSG_RET_BF(cchName > 0);
836 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec >= 2 + 2+2+2+1 + cchName);
837
838 rc = rtDbgModCvAddSymbol(pThis, iSeg, off, uCursor.pch, cchName, 0);
839 break;
840 }
841
842 case kCvSymType_LData32:
843 case kCvSymType_GData32:
844 case kCvSymType_Pub32:
845 {
846 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec > 2 + 4+2+2+1);
847 uint32_t off = *uCursor.pu32++;
848 uint16_t iSeg = *uCursor.pu16++;
849 /*uint16_t iType =*/ *uCursor.pu16++;
850 uint8_t cchName = *uCursor.pu8++;
851 RTDBGMODCV_CHECK_NOMSG_RET_BF(cchName > 0);
852 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbRec >= 2 + 4+2+2+1 + cchName);
853
854 rc = rtDbgModCvAddSymbol(pThis, iSeg, off, uCursor.pch, cchName, 0);
855 break;
856 }
857
858 /** @todo add GProc and LProc so we can gather sizes as well as just symbols. */
859 }
860 }
861 /*else: shorter records can be used for alignment, I guess. */
862
863 /* next */
864 uCursor.pu8 = pbRecStart + cbRec + 2;
865 cbSymTab -= cbRec + 2;
866 }
867 return rc;
868}
869
870
871/** @callback_method_impl{FNDBGMODCVSUBSECTCALLBACK,
872 * Parses kCvSst_GlobalPub, kCvSst_GlobalSym and kCvSst_StaticSym subsections,
873 * adding symbols it finds to the container.} */
874static DECLCALLBACK(int)
875rtDbgModCvSs_GlobalPub_GlobalSym_StaticSym(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect, PCRTCVDIRENT32 pDirEnt)
876{
877 PCRTCVGLOBALSYMTABHDR pHdr = (PCRTCVGLOBALSYMTABHDR)pvSubSect;
878
879 /*
880 * Quick data validation.
881 */
882 Log2(("RTDbgModCv: %s: uSymHash=%#x uAddrHash=%#x cbSymbols=%#x cbSymHash=%#x cbAddrHash=%#x\n",
883 rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType), pHdr->uSymHash,
884 pHdr->uAddrHash, pHdr->cbSymbols, pHdr->cbSymHash, pHdr->cbAddrHash));
885 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= sizeof(RTCVGLOBALSYMTABHDR));
886 RTDBGMODCV_CHECK_NOMSG_RET_BF((uint64_t)pHdr->cbSymbols + pHdr->cbSymHash + pHdr->cbAddrHash <= cbSubSect - sizeof(*pHdr));
887 RTDBGMODCV_CHECK_NOMSG_RET_BF(pHdr->uSymHash < 0x20);
888 RTDBGMODCV_CHECK_NOMSG_RET_BF(pHdr->uAddrHash < 0x20);
889 if (!pHdr->cbSymbols)
890 return VINF_SUCCESS;
891
892 /*
893 * Parse the symbols.
894 */
895 return rtDbgModCvSsProcessV4SymTab(pThis, pHdr + 1, pHdr->cbSymbols, 0);
896}
897
898
899/** @callback_method_impl{FNDBGMODCVSUBSECTCALLBACK,
900 * Parses kCvSst_Module subsection, storing the debugging style in pThis.} */
901static DECLCALLBACK(int)
902rtDbgModCvSs_Module(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect, PCRTCVDIRENT32 pDirEnt)
903{
904 RTCPTRUNION uCursor;
905 uCursor.pv = pvSubSect;
906 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= 2 + 2 + 2 + 2 + 0 + 1);
907 uint16_t iOverlay = *uCursor.pu16++;
908 uint16_t iLib = *uCursor.pu16++;
909 uint16_t cSegs = *uCursor.pu16++;
910 pThis->uCurStyle = *uCursor.pu16++;
911 if (pThis->uCurStyle == 0)
912 pThis->uCurStyle = RT_MAKE_U16('C', 'V');
913 pThis->uCurStyleVer = 0;
914 uint8_t cchName = uCursor.pu8[cSegs * 12];
915 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= 2 + 2 + 2 + 2 + cSegs * 12U + 1 + cchName);
916
917 const char *pchName = (const char *)&uCursor.pu8[cSegs * 12 + 1];
918 Log2(("RTDbgModCv: Module: iOverlay=%#x iLib=%#x cSegs=%#x Style=%c%c (%#x) %.*s\n", iOverlay, iLib, cSegs,
919 RT_BYTE1(pThis->uCurStyle), RT_BYTE2(pThis->uCurStyle), pThis->uCurStyle, cchName, pchName));
920 RTDBGMODCV_CHECK_NOMSG_RET_BF(pThis->uCurStyle == RT_MAKE_U16('C', 'V'));
921
922 PCRTCVMODSEGINFO32 paSegs = (PCRTCVMODSEGINFO32)uCursor.pv;
923 for (uint16_t iSeg = 0; iSeg < cSegs; iSeg++)
924 Log2((" #%02u: %04x:%08x LB %08x\n", iSeg, paSegs[iSeg].iSeg, paSegs[iSeg].off, paSegs[iSeg].cb));
925
926 return VINF_SUCCESS;
927}
928
929
930/** @callback_method_impl{FNDBGMODCVSUBSECTCALLBACK,
931 * Parses kCvSst_Symbols, kCvSst_PublicSym and kCvSst_AlignSym subsections,
932 * adding symbols it finds to the container.} */
933static DECLCALLBACK(int)
934rtDbgModCvSs_Symbols_PublicSym_AlignSym(PRTDBGMODCV pThis, void const *pvSubSect, size_t cbSubSect, PCRTCVDIRENT32 pDirEnt)
935{
936 RTDBGMODCV_CHECK_NOMSG_RET_BF(pThis->uCurStyle == RT_MAKE_U16('C', 'V'));
937 RTDBGMODCV_CHECK_NOMSG_RET_BF(cbSubSect >= 8);
938
939 uint32_t u32Signature = *(uint32_t const *)pvSubSect;
940 RTDBGMODCV_CHECK_RET_BF(u32Signature == RTCVSYMBOLS_SIGNATURE_CV4,
941 ("%#x, expected %#x\n", u32Signature, RTCVSYMBOLS_SIGNATURE_CV4));
942
943 return rtDbgModCvSsProcessV4SymTab(pThis, (uint8_t const *)pvSubSect + 4, cbSubSect - 4, 0);
944}
945
946
947static int rtDbgModCvLoadSegmentMap(PRTDBGMODCV pThis)
948{
949 /*
950 * Search for the segment map and segment names. They will be at the end of the directory.
951 */
952 uint32_t iSegMap = UINT32_MAX;
953 uint32_t iSegNames = UINT32_MAX;
954 uint32_t i = pThis->cDirEnts;
955 while (i-- > 0)
956 {
957 if ( pThis->paDirEnts[i].iMod != 0xffff
958 && pThis->paDirEnts[i].iMod != 0x0000)
959 break;
960 if (pThis->paDirEnts[i].uSubSectType == kCvSst_SegMap)
961 iSegMap = i;
962 else if (pThis->paDirEnts[i].uSubSectType == kCvSst_SegName)
963 iSegNames = i;
964 }
965 if (iSegMap == UINT32_MAX)
966 {
967 Log(("RTDbgModCv: No segment map present, using segment indexes as is then...\n"));
968 return VINF_SUCCESS;
969 }
970 RTDBGMODCV_CHECK_RET_BF(pThis->paDirEnts[iSegMap].cb >= sizeof(RTCVSEGMAPHDR),
971 ("Bad sstSegMap entry: cb=%#x\n", pThis->paDirEnts[iSegMap].cb));
972 RTDBGMODCV_CHECK_NOMSG_RET_BF(iSegNames == UINT32_MAX || pThis->paDirEnts[iSegNames].cb > 0);
973
974 /*
975 * Read them into memory.
976 */
977 int rc = rtDbgModCvReadAtAlloc(pThis, pThis->paDirEnts[iSegMap].off, (void **)&pThis->pSegMap,
978 pThis->paDirEnts[iSegMap].cb);
979 if (iSegNames != UINT32_MAX && RT_SUCCESS(rc))
980 {
981 pThis->cbSegNames = pThis->paDirEnts[iSegNames].cb;
982 rc = rtDbgModCvReadAtAlloc(pThis, pThis->paDirEnts[iSegNames].off, (void **)&pThis->pszzSegNames,
983 pThis->paDirEnts[iSegNames].cb);
984 }
985 if (RT_FAILURE(rc))
986 return rc;
987 RTDBGMODCV_CHECK_NOMSG_RET_BF(!pThis->pszzSegNames || !pThis->pszzSegNames[pThis->cbSegNames - 1]); /* must be terminated */
988
989 /* Use local pointers to avoid lots of indirection and typing. */
990 PCRTCVSEGMAPHDR pHdr = &pThis->pSegMap->Hdr;
991 PRTCVSEGMAPDESC paDescs = &pThis->pSegMap->aDescs[0];
992
993 /*
994 * If there are only logical segments, assume a direct mapping.
995 * PE images, like the NT4 kernel, does it like this.
996 */
997 bool const fNoGroups = pHdr->cSegs == pHdr->cLogSegs;
998
999 /*
1000 * The PE image has an extra section/segment for the headers, the others
1001 * doesn't. PE images doesn't have DOS frames. So, figure the image type now.
1002 */
1003 RTLDRFMT enmImgFmt = RTLDRFMT_INVALID;
1004 if (pThis->pMod->pImgVt)
1005 enmImgFmt = pThis->pMod->pImgVt->pfnGetFormat(pThis->pMod);
1006
1007 /*
1008 * Validate and display it all.
1009 */
1010 Log2(("RTDbgModCv: SegMap: cSegs=%#x cLogSegs=%#x (cbSegNames=%#x)\n", pHdr->cSegs, pHdr->cLogSegs, pThis->cbSegNames));
1011 RTDBGMODCV_CHECK_RET_BF(pThis->paDirEnts[iSegMap].cb >= sizeof(*pHdr) + pHdr->cSegs * sizeof(paDescs[0]),
1012 ("SegMap is out of bounds: cbSubSect=%#x cSegs=%#x\n", pThis->paDirEnts[iSegMap].cb, pHdr->cSegs));
1013 RTDBGMODCV_CHECK_NOMSG_RET_BF(pHdr->cSegs >= pHdr->cLogSegs);
1014
1015 Log2(("Logical segment descriptors: %u\n", pHdr->cLogSegs));
1016
1017 bool fHaveDosFrames = false;
1018 for (i = 0; i < pHdr->cSegs; i++)
1019 {
1020 if (i == pHdr->cLogSegs)
1021 Log2(("Group/Physical descriptors: %u\n", pHdr->cSegs - pHdr->cLogSegs));
1022 uint16_t idx = i < pHdr->cLogSegs ? i : i - pHdr->cLogSegs;
1023 char szFlags[16];
1024 memset(szFlags, '-', sizeof(szFlags));
1025 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_READ)
1026 szFlags[0] = 'R';
1027 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_WRITE)
1028 szFlags[1] = 'W';
1029 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_EXECUTE)
1030 szFlags[2] = 'X';
1031 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_32BIT)
1032 szFlags[3] = '3', szFlags[4] = '2';
1033 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_SEL)
1034 szFlags[5] = 'S';
1035 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_ABS)
1036 szFlags[6] = 'A';
1037 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP)
1038 szFlags[7] = 'G';
1039 szFlags[8] = '\0';
1040 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_RESERVED)
1041 szFlags[8] = '!', szFlags[9] = '\0';
1042 Log2((" #%02u: %#010x LB %#010x flags=%#06x ovl=%#06x group=%#06x frame=%#06x iSegName=%#06x iClassName=%#06x %s\n",
1043 idx, paDescs[i].off, paDescs[i].cb, paDescs[i].fFlags, paDescs[i].iOverlay, paDescs[i].iGroup,
1044 paDescs[i].iFrame, paDescs[i].offSegName, paDescs[i].offClassName, szFlags));
1045
1046 RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].offSegName == UINT16_MAX || paDescs[i].offSegName < pThis->cbSegNames);
1047 RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].offClassName == UINT16_MAX || paDescs[i].offClassName < pThis->cbSegNames);
1048 const char *pszName = paDescs[i].offSegName != UINT16_MAX
1049 ? pThis->pszzSegNames + paDescs[i].offSegName
1050 : NULL;
1051 const char *pszClass = paDescs[i].offClassName != UINT16_MAX
1052 ? pThis->pszzSegNames + paDescs[i].offClassName
1053 : NULL;
1054 if (pszName || pszClass)
1055 Log2((" pszName=%s pszClass=%s\n", pszName, pszClass));
1056
1057 /* Validate the group link. */
1058 RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].iGroup == 0 || !(paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP));
1059 RTDBGMODCV_CHECK_NOMSG_RET_BF( paDescs[i].iGroup == 0
1060 || ( paDescs[i].iGroup >= pHdr->cLogSegs
1061 && paDescs[i].iGroup < pHdr->cSegs));
1062 RTDBGMODCV_CHECK_NOMSG_RET_BF( paDescs[i].iGroup == 0
1063 || (paDescs[paDescs[i].iGroup].fFlags & RTCVSEGMAPDESC_F_GROUP));
1064 RTDBGMODCV_CHECK_NOMSG_RET_BF(!(paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP) || paDescs[i].off == 0); /* assumed below */
1065
1066 if (fNoGroups)
1067 {
1068 RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].iGroup == 0);
1069 if ( !fHaveDosFrames
1070 && paDescs[i].iFrame != 0
1071 && (paDescs[i].fFlags & (RTCVSEGMAPDESC_F_SEL | RTCVSEGMAPDESC_F_ABS))
1072 && paDescs[i].iOverlay == 0
1073 && enmImgFmt != RTLDRFMT_PE
1074 && pThis->enmType != RTCVFILETYPE_DBG)
1075 fHaveDosFrames = true; /* BIOS, only groups with frames. */
1076 }
1077 }
1078
1079 /*
1080 * Further valiations based on fHaveDosFrames or not.
1081 */
1082 if (fNoGroups)
1083 {
1084 if (fHaveDosFrames)
1085 for (i = 0; i < pHdr->cSegs; i++)
1086 {
1087 RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].iOverlay == 0);
1088 RTDBGMODCV_CHECK_NOMSG_RET_BF( (paDescs[i].fFlags & (RTCVSEGMAPDESC_F_SEL | RTCVSEGMAPDESC_F_ABS))
1089 == RTCVSEGMAPDESC_F_SEL
1090 || (paDescs[i].fFlags & (RTCVSEGMAPDESC_F_SEL | RTCVSEGMAPDESC_F_ABS))
1091 == RTCVSEGMAPDESC_F_ABS);
1092 RTDBGMODCV_CHECK_NOMSG_RET_BF(!(paDescs[i].fFlags & RTCVSEGMAPDESC_F_ABS));
1093 }
1094 else
1095 for (i = 0; i < pHdr->cSegs; i++)
1096 RTDBGMODCV_CHECK_NOMSG_RET_BF(paDescs[i].off == 0);
1097 }
1098
1099 /*
1100 * Modify the groups index to be the loader segment index instead, also
1101 * add the segments to the container if we haven't done that already.
1102 */
1103
1104 /* Guess work: Group can be implicit if used. Observed Visual C++ v1.5,
1105 omitting the CODE group. */
1106 const char *pszGroup0 = NULL;
1107 uint64_t cbGroup0 = 0;
1108 if (!fNoGroups && !fHaveDosFrames)
1109 {
1110 for (i = 0; i < pHdr->cSegs; i++)
1111 if ( !(paDescs[i].fFlags & (RTCVSEGMAPDESC_F_GROUP | RTCVSEGMAPDESC_F_ABS))
1112 && paDescs[i].iGroup == 0)
1113 {
1114 if (pszGroup0 == NULL && paDescs[i].offClassName != UINT16_MAX)
1115 pszGroup0 = pThis->pszzSegNames + paDescs[i].offClassName;
1116 uint64_t offEnd = (uint64_t)paDescs[i].off + paDescs[i].cb;
1117 if (offEnd > cbGroup0)
1118 cbGroup0 = offEnd;
1119 }
1120 }
1121
1122 /* Add the segments.
1123 Note! The RVAs derived from this exercise are all wrong. :-/
1124 Note! We don't have an image loader, so we cannot add any fake sections. */
1125 /** @todo Try see if we can figure something out from the frame value later. */
1126 if (!pThis->fHaveLoadedSegments)
1127 {
1128 uint16_t iSeg = 0;
1129 if (!fHaveDosFrames)
1130 {
1131 Assert(!pThis->pMod->pImgVt); Assert(pThis->enmType != RTCVFILETYPE_DBG);
1132 uint64_t uRva = 0;
1133 if (cbGroup0 && !fNoGroups)
1134 {
1135 rc = RTDbgModSegmentAdd(pThis->hCnt, 0, cbGroup0, pszGroup0 ? pszGroup0 : "Seg00", 0 /*fFlags*/, NULL);
1136 uRva += cbGroup0;
1137 iSeg++;
1138 }
1139
1140 for (i = 0; RT_SUCCESS(rc) && i < pHdr->cSegs; i++)
1141 if ((paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP) || fNoGroups)
1142 {
1143 char szName[16];
1144 char *pszName = szName;
1145 if (paDescs[i].offSegName != UINT16_MAX)
1146 pszName = pThis->pszzSegNames + paDescs[i].offSegName;
1147 else
1148 RTStrPrintf(szName, sizeof(szName), "Seg%02u", iSeg);
1149 rc = RTDbgModSegmentAdd(pThis->hCnt, uRva, paDescs[i].cb, pszName, 0 /*fFlags*/, NULL);
1150 uRva += paDescs[i].cb;
1151 iSeg++;
1152 }
1153 }
1154 else
1155 {
1156 /* The map is not sorted by RVA, very annoying, but I'm countering
1157 by being lazy and slow about it. :-) Btw. this is the BIOS case. */
1158 Assert(fNoGroups);
1159#if 1 /** @todo need more inputs */
1160
1161 /* Figure image base address. */
1162 uint64_t uImageBase = UINT64_MAX;
1163 for (i = 0; RT_SUCCESS(rc) && i < pHdr->cSegs; i++)
1164 {
1165 uint64_t uAddr = (uint64_t)paDescs[i].off + ((uint32_t)paDescs[i].iFrame << 4);
1166 if (uAddr < uImageBase)
1167 uImageBase = uAddr;
1168 }
1169
1170 /* Add the segments. */
1171 uint64_t uMinAddr = uImageBase;
1172 for (i = 0; RT_SUCCESS(rc) && i < pHdr->cSegs; i++)
1173 {
1174 /* Figure out the next one. */
1175 uint16_t cOverlaps = 0;
1176 uint16_t iBest = UINT16_MAX;
1177 uint64_t uBestAddr = UINT64_MAX;
1178 for (uint16_t j = 0; j < pHdr->cSegs; j++)
1179 {
1180 uint64_t uAddr = (uint64_t)paDescs[j].off + ((uint32_t)paDescs[j].iFrame << 4);
1181 if (uAddr >= uMinAddr && uAddr < uBestAddr)
1182 {
1183 uBestAddr = uAddr;
1184 iBest = j;
1185 }
1186 else if (uAddr == uBestAddr)
1187 {
1188 cOverlaps++;
1189 if (paDescs[j].cb > paDescs[iBest].cb)
1190 {
1191 uBestAddr = uAddr;
1192 iBest = j;
1193 }
1194 }
1195 }
1196 if (iBest == UINT16_MAX && RT_SUCCESS(rc))
1197 {
1198 rc = VERR_CV_IPE;
1199 break;
1200 }
1201
1202 /* Add it. */
1203 char szName[16];
1204 char *pszName = szName;
1205 if (paDescs[iBest].offSegName != UINT16_MAX)
1206 pszName = pThis->pszzSegNames + paDescs[iBest].offSegName;
1207 else
1208 RTStrPrintf(szName, sizeof(szName), "Seg%02u", iSeg);
1209 Log(("CV: %#010x LB %#010x %s uRVA=%#010x iBest=%u cOverlaps=%u\n",
1210 uBestAddr, paDescs[iBest].cb, szName, uBestAddr - uImageBase, iBest, cOverlaps));
1211 rc = RTDbgModSegmentAdd(pThis->hCnt, uBestAddr - uImageBase, paDescs[iBest].cb, pszName, 0 /*fFlags*/, NULL);
1212
1213 /* Update translations. */
1214 paDescs[iBest].iGroup = iSeg;
1215 if (cOverlaps > 0)
1216 {
1217 for (uint16_t j = 0; j < pHdr->cSegs; j++)
1218 if ((uint64_t)paDescs[j].off + ((uint32_t)paDescs[j].iFrame << 4) == uBestAddr)
1219 paDescs[iBest].iGroup = iSeg;
1220 i += cOverlaps;
1221 }
1222
1223 /* Advance. */
1224 uMinAddr = uBestAddr + 1;
1225 iSeg++;
1226 }
1227
1228 pThis->fHaveDosFrames = true;
1229#else
1230 uint32_t iFrameFirst = UINT32_MAX;
1231 uint16_t iSeg = 0;
1232 uint32_t iFrameMin = 0;
1233 do
1234 {
1235 /* Find next frame. */
1236 uint32_t iFrame = UINT32_MAX;
1237 for (uint16_t j = 0; j < pHdr->cSegs; j++)
1238 if (paDescs[j].iFrame >= iFrameMin && paDescs[j].iFrame < iFrame)
1239 iFrame = paDescs[j].iFrame;
1240 if (iFrame == UINT32_MAX)
1241 break;
1242
1243 /* Figure the frame span. */
1244 uint32_t offFirst = UINT32_MAX;
1245 uint64_t offEnd = 0;
1246 for (uint16_t j = 0; j < pHdr->cSegs; j++)
1247 if (paDescs[j].iFrame == iFrame)
1248 {
1249 uint64_t offThisEnd = paDescs[j].off + paDescs[j].cb;
1250 if (offThisEnd > offEnd)
1251 offEnd = offThisEnd;
1252 if (paDescs[j].off < offFirst)
1253 offFirst = paDescs[j].off;
1254 }
1255
1256 if (offFirst < offEnd)
1257 {
1258 /* Add it. */
1259 char szName[16];
1260 RTStrPrintf(szName, sizeof(szName), "Frame_%04x", iFrame);
1261 Log(("CV: %s offEnd=%#x offFirst=%#x\n", szName, offEnd, offFirst));
1262 if (iFrameFirst == UINT32_MAX)
1263 iFrameFirst = iFrame;
1264 rc = RTDbgModSegmentAdd(pThis->hCnt, (iFrame - iFrameFirst) << 4, offEnd, szName, 0 /*fFlags*/, NULL);
1265
1266 /* Translation updates. */
1267 for (uint16_t j = 0; j < pHdr->cSegs; j++)
1268 if (paDescs[j].iFrame == iFrame)
1269 {
1270 paDescs[j].iGroup = iSeg;
1271 paDescs[j].off = 0;
1272 paDescs[j].cb = offEnd > UINT32_MAX ? UINT32_MAX : (uint32_t)offEnd;
1273 }
1274
1275 iSeg++;
1276 }
1277
1278 iFrameMin = iFrame + 1;
1279 } while (RT_SUCCESS(rc));
1280#endif
1281 }
1282
1283 if (RT_FAILURE(rc))
1284 {
1285 Log(("RTDbgModCv: %Rrc while adding segments from SegMap\n", rc));
1286 return rc;
1287 }
1288
1289 pThis->fHaveLoadedSegments = true;
1290
1291 /* Skip the stuff below if we have DOS frames since we did it all above. */
1292 if (fHaveDosFrames)
1293 return VINF_SUCCESS;
1294 }
1295
1296 /* Pass one: Fixate the group segment indexes. */
1297 uint16_t iSeg0 = enmImgFmt == RTLDRFMT_PE || pThis->enmType == RTCVFILETYPE_DBG ? 1 : 0;
1298 uint16_t iSeg = iSeg0 + (cbGroup0 > 0); /** @todo probably wrong... */
1299 for (i = 0; i < pHdr->cSegs; i++)
1300 if (paDescs[i].fFlags & RTCVSEGMAPDESC_F_ABS)
1301 paDescs[i].iGroup = (uint16_t)RTDBGSEGIDX_ABS;
1302 else if ((paDescs[i].fFlags & RTCVSEGMAPDESC_F_GROUP) || fNoGroups)
1303 paDescs[i].iGroup = iSeg++;
1304
1305 /* Pass two: Resolve group references in to segment indexes. */
1306 Log2(("Mapped segments (both kinds):\n"));
1307 for (i = 0; i < pHdr->cSegs; i++)
1308 {
1309 if (!fNoGroups && !(paDescs[i].fFlags & (RTCVSEGMAPDESC_F_GROUP | RTCVSEGMAPDESC_F_ABS)))
1310 paDescs[i].iGroup = paDescs[i].iGroup == 0 ? iSeg0 : paDescs[paDescs[i].iGroup].iGroup;
1311
1312 Log2((" #%02u: %#010x LB %#010x -> %#06x (flags=%#06x ovl=%#06x frame=%#06x)\n",
1313 i, paDescs[i].off, paDescs[i].cb, paDescs[i].iGroup,
1314 paDescs[i].fFlags, paDescs[i].iOverlay, paDescs[i].iFrame));
1315 }
1316
1317 return VINF_SUCCESS;
1318}
1319
1320
1321/**
1322 * Loads the directory into memory (RTDBGMODCV::paDirEnts and
1323 * RTDBGMODCV::cDirEnts).
1324 *
1325 * Converting old format version into the newer format to simplifying the code
1326 * using the directory.
1327 *
1328 *
1329 * @returns IPRT status code. (May leave with paDirEnts allocated on failure.)
1330 * @param pThis The CV reader instance.
1331 */
1332static int rtDbgModCvLoadDirectory(PRTDBGMODCV pThis)
1333{
1334 /*
1335 * Read in the CV directory.
1336 */
1337 int rc;
1338 if ( pThis->u32CvMagic == RTCVHDR_MAGIC_NB00
1339 || pThis->u32CvMagic == RTCVHDR_MAGIC_NB02)
1340 {
1341 /*
1342 * 16-bit type.
1343 */
1344 RTCVDIRHDR16 DirHdr;
1345 rc = rtDbgModCvReadAt(pThis, pThis->offDir, &DirHdr, sizeof(DirHdr));
1346 if (RT_SUCCESS(rc))
1347 {
1348 if (DirHdr.cEntries > 2 && DirHdr.cEntries < _64K - 32U)
1349 {
1350 pThis->cDirEnts = DirHdr.cEntries;
1351 pThis->paDirEnts = (PRTCVDIRENT32)RTMemAlloc(DirHdr.cEntries * sizeof(pThis->paDirEnts[0]));
1352 if (pThis->paDirEnts)
1353 {
1354 rc = rtDbgModCvReadAt(pThis, pThis->offDir + sizeof(DirHdr),
1355 pThis->paDirEnts, DirHdr.cEntries * sizeof(RTCVDIRENT16));
1356 if (RT_SUCCESS(rc))
1357 {
1358 /* Convert the entries (from the end). */
1359 uint32_t cLeft = DirHdr.cEntries;
1360 RTCVDIRENT32 volatile *pDst = pThis->paDirEnts + cLeft;
1361 RTCVDIRENT16 volatile *pSrc = (RTCVDIRENT16 volatile *)pThis->paDirEnts + cLeft;
1362 while (cLeft--)
1363 {
1364 pDst--;
1365 pSrc--;
1366
1367 pDst->cb = pSrc->cb;
1368 pDst->off = RT_MAKE_U32(pSrc->offLow, pSrc->offHigh);
1369 pDst->iMod = pSrc->iMod;
1370 pDst->uSubSectType = pSrc->uSubSectType;
1371 }
1372 }
1373 }
1374 else
1375 rc = VERR_NO_MEMORY;
1376 }
1377 else
1378 {
1379 Log(("Old CV directory count is out of considered valid range: %#x\n", DirHdr.cEntries));
1380 rc = VERR_CV_BAD_FORMAT;
1381 }
1382 }
1383 }
1384 else
1385 {
1386 /*
1387 * 32-bit type (reading too much for NB04 is no problem).
1388 */
1389 RTCVDIRHDR32EX DirHdr;
1390 rc = rtDbgModCvReadAt(pThis, pThis->offDir, &DirHdr, sizeof(DirHdr));
1391 if (RT_SUCCESS(rc))
1392 {
1393 if ( DirHdr.Core.cbHdr != sizeof(DirHdr.Core)
1394 && DirHdr.Core.cbHdr != sizeof(DirHdr))
1395 {
1396 Log(("Unexpected CV directory size: %#x\n", DirHdr.Core.cbHdr));
1397 rc = VERR_CV_BAD_FORMAT;
1398 }
1399 if ( DirHdr.Core.cbHdr == sizeof(DirHdr)
1400 && ( DirHdr.offNextDir != 0
1401 || DirHdr.fFlags != 0) )
1402 {
1403 Log(("Extended CV directory headers fields are not zero: fFlags=%#x offNextDir=%#x\n",
1404 DirHdr.fFlags, DirHdr.offNextDir));
1405 rc = VERR_CV_BAD_FORMAT;
1406 }
1407 if (DirHdr.Core.cbEntry != sizeof(RTCVDIRENT32))
1408 {
1409 Log(("Unexpected CV directory entry size: %#x (expected %#x)\n", DirHdr.Core.cbEntry, sizeof(RTCVDIRENT32)));
1410 rc = VERR_CV_BAD_FORMAT;
1411 }
1412 if (DirHdr.Core.cEntries < 2 || DirHdr.Core.cEntries >= _512K)
1413 {
1414 Log(("CV directory count is out of considered valid range: %#x\n", DirHdr.Core.cEntries));
1415 rc = VERR_CV_BAD_FORMAT;
1416 }
1417 if (RT_SUCCESS(rc))
1418 {
1419 pThis->cDirEnts = DirHdr.Core.cEntries;
1420 pThis->paDirEnts = (PRTCVDIRENT32)RTMemAlloc(DirHdr.Core.cEntries * sizeof(pThis->paDirEnts[0]));
1421 if (pThis->paDirEnts)
1422 rc = rtDbgModCvReadAt(pThis, pThis->offDir + DirHdr.Core.cbHdr,
1423 pThis->paDirEnts, DirHdr.Core.cEntries * sizeof(RTCVDIRENT32));
1424 else
1425 rc = VERR_NO_MEMORY;
1426 }
1427 }
1428 }
1429
1430 if (RT_SUCCESS(rc))
1431 {
1432 /*
1433 * Basic info validation and determining the directory ordering.
1434 */
1435 bool fWatcom = 0;
1436 uint16_t cGlobalMods = 0;
1437 uint16_t cNormalMods = 0;
1438 uint16_t iModLast = 0;
1439 uint32_t const cbDbgInfo = pThis->cbDbgInfo;
1440 uint32_t const cDirEnts = pThis->cDirEnts;
1441 Log2(("RTDbgModCv: %u (%#x) directory entries:\n", cDirEnts, cDirEnts));
1442 for (uint32_t i = 0; i < cDirEnts; i++)
1443 {
1444 PCRTCVDIRENT32 pDirEnt = &pThis->paDirEnts[i];
1445 Log2((" #%04u mod=%#06x sst=%#06x at %#010x LB %#07x %s\n",
1446 i, pDirEnt->iMod, pDirEnt->uSubSectType, pDirEnt->off, pDirEnt->cb,
1447 rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType)));
1448
1449 if ( pDirEnt->off >= cbDbgInfo
1450 || pDirEnt->cb >= cbDbgInfo
1451 || pDirEnt->off + pDirEnt->cb > cbDbgInfo)
1452 {
1453 Log(("CV directory entry #%u is out of bounds: %#x LB %#x, max %#x\n", i, pDirEnt->off, pDirEnt->cb, cbDbgInfo));
1454 rc = VERR_CV_BAD_FORMAT;
1455 }
1456 if ( pDirEnt->iMod == 0
1457 && pThis->u32CvMagic != RTCVHDR_MAGIC_NB04
1458 && pThis->u32CvMagic != RTCVHDR_MAGIC_NB02
1459 && pThis->u32CvMagic != RTCVHDR_MAGIC_NB00)
1460 {
1461 Log(("CV directory entry #%u uses module index 0 (uSubSectType=%#x)\n", i, pDirEnt->iMod, pDirEnt->uSubSectType));
1462 rc = VERR_CV_BAD_FORMAT;
1463 }
1464 if (pDirEnt->iMod == 0 || pDirEnt->iMod == 0xffff)
1465 cGlobalMods++;
1466 else
1467 {
1468 if (pDirEnt->iMod > iModLast)
1469 {
1470 if ( pDirEnt->uSubSectType != kCvSst_Module
1471 && pDirEnt->uSubSectType != kCvSst_OldModule)
1472 {
1473 Log(("CV directory entry #%u: expected module subsection first, found %s (%#x)\n",
1474 i, rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType), pDirEnt->uSubSectType));
1475 rc = VERR_CV_BAD_FORMAT;
1476 }
1477 if (pDirEnt->iMod != iModLast + 1)
1478 {
1479 Log(("CV directory entry #%u: skips from mod %#x to %#x modules\n", iModLast, pDirEnt->iMod));
1480 rc = VERR_CV_BAD_FORMAT;
1481 }
1482 iModLast = pDirEnt->iMod;
1483 }
1484 else if (pDirEnt->iMod < iModLast)
1485 fWatcom = true;
1486 cNormalMods++;
1487 }
1488 }
1489 if (cGlobalMods == 0)
1490 {
1491 Log(("CV directory contains no global modules\n"));
1492 rc = VERR_CV_BAD_FORMAT;
1493 }
1494 if (RT_SUCCESS(rc))
1495 {
1496 if (fWatcom)
1497 pThis->enmDirOrder = RTCVDIRORDER_BY_SST_MOD;
1498 else if (pThis->paDirEnts[0].iMod == 0)
1499 pThis->enmDirOrder = RTCVDIRORDER_BY_MOD_0;
1500 else
1501 pThis->enmDirOrder = RTCVDIRORDER_BY_MOD;
1502 Log(("CV dir stats: %u total, %u normal, %u special, iModLast=%#x (%u), enmDirOrder=%d\n",
1503 cDirEnts, cNormalMods, cGlobalMods, iModLast, iModLast, pThis->enmDirOrder));
1504
1505
1506 /*
1507 * Validate the directory ordering.
1508 */
1509 uint16_t i = 0;
1510
1511 /* Old style with special modules up front. */
1512 if (pThis->enmDirOrder == RTCVDIRORDER_BY_MOD_0)
1513 while (i < cGlobalMods)
1514 {
1515 if (pThis->paDirEnts[i].iMod != 0)
1516 {
1517 Log(("CV directory entry #%u: Expected iMod=%x instead of %x\n", i, 0, pThis->paDirEnts[i].iMod));
1518 rc = VERR_CV_BAD_FORMAT;
1519 }
1520 i++;
1521 }
1522
1523 /* Normal modules. */
1524 if (pThis->enmDirOrder != RTCVDIRORDER_BY_SST_MOD)
1525 {
1526 uint16_t iEndNormalMods = cNormalMods + (pThis->enmDirOrder == RTCVDIRORDER_BY_MOD_0 ? cGlobalMods : 0);
1527 while (i < iEndNormalMods)
1528 {
1529 if (pThis->paDirEnts[i].iMod == 0 || pThis->paDirEnts[i].iMod == 0xffff)
1530 {
1531 Log(("CV directory entry #%u: Unexpected global module entry.\n", i));
1532 rc = VERR_CV_BAD_FORMAT;
1533 }
1534 i++;
1535 }
1536 }
1537 else
1538 {
1539 uint32_t fSeen = RT_BIT_32(kCvSst_Module - kCvSst_Module)
1540 | RT_BIT_32(kCvSst_Libraries - kCvSst_Module)
1541 | RT_BIT_32(kCvSst_GlobalSym - kCvSst_Module)
1542 | RT_BIT_32(kCvSst_GlobalPub - kCvSst_Module)
1543 | RT_BIT_32(kCvSst_GlobalTypes - kCvSst_Module)
1544 | RT_BIT_32(kCvSst_SegName - kCvSst_Module)
1545 | RT_BIT_32(kCvSst_SegMap - kCvSst_Module)
1546 | RT_BIT_32(kCvSst_StaticSym - kCvSst_Module)
1547 | RT_BIT_32(kCvSst_FileIndex - kCvSst_Module)
1548 | RT_BIT_32(kCvSst_MPC - kCvSst_Module);
1549 uint16_t iMod = 0;
1550 uint16_t uSst = kCvSst_Module;
1551 while (i < cNormalMods)
1552 {
1553 PCRTCVDIRENT32 pDirEnt = &pThis->paDirEnts[i];
1554 if (pDirEnt->iMod > iMod)
1555 {
1556 if (pDirEnt->uSubSectType != uSst)
1557 {
1558 Log(("CV directory entry #%u: Expected %s (%#x), found %s (%#x).\n",
1559 i, rtDbgModCvGetSubSectionName(uSst), uSst,
1560 rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType), pDirEnt->uSubSectType));
1561 rc = VERR_CV_BAD_FORMAT;
1562 }
1563 }
1564 else
1565 {
1566 uint32_t iBit = pDirEnt->uSubSectType - kCvSst_Module;
1567 if (iBit >= 32U || (fSeen & RT_BIT_32(iBit)))
1568 {
1569 Log(("CV directory entry #%u: SST %s (%#x) has already been seen or is for globals.\n",
1570 i, rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType), pDirEnt->uSubSectType));
1571 rc = VERR_CV_BAD_FORMAT;
1572 }
1573 fSeen |= RT_BIT_32(iBit);
1574 }
1575
1576 uSst = pDirEnt->uSubSectType;
1577 iMod = pDirEnt->iMod;
1578 i++;
1579 }
1580 }
1581
1582 /* New style with special modules at the end. */
1583 if (pThis->enmDirOrder != RTCVDIRORDER_BY_MOD_0)
1584 while (i < cDirEnts)
1585 {
1586 if (pThis->paDirEnts[i].iMod != 0 && pThis->paDirEnts[i].iMod != 0xffff)
1587 {
1588 Log(("CV directory entry #%u: Expected global module entry, not %#x.\n", i,
1589 pThis->paDirEnts[i].iMod));
1590 rc = VERR_CV_BAD_FORMAT;
1591 }
1592 i++;
1593 }
1594 }
1595
1596 }
1597
1598 return rc;
1599}
1600
1601
1602static int rtDbgModCvLoadCodeViewInfo(PRTDBGMODCV pThis)
1603{
1604 /*
1605 * Load the directory, the segment map (if any) and then scan for segments
1606 * if necessary.
1607 */
1608 int rc = rtDbgModCvLoadDirectory(pThis);
1609 if (RT_SUCCESS(rc))
1610 rc = rtDbgModCvLoadSegmentMap(pThis);
1611 if (RT_SUCCESS(rc) && !pThis->fHaveLoadedSegments)
1612 {
1613 rc = VERR_CV_TODO; /** @todo Scan anything containing address, in particular sstSegMap and sstModule,
1614 * and reconstruct the segments from that information. */
1615 pThis->cbImage = 0x1000;
1616 rc = VINF_SUCCESS;
1617 }
1618
1619 /*
1620 * Process the directory.
1621 */
1622 for (uint32_t i = 0; RT_SUCCESS(rc) && i < pThis->cDirEnts; i++)
1623 {
1624 PCRTCVDIRENT32 pDirEnt = &pThis->paDirEnts[i];
1625 Log3(("Processing subsection %#u %s\n", i, rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType)));
1626 PFNDBGMODCVSUBSECTCALLBACK pfnCallback = NULL;
1627 switch (pDirEnt->uSubSectType)
1628 {
1629 case kCvSst_GlobalPub:
1630 case kCvSst_GlobalSym:
1631 case kCvSst_StaticSym:
1632 pfnCallback = rtDbgModCvSs_GlobalPub_GlobalSym_StaticSym;
1633 break;
1634 case kCvSst_Module:
1635 pfnCallback = rtDbgModCvSs_Module;
1636 break;
1637 case kCvSst_PublicSym:
1638 case kCvSst_Symbols:
1639 case kCvSst_AlignSym:
1640 pfnCallback = rtDbgModCvSs_Symbols_PublicSym_AlignSym;
1641 break;
1642
1643 case kCvSst_OldModule:
1644 case kCvSst_OldPublic:
1645 case kCvSst_OldTypes:
1646 case kCvSst_OldSymbols:
1647 case kCvSst_OldSrcLines:
1648 case kCvSst_OldLibraries:
1649 case kCvSst_OldImports:
1650 case kCvSst_OldCompacted:
1651 case kCvSst_OldSrcLnSeg:
1652 case kCvSst_OldSrcLines3:
1653
1654 case kCvSst_Types:
1655 case kCvSst_Public:
1656 case kCvSst_SrcLnSeg:
1657 case kCvSst_SrcModule:
1658 case kCvSst_Libraries:
1659 case kCvSst_GlobalTypes:
1660 case kCvSst_MPC:
1661 case kCvSst_PreComp:
1662 case kCvSst_PreCompMap:
1663 case kCvSst_OffsetMap16:
1664 case kCvSst_OffsetMap32:
1665 case kCvSst_FileIndex:
1666
1667 default:
1668 /** @todo implement more. */
1669 break;
1670
1671 /* Skip because we've already processed them: */
1672 case kCvSst_SegMap:
1673 case kCvSst_SegName:
1674 pfnCallback = NULL;
1675 break;
1676 }
1677
1678 if (pfnCallback)
1679 {
1680 void *pvSubSect;
1681 rc = rtDbgModCvReadAtAlloc(pThis, pDirEnt->off, &pvSubSect, pDirEnt->cb);
1682 if (RT_SUCCESS(rc))
1683 {
1684 rc = pfnCallback(pThis, pvSubSect, pDirEnt->cb, pDirEnt);
1685 RTMemFree(pvSubSect);
1686 }
1687 }
1688 }
1689
1690 return rc;
1691}
1692
1693
1694/*
1695 *
1696 * COFF Debug Info Parsing.
1697 * COFF Debug Info Parsing.
1698 * COFF Debug Info Parsing.
1699 *
1700 */
1701
1702static const char *rtDbgModCvGetCoffStorageClassName(uint8_t bStorageClass)
1703{
1704 switch (bStorageClass)
1705 {
1706 case IMAGE_SYM_CLASS_END_OF_FUNCTION: return "END_OF_FUNCTION";
1707 case IMAGE_SYM_CLASS_NULL: return "NULL";
1708 case IMAGE_SYM_CLASS_AUTOMATIC: return "AUTOMATIC";
1709 case IMAGE_SYM_CLASS_EXTERNAL: return "EXTERNAL";
1710 case IMAGE_SYM_CLASS_STATIC: return "STATIC";
1711 case IMAGE_SYM_CLASS_REGISTER: return "REGISTER";
1712 case IMAGE_SYM_CLASS_EXTERNAL_DEF: return "EXTERNAL_DEF";
1713 case IMAGE_SYM_CLASS_LABEL: return "LABEL";
1714 case IMAGE_SYM_CLASS_UNDEFINED_LABEL: return "UNDEFINED_LABEL";
1715 case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT: return "MEMBER_OF_STRUCT";
1716 case IMAGE_SYM_CLASS_ARGUMENT: return "ARGUMENT";
1717 case IMAGE_SYM_CLASS_STRUCT_TAG: return "STRUCT_TAG";
1718 case IMAGE_SYM_CLASS_MEMBER_OF_UNION: return "MEMBER_OF_UNION";
1719 case IMAGE_SYM_CLASS_UNION_TAG: return "UNION_TAG";
1720 case IMAGE_SYM_CLASS_TYPE_DEFINITION: return "TYPE_DEFINITION";
1721 case IMAGE_SYM_CLASS_UNDEFINED_STATIC: return "UNDEFINED_STATIC";
1722 case IMAGE_SYM_CLASS_ENUM_TAG: return "ENUM_TAG";
1723 case IMAGE_SYM_CLASS_MEMBER_OF_ENUM: return "MEMBER_OF_ENUM";
1724 case IMAGE_SYM_CLASS_REGISTER_PARAM: return "REGISTER_PARAM";
1725 case IMAGE_SYM_CLASS_BIT_FIELD: return "BIT_FIELD";
1726 case IMAGE_SYM_CLASS_FAR_EXTERNAL: return "FAR_EXTERNAL";
1727 case IMAGE_SYM_CLASS_BLOCK: return "BLOCK";
1728 case IMAGE_SYM_CLASS_FUNCTION: return "FUNCTION";
1729 case IMAGE_SYM_CLASS_END_OF_STRUCT: return "END_OF_STRUCT";
1730 case IMAGE_SYM_CLASS_FILE: return "FILE";
1731 case IMAGE_SYM_CLASS_SECTION: return "SECTION";
1732 case IMAGE_SYM_CLASS_WEAK_EXTERNAL: return "WEAK_EXTERNAL";
1733 case IMAGE_SYM_CLASS_CLR_TOKEN: return "CLR_TOKEN";
1734 }
1735
1736 static char s_szName[32];
1737 RTStrPrintf(s_szName, sizeof(s_szName), "Unknown%#04x", bStorageClass);
1738 return s_szName;
1739}
1740
1741
1742/**
1743 * Adds a chunk of COFF line numbers.
1744 *
1745 * @param pThis The COFF/CodeView reader instance.
1746 * @param pszFile The source file name.
1747 * @param iSection The section number.
1748 * @param paLines Pointer to the first line number table entry.
1749 * @param cLines The number of line number table entries to add.
1750 */
1751static void rtDbgModCvAddCoffLineNumbers(PRTDBGMODCV pThis, const char *pszFile, uint32_t iSection,
1752 PCIMAGE_LINENUMBER paLines, uint32_t cLines)
1753{
1754 Log4(("Adding %u line numbers in section #%u for %s\n", cLines, iSection, pszFile));
1755 PCIMAGE_LINENUMBER pCur = paLines;
1756 while (cLines-- > 0)
1757 {
1758 if (pCur->Linenumber)
1759 {
1760 int rc = RTDbgModLineAdd(pThis->hCnt, pszFile, pCur->Linenumber, RTDBGSEGIDX_RVA, pCur->Type.VirtualAddress, NULL);
1761 Log4((" %#010x: %u [%Rrc]\n", pCur->Type.VirtualAddress, pCur->Linenumber, rc));
1762 }
1763 pCur++;
1764 }
1765}
1766
1767
1768/**
1769 * Adds a COFF symbol.
1770 *
1771 * @returns IPRT status (ignored)
1772 * @param pThis The COFF/CodeView reader instance.
1773 * @param idxSeg IPRT RVA or ABS segment index indicator.
1774 * @param uValue The symbol value.
1775 * @param pszName The symbol name.
1776 */
1777static int rtDbgModCvAddCoffSymbol(PRTDBGMODCV pThis, uint32_t idxSeg, uint32_t uValue, const char *pszName)
1778{
1779 int rc = RTDbgModSymbolAdd(pThis->hCnt, pszName, idxSeg, uValue, 0, 0 /*fFlags*/, NULL);
1780 Log(("Symbol: %s:%08x %s [%Rrc]\n", idxSeg == RTDBGSEGIDX_RVA ? "rva" : "abs", uValue, pszName, rc));
1781 if (rc == VERR_DBG_ADDRESS_CONFLICT || rc == VERR_DBG_DUPLICATE_SYMBOL)
1782 rc = VINF_SUCCESS;
1783 return rc;
1784}
1785
1786
1787/**
1788 * Processes the COFF symbol table.
1789 *
1790 * @returns IPRT status code
1791 * @param pThis The COFF/CodeView reader instance.
1792 * @param paSymbols Pointer to the symbol table.
1793 * @param cSymbols The number of entries in the symbol table.
1794 * @param paLines Pointer to the line number table.
1795 * @param cLines The number of entires in the line number table.
1796 * @param pszzStrTab Pointer to the string table.
1797 * @param cbStrTab Size of the string table.
1798 */
1799static int rtDbgModCvProcessCoffSymbolTable(PRTDBGMODCV pThis,
1800 PCIMAGE_SYMBOL paSymbols, uint32_t cSymbols,
1801 PCIMAGE_LINENUMBER paLines, uint32_t cLines,
1802 const char *pszzStrTab, uint32_t cbStrTab)
1803{
1804 Log3(("Processing COFF symbol table with %#x symbols\n", cSymbols));
1805
1806 /*
1807 * Making some bold assumption that the line numbers for the section in
1808 * the file are allocated sequentially, we do multiple passes until we've
1809 * gathered them all.
1810 */
1811 int rc = VINF_SUCCESS;
1812 uint32_t cSections = 1;
1813 uint32_t iLineSect = 1;
1814 uint32_t iLine = 0;
1815 do
1816 {
1817 /*
1818 * Process the symbols.
1819 */
1820 char szShort[9];
1821 char szFile[RTPATH_MAX];
1822 uint32_t iSymbol = 0;
1823 szFile[0] = '\0';
1824 szShort[8] = '\0'; /* avoid having to terminate it all the time. */
1825
1826 while (iSymbol < cSymbols && RT_SUCCESS(rc))
1827 {
1828 /* Copy the symbol in and hope it works around the misalignment
1829 issues everywhere. */
1830 IMAGE_SYMBOL Sym;
1831 memcpy(&Sym, &paSymbols[iSymbol], sizeof(Sym));
1832 RTDBGMODCV_CHECK_NOMSG_RET_BF(Sym.NumberOfAuxSymbols < cSymbols);
1833
1834 /* Calc a zero terminated symbol name. */
1835 const char *pszName;
1836 if (Sym.N.Name.Short)
1837 pszName = (const char *)memcpy(szShort, &Sym.N, 8);
1838 else
1839 {
1840 RTDBGMODCV_CHECK_NOMSG_RET_BF(Sym.N.Name.Long < cbStrTab);
1841 pszName = pszzStrTab + Sym.N.Name.Long;
1842 }
1843
1844 /* Only log stuff and count sections the in the first pass.*/
1845 if (iLineSect == 1)
1846 {
1847 Log3(("%04x: s=%#06x v=%#010x t=%#06x a=%#04x c=%#04x (%s) name='%s'\n",
1848 iSymbol, Sym.SectionNumber, Sym.Value, Sym.Type, Sym.NumberOfAuxSymbols,
1849 Sym.StorageClass, rtDbgModCvGetCoffStorageClassName(Sym.StorageClass), pszName));
1850 if ((int16_t)cSections <= Sym.SectionNumber && Sym.SectionNumber > 0)
1851 cSections = Sym.SectionNumber + 1;
1852 }
1853
1854 /*
1855 * Use storage class to pick what we need (which isn't much because,
1856 * MS only provides a very restricted set of symbols).
1857 */
1858 IMAGE_AUX_SYMBOL Aux;
1859 switch (Sym.StorageClass)
1860 {
1861 case IMAGE_SYM_CLASS_NULL:
1862 /* a NOP */
1863 break;
1864
1865 case IMAGE_SYM_CLASS_FILE:
1866 {
1867 /* Change the current file name (for line numbers). Pretend
1868 ANSI and ISO-8859-1 are similar enough for out purposes... */
1869 RTDBGMODCV_CHECK_NOMSG_RET_BF(Sym.NumberOfAuxSymbols > 0);
1870 const char *pszFile = (const char *)&paSymbols[iSymbol + 1];
1871 char *pszDst = szFile;
1872 rc = RTLatin1ToUtf8Ex(pszFile, Sym.NumberOfAuxSymbols * sizeof(IMAGE_SYMBOL), &pszDst, sizeof(szFile), NULL);
1873 if (RT_FAILURE(rc))
1874 Log(("Error converting COFF filename: %Rrc\n", rc));
1875 else if (iLineSect == 1)
1876 Log3((" filename='%s'\n", szFile));
1877 break;
1878 }
1879
1880 case IMAGE_SYM_CLASS_STATIC:
1881 if ( Sym.NumberOfAuxSymbols == 1
1882 && ( iLineSect == 1
1883 || Sym.SectionNumber == (int32_t)iLineSect) )
1884 {
1885 memcpy(&Aux, &paSymbols[iSymbol + 1], sizeof(Aux));
1886 if (iLineSect == 1)
1887 Log3((" section: cb=%#010x #relocs=%#06x #lines=%#06x csum=%#x num=%#x sel=%x rvd=%u\n",
1888 Aux.Section.Length, Aux.Section.NumberOfRelocations,
1889 Aux.Section.NumberOfLinenumbers,
1890 Aux.Section.CheckSum,
1891 RT_MAKE_U32(Aux.Section.Number, Aux.Section.HighNumber),
1892 Aux.Section.Selection,
1893 Aux.Section.bReserved));
1894 if ( Sym.SectionNumber == (int32_t)iLineSect
1895 && Aux.Section.NumberOfLinenumbers > 0)
1896 {
1897 uint32_t cLinesToAdd = RT_MIN(Aux.Section.NumberOfLinenumbers, cLines - iLine);
1898 if (iLine < cLines && szFile[0])
1899 rtDbgModCvAddCoffLineNumbers(pThis, szFile, iLineSect, &paLines[iLine], cLinesToAdd);
1900 iLine += cLinesToAdd;
1901 }
1902 }
1903 /* Not so sure about the quality here, but might be useful. */
1904 else if ( iLineSect == 1
1905 && Sym.NumberOfAuxSymbols == 0
1906 && Sym.SectionNumber != IMAGE_SYM_UNDEFINED
1907 && Sym.SectionNumber != IMAGE_SYM_ABSOLUTE
1908 && Sym.SectionNumber != IMAGE_SYM_DEBUG
1909 && Sym.Value > 0
1910 && *pszName)
1911 rtDbgModCvAddCoffSymbol(pThis, RTDBGSEGIDX_RVA, Sym.Value, pszName);
1912 break;
1913
1914 case IMAGE_SYM_CLASS_EXTERNAL:
1915 /* Add functions (first pass only). */
1916 if ( iLineSect == 1
1917 && (ISFCN(Sym.Type) || Sym.Type == 0)
1918 && Sym.NumberOfAuxSymbols == 0
1919 && *pszName )
1920 {
1921 if (Sym.SectionNumber == IMAGE_SYM_ABSOLUTE)
1922 rtDbgModCvAddCoffSymbol(pThis, RTDBGSEGIDX_ABS, Sym.Value, pszName);
1923 else if ( Sym.SectionNumber != IMAGE_SYM_UNDEFINED
1924 && Sym.SectionNumber != IMAGE_SYM_DEBUG)
1925 rtDbgModCvAddCoffSymbol(pThis, RTDBGSEGIDX_RVA, Sym.Value, pszName);
1926 }
1927 break;
1928
1929 case IMAGE_SYM_CLASS_FUNCTION:
1930 /* Not sure this is really used. */
1931 break;
1932
1933 case IMAGE_SYM_CLASS_END_OF_FUNCTION:
1934 case IMAGE_SYM_CLASS_AUTOMATIC:
1935 case IMAGE_SYM_CLASS_REGISTER:
1936 case IMAGE_SYM_CLASS_EXTERNAL_DEF:
1937 case IMAGE_SYM_CLASS_LABEL:
1938 case IMAGE_SYM_CLASS_UNDEFINED_LABEL:
1939 case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT:
1940 case IMAGE_SYM_CLASS_ARGUMENT:
1941 case IMAGE_SYM_CLASS_STRUCT_TAG:
1942 case IMAGE_SYM_CLASS_MEMBER_OF_UNION:
1943 case IMAGE_SYM_CLASS_UNION_TAG:
1944 case IMAGE_SYM_CLASS_TYPE_DEFINITION:
1945 case IMAGE_SYM_CLASS_UNDEFINED_STATIC:
1946 case IMAGE_SYM_CLASS_ENUM_TAG:
1947 case IMAGE_SYM_CLASS_MEMBER_OF_ENUM:
1948 case IMAGE_SYM_CLASS_REGISTER_PARAM:
1949 case IMAGE_SYM_CLASS_BIT_FIELD:
1950 case IMAGE_SYM_CLASS_FAR_EXTERNAL:
1951 case IMAGE_SYM_CLASS_BLOCK:
1952 case IMAGE_SYM_CLASS_END_OF_STRUCT:
1953 case IMAGE_SYM_CLASS_SECTION:
1954 case IMAGE_SYM_CLASS_WEAK_EXTERNAL:
1955 case IMAGE_SYM_CLASS_CLR_TOKEN:
1956 /* Not used by MS, I think. */
1957 break;
1958
1959 default:
1960 Log(("RTDbgCv: Unexpected COFF storage class %#x (%u)\n", Sym.StorageClass, Sym.StorageClass));
1961 break;
1962 }
1963
1964 /* next symbol */
1965 iSymbol += 1 + Sym.NumberOfAuxSymbols;
1966 }
1967
1968 /* Next section with line numbers. */
1969 iLineSect++;
1970 } while (iLine < cLines && iLineSect < cSections && RT_SUCCESS(rc));
1971
1972 return rc;
1973}
1974
1975
1976/**
1977 * Loads COFF debug information into the container.
1978 *
1979 * @returns IPRT status code.
1980 * @param pThis The COFF/CodeView debug reader instance.
1981 */
1982static int rtDbgModCvLoadCoffInfo(PRTDBGMODCV pThis)
1983{
1984 /*
1985 * Read the whole section into memory.
1986 * Note! Cannot use rtDbgModCvReadAt or rtDbgModCvReadAtAlloc here.
1987 */
1988 int rc;
1989 uint8_t *pbDbgSect = (uint8_t *)RTMemAlloc(pThis->cbCoffDbgInfo);
1990 if (pbDbgSect)
1991 {
1992 if (pThis->hFile == NIL_RTFILE)
1993 rc = pThis->pMod->pImgVt->pfnReadAt(pThis->pMod, UINT32_MAX, pThis->offCoffDbgInfo, pbDbgSect, pThis->cbCoffDbgInfo);
1994 else
1995 rc = RTFileReadAt(pThis->hFile, pThis->offCoffDbgInfo, pbDbgSect, pThis->cbCoffDbgInfo, NULL);
1996 if (RT_SUCCESS(rc))
1997 {
1998 /* The string table follows after the symbol table. */
1999 const char *pszzStrTab = (const char *)( pbDbgSect
2000 + pThis->CoffHdr.LvaToFirstSymbol
2001 + pThis->CoffHdr.NumberOfSymbols * sizeof(IMAGE_SYMBOL));
2002 uint32_t cbStrTab = (uint32_t)((uintptr_t)(pbDbgSect + pThis->cbCoffDbgInfo) - (uintptr_t)pszzStrTab);
2003 /** @todo The symbol table starts with a size. Read it and checking. Also verify
2004 * that the symtab ends with a terminator character. */
2005
2006 rc = rtDbgModCvProcessCoffSymbolTable(pThis,
2007 (PCIMAGE_SYMBOL)(pbDbgSect + pThis->CoffHdr.LvaToFirstSymbol),
2008 pThis->CoffHdr.NumberOfSymbols,
2009 (PCIMAGE_LINENUMBER)(pbDbgSect + pThis->CoffHdr.LvaToFirstLinenumber),
2010 pThis->CoffHdr.NumberOfLinenumbers,
2011 pszzStrTab, cbStrTab);
2012 }
2013 RTMemFree(pbDbgSect);
2014 }
2015 else
2016 rc = VERR_NO_MEMORY;
2017 return rc;
2018}
2019
2020
2021
2022
2023
2024
2025/*
2026 *
2027 * CodeView Debug module implementation.
2028 * CodeView Debug module implementation.
2029 * CodeView Debug module implementation.
2030 *
2031 */
2032
2033
2034/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByAddr} */
2035static DECLCALLBACK(int) rtDbgModCv_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
2036 PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
2037{
2038 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2039 return RTDbgModLineByAddr(pThis->hCnt, iSeg, off, poffDisp, pLineInfo);
2040}
2041
2042
2043/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByOrdinal} */
2044static DECLCALLBACK(int) rtDbgModCv_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
2045{
2046 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2047 return RTDbgModLineByOrdinal(pThis->hCnt, iOrdinal, pLineInfo);
2048}
2049
2050
2051/** @interface_method_impl{RTDBGMODVTDBG,pfnLineCount} */
2052static DECLCALLBACK(uint32_t) rtDbgModCv_LineCount(PRTDBGMODINT pMod)
2053{
2054 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2055 return RTDbgModLineCount(pThis->hCnt);
2056}
2057
2058
2059/** @interface_method_impl{RTDBGMODVTDBG,pfnLineAdd} */
2060static DECLCALLBACK(int) rtDbgModCv_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
2061 uint32_t iSeg, RTUINTPTR off, uint32_t *piOrdinal)
2062{
2063 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2064 Assert(!pszFile[cchFile]); NOREF(cchFile);
2065 return RTDbgModLineAdd(pThis->hCnt, pszFile, uLineNo, iSeg, off, piOrdinal);
2066}
2067
2068
2069/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByAddr} */
2070static DECLCALLBACK(int) rtDbgModCv_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
2071 PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
2072{
2073 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2074 return RTDbgModSymbolByAddr(pThis->hCnt, iSeg, off, fFlags, poffDisp, pSymInfo);
2075}
2076
2077
2078/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByName} */
2079static DECLCALLBACK(int) rtDbgModCv_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
2080 PRTDBGSYMBOL pSymInfo)
2081{
2082 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2083 Assert(!pszSymbol[cchSymbol]);
2084 return RTDbgModSymbolByName(pThis->hCnt, pszSymbol/*, cchSymbol*/, pSymInfo);
2085}
2086
2087
2088/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByOrdinal} */
2089static DECLCALLBACK(int) rtDbgModCv_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
2090{
2091 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2092 return RTDbgModSymbolByOrdinal(pThis->hCnt, iOrdinal, pSymInfo);
2093}
2094
2095
2096/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolCount} */
2097static DECLCALLBACK(uint32_t) rtDbgModCv_SymbolCount(PRTDBGMODINT pMod)
2098{
2099 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2100 return RTDbgModSymbolCount(pThis->hCnt);
2101}
2102
2103
2104/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolAdd} */
2105static DECLCALLBACK(int) rtDbgModCv_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
2106 RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags,
2107 uint32_t *piOrdinal)
2108{
2109 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2110 Assert(!pszSymbol[cchSymbol]); NOREF(cchSymbol);
2111 return RTDbgModSymbolAdd(pThis->hCnt, pszSymbol, iSeg, off, cb, fFlags, piOrdinal);
2112}
2113
2114
2115/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentByIndex} */
2116static DECLCALLBACK(int) rtDbgModCv_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
2117{
2118 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2119 return RTDbgModSegmentByIndex(pThis->hCnt, iSeg, pSegInfo);
2120}
2121
2122
2123/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentCount} */
2124static DECLCALLBACK(RTDBGSEGIDX) rtDbgModCv_SegmentCount(PRTDBGMODINT pMod)
2125{
2126 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2127 return RTDbgModSegmentCount(pThis->hCnt);
2128}
2129
2130
2131/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentAdd} */
2132static DECLCALLBACK(int) rtDbgModCv_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName, size_t cchName,
2133 uint32_t fFlags, PRTDBGSEGIDX piSeg)
2134{
2135 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2136 Assert(!pszName[cchName]); NOREF(cchName);
2137 return RTDbgModSegmentAdd(pThis->hCnt, uRva, cb, pszName, fFlags, piSeg);
2138}
2139
2140
2141/** @interface_method_impl{RTDBGMODVTDBG,pfnImageSize} */
2142static DECLCALLBACK(RTUINTPTR) rtDbgModCv_ImageSize(PRTDBGMODINT pMod)
2143{
2144 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2145 if (pThis->cbImage)
2146 return pThis->cbImage;
2147 return RTDbgModImageSize(pThis->hCnt);
2148}
2149
2150
2151/** @interface_method_impl{RTDBGMODVTDBG,pfnRvaToSegOff} */
2152static DECLCALLBACK(RTDBGSEGIDX) rtDbgModCv_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
2153{
2154 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2155 return RTDbgModRvaToSegOff(pThis->hCnt, uRva, poffSeg);
2156}
2157
2158
2159/** @interface_method_impl{RTDBGMODVTDBG,pfnClose} */
2160static DECLCALLBACK(int) rtDbgModCv_Close(PRTDBGMODINT pMod)
2161{
2162 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2163
2164 RTDbgModRelease(pThis->hCnt);
2165 if (pThis->hFile != NIL_RTFILE)
2166 RTFileClose(pThis->hFile);
2167 RTMemFree(pThis->paDirEnts);
2168 RTMemFree(pThis);
2169
2170 pMod->pvDbgPriv = NULL; /* for internal use */
2171 return VINF_SUCCESS;
2172}
2173
2174
2175/*
2176 *
2177 * Probing code used by rtDbgModCv_TryOpen.
2178 * Probing code used by rtDbgModCv_TryOpen.
2179 *
2180 */
2181
2182
2183
2184/** @callback_method_impl{FNRTLDRENUMSEGS,
2185 * Used to add segments from the image.} */
2186static DECLCALLBACK(int) rtDbgModCvAddSegmentsCallback(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
2187{
2188 PRTDBGMODCV pThis = (PRTDBGMODCV)pvUser;
2189 Log(("Segment %s: LinkAddress=%#llx RVA=%#llx cb=%#llx\n",
2190 pSeg->pszName, (uint64_t)pSeg->LinkAddress, (uint64_t)pSeg->RVA, pSeg->cb));
2191 NOREF(hLdrMod);
2192
2193 /* If the segment doesn't have a mapping, just add a dummy so the indexing
2194 works out correctly (same as for the image). */
2195 if (pSeg->RVA == NIL_RTLDRADDR)
2196 return RTDbgModSegmentAdd(pThis->hCnt, 0, 0, pSeg->pszName, 0 /*fFlags*/, NULL);
2197
2198 RTLDRADDR cb = RT_MAX(pSeg->cb, pSeg->cbMapped);
2199 return RTDbgModSegmentAdd(pThis->hCnt, pSeg->RVA, cb, pSeg->pszName, 0 /*fFlags*/, NULL);
2200}
2201
2202
2203/**
2204 * Copies the sections over from the DBG file.
2205 *
2206 * Called if we don't have an associated executable image.
2207 *
2208 * @returns IPRT status code.
2209 * @param pThis The CV module instance.
2210 * @param pDbgHdr The DBG file header.
2211 * @param pszFilename The filename (for logging).
2212 */
2213static int rtDbgModCvAddSegmentsFromDbg(PRTDBGMODCV pThis, PCIMAGE_SEPARATE_DEBUG_HEADER pDbgHdr, const char *pszFilename)
2214{
2215 /*
2216 * Validate the header fields a little.
2217 */
2218 if ( pDbgHdr->NumberOfSections < 1
2219 || pDbgHdr->NumberOfSections > 4096)
2220 {
2221 Log(("RTDbgModCv: Bad NumberOfSections: %d\n", pDbgHdr->NumberOfSections));
2222 return VERR_CV_BAD_FORMAT;
2223 }
2224 if (!RT_IS_POWER_OF_TWO(pDbgHdr->SectionAlignment))
2225 {
2226 Log(("RTDbgModCv: Bad SectionAlignment: %#x\n", pDbgHdr->SectionAlignment));
2227 return VERR_CV_BAD_FORMAT;
2228 }
2229
2230 /*
2231 * Read the section table.
2232 */
2233 size_t cbShs = pDbgHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
2234 PIMAGE_SECTION_HEADER paShs = (PIMAGE_SECTION_HEADER)RTMemAlloc(cbShs);
2235 if (!paShs)
2236 return VERR_NO_MEMORY;
2237 int rc = RTFileReadAt(pThis->hFile, sizeof(*pDbgHdr), paShs, cbShs, NULL);
2238 if (RT_SUCCESS(rc))
2239 {
2240 /*
2241 * Do some basic validation.
2242 */
2243 uint32_t cbHeaders = 0;
2244 uint32_t uRvaPrev = 0;
2245 for (uint32_t i = 0; i < pDbgHdr->NumberOfSections; i++)
2246 {
2247 Log3(("RTDbgModCv: Section #%02u %#010x LB %#010x %.*s\n",
2248 i, paShs[i].VirtualAddress, paShs[i].Misc.VirtualSize, sizeof(paShs[i].Name), paShs[i].Name));
2249
2250 if (paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
2251 continue;
2252
2253 if (paShs[i].VirtualAddress < uRvaPrev)
2254 {
2255 Log(("RTDbgModCv: %s: Overlap or soring error, VirtualAddress=%#x uRvaPrev=%#x - section #%d '%.*s'!!!\n",
2256 pszFilename, paShs[i].VirtualAddress, uRvaPrev, i, sizeof(paShs[i].Name), paShs[i].Name));
2257 rc = VERR_CV_BAD_FORMAT;
2258 }
2259 else if ( paShs[i].VirtualAddress > pDbgHdr->SizeOfImage
2260 || paShs[i].Misc.VirtualSize > pDbgHdr->SizeOfImage
2261 || paShs[i].VirtualAddress + paShs[i].Misc.VirtualSize > pDbgHdr->SizeOfImage)
2262 {
2263 Log(("RTDbgModCv: %s: VirtualAddress=%#x VirtualSize=%#x (total %x) - beyond image size (%#x) - section #%d '%.*s'!!!\n",
2264 pszFilename, paShs[i].VirtualAddress, paShs[i].Misc.VirtualSize,
2265 paShs[i].VirtualAddress + paShs[i].Misc.VirtualSize,
2266 pThis->cbImage, i, sizeof(paShs[i].Name), paShs[i].Name));
2267 rc = VERR_CV_BAD_FORMAT;
2268 }
2269 else if (paShs[i].VirtualAddress & (pDbgHdr->SectionAlignment - 1))
2270 {
2271 Log(("RTDbgModCv: %s: VirtualAddress=%#x misaligned (%#x) - section #%d '%.*s'!!!\n",
2272 pszFilename, paShs[i].VirtualAddress, pDbgHdr->SectionAlignment, i, sizeof(paShs[i].Name), paShs[i].Name));
2273 rc = VERR_CV_BAD_FORMAT;
2274 }
2275 else
2276 {
2277 if (uRvaPrev == 0)
2278 cbHeaders = paShs[i].VirtualAddress;
2279 uRvaPrev = paShs[i].VirtualAddress + paShs[i].Misc.VirtualSize;
2280 continue;
2281 }
2282 }
2283 if (RT_SUCCESS(rc) && uRvaPrev == 0)
2284 {
2285 Log(("RTDbgModCv: %s: No loadable sections.\n", pszFilename));
2286 rc = VERR_CV_BAD_FORMAT;
2287 }
2288 if (RT_SUCCESS(rc) && cbHeaders == 0)
2289 {
2290 Log(("RTDbgModCv: %s: No space for PE headers.\n", pszFilename));
2291 rc = VERR_CV_BAD_FORMAT;
2292 }
2293 if (RT_SUCCESS(rc))
2294 {
2295 /*
2296 * Add sections.
2297 */
2298 rc = RTDbgModSegmentAdd(pThis->hCnt, 0, cbHeaders, "NtHdrs", 0 /*fFlags*/, NULL);
2299 for (uint32_t i = 0; RT_SUCCESS(rc) && i < pDbgHdr->NumberOfSections; i++)
2300 {
2301 char szName[sizeof(paShs[i].Name) + 1];
2302 memcpy(szName, paShs[i].Name, sizeof(paShs[i].Name));
2303 szName[sizeof(szName) - 1] = '\0';
2304
2305 if (paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
2306 rc = RTDbgModSegmentAdd(pThis->hCnt, 0, 0, szName, 0 /*fFlags*/, NULL);
2307 else
2308 rc = RTDbgModSegmentAdd(pThis->hCnt, paShs[i].VirtualAddress, paShs[i].Misc.VirtualSize, szName,
2309 0 /*fFlags*/, NULL);
2310 }
2311 if (RT_SUCCESS(rc))
2312 pThis->fHaveLoadedSegments = true;
2313 }
2314 }
2315
2316 RTMemFree(paShs);
2317 return rc;
2318}
2319
2320
2321/**
2322 * Instantiates the CV/COFF reader.
2323 *
2324 * @returns IPRT status code
2325 * @param pDbgMod The debug module instance.
2326 * @param enmFileType The type of input file.
2327 * @param hFile The file handle, NIL_RTFILE of image.
2328 * @param ppThis Where to return the reader instance.
2329 */
2330static int rtDbgModCvCreateInstance(PRTDBGMODINT pDbgMod, RTCVFILETYPE enmFileType, RTFILE hFile, PRTDBGMODCV *ppThis)
2331{
2332 /*
2333 * Do we already have an instance? Happens if we find multiple debug
2334 * formats we support.
2335 */
2336 PRTDBGMODCV pThis = (PRTDBGMODCV)pDbgMod->pvDbgPriv;
2337 if (pThis)
2338 {
2339 Assert(pThis->enmType == enmFileType);
2340 Assert(pThis->hFile == hFile);
2341 Assert(pThis->pMod == pDbgMod);
2342 *ppThis = pThis;
2343 return VINF_SUCCESS;
2344 }
2345
2346 /*
2347 * Create a new instance.
2348 */
2349 pThis = (PRTDBGMODCV)RTMemAllocZ(sizeof(RTDBGMODCV));
2350 if (!pThis)
2351 return VERR_NO_MEMORY;
2352 int rc = RTDbgModCreate(&pThis->hCnt, pDbgMod->pszName, 0 /*cbSeg*/, 0 /*fFlags*/);
2353 if (RT_SUCCESS(rc))
2354 {
2355 pDbgMod->pvDbgPriv = pThis;
2356 pThis->enmType = enmFileType;
2357 pThis->hFile = hFile;
2358 pThis->pMod = pDbgMod;
2359 pThis->offBase = UINT32_MAX;
2360 pThis->offCoffDbgInfo = UINT32_MAX;
2361 *ppThis = pThis;
2362 return VINF_SUCCESS;
2363 }
2364 RTMemFree(pThis);
2365 return rc;
2366}
2367
2368
2369/**
2370 * Common part of the COFF probing.
2371 *
2372 * @returns status code.
2373 * @param pDbgMod The debug module instance. On success pvDbgPriv
2374 * will point to a valid RTDBGMODCV.
2375 * @param hFile The file with debug info in it.
2376 * @param off The offset where to expect CV debug info.
2377 * @param cb The number of bytes of debug info.
2378 * @param enmArch The desired image architecture.
2379 * @param pszFilename The path to the file (for logging).
2380 */
2381static int rtDbgModCvProbeCoff(PRTDBGMODINT pDbgMod, RTCVFILETYPE enmFileType, RTFILE hFile,
2382 uint32_t off, uint32_t cb, const char *pszFilename)
2383{
2384 /*
2385 * Check that there is sufficient data for a header, then read it.
2386 */
2387 if (cb < sizeof(IMAGE_COFF_SYMBOLS_HEADER))
2388 {
2389 Log(("RTDbgModCv: Not enough room for COFF header.\n"));
2390 return VERR_BAD_EXE_FORMAT;
2391 }
2392 if (cb >= UINT32_C(128) * _1M)
2393 {
2394 Log(("RTDbgModCv: COFF debug information is to large (%'u bytes), max is 128MB\n", cb));
2395 return VERR_BAD_EXE_FORMAT;
2396 }
2397
2398 int rc;
2399 IMAGE_COFF_SYMBOLS_HEADER Hdr;
2400 if (hFile == NIL_RTFILE)
2401 rc = pDbgMod->pImgVt->pfnReadAt(pDbgMod, UINT32_MAX, off, &Hdr, sizeof(Hdr));
2402 else
2403 rc = RTFileReadAt(hFile, off, &Hdr, sizeof(Hdr), NULL);
2404 if (RT_FAILURE(rc))
2405 {
2406 Log(("RTDbgModCv: Error reading COFF header: %Rrc\n", rc));
2407 return rc;
2408 }
2409
2410 Log2(("RTDbgModCv: Found COFF debug info header at %#x (LB %#x) in %s\n", off, cb, pszFilename));
2411 Log2((" NumberOfSymbols = %#010x\n", Hdr.NumberOfSymbols));
2412 Log2((" LvaToFirstSymbol = %#010x\n", Hdr.LvaToFirstSymbol));
2413 Log2((" NumberOfLinenumbers = %#010x\n", Hdr.NumberOfLinenumbers));
2414 Log2((" LvaToFirstLinenumber = %#010x\n", Hdr.LvaToFirstLinenumber));
2415 Log2((" RvaToFirstByteOfCode = %#010x\n", Hdr.RvaToFirstByteOfCode));
2416 Log2((" RvaToLastByteOfCode = %#010x\n", Hdr.RvaToLastByteOfCode));
2417 Log2((" RvaToFirstByteOfData = %#010x\n", Hdr.RvaToFirstByteOfData));
2418 Log2((" RvaToLastByteOfData = %#010x\n", Hdr.RvaToLastByteOfData));
2419
2420 /*
2421 * Validate the COFF header.
2422 */
2423 if ( (uint64_t)Hdr.LvaToFirstSymbol + (uint64_t)Hdr.NumberOfSymbols * sizeof(IMAGE_SYMBOL) > cb
2424 || (Hdr.LvaToFirstSymbol < sizeof(Hdr) && Hdr.NumberOfSymbols > 0))
2425 {
2426 Log(("RTDbgModCv: Bad COFF symbol count or/and offset: LvaToFirstSymbol=%#x, NumberOfSymbols=%#x cbCoff=%#x\n",
2427 Hdr.LvaToFirstSymbol, Hdr.NumberOfSymbols, cb));
2428 return VERR_BAD_EXE_FORMAT;
2429 }
2430 if ( (uint64_t)Hdr.LvaToFirstLinenumber + (uint64_t)Hdr.NumberOfLinenumbers * sizeof(IMAGE_LINENUMBER) > cb
2431 || (Hdr.LvaToFirstLinenumber < sizeof(Hdr) && Hdr.NumberOfLinenumbers > 0))
2432 {
2433 Log(("RTDbgModCv: Bad COFF symbol count or/and offset: LvaToFirstSymbol=%#x, NumberOfSymbols=%#x cbCoff=%#x\n",
2434 Hdr.LvaToFirstSymbol, Hdr.NumberOfSymbols, cb));
2435 return VERR_BAD_EXE_FORMAT;
2436 }
2437 if (Hdr.NumberOfSymbols < 2)
2438 {
2439 Log(("RTDbgModCv: The COFF symbol table is too short to be of any worth... (%u syms)\n", Hdr.NumberOfSymbols));
2440 return VERR_NO_DATA;
2441 }
2442
2443 /*
2444 * What we care about looks fine, use it.
2445 */
2446 PRTDBGMODCV pThis;
2447 rc = rtDbgModCvCreateInstance(pDbgMod, enmFileType, hFile, &pThis);
2448 if (RT_SUCCESS(rc))
2449 {
2450 pThis->offCoffDbgInfo = off;
2451 pThis->cbCoffDbgInfo = cb;
2452 pThis->CoffHdr = Hdr;
2453 }
2454
2455 return rc;
2456}
2457
2458
2459/**
2460 * Common part of the CodeView probing.
2461 *
2462 * @returns status code.
2463 * @param pDbgMod The debug module instance. On success pvDbgPriv
2464 * will point to a valid RTDBGMODCV.
2465 * @param pCvHdr The CodeView base header.
2466 * @param enmFileType The kind of file this is we're probing.
2467 * @param hFile The file with debug info in it.
2468 * @param off The offset where to expect CV debug info.
2469 * @param cb The number of bytes of debug info.
2470 * @param pszFilename The path to the file (for logging).
2471 */
2472static int rtDbgModCvProbeCommon(PRTDBGMODINT pDbgMod, PRTCVHDR pCvHdr, RTCVFILETYPE enmFileType, RTFILE hFile,
2473 uint32_t off, uint32_t cb, RTLDRARCH enmArch, const char *pszFilename)
2474{
2475 int rc = VERR_DBG_NO_MATCHING_INTERPRETER;
2476
2477 /* Is a codeview format we (wish to) support? */
2478 if ( pCvHdr->u32Magic == RTCVHDR_MAGIC_NB11
2479 || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB09
2480 || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB08
2481 || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB05
2482 || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB04
2483 || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB02
2484 || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB00
2485 )
2486 {
2487 /* We're assuming it's a base header, so the offset must be within
2488 the area defined by the debug info we got from the loader. */
2489 if (pCvHdr->off < cb && pCvHdr->off >= sizeof(*pCvHdr))
2490 {
2491 Log(("RTDbgModCv: Found %c%c%c%c at %#RTfoff - size %#x, directory at %#x. file type %d\n",
2492 RT_BYTE1(pCvHdr->u32Magic), RT_BYTE2(pCvHdr->u32Magic), RT_BYTE3(pCvHdr->u32Magic), RT_BYTE4(pCvHdr->u32Magic),
2493 off, cb, pCvHdr->off, enmFileType));
2494
2495 /*
2496 * Create a module instance, if not already done.
2497 */
2498 PRTDBGMODCV pThis;
2499 rc = rtDbgModCvCreateInstance(pDbgMod, enmFileType, hFile, &pThis);
2500 if (RT_SUCCESS(rc))
2501 {
2502 pThis->u32CvMagic = pCvHdr->u32Magic;
2503 pThis->offBase = off;
2504 pThis->cbDbgInfo = cb;
2505 pThis->offDir = pCvHdr->off;
2506 return VINF_SUCCESS;
2507 }
2508 }
2509 }
2510
2511 return rc;
2512}
2513
2514
2515/** @callback_method_impl{FNRTLDRENUMDBG} */
2516static DECLCALLBACK(int) rtDbgModCvEnumCallback(RTLDRMOD hLdrMod, PCRTLDRDBGINFO pDbgInfo, void *pvUser)
2517{
2518 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)pvUser;
2519 Assert(!pDbgMod->pvDbgPriv);
2520
2521 /* Skip external files, RTDbgMod will deal with those
2522 via RTDBGMODINT::pszDbgFile. */
2523 if (pDbgInfo->pszExtFile)
2524 return VINF_SUCCESS;
2525
2526 /* We only handle the codeview sections. */
2527 if (pDbgInfo->enmType == RTLDRDBGINFOTYPE_CODEVIEW)
2528 {
2529 /* Read the specified header and check if we like it. */
2530 RTCVHDR CvHdr;
2531 int rc = pDbgMod->pImgVt->pfnReadAt(pDbgMod, pDbgInfo->iDbgInfo, pDbgInfo->offFile, &CvHdr, sizeof(CvHdr));
2532 if (RT_SUCCESS(rc))
2533 rc = rtDbgModCvProbeCommon(pDbgMod, &CvHdr, RTCVFILETYPE_IMAGE, NIL_RTFILE, pDbgInfo->offFile, pDbgInfo->cb,
2534 pDbgMod->pImgVt->pfnGetArch(pDbgMod), pDbgMod->pszImgFile);
2535 }
2536 else if (pDbgInfo->enmType == RTLDRDBGINFOTYPE_COFF)
2537 {
2538 /* Join paths with the DBG code. */
2539 rtDbgModCvProbeCoff(pDbgMod, RTCVFILETYPE_IMAGE, NIL_RTFILE, pDbgInfo->offFile, pDbgInfo->cb, pDbgMod->pszImgFile);
2540 }
2541
2542 return VINF_SUCCESS;
2543}
2544
2545
2546/**
2547 * Part two of the external file probing.
2548 *
2549 * @returns status code.
2550 * @param pDbgMod The debug module instance. On success pvDbgPriv
2551 * will point to a valid RTDBGMODCV.
2552 * @param enmFileType The kind of file this is we're probing.
2553 * @param hFile The file with debug info in it.
2554 * @param off The offset where to expect CV debug info.
2555 * @param cb The number of bytes of debug info.
2556 * @param enmArch The desired image architecture.
2557 * @param pszFilename The path to the file (for logging).
2558 */
2559static int rtDbgModCvProbeFile2(PRTDBGMODINT pThis, RTCVFILETYPE enmFileType, RTFILE hFile, uint32_t off, uint32_t cb,
2560 RTLDRARCH enmArch, const char *pszFilename)
2561{
2562 RTCVHDR CvHdr;
2563 int rc = RTFileReadAt(hFile, off, &CvHdr, sizeof(CvHdr), NULL);
2564 if (RT_SUCCESS(rc))
2565 rc = rtDbgModCvProbeCommon(pThis, &CvHdr, enmFileType, hFile, off, cb, enmArch, pszFilename);
2566 return rc;
2567}
2568
2569
2570/**
2571 * Probes an external file for CodeView information.
2572 *
2573 * @returns status code.
2574 * @param pDbgMod The debug module instance. On success pvDbgPriv
2575 * will point to a valid RTDBGMODCV.
2576 * @param pszFilename The path to the file to probe.
2577 * @param enmArch The desired image architecture.
2578 */
2579static int rtDbgModCvProbeFile(PRTDBGMODINT pDbgMod, const char *pszFilename, RTLDRARCH enmArch)
2580{
2581 RTFILE hFile;
2582 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN);
2583 if (RT_FAILURE(rc))
2584 return rc;
2585
2586 /*
2587 * Check for .DBG file
2588 */
2589 IMAGE_SEPARATE_DEBUG_HEADER DbgHdr;
2590 rc = RTFileReadAt(hFile, 0, &DbgHdr, sizeof(DbgHdr), NULL);
2591 if ( RT_SUCCESS(rc)
2592 && DbgHdr.Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE)
2593 {
2594 Log2(("RTDbgModCv: Found separate debug header in %s:\n", pszFilename));
2595 Log2((" Flags = %#x\n", DbgHdr.Flags));
2596 Log2((" Machine = %#x\n", DbgHdr.Machine));
2597 Log2((" Characteristics = %#x\n", DbgHdr.Characteristics));
2598 Log2((" TimeDateStamp = %#x\n", DbgHdr.TimeDateStamp));
2599 Log2((" CheckSum = %#x\n", DbgHdr.CheckSum));
2600 Log2((" ImageBase = %#x\n", DbgHdr.ImageBase));
2601 Log2((" SizeOfImage = %#x\n", DbgHdr.SizeOfImage));
2602 Log2((" NumberOfSections = %#x\n", DbgHdr.NumberOfSections));
2603 Log2((" ExportedNamesSize = %#x\n", DbgHdr.ExportedNamesSize));
2604 Log2((" DebugDirectorySize = %#x\n", DbgHdr.DebugDirectorySize));
2605 Log2((" SectionAlignment = %#x\n", DbgHdr.SectionAlignment));
2606
2607 /*
2608 * Match up the architecture if specified.
2609 */
2610 switch (enmArch)
2611 {
2612 case RTLDRARCH_X86_32:
2613 if (DbgHdr.Machine != IMAGE_FILE_MACHINE_I386)
2614 rc = VERR_LDR_ARCH_MISMATCH;
2615 break;
2616 case RTLDRARCH_AMD64:
2617 if (DbgHdr.Machine != IMAGE_FILE_MACHINE_AMD64)
2618 rc = VERR_LDR_ARCH_MISMATCH;
2619 break;
2620
2621 default:
2622 case RTLDRARCH_HOST:
2623 AssertFailed();
2624 case RTLDRARCH_WHATEVER:
2625 break;
2626 }
2627 if (RT_FAILURE(rc))
2628 {
2629 RTFileClose(hFile);
2630 return rc;
2631 }
2632
2633 /*
2634 * Probe for readable debug info in the debug directory.
2635 */
2636 uint32_t offDbgDir = sizeof(DbgHdr)
2637 + DbgHdr.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
2638 + DbgHdr.ExportedNamesSize;
2639
2640 uint32_t cEntries = DbgHdr.DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY);
2641 for (uint32_t i = 0; i < cEntries; i++, offDbgDir += sizeof(IMAGE_DEBUG_DIRECTORY))
2642 {
2643 IMAGE_DEBUG_DIRECTORY DbgDir;
2644 rc = RTFileReadAt(hFile, offDbgDir, &DbgDir, sizeof(DbgDir), NULL);
2645 if (RT_FAILURE(rc))
2646 break;
2647 if (DbgDir.Type == IMAGE_DEBUG_TYPE_CODEVIEW)
2648 rc = rtDbgModCvProbeFile2(pDbgMod, RTCVFILETYPE_DBG, hFile,
2649 DbgDir.PointerToRawData, DbgDir.SizeOfData,
2650 enmArch, pszFilename);
2651 else if (DbgDir.Type == IMAGE_DEBUG_TYPE_COFF)
2652 rc = rtDbgModCvProbeCoff(pDbgMod, RTCVFILETYPE_DBG, hFile,
2653 DbgDir.PointerToRawData, DbgDir.SizeOfData, pszFilename);
2654 }
2655
2656 /*
2657 * If we get down here with an instance, it prooves that we've found
2658 * something, regardless of any errors. Add the sections and such.
2659 */
2660 PRTDBGMODCV pThis = (PRTDBGMODCV)pDbgMod->pvDbgPriv;
2661 if (pThis)
2662 {
2663 pThis->cbImage = DbgHdr.SizeOfImage;
2664 if (pDbgMod->pImgVt)
2665 rc = VINF_SUCCESS;
2666 else
2667 {
2668 rc = rtDbgModCvAddSegmentsFromDbg(pThis, &DbgHdr, pszFilename);
2669 if (RT_FAILURE(rc))
2670 rtDbgModCv_Close(pDbgMod);
2671 }
2672 return rc;
2673 }
2674
2675 /* Failed to find CV or smth, look at the end of the file just to be sure... */
2676 }
2677
2678 /*
2679 * Look for CV tail header.
2680 */
2681 uint64_t cbFile;
2682 rc = RTFileSeek(hFile, -(RTFOFF)sizeof(RTCVHDR), RTFILE_SEEK_END, &cbFile);
2683 if (RT_SUCCESS(rc))
2684 {
2685 cbFile += sizeof(RTCVHDR);
2686 RTCVHDR CvHdr;
2687 rc = RTFileRead(hFile, &CvHdr, sizeof(CvHdr), NULL);
2688 if (RT_SUCCESS(rc))
2689 rc = rtDbgModCvProbeFile2(pDbgMod, RTCVFILETYPE_OTHER_AT_END, hFile,
2690 cbFile - CvHdr.off, CvHdr.off, enmArch, pszFilename);
2691 }
2692
2693 if (RT_FAILURE(rc))
2694 RTFileClose(hFile);
2695 return rc;
2696}
2697
2698
2699
2700/** @interface_method_impl{RTDBGMODVTDBG,pfnTryOpen} */
2701static DECLCALLBACK(int) rtDbgModCv_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch)
2702{
2703 /*
2704 * Look for debug info.
2705 */
2706 int rc = VERR_DBG_NO_MATCHING_INTERPRETER;
2707 if (pMod->pszDbgFile)
2708 rc = rtDbgModCvProbeFile(pMod, pMod->pszDbgFile, enmArch);
2709
2710 if (!pMod->pvDbgPriv && pMod->pImgVt)
2711 {
2712 int rc2 = pMod->pImgVt->pfnEnumDbgInfo(pMod, rtDbgModCvEnumCallback, pMod);
2713 if (RT_FAILURE(rc2))
2714 rc = rc2;
2715
2716 if (!pMod->pvDbgPriv)
2717 {
2718 /* Try the executable in case it has a NBxx tail header. */
2719 rc2 = rtDbgModCvProbeFile(pMod, pMod->pszImgFile, enmArch);
2720 if (RT_FAILURE(rc2) && (RT_SUCCESS(rc) || VERR_DBG_NO_MATCHING_INTERPRETER))
2721 rc = rc2;
2722 }
2723 }
2724
2725 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
2726 if (!pThis)
2727 return RT_SUCCESS_NP(rc) ? VERR_DBG_NO_MATCHING_INTERPRETER : rc;
2728 Assert(pThis->offBase != UINT32_MAX || pThis->offCoffDbgInfo != UINT32_MAX);
2729
2730 /*
2731 * Load the debug info.
2732 */
2733 if (pMod->pImgVt)
2734 {
2735 rc = pMod->pImgVt->pfnEnumSegments(pMod, rtDbgModCvAddSegmentsCallback, pThis);
2736 pThis->fHaveLoadedSegments = true;
2737 }
2738 if (RT_SUCCESS(rc) && pThis->offBase != UINT32_MAX)
2739 rc = rtDbgModCvLoadCodeViewInfo(pThis);
2740 if (RT_SUCCESS(rc) && pThis->offCoffDbgInfo != UINT32_MAX)
2741 rc = rtDbgModCvLoadCoffInfo(pThis);
2742 if (RT_SUCCESS(rc))
2743 {
2744 Log(("RTDbgCv: Successfully loaded debug info\n"));
2745 return VINF_SUCCESS;
2746 }
2747
2748 Log(("RTDbgCv: Debug info load error %Rrc\n", rc));
2749 rtDbgModCv_Close(pMod);
2750 return rc;
2751}
2752
2753
2754
2755
2756
2757/** Virtual function table for the CodeView debug info reader. */
2758DECL_HIDDEN_CONST(RTDBGMODVTDBG) const g_rtDbgModVtDbgCodeView =
2759{
2760 /*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
2761 /*.fSupports = */ RT_DBGTYPE_CODEVIEW,
2762 /*.pszName = */ "codeview",
2763 /*.pfnTryOpen = */ rtDbgModCv_TryOpen,
2764 /*.pfnClose = */ rtDbgModCv_Close,
2765
2766 /*.pfnRvaToSegOff = */ rtDbgModCv_RvaToSegOff,
2767 /*.pfnImageSize = */ rtDbgModCv_ImageSize,
2768
2769 /*.pfnSegmentAdd = */ rtDbgModCv_SegmentAdd,
2770 /*.pfnSegmentCount = */ rtDbgModCv_SegmentCount,
2771 /*.pfnSegmentByIndex = */ rtDbgModCv_SegmentByIndex,
2772
2773 /*.pfnSymbolAdd = */ rtDbgModCv_SymbolAdd,
2774 /*.pfnSymbolCount = */ rtDbgModCv_SymbolCount,
2775 /*.pfnSymbolByOrdinal = */ rtDbgModCv_SymbolByOrdinal,
2776 /*.pfnSymbolByName = */ rtDbgModCv_SymbolByName,
2777 /*.pfnSymbolByAddr = */ rtDbgModCv_SymbolByAddr,
2778
2779 /*.pfnLineAdd = */ rtDbgModCv_LineAdd,
2780 /*.pfnLineCount = */ rtDbgModCv_LineCount,
2781 /*.pfnLineByOrdinal = */ rtDbgModCv_LineByOrdinal,
2782 /*.pfnLineByAddr = */ rtDbgModCv_LineByAddr,
2783
2784 /*.u32EndMagic = */ RTDBGMODVTDBG_MAGIC
2785};
2786
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette