VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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