VirtualBox

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

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

IPRT: Changed RTLDRSEG::pchName to pszName and make sure it's always set to something. Started on implementing a codeview reader.

  • Property svn:executable set to *
File size: 42.8 KB
Line 
1/* $Id: dbgmoddeferred.cpp 85864 2013-05-19 16:58:01Z bird $ */
2/** @file
3 * IPRT - Debug Module Reader For Microsoft CodeView.
4 */
5
6/*
7 * Copyright (C) 2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#define LOG_GROUP RTLOGGROUP_DBG
32#include <iprt/dbg.h>
33#include "internal/iprt.h"
34
35#include <iprt/alloca.h>
36#include <iprt/asm.h>
37#include <iprt/assert.h>
38#include <iprt/err.h>
39#include <iprt/file.h>
40#include <iprt/log.h>
41#include <iprt/mem.h>
42#include <iprt/param.h>
43#include <iprt/path.h>
44#include <iprt/string.h>
45#include "internal/dbgmod.h"
46#include "internal/ldrPE.h"
47#include "internal/magics.h"
48
49
50/*******************************************************************************
51* Structures and Typedefs *
52*******************************************************************************/
53/**
54 * CodeView Header. There are two of this, base header at the start of the debug
55 * information and a trailing header at the end.
56 */
57typedef struct RTCVHDR
58{
59 /** The magic ('NBxx'). */
60 uint32_t u32Magic;
61 /**
62 * Base header: Subsection directory offset relative to this header (start).
63 * Trailing header: Offset of the base header relative to the end of the file.
64 *
65 * Called lfoBase, lfaBase, lfoDirectory, lfoDir and probably other things in
66 * the various specs/docs available. */
67 uint32_t off;
68} RTCVHDR;
69/** Pointer to a CodeView header. */
70typedef RTCVHDR *PRTCVHDR;
71
72
73/** @name CV directory headers.
74 * @{ */
75
76/**
77 * Really old CV directory header used with NB00 and NB02.
78 *
79 * Uses 16-bit directory entires (RTCVDIRENT16).
80 */
81typedef struct RTCVDIRHDR16
82{
83 /** The number of directory entries. */
84 uint16_t cEntries;
85} RTCVDIRHDR16;
86/** Pointer to a old CV directory header. */
87typedef RTCVDIRHDR16 *PRTCVDIRHDR16;
88
89/**
90 * Simple 32-bit CV directory base header, used by NB04 (aka IBM HLL).
91 */
92typedef struct RTCVDIRHDR32
93{
94 /** The number of bytes of this header structure. */
95 uint16_t cbHdr;
96 /** The number of bytes per entry. */
97 uint16_t cbEntry;
98 /** The number of directory entries. */
99 uint32_t cEntries;
100} RTCVDIRHDR32;
101/** Pointer to a 32-bit CV directory header. */
102typedef RTCVDIRHDR32 *PRTCVDIRHDR32;
103
104/**
105 * Extended 32-bit CV directory header as specified in the TIS doc.
106 * The two extra fields seems to never have been assigned any official purpose.
107 */
108typedef struct RTCVDIRHDR32EX
109{
110 /** This starts the same way as the NB04 header. */
111 RTCVDIRHDR32 Core;
112 /** Tentatively decleared as the offset to the next directory generated by
113 * the incremental linker. Haven't seen this used yet. */
114 uint32_t offNextDir;
115 /** Flags, non defined apparently, so MBZ. */
116 uint32_t fFlags;
117} RTCVDIRHDR32EX;
118/** Pointer to an extended 32-bit CV directory header. */
119typedef RTCVDIRHDR32EX *PRTCVDIRHDR32EX;
120
121/** @} */
122
123
124/**
125 * 16-bit CV directory entry used with NB00 and NB02.
126 */
127typedef struct RTCVDIRENT16
128{
129 /** Subsection type (RTCVSST). */
130 uint16_t uSubSectType;
131 /** Which module (1-based, 0xffff is special). */
132 uint16_t iMod;
133 /** The lowe offset of this subsection relative to the base CV header. */
134 uint16_t offLow;
135 /** The high part of the subsection offset. */
136 uint16_t offHigh;
137 /** The size of the subsection. */
138 uint16_t cb;
139} RTCVDIRENT16;
140AssertCompileSize(RTCVDIRENT16, 10);
141/** Pointer to a 16-bit CV directory entry. */
142typedef RTCVDIRENT16 *PRTCVDIRENT16;
143
144
145/**
146 * 32-bit CV directory entry used starting with NB04.
147 */
148typedef struct RTCVDIRENT32
149{
150 /** Subsection type (RTCVSST). */
151 uint16_t uSubSectType;
152 /** Which module (1-based, 0xffff is special). */
153 uint16_t iMod;
154 /** The offset of this subsection relative to the base CV header. */
155 uint32_t off;
156 /** The size of the subsection. */
157 uint32_t cb;
158} RTCVDIRENT32;
159AssertCompileSize(RTCVDIRENT32, 12);
160/** Pointer to a 32-bit CV directory entry. */
161typedef RTCVDIRENT32 *PRTCVDIRENT32;
162/** Pointer to a const 32-bit CV directory entry. */
163typedef RTCVDIRENT32 const *PCRTCVDIRENT32;
164
165
166/**
167 * CodeView subsection types.
168 */
169typedef enum RTCVSST
170{
171 /** @name NB00, NB02 and NB04 subsection types.
172 * The actual format of each subsection varies between NB04 and the others,
173 * and it may further vary in NB04 depending on the module type.
174 * @{ */
175 kCvSst_OldModule = 0x101,
176 kCvSst_OldPublic,
177 kCvSst_OldTypes,
178 kCvSst_OldSymbols,
179 kCvSst_OldSrcLines,
180 kCvSst_OldLibraries,
181 kCvSst_OldImports,
182 kCvSst_OldCompacted,
183 kCvSst_OldSrcLnSeg = 0x109,
184 kCvSst_OldSrcLines3 = 0x10b,
185 /** @} */
186
187 /** @name NB09, NB11 (and possibly NB05, NB06, NB07, and NB08) subsection types.
188 * @{ */
189 kCvSst_Module = 0x120,
190 kCvSst_Types,
191 kCvSst_Public,
192 kCvSst_PublicSym,
193 kCvSst_Symbols,
194 kCvSst_AlignSym,
195 kCvSst_SrcLnSeg,
196 kCvSst_SrcModule,
197 kCvSst_Libraries,
198 kCvSst_GlobalSym,
199 kCvSst_GlobalPub,
200 kCvSst_GlobalTypes,
201 kCvSst_MPC,
202 kCvSst_SegMap,
203 kCvSst_SegName,
204 kCvSst_PreComp,
205 kCvSst_PreCompMap,
206 kCvSst_OffsetMap16,
207 kCvSst_OffsetMap32,
208 kCvSst_FileIndex = 0x133,
209 kCvSst_StaticSym
210 /** @} */
211} RTCVSST;
212/** Pointer to a CV subsection type value. */
213typedef RTCVSST *PRTCVSST;
214/** Pointer to a const CV subsection type value. */
215typedef RTCVSST const *PCRTCVSST;
216
217
218/** @name CodeView magic values.
219 * @{ */
220/** CodeView from Visual C++ 5.0. Specified in the 2001 MSDN specs.chm file. */
221#define RTCVHDR_MAGIC_NB11 RT_MAKE_U32_FROM_U8('N', 'B', '1', '1')
222/** External PDB reference (often referred to as PDB 2.0). */
223#define RTCVHDR_MAGIC_NB10 RT_MAKE_U32_FROM_U8('N', 'B', '1', '0')
224/** CodeView v4.10, packed. Specified in the TIS document. */
225#define RTCVHDR_MAGIC_NB09 RT_MAKE_U32_FROM_U8('N', 'B', '0', '9')
226/** CodeView v4.00 thru v4.05. Specified in the TIS document? */
227#define RTCVHDR_MAGIC_NB08 RT_MAKE_U32_FROM_U8('N', 'B', '0', '8')
228/** Quick C for Windows 1.0 debug info. */
229#define RTCVHDR_MAGIC_NB07 RT_MAKE_U32_FROM_U8('N', 'B', '0', '7')
230/** Emitted by ILINK indicating incremental link. Comparable to NB05? */
231#define RTCVHDR_MAGIC_NB06 RT_MAKE_U32_FROM_U8('N', 'B', '0', '6')
232/** Emitted by LINK version 5.20 and later before packing. */
233#define RTCVHDR_MAGIC_NB05 RT_MAKE_U32_FROM_U8('N', 'B', '0', '5')
234/** Emitted by IBM ILINK for HLL (similar to NB02 in many ways). */
235#define RTCVHDR_MAGIC_NB04 RT_MAKE_U32_FROM_U8('N', 'B', '0', '4')
236/** Emitted by LINK version 5.10 (or similar OMF linkers), as shipped with
237 * Microsoft C v6.0 for example. More or less entirely 16-bit. */
238#define RTCVHDR_MAGIC_NB02 RT_MAKE_U32_FROM_U8('N', 'B', '0', '2')
239/* No idea what NB03 might have been. */
240/** AIX debugger format according to "IBM OS/2 16/32-bit Object Module Format
241 * (OMF) and Linear eXecutable Module Format (LX)" revision 10 (LXOMF.PDF). */
242#define RTCVHDR_MAGIC_NB01 RT_MAKE_U32_FROM_U8('N', 'B', '0', '1')
243/** Ancient CodeView format according to LXOMF.PDF. */
244#define RTCVHDR_MAGIC_NB00 RT_MAKE_U32_FROM_U8('N', 'B', '0', '0')
245/** @} */
246
247
248/**
249 * File type.
250 */
251typedef enum RTCVFILETYPE
252{
253 RTCVFILETYPE_INVALID = 0,
254 /** Executable image. */
255 RTCVFILETYPE_IMAGE,
256 /** A DBG-file with a IMAGE_SEPARATE_DEBUG_HEADER. */
257 RTCVFILETYPE_DBG,
258 /** A PDB file. */
259 RTCVFILETYPE_PDB,
260 /** Some other kind of file with CV at the end. */
261 RTCVFILETYPE_OTHER_AT_END,
262 /** The end of the valid values. */
263 RTCVFILETYPE_END,
264 /** Type blowup. */
265 RTCVFILETYPE_32BIT_HACK = 0x7fffffff
266} RTCVFILETYPE;
267
268
269/**
270 * CodeView debug info reader instance.
271 */
272typedef struct RTDBGMODCV
273{
274 /** Using a container for managing the debug info. */
275 RTDBGMOD hCnt;
276
277 /** The code view magic (used as format indicator). */
278 uint32_t u32CvMagic;
279 /** The file type. */
280 RTCVFILETYPE enmType;
281 /** The offset of the CV debug info in the file. */
282 uint32_t offBase;
283 /** The size of the CV debug info. */
284 uint32_t cbDbgInfo;
285 /** The offset of the subsection directory (relative to offBase). */
286 uint32_t offDir;
287
288 /** The file handle (if external). */
289 RTFILE hFile;
290 /** Pointer to the module (no reference retained). */
291 PRTDBGMODINT pMod;
292
293 /** The image size, if we know it. This is 0 if we don't know it. */
294 uint32_t cbImage;
295
296 /** Indicates that we've loaded segments intot he container already. */
297 bool fHaveLoadedSegments;
298
299 /** @name Parsing state.
300 * @{ */
301 /** Number of directory entries. */
302 uint32_t cDirEnts;
303 /** The directory (converted to 32-bit). */
304 PRTCVDIRENT32 paDirEnts;
305
306 /** @} */
307
308} RTDBGMODCV;
309/** Pointer to a codeview debug info reader instance. */
310typedef RTDBGMODCV *PRTDBGMODCV;
311/** Pointer to a const codeview debug info reader instance. */
312typedef RTDBGMODCV *PCRTDBGMODCV;
313
314
315static int rtDbgModCvReadAt(PRTDBGMODCV pThis, uint32_t off, void *pvBuf, size_t cb)
316{
317 int rc;
318 if (pThis->hFile == NIL_RTFILE)
319 rc = pThis->pMod->pImgVt->pfnReadAt(pThis->pMod, UINT32_MAX, off, pvBuf, cb);
320 else
321 rc = RTFileReadAt(pThis->hFile, off, pvBuf, cb, NULL);
322 return rc;
323}
324
325
326
327/**
328 * Gets a name string for a subsection type.
329 *
330 * @returns Section name (read only).
331 * @param uSubSectType The subsection type.
332 */
333static const char *rtDbgModCvGetSubSectionName(uint16_t uSubSectType)
334{
335 switch (uSubSectType)
336 {
337 case kCvSst_OldModule: return "sstOldModule";
338 case kCvSst_OldPublic: return "sstOldPublic";
339 case kCvSst_OldTypes: return "sstOldTypes";
340 case kCvSst_OldSymbols: return "sstOldSymbols";
341 case kCvSst_OldSrcLines: return "sstOldSrcLines";
342 case kCvSst_OldLibraries: return "sstOldLibraries";
343 case kCvSst_OldImports: return "sstOldImports";
344 case kCvSst_OldCompacted: return "sstOldCompacted";
345 case kCvSst_OldSrcLnSeg: return "sstOldSrcLnSeg";
346 case kCvSst_OldSrcLines3: return "sstOldSrcLines3";
347
348 case kCvSst_Module: return "sstModule";
349 case kCvSst_Types: return "sstTypes";
350 case kCvSst_Public: return "sstPublic";
351 case kCvSst_PublicSym: return "sstPublicSym";
352 case kCvSst_Symbols: return "sstSymbols";
353 case kCvSst_AlignSym: return "sstAlignSym";
354 case kCvSst_SrcLnSeg: return "sstSrcLnSeg";
355 case kCvSst_SrcModule: return "sstSrcModule";
356 case kCvSst_Libraries: return "sstLibraries";
357 case kCvSst_GlobalSym: return "sstGlobalSym";
358 case kCvSst_GlobalPub: return "sstGlobalPub";
359 case kCvSst_GlobalTypes: return "sstGlobalTypes";
360 case kCvSst_MPC: return "sstMPC";
361 case kCvSst_SegMap: return "sstSegMap";
362 case kCvSst_SegName: return "sstSegName";
363 case kCvSst_PreComp: return "sstPreComp";
364 case kCvSst_PreCompMap: return "sstPreCompMap";
365 case kCvSst_OffsetMap16: return "sstOffsetMap16";
366 case kCvSst_OffsetMap32: return "sstOffsetMap32";
367 case kCvSst_FileIndex: return "sstFileIndex";
368 case kCvSst_StaticSym: return "sstStaticSym";
369 }
370 static char s_sz[32];
371 RTStrPrintf(s_sz, sizeof(s_sz), "Unknown%#x", uSubSectType);
372 return s_sz;
373}
374
375
376/**
377 * Loads the directory into memory (RTDBGMODCV::paDirEnts and
378 * RTDBGMODCV::cDirEnts).
379 *
380 * Converting old format version into the newer format to simplifying the code
381 * using the directory.
382 *
383 *
384 * @returns IPRT status code. (May leave with paDirEnts allocated on failure.)
385 * @param pThis The CV reader instance.
386 */
387static int rtDbgModCvLoadDirectory(PRTDBGMODCV pThis)
388{
389 /*
390 * Read in the CV directory.
391 */
392 int rc;
393 if ( pThis->u32CvMagic == RTCVHDR_MAGIC_NB00
394 || pThis->u32CvMagic == RTCVHDR_MAGIC_NB02)
395 {
396 /*
397 * 16-bit type.
398 */
399 RTCVDIRHDR16 DirHdr;
400 rc = rtDbgModCvReadAt(pThis, pThis->offBase + pThis->offDir, &DirHdr, sizeof(DirHdr));
401 if (RT_SUCCESS(rc))
402 {
403 if (DirHdr.cEntries > 2 && DirHdr.cEntries < _64K - 32U)
404 {
405 pThis->cDirEnts = DirHdr.cEntries;
406 pThis->paDirEnts = (PRTCVDIRENT32)RTMemAlloc(DirHdr.cEntries * sizeof(pThis->paDirEnts[0]));
407 if (pThis->paDirEnts)
408 {
409 rc = rtDbgModCvReadAt(pThis, pThis->offBase + pThis->offDir + sizeof(DirHdr),
410 pThis->paDirEnts, DirHdr.cEntries * sizeof(RTCVDIRENT16));
411 if (RT_SUCCESS(rc))
412 {
413 /* Convert the entries (from the end). */
414 uint32_t cLeft = DirHdr.cEntries;
415 RTCVDIRENT32 volatile *pDst = pThis->paDirEnts + cLeft;
416 RTCVDIRENT16 volatile *pSrc = (RTCVDIRENT16 volatile *)pThis->paDirEnts + cLeft;
417 while (cLeft--)
418 {
419 pDst--;
420 pSrc--;
421
422 pDst->cb = pSrc->cb;
423 pDst->off = RT_MAKE_U32(pSrc->offLow, pSrc->offHigh);
424 pDst->iMod = pSrc->iMod;
425 pDst->uSubSectType = pSrc->uSubSectType;
426 }
427 }
428 }
429 else
430 rc = VERR_NO_MEMORY;
431 }
432 else
433 {
434 Log(("Old CV directory count is out of considered valid range: %#x\n", DirHdr.cEntries));
435 rc = VERR_CV_BAD_FORMAT;
436 }
437 }
438 }
439 else
440 {
441 /*
442 * 32-bit type (reading too much for NB04 is no problem).
443 */
444 RTCVDIRHDR32EX DirHdr;
445 rc = rtDbgModCvReadAt(pThis, pThis->offBase + pThis->offDir, &DirHdr, sizeof(DirHdr));
446 if (RT_SUCCESS(rc))
447 {
448 if ( DirHdr.Core.cbHdr != sizeof(DirHdr.Core)
449 && DirHdr.Core.cbHdr != sizeof(DirHdr))
450 {
451 Log(("Unexpected CV directory size: %#x\n", DirHdr.Core.cbHdr));
452 rc = VERR_CV_BAD_FORMAT;
453 }
454 if ( DirHdr.Core.cbHdr == sizeof(DirHdr)
455 && ( DirHdr.offNextDir != 0
456 || DirHdr.fFlags != 0) )
457 {
458 Log(("Extended CV directory headers fields are not zero: fFlags=%#x offNextDir=%#x\n",
459 DirHdr.fFlags, DirHdr.offNextDir));
460 rc = VERR_CV_BAD_FORMAT;
461 }
462 if (DirHdr.Core.cbEntry != sizeof(RTCVDIRENT32))
463 {
464 Log(("Unexpected CV directory entry size: %#x (expected %#x)\n", DirHdr.Core.cbEntry, sizeof(RTCVDIRENT32)));
465 rc = VERR_CV_BAD_FORMAT;
466 }
467 if (DirHdr.Core.cEntries < 2 || DirHdr.Core.cEntries >= _512K)
468 {
469 Log(("CV directory count is out of considered valid range: %#x\n", DirHdr.Core.cEntries));
470 rc = VERR_CV_BAD_FORMAT;
471 }
472 if (RT_SUCCESS(rc))
473 {
474 pThis->cDirEnts = DirHdr.Core.cEntries;
475 pThis->paDirEnts = (PRTCVDIRENT32)RTMemAlloc(DirHdr.Core.cEntries * sizeof(pThis->paDirEnts[0]));
476 if (pThis->paDirEnts)
477 rc = rtDbgModCvReadAt(pThis, pThis->offBase + pThis->offDir + DirHdr.Core.cbHdr,
478 pThis->paDirEnts, DirHdr.Core.cEntries * sizeof(RTCVDIRENT32));
479 else
480 rc = VERR_NO_MEMORY;
481 }
482 }
483 }
484
485 /*
486 * Validate the information in the directory a little.
487 */
488 if (RT_SUCCESS(rc))
489 {
490 uint32_t const cbDbgInfo = pThis->cbDbgInfo;
491 uint32_t const cDirEnts = pThis->cDirEnts;
492 Log2(("RTDbgModCv: %u (%#x) directory entries:\n", cDirEnts, cDirEnts));
493 for (uint32_t i = 0; i < cDirEnts; i++)
494 {
495 PCRTCVDIRENT32 pDirEnt = &pThis->paDirEnts[i];
496 Log2((" #%04u mod=%#06x sst=%#06x at %#010x LB %#07x %s\n",
497 i, pDirEnt->iMod, pDirEnt->uSubSectType, pDirEnt->off, pDirEnt->cb,
498 rtDbgModCvGetSubSectionName(pDirEnt->uSubSectType)));
499
500 if ( pDirEnt->off >= cbDbgInfo
501 || pDirEnt->cb >= cbDbgInfo
502 || pDirEnt->off + pDirEnt->cb > cbDbgInfo)
503 {
504 Log(("CV directory entry #%u is out of bounds: %#x LB %#x, max %#x\n", i, pDirEnt->off, pDirEnt->cb, cbDbgInfo));
505 rc = VERR_CV_BAD_FORMAT;
506 }
507 if ( pDirEnt->iMod == 0
508 && pThis->u32CvMagic != RTCVHDR_MAGIC_NB04
509 && pThis->u32CvMagic != RTCVHDR_MAGIC_NB02
510 && pThis->u32CvMagic != RTCVHDR_MAGIC_NB00)
511 {
512 Log(("CV directory entry #%u uses module index 0 (uSubSectType=%#x)\n", i, pDirEnt->iMod, pDirEnt->uSubSectType));
513 rc = VERR_CV_BAD_FORMAT;
514 }
515 }
516 }
517
518 return rc;
519}
520
521
522
523static int rtDbgModCvLoadInfo(PRTDBGMODCV pThis)
524{
525 /*
526 * Load the directory and segments.
527 */
528 int rc = rtDbgModCvLoadDirectory(pThis);
529 if (RT_SUCCESS(rc) && !pThis->fHaveLoadedSegments)
530 rc = VERR_CV_TODO; /** @todo Scan anything containing address, in particular sstSegMap and sstModule,
531 * and reconstruct the segments from that information. */
532
533 /*
534 * Load segment map, if present.
535 */
536 //if (RT_SUCCESS(rc))
537 // rc = rtDbgModCvLoadGlobals(pThis);
538
539 /*
540 * Process the directory.
541 */
542 uint32_t i = pThis->cDirEnts;
543 while (i-- > 0)
544 {
545#if 0
546 if ( pThis->paDirEnts[i].uSubSectType == kCvSst_OldPublic
547 || pThis->paDirEnts[i].uSubSectType == kCvSst_Public
548 )
549 {
550 }
551#endif
552 }
553
554 return rc;
555}
556
557
558
559
560/*
561 *
562 * CodeView Debug module implementation.
563 * CodeView Debug module implementation.
564 * CodeView Debug module implementation.
565 *
566 */
567
568
569/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByAddr} */
570static DECLCALLBACK(int) rtDbgModCv_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
571 PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
572{
573 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
574 return RTDbgModLineByAddr(pThis->hCnt, iSeg, off, poffDisp, pLineInfo);
575}
576
577
578/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByOrdinal} */
579static DECLCALLBACK(int) rtDbgModCv_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
580{
581 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
582 return RTDbgModLineByOrdinal(pThis->hCnt, iOrdinal, pLineInfo);
583}
584
585
586/** @interface_method_impl{RTDBGMODVTDBG,pfnLineCount} */
587static DECLCALLBACK(uint32_t) rtDbgModCv_LineCount(PRTDBGMODINT pMod)
588{
589 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
590 return RTDbgModLineCount(pThis->hCnt);
591}
592
593
594/** @interface_method_impl{RTDBGMODVTDBG,pfnLineAdd} */
595static DECLCALLBACK(int) rtDbgModCv_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
596 uint32_t iSeg, RTUINTPTR off, uint32_t *piOrdinal)
597{
598 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
599 Assert(!pszFile[cchFile]); NOREF(cchFile);
600 return RTDbgModLineAdd(pThis->hCnt, pszFile, uLineNo, iSeg, off, piOrdinal);
601}
602
603
604/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByAddr} */
605static DECLCALLBACK(int) rtDbgModCv_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
606 PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
607{
608 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
609 return RTDbgModSymbolByAddr(pThis->hCnt, iSeg, off, fFlags, poffDisp, pSymInfo);
610}
611
612
613/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByName} */
614static DECLCALLBACK(int) rtDbgModCv_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
615 PRTDBGSYMBOL pSymInfo)
616{
617 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
618 Assert(!pszSymbol[cchSymbol]);
619 return RTDbgModSymbolByName(pThis->hCnt, pszSymbol/*, cchSymbol*/, pSymInfo);
620}
621
622
623/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByOrdinal} */
624static DECLCALLBACK(int) rtDbgModCv_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
625{
626 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
627 return RTDbgModSymbolByOrdinal(pThis->hCnt, iOrdinal, pSymInfo);
628}
629
630
631/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolCount} */
632static DECLCALLBACK(uint32_t) rtDbgModCv_SymbolCount(PRTDBGMODINT pMod)
633{
634 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
635 return RTDbgModSymbolCount(pThis->hCnt);
636}
637
638
639/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolAdd} */
640static DECLCALLBACK(int) rtDbgModCv_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
641 RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags,
642 uint32_t *piOrdinal)
643{
644 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
645 Assert(!pszSymbol[cchSymbol]); NOREF(cchSymbol);
646 return RTDbgModSymbolAdd(pThis->hCnt, pszSymbol, iSeg, off, cb, fFlags, piOrdinal);
647}
648
649
650/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentByIndex} */
651static DECLCALLBACK(int) rtDbgModCv_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
652{
653 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
654 return RTDbgModSegmentByIndex(pThis->hCnt, iSeg, pSegInfo);
655}
656
657
658/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentCount} */
659static DECLCALLBACK(RTDBGSEGIDX) rtDbgModCv_SegmentCount(PRTDBGMODINT pMod)
660{
661 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
662 return RTDbgModSegmentCount(pThis->hCnt);
663}
664
665
666/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentAdd} */
667static DECLCALLBACK(int) rtDbgModCv_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName, size_t cchName,
668 uint32_t fFlags, PRTDBGSEGIDX piSeg)
669{
670 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
671 Assert(!pszName[cchName]); NOREF(cchName);
672 return RTDbgModSegmentAdd(pThis->hCnt, uRva, cb, pszName, fFlags, piSeg);
673}
674
675
676/** @interface_method_impl{RTDBGMODVTDBG,pfnImageSize} */
677static DECLCALLBACK(RTUINTPTR) rtDbgModCv_ImageSize(PRTDBGMODINT pMod)
678{
679 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
680 if (pThis->cbImage)
681 return pThis->cbImage;
682 return RTDbgModImageSize(pThis->hCnt);
683}
684
685
686/** @interface_method_impl{RTDBGMODVTDBG,pfnRvaToSegOff} */
687static DECLCALLBACK(RTDBGSEGIDX) rtDbgModCv_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
688{
689 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
690 return RTDbgModRvaToSegOff(pThis->hCnt, uRva, poffSeg);
691}
692
693
694/** @interface_method_impl{RTDBGMODVTDBG,pfnClose} */
695static DECLCALLBACK(int) rtDbgModCv_Close(PRTDBGMODINT pMod)
696{
697 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
698
699 RTDbgModRelease(pThis->hCnt);
700 if (pThis->hFile != NIL_RTFILE)
701 RTFileClose(pThis->hFile);
702 RTMemFree(pThis->paDirEnts);
703 RTMemFree(pThis);
704
705 pMod->pvDbgPriv = NULL; /* for internal use */
706 return VINF_SUCCESS;
707}
708
709
710/*
711 *
712 * Probing code used by rtDbgModCv_TryOpen.
713 * Probing code used by rtDbgModCv_TryOpen.
714 *
715 */
716
717
718
719/** @callback_method_impl{FNRTLDRENUMSEGS,
720 * Used to add segments from the image.} */
721static DECLCALLBACK(int) rtDbgModCvAddSegmentsCallback(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
722{
723 PRTDBGMODCV pThis = (PRTDBGMODCV)pvUser;
724 Log(("Segment %s: LinkAddress=%#llx RVA=%#llx cb=%#llx\n",
725 pSeg->pszName, (uint64_t)pSeg->LinkAddress, (uint64_t)pSeg->RVA, pSeg->cb));
726 NOREF(hLdrMod);
727
728 /* If the segment doesn't have a mapping, just add a dummy so the indexing
729 works out correctly (same as for the image). */
730 if (pSeg->RVA == NIL_RTLDRADDR)
731 return RTDbgModSegmentAdd(pThis->hCnt, 0, 0, pSeg->pszName, 0 /*fFlags*/, NULL);
732
733 RTLDRADDR cb = RT_MAX(pSeg->cb, pSeg->cbMapped);
734 return RTDbgModSegmentAdd(pThis->hCnt, pSeg->RVA, cb, pSeg->pszName, 0 /*fFlags*/, NULL);
735}
736
737
738/**
739 * Copies the sections over from the DBG file.
740 *
741 * Called if we don't have an associated executable image.
742 *
743 * @returns IPRT status code.
744 * @param pThis The CV module instance.
745 * @param pDbgHdr The DBG file header.
746 * @param pszFilename The filename (for logging).
747 */
748static int rtDbgModCvAddSegmentsFromDbg(PRTDBGMODCV pThis, PCIMAGE_SEPARATE_DEBUG_HEADER pDbgHdr, const char *pszFilename)
749{
750 /*
751 * Validate the header fields a little.
752 */
753 if ( pDbgHdr->NumberOfSections < 1
754 || pDbgHdr->NumberOfSections > 4096)
755 {
756 Log(("RTDbgModCv: Bad NumberOfSections: %d\n", pDbgHdr->NumberOfSections));
757 return VERR_CV_BAD_FORMAT;
758 }
759 if (!RT_IS_POWER_OF_TWO(pDbgHdr->SectionAlignment))
760 {
761 Log(("RTDbgModCv: Bad SectionAlignment: %#x\n", pDbgHdr->SectionAlignment));
762 return VERR_CV_BAD_FORMAT;
763 }
764
765 /*
766 * Read the section table.
767 */
768 size_t cbShs = pDbgHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
769 PIMAGE_SECTION_HEADER paShs = (PIMAGE_SECTION_HEADER)RTMemAlloc(cbShs);
770 if (!paShs)
771 return VERR_NO_MEMORY;
772 int rc = RTFileReadAt(pThis->hFile, sizeof(*pDbgHdr), paShs, cbShs, NULL);
773 if (RT_SUCCESS(rc))
774 {
775 /*
776 * Do some basic validation.
777 */
778 uint32_t cbHeaders = 0;
779 uint32_t uRvaPrev = 0;
780 for (uint32_t i = 0; i < pDbgHdr->NumberOfSections; i++)
781 {
782 Log3(("RTDbgModCv: Section #%02u %#010x LB %#010x %.*s\n",
783 i, paShs[i].VirtualAddress, paShs[i].Misc.VirtualSize, sizeof(paShs[i].Name), paShs[i].Name));
784
785 if (paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
786 continue;
787
788 if (paShs[i].VirtualAddress < uRvaPrev)
789 {
790 Log(("RTDbgModCv: %s: Overlap or soring error, VirtualAddress=%#x uRvaPrev=%#x - section #%d '%.*s'!!!\n",
791 pszFilename, paShs[i].VirtualAddress, uRvaPrev, i, sizeof(paShs[i].Name), paShs[i].Name));
792 rc = VERR_CV_BAD_FORMAT;
793 }
794 else if ( paShs[i].VirtualAddress > pDbgHdr->SizeOfImage
795 || paShs[i].Misc.VirtualSize > pDbgHdr->SizeOfImage
796 || paShs[i].VirtualAddress + paShs[i].Misc.VirtualSize > pDbgHdr->SizeOfImage)
797 {
798 Log(("RTDbgModCv: %s: VirtualAddress=%#x VirtualSize=%#x (total %x) - beyond image size (%#x) - section #%d '%.*s'!!!\n",
799 pszFilename, paShs[i].VirtualAddress, paShs[i].Misc.VirtualSize,
800 paShs[i].VirtualAddress + paShs[i].Misc.VirtualSize,
801 pThis->cbImage, i, sizeof(paShs[i].Name), paShs[i].Name));
802 rc = VERR_CV_BAD_FORMAT;
803 }
804 else if (paShs[i].VirtualAddress & (pDbgHdr->SectionAlignment - 1))
805 {
806 Log(("RTDbgModCv: %s: VirtualAddress=%#x misaligned (%#x) - section #%d '%.*s'!!!\n",
807 pszFilename, paShs[i].VirtualAddress, pDbgHdr->SectionAlignment, i, sizeof(paShs[i].Name), paShs[i].Name));
808 rc = VERR_CV_BAD_FORMAT;
809 }
810 else
811 {
812 if (uRvaPrev == 0)
813 cbHeaders = paShs[i].VirtualAddress;
814 uRvaPrev = paShs[i].VirtualAddress + paShs[i].Misc.VirtualSize;
815 continue;
816 }
817 }
818 if (RT_SUCCESS(rc) && uRvaPrev == 0)
819 {
820 Log(("RTDbgModCv: %s: No loadable sections.\n", pszFilename));
821 rc = VERR_CV_BAD_FORMAT;
822 }
823 if (RT_SUCCESS(rc) && cbHeaders == 0)
824 {
825 Log(("RTDbgModCv: %s: No space for PE headers.\n", pszFilename));
826 rc = VERR_CV_BAD_FORMAT;
827 }
828 if (RT_SUCCESS(rc))
829 {
830 /*
831 * Add sections.
832 */
833 rc = RTDbgModSegmentAdd(pThis->hCnt, 0, cbHeaders, "NtHdrs", 0 /*fFlags*/, NULL);
834 for (uint32_t i = 0; RT_SUCCESS(rc) && i < pDbgHdr->NumberOfSections; i++)
835 {
836 char szName[sizeof(paShs[i].Name) + 1];
837 memcpy(szName, paShs[i].Name, sizeof(paShs[i].Name));
838 szName[sizeof(szName) - 1] = '\0';
839
840 if (paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
841 rc = RTDbgModSegmentAdd(pThis->hCnt, 0, 0, szName, 0 /*fFlags*/, NULL);
842 else
843 rc = RTDbgModSegmentAdd(pThis->hCnt, paShs[i].VirtualAddress, paShs[i].Misc.VirtualSize, szName,
844 0 /*fFlags*/, NULL);
845 }
846 if (RT_SUCCESS(rc))
847 pThis->fHaveLoadedSegments = true;
848 }
849 }
850
851 RTMemFree(paShs);
852 return rc;
853}
854
855
856/**
857 * Common part of the probing.
858 *
859 * @returns status code.
860 * @param pDbgMod The debug module instance. On success pvDbgPriv
861 * will point to a valid RTDBGMODCV.
862 * @param hFile The file with debug info in it.
863 * @param off The offset where to expect CV debug info.
864 * @param cb The number of bytes of debug info.
865 * @param enmArch The desired image architecture.
866 * @param pszFilename The path to the file (for logging).
867 */
868static int rtDbgModCvProbeCommon(PRTDBGMODINT pDbgMod, PRTCVHDR pCvHdr, RTCVFILETYPE enmFileType, RTFILE hFile,
869 uint32_t off, uint32_t cb, RTLDRARCH enmArch, const char *pszFilename)
870{
871 int rc = VERR_DBG_NO_MATCHING_INTERPRETER;
872
873 /* Is a codeview format we (wish to) support? */
874 if ( pCvHdr->u32Magic == RTCVHDR_MAGIC_NB11
875 || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB09
876 || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB08
877 || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB05
878 || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB04
879 || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB02
880 || pCvHdr->u32Magic == RTCVHDR_MAGIC_NB00
881 )
882 {
883 /* We're assuming it's a base header, so the offset must be within
884 the area defined by the debug info we got from the loader. */
885 if (pCvHdr->off < cb)
886 {
887 Log(("RTDbgModCv: Found %c%c%c%c at %#RTfoff - size %#x, directory at %#x. file type %d\n",
888 RT_BYTE1(pCvHdr->u32Magic), RT_BYTE2(pCvHdr->u32Magic), RT_BYTE3(pCvHdr->u32Magic), RT_BYTE4(pCvHdr->u32Magic),
889 off, cb, pCvHdr->off, enmFileType));
890
891 /*
892 * Create a module instance.
893 */
894 PRTDBGMODCV pThis = (PRTDBGMODCV)RTMemAllocZ(sizeof(RTDBGMODCV));
895 if (pThis)
896 {
897 rc = RTDbgModCreate(&pThis->hCnt, pDbgMod->pszName, 0 /*cbSeg*/, 0 /*fFlags*/);
898 if (RT_SUCCESS(rc))
899 {
900 pDbgMod->pvDbgPriv = pThis;
901 pThis->u32CvMagic = pCvHdr->u32Magic;
902 pThis->enmType = enmFileType;
903 pThis->offBase = off;
904 pThis->cbDbgInfo = cb;
905 pThis->offDir = pCvHdr->off;
906 pThis->hFile = hFile;
907 return VINF_CALLBACK_RETURN;
908 }
909
910 RTMemFree(pThis);
911 }
912 else
913 rc = VERR_NO_MEMORY;
914 }
915 }
916
917 return rc;
918}
919
920
921/** @callback_method_impl{FNRTLDRENUMDBG} */
922static DECLCALLBACK(int) rtDbgModCvEnumCallback(RTLDRMOD hLdrMod, PCRTLDRDBGINFO pDbgInfo, void *pvUser)
923{
924 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)pvUser;
925 Assert(!pDbgMod->pvDbgPriv);
926
927 /* Skip external files, RTDbgMod will deal with those
928 via RTDBGMODINT::pszDbgFile. */
929 if (pDbgInfo->pszExtFile)
930 return VINF_SUCCESS;
931
932 /* We only handle the codeview sections. */
933 if (pDbgInfo->enmType != RTLDRDBGINFOTYPE_CODEVIEW)
934 return VINF_SUCCESS;
935
936 /* Read the specified header and check if we like it. */
937 RTCVHDR CvHdr;
938 int rc = pDbgMod->pImgVt->pfnReadAt(pDbgMod, pDbgInfo->iDbgInfo, pDbgInfo->offFile, &CvHdr, sizeof(CvHdr));
939 if (RT_SUCCESS(rc))
940 rc = rtDbgModCvProbeCommon(pDbgMod, &CvHdr, RTCVFILETYPE_IMAGE, NIL_RTFILE, pDbgInfo->offFile, pDbgInfo->cb,
941 pDbgMod->pImgVt->pfnGetArch(pDbgMod), pDbgMod->pszImgFile);
942 return VINF_SUCCESS;
943}
944
945
946/**
947 * Part two of the external file probing.
948 *
949 * @returns status code.
950 * @param pDbgMod The debug module instance. On success pvDbgPriv
951 * will point to a valid RTDBGMODCV.
952 * @param enmFileType The kind of file this is we're probing.
953 * @param hFile The file with debug info in it.
954 * @param off The offset where to expect CV debug info.
955 * @param cb The number of bytes of debug info.
956 * @param enmArch The desired image architecture.
957 * @param pszFilename The path to the file (for logging).
958 */
959static int rtDbgModCvProbeFile2(PRTDBGMODINT pThis, RTCVFILETYPE enmFileType, RTFILE hFile, uint32_t off, uint32_t cb,
960 RTLDRARCH enmArch, const char *pszFilename)
961{
962 RTCVHDR CvHdr;
963 int rc = RTFileReadAt(hFile, off, &CvHdr, sizeof(CvHdr), NULL);
964 if (RT_SUCCESS(rc))
965 rc = rtDbgModCvProbeCommon(pThis, &CvHdr, enmFileType, hFile, off, cb, enmArch, pszFilename);
966 return rc;
967}
968
969
970/**
971 * Probes an external file for CodeView information.
972 *
973 * @returns status code.
974 * @param pDbgMod The debug module instance. On success pvDbgPriv
975 * will point to a valid RTDBGMODCV.
976 * @param pszFilename The path to the file to probe.
977 * @param enmArch The desired image architecture.
978 */
979static int rtDbgModCvProbeFile(PRTDBGMODINT pDbgMod, const char *pszFilename, RTLDRARCH enmArch)
980{
981 RTFILE hFile;
982 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN);
983 if (RT_FAILURE(rc))
984 return rc;
985
986 /*
987 * Check for .DBG file
988 */
989 IMAGE_SEPARATE_DEBUG_HEADER DbgHdr;
990 rc = RTFileReadAt(hFile, 0, &DbgHdr, sizeof(DbgHdr), NULL);
991 if ( RT_SUCCESS(rc)
992 && DbgHdr.Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE)
993 {
994 Log2(("RTDbgModCv: Found separate debug header in %s:\n", pszFilename));
995 Log2((" Flags = %#x\n", DbgHdr.Flags));
996 Log2((" Machine = %#x\n", DbgHdr.Machine));
997 Log2((" Characteristics = %#x\n", DbgHdr.Characteristics));
998 Log2((" TimeDateStamp = %#x\n", DbgHdr.TimeDateStamp));
999 Log2((" CheckSum = %#x\n", DbgHdr.CheckSum));
1000 Log2((" ImageBase = %#x\n", DbgHdr.ImageBase));
1001 Log2((" SizeOfImage = %#x\n", DbgHdr.SizeOfImage));
1002 Log2((" NumberOfSections = %#x\n", DbgHdr.NumberOfSections));
1003 Log2((" ExportedNamesSize = %#x\n", DbgHdr.ExportedNamesSize));
1004 Log2((" DebugDirectorySize = %#x\n", DbgHdr.DebugDirectorySize));
1005 Log2((" SectionAlignment = %#x\n", DbgHdr.SectionAlignment));
1006
1007 /*
1008 * Match up the architecture if specified.
1009 */
1010 switch (enmArch)
1011 {
1012 case RTLDRARCH_X86_32:
1013 if (DbgHdr.Machine != IMAGE_FILE_MACHINE_I386)
1014 rc = VERR_LDR_ARCH_MISMATCH;
1015 break;
1016 case RTLDRARCH_AMD64:
1017 if (DbgHdr.Machine != IMAGE_FILE_MACHINE_AMD64)
1018 rc = VERR_LDR_ARCH_MISMATCH;
1019 break;
1020
1021 default:
1022 case RTLDRARCH_HOST:
1023 AssertFailed();
1024 case RTLDRARCH_WHATEVER:
1025 break;
1026 }
1027 if (RT_FAILURE(rc))
1028 {
1029 RTFileClose(hFile);
1030 return rc;
1031 }
1032
1033 /*
1034 * Probe for readable debug info in the debug directory.
1035 */
1036 uint32_t offDbgDir = sizeof(DbgHdr)
1037 + DbgHdr.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
1038 + DbgHdr.ExportedNamesSize;
1039
1040 uint32_t cEntries = DbgHdr.DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY);
1041 for (uint32_t i = 0; i < cEntries; i++, offDbgDir += sizeof(IMAGE_DEBUG_DIRECTORY))
1042 {
1043 IMAGE_DEBUG_DIRECTORY DbgDir;
1044 rc = RTFileReadAt(hFile, offDbgDir, &DbgDir, sizeof(DbgDir), NULL);
1045 if (RT_FAILURE(rc))
1046 break;
1047 if (DbgDir.Type == IMAGE_DEBUG_TYPE_CODEVIEW)
1048 {
1049 rc = rtDbgModCvProbeFile2(pDbgMod, RTCVFILETYPE_DBG, hFile,
1050 DbgDir.PointerToRawData, DbgDir.SizeOfData,
1051 enmArch, pszFilename);
1052 if (RT_SUCCESS(rc))
1053 {
1054 /*
1055 * Add section headers and such if necessary.
1056 */
1057 PRTDBGMODCV pThis = (PRTDBGMODCV)pDbgMod->pvDbgPriv;
1058 pThis->cbImage = DbgHdr.SizeOfImage;
1059 if (!pDbgMod->pImgVt)
1060 {
1061 rc = rtDbgModCvAddSegmentsFromDbg(pThis, &DbgHdr, pszFilename);
1062 if (RT_FAILURE(rc))
1063 rtDbgModCv_Close(pDbgMod);
1064 }
1065 return rc;
1066 }
1067 }
1068 }
1069
1070 /* Failed to find CV or smth, look at the end of the file just to be sure... */
1071 }
1072
1073 /*
1074 * Look for CV tail header.
1075 */
1076 uint64_t cbFile;
1077 rc = RTFileSeek(hFile, -(RTFOFF)sizeof(RTCVHDR), RTFILE_SEEK_END, &cbFile);
1078 if (RT_SUCCESS(rc))
1079 {
1080 cbFile += sizeof(RTCVHDR);
1081 RTCVHDR CvHdr;
1082 rc = RTFileRead(hFile, &CvHdr, sizeof(CvHdr), NULL);
1083 if (RT_SUCCESS(rc))
1084 rc = rtDbgModCvProbeFile2(pDbgMod, RTCVFILETYPE_OTHER_AT_END, hFile,
1085 cbFile - CvHdr.off, CvHdr.off, enmArch, pszFilename);
1086 }
1087
1088 if (RT_FAILURE(rc))
1089 RTFileClose(hFile);
1090 return rc;
1091}
1092
1093
1094
1095/** @interface_method_impl{RTDBGMODVTDBG,pfnTryOpen} */
1096static DECLCALLBACK(int) rtDbgModCv_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch)
1097{
1098 /*
1099 * Look for debug info.
1100 */
1101 int rc = VERR_DBG_NO_MATCHING_INTERPRETER;
1102 if (pMod->pszDbgFile)
1103 rc = rtDbgModCvProbeFile(pMod, pMod->pszDbgFile, enmArch);
1104
1105 if (!pMod->pvDbgPriv && pMod->pImgVt)
1106 {
1107 int rc2 = pMod->pImgVt->pfnEnumDbgInfo(pMod, rtDbgModCvEnumCallback, pMod);
1108 if (RT_FAILURE(rc2))
1109 rc = rc2;
1110
1111 if (!pMod->pvDbgPriv)
1112 {
1113 /* Try the executable in case it has a NBxx tail header. */
1114 rc2 = rtDbgModCvProbeFile(pMod, pMod->pszImgFile, enmArch);
1115 if (RT_FAILURE(rc2) && (RT_SUCCESS(rc) || VERR_DBG_NO_MATCHING_INTERPRETER))
1116 rc = rc2;
1117 }
1118 }
1119
1120 PRTDBGMODCV pThis = (PRTDBGMODCV)pMod->pvDbgPriv;
1121 if (!pThis)
1122 return RT_SUCCESS_NP(rc) ? VERR_DBG_NO_MATCHING_INTERPRETER : rc;
1123
1124 /*
1125 * Load the debug info.
1126 */
1127 if (pMod->pImgVt)
1128 {
1129 rc = pMod->pImgVt->pfnEnumSegments(pMod, rtDbgModCvAddSegmentsCallback, pThis);
1130 pThis->fHaveLoadedSegments = true;
1131 }
1132 if (RT_SUCCESS(rc))
1133 rc = rtDbgModCvLoadInfo(pThis);
1134 if (RT_SUCCESS(rc))
1135 {
1136 Log(("RTDbgCv: Successfully loaded debug info\n"));
1137 return VINF_SUCCESS;
1138 }
1139
1140 Log(("RTDbgCv: Debug info load error %Rrc\n", rc));
1141 rtDbgModCv_Close(pMod);
1142 return rc;
1143}
1144
1145
1146
1147
1148
1149/** Virtual function table for the CodeView debug info reader. */
1150DECL_HIDDEN_CONST(RTDBGMODVTDBG) const g_rtDbgModVtDbgCodeView =
1151{
1152 /*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
1153 /*.fSupports = */ RT_DBGTYPE_CODEVIEW,
1154 /*.pszName = */ "codeview",
1155 /*.pfnTryOpen = */ rtDbgModCv_TryOpen,
1156 /*.pfnClose = */ rtDbgModCv_Close,
1157
1158 /*.pfnRvaToSegOff = */ rtDbgModCv_RvaToSegOff,
1159 /*.pfnImageSize = */ rtDbgModCv_ImageSize,
1160
1161 /*.pfnSegmentAdd = */ rtDbgModCv_SegmentAdd,
1162 /*.pfnSegmentCount = */ rtDbgModCv_SegmentCount,
1163 /*.pfnSegmentByIndex = */ rtDbgModCv_SegmentByIndex,
1164
1165 /*.pfnSymbolAdd = */ rtDbgModCv_SymbolAdd,
1166 /*.pfnSymbolCount = */ rtDbgModCv_SymbolCount,
1167 /*.pfnSymbolByOrdinal = */ rtDbgModCv_SymbolByOrdinal,
1168 /*.pfnSymbolByName = */ rtDbgModCv_SymbolByName,
1169 /*.pfnSymbolByAddr = */ rtDbgModCv_SymbolByAddr,
1170
1171 /*.pfnLineAdd = */ rtDbgModCv_LineAdd,
1172 /*.pfnLineCount = */ rtDbgModCv_LineCount,
1173 /*.pfnLineByOrdinal = */ rtDbgModCv_LineByOrdinal,
1174 /*.pfnLineByAddr = */ rtDbgModCv_LineByAddr,
1175
1176 /*.u32EndMagic = */ RTDBGMODVTDBG_MAGIC
1177};
1178
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