VirtualBox

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

Last change on this file since 74981 was 74981, checked in by vboxsync, 6 years ago

IPRT/Dbg: Made the codeview debug info parser prefer symbols with sizes. This helps MakeAlternativeSource avoiding jump tables.

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