VirtualBox

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

Last change on this file since 59037 was 58742, checked in by vboxsync, 9 years ago

Various: Use our pecoff.h and mz.h instead of the internal IPRT headers.

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