VirtualBox

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

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

IPRT/rtDbgModCvLoadDirectory: Added note about what seems to be wlink trashing the directory header. I think I've wasted time debugging this once before, hope the comments will prevent a 3rd time. :-)

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