VirtualBox

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

Last change on this file since 46274 was 46274, checked in by vboxsync, 12 years ago

dbgmodcodeview.cpp: Added code for parsing microsoft COFF debug information. Current strategy is to parse both CodeView and COFF when present since we don't know which have most details, and COFF are more likely to include line numbers.

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