VirtualBox

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

Last change on this file since 60798 was 60798, checked in by vboxsync, 9 years ago

dbgmodcodeview.cpp: fixed assertion in rtDbgModCvAddSanitizedStringToCache,

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