VirtualBox

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

Last change on this file since 100931 was 100931, checked in by vboxsync, 16 months ago

IPRT/dbg: Early PDB support.

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