VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

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