VirtualBox

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

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

rtDbgModCvLoadDirectory: Sort the directory the way we like it, stop being uptight about how it is sorted by the linker or debug info packer.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette