VirtualBox

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

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

dbgmodcodeview.cpp: Fix typo in a comment. dabbrev-expand is very
good at cloning those.

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