1 | /* $Id: dbgmodmapsym.cpp 100931 2023-08-21 23:11:01Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * IPRT - Debug Map Reader for MAPSYM files (used by SYMDBG from old MASM).
|
---|
4 | *
|
---|
5 | * MAPSYM is was the tool producing these files from linker map files for
|
---|
6 | * use with SYMDBG (which shipped with MASM 3.0 (possibly earlier)), the OS/2
|
---|
7 | * kernel debugger, and other tools. The format is very limited and they had
|
---|
8 | * to strip down the os2krnl.map file in later years to keep MAPSYM happy.
|
---|
9 | */
|
---|
10 |
|
---|
11 | /*
|
---|
12 | * Copyright (C) 2009-2023 Oracle and/or its affiliates.
|
---|
13 | *
|
---|
14 | * This file is part of VirtualBox base platform packages, as
|
---|
15 | * available from https://www.virtualbox.org.
|
---|
16 | *
|
---|
17 | * This program is free software; you can redistribute it and/or
|
---|
18 | * modify it under the terms of the GNU General Public License
|
---|
19 | * as published by the Free Software Foundation, in version 3 of the
|
---|
20 | * License.
|
---|
21 | *
|
---|
22 | * This program is distributed in the hope that it will be useful, but
|
---|
23 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
25 | * General Public License for more details.
|
---|
26 | *
|
---|
27 | * You should have received a copy of the GNU General Public License
|
---|
28 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
29 | *
|
---|
30 | * The contents of this file may alternatively be used under the terms
|
---|
31 | * of the Common Development and Distribution License Version 1.0
|
---|
32 | * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
|
---|
33 | * in the VirtualBox distribution, in which case the provisions of the
|
---|
34 | * CDDL are applicable instead of those of the GPL.
|
---|
35 | *
|
---|
36 | * You may elect to license modified versions of this file under the
|
---|
37 | * terms and conditions of either the GPL or the CDDL or both.
|
---|
38 | *
|
---|
39 | * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
|
---|
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/err.h>
|
---|
51 | #include <iprt/ctype.h>
|
---|
52 | #include <iprt/file.h>
|
---|
53 | #include <iprt/log.h>
|
---|
54 | #include <iprt/mem.h>
|
---|
55 | #include <iprt/stream.h>
|
---|
56 | #include <iprt/string.h>
|
---|
57 | #include "internal/dbgmod.h"
|
---|
58 |
|
---|
59 |
|
---|
60 | /*********************************************************************************************************************************
|
---|
61 | * Structures and Typedefs *
|
---|
62 | *********************************************************************************************************************************/
|
---|
63 | /** @name MAPSYM structures and constants.
|
---|
64 | * @{ */
|
---|
65 |
|
---|
66 | /** MAPSYM: Header structure. */
|
---|
67 | typedef struct MAPSYMHDR
|
---|
68 | {
|
---|
69 | uint16_t off16NextMap; /**< 0x00: Offset of the next map divided by 16. */
|
---|
70 | uint8_t bFlags; /**< 0x02: Who really knows... */
|
---|
71 | uint8_t bReserved; /**< 0x03: Reserved / unknown. */
|
---|
72 | uint16_t uSegEntry; /**< 0x04: Some entrypoint/segment thing we don't care about. */
|
---|
73 | uint16_t cConsts; /**< 0x06: Constants referenced by offConstDef. */
|
---|
74 | uint16_t offConstDef; /**< 0x08: Offset to head of constant chain. Not div 16? */
|
---|
75 | uint16_t cSegs; /**< 0x0a: Number of segments in the map. */
|
---|
76 | uint16_t off16SegDef; /**< 0x0c: Offset of the segment defintions divided by 16. */
|
---|
77 | uint8_t cchMaxSym; /**< 0x0e: Maximum symbol-name length. */
|
---|
78 | uint8_t cchModule; /**< 0x0f: Length of the module name. */
|
---|
79 | RT_FLEXIBLE_ARRAY_EXTENSION
|
---|
80 | char achModule[RT_FLEXIBLE_ARRAY]; /**< 0x10: Module name, length given by cchModule. */
|
---|
81 | } MAPSYMHDR;
|
---|
82 |
|
---|
83 | /** MAPSYM: Tail structure. */
|
---|
84 | typedef struct MAPSYMTAIL
|
---|
85 | {
|
---|
86 | uint16_t offNextMap; /**< 0x00: Always zero (it's the tail, see). */
|
---|
87 | uint8_t bRelease; /**< 0x02: Minor version number. */
|
---|
88 | uint8_t bVersion; /**< 0x03: Major version number. */
|
---|
89 | } MAPSYMTAIL;
|
---|
90 |
|
---|
91 | /** MAPSYM: Segment defintion. */
|
---|
92 | typedef struct MAPSYMSEGDEF
|
---|
93 | {
|
---|
94 | uint16_t off16NextSeg; /**< 0x00: Offset of the next segment divided by 16. */
|
---|
95 | uint16_t cSymbols; /**< 0x02: Number of symbol offsets . */
|
---|
96 | uint16_t offSymbolOffsets; /**< 0x04: Offset of the symbol offset table. Each entry is a 16-bit value giving
|
---|
97 | * the offset symbol relative to this structure. */
|
---|
98 | uint16_t au16Reserved0[4]; /**< 0x06: Reserved / unknown.
|
---|
99 | * First byte/word seems to be 1-based segment number. */
|
---|
100 | uint8_t bFlags; /**< 0x0e: MAPSYMSEGDEF_F_32BIT or zero. */
|
---|
101 | uint8_t bReserved1; /**< 0x0f: Reserved / unknown. */
|
---|
102 | uint16_t offLineDef; /**< 0x10: Offset to the line defintions. */
|
---|
103 | uint16_t u16Reserved2; /**< 0x12: Reserved / unknown. Often seen holding 0xff00. */
|
---|
104 | uint8_t cchSegName; /**< 0x14: Segment name length. */
|
---|
105 | RT_FLEXIBLE_ARRAY_EXTENSION
|
---|
106 | char achSegName[RT_FLEXIBLE_ARRAY]; /**< 0x15: Segment name, length given by cchSegName. */
|
---|
107 | } MAPSYMSEGDEF;
|
---|
108 |
|
---|
109 | #define MAPSYMSEGDEF_F_32BIT UINT8_C(0x01) /**< Indicates 32-bit segment rather than 16-bit, relevant for symbols. */
|
---|
110 | #define MAPSYMSEGDEF_F_UNKNOWN UINT8_C(0x02) /**< Set on all segments in os2krnlr.sym from ACP2. */
|
---|
111 |
|
---|
112 | /** MAPSYM: 16-bit symbol */
|
---|
113 | typedef struct MAPSYMSYMDEF16
|
---|
114 | {
|
---|
115 | uint16_t uValue; /**< 0x00: The symbol value (address). */
|
---|
116 | uint8_t cchName; /**< 0x02: Symbol name length. */
|
---|
117 | char achName[1]; /**< 0x03: The symbol name, length give by cchName. */
|
---|
118 | } MAPSYMSYMDEF16;
|
---|
119 |
|
---|
120 | /** MAPSYM: 16-bit symbol */
|
---|
121 | typedef struct MAPSYMSYMDEF32
|
---|
122 | {
|
---|
123 | uint32_t uValue; /**< 0x00: The symbol value (address). */
|
---|
124 | uint8_t cchName; /**< 0x04: Symbol name length. */
|
---|
125 | char achName[1]; /**< 0x05: The symbol name, length give by cchName. */
|
---|
126 | } MAPSYMSYMDEF32;
|
---|
127 |
|
---|
128 | /** MAPSYM: Line number defintions. */
|
---|
129 | typedef struct MAPSYMLINEDEF
|
---|
130 | {
|
---|
131 | uint16_t off16NextLine; /**< 0x00: Offset to the next line defintion divided by 16. */
|
---|
132 | uint16_t uSegment; /**< 0x02: Guessing this must be segment number. */
|
---|
133 | uint16_t offLines; /**< 0x04: Offset to the line number array, relative to this structure. */
|
---|
134 | uint16_t cLines; /**< 0x08: Number of line numbers in the array. */
|
---|
135 | uint8_t cchSrcFile; /**< 0x0a: Length of source filename. */
|
---|
136 | RT_FLEXIBLE_ARRAY_EXTENSION
|
---|
137 | char achSrcFile[RT_FLEXIBLE_ARRAY]; /**< 0x0b: Source filename, length given by cchSrcFile. */
|
---|
138 | } MAPSYMLINEDEF;
|
---|
139 |
|
---|
140 | /** MAPSYM: 16-bit line numbers. */
|
---|
141 | typedef struct MAPSYMLINENO16
|
---|
142 | {
|
---|
143 | uint16_t offSeg;
|
---|
144 | uint16_t uLineNo;
|
---|
145 | } MAPSYMLINENO16;
|
---|
146 |
|
---|
147 | /** @} */
|
---|
148 |
|
---|
149 |
|
---|
150 | /*********************************************************************************************************************************
|
---|
151 | * Defined Constants And Macros *
|
---|
152 | *********************************************************************************************************************************/
|
---|
153 | /** Maximum number of segments we expect in a MAPSYM file. */
|
---|
154 | #define RTDBGMODMAPSYM_MAX_SEGMENTS 256
|
---|
155 |
|
---|
156 |
|
---|
157 |
|
---|
158 | /** @interface_method_impl{RTDBGMODVTDBG,pfnUnwindFrame} */
|
---|
159 | static DECLCALLBACK(int) rtDbgModMapSym_UnwindFrame(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTDBGUNWINDSTATE pState)
|
---|
160 | {
|
---|
161 | RT_NOREF(pMod, iSeg, off, pState);
|
---|
162 | return VERR_DBG_NO_UNWIND_INFO;
|
---|
163 | }
|
---|
164 |
|
---|
165 |
|
---|
166 | /** @interface_method_impl{RTDBGMODVTDBG,pfnLineByAddr} */
|
---|
167 | static DECLCALLBACK(int) rtDbgModMapSym_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
|
---|
168 | PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
|
---|
169 | {
|
---|
170 | RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
|
---|
171 | return RTDbgModLineByAddr(hCnt, iSeg, off, poffDisp, pLineInfo);
|
---|
172 | }
|
---|
173 |
|
---|
174 |
|
---|
175 | /** @interface_method_impl{RTDBGMODVTDBG,pfnLineByOrdinal} */
|
---|
176 | static DECLCALLBACK(int) rtDbgModMapSym_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
|
---|
177 | {
|
---|
178 | RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
|
---|
179 | return RTDbgModLineByOrdinal(hCnt, iOrdinal, pLineInfo);
|
---|
180 | }
|
---|
181 |
|
---|
182 |
|
---|
183 | /** @interface_method_impl{RTDBGMODVTDBG,pfnLineCount} */
|
---|
184 | static DECLCALLBACK(uint32_t) rtDbgModMapSym_LineCount(PRTDBGMODINT pMod)
|
---|
185 | {
|
---|
186 | RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
|
---|
187 | return RTDbgModLineCount(hCnt);
|
---|
188 | }
|
---|
189 |
|
---|
190 |
|
---|
191 | /** @interface_method_impl{RTDBGMODVTDBG,pfnLineAdd} */
|
---|
192 | static DECLCALLBACK(int) rtDbgModMapSym_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
|
---|
193 | uint32_t iSeg, RTUINTPTR off, uint32_t *piOrdinal)
|
---|
194 | {
|
---|
195 | RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
|
---|
196 | Assert(!pszFile[cchFile]); NOREF(cchFile);
|
---|
197 | return RTDbgModLineAdd(hCnt, pszFile, uLineNo, iSeg, off, piOrdinal);
|
---|
198 | }
|
---|
199 |
|
---|
200 |
|
---|
201 | /** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByAddr} */
|
---|
202 | static DECLCALLBACK(int) rtDbgModMapSym_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
|
---|
203 | PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
|
---|
204 | {
|
---|
205 | RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
|
---|
206 | return RTDbgModSymbolByAddr(hCnt, iSeg, off, fFlags, poffDisp, pSymInfo);
|
---|
207 | }
|
---|
208 |
|
---|
209 |
|
---|
210 | /** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByName} */
|
---|
211 | static DECLCALLBACK(int) rtDbgModMapSym_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
|
---|
212 | PRTDBGSYMBOL pSymInfo)
|
---|
213 | {
|
---|
214 | RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
|
---|
215 | Assert(!pszSymbol[cchSymbol]); NOREF(cchSymbol);
|
---|
216 | return RTDbgModSymbolByName(hCnt, pszSymbol, pSymInfo);
|
---|
217 | }
|
---|
218 |
|
---|
219 |
|
---|
220 | /** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByOrdinal} */
|
---|
221 | static DECLCALLBACK(int) rtDbgModMapSym_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
|
---|
222 | {
|
---|
223 | RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
|
---|
224 | return RTDbgModSymbolByOrdinal(hCnt, iOrdinal, pSymInfo);
|
---|
225 | }
|
---|
226 |
|
---|
227 |
|
---|
228 | /** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolCount} */
|
---|
229 | static DECLCALLBACK(uint32_t) rtDbgModMapSym_SymbolCount(PRTDBGMODINT pMod)
|
---|
230 | {
|
---|
231 | RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
|
---|
232 | return RTDbgModSymbolCount(hCnt);
|
---|
233 | }
|
---|
234 |
|
---|
235 |
|
---|
236 | /** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolAdd} */
|
---|
237 | static DECLCALLBACK(int) rtDbgModMapSym_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
|
---|
238 | RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags,
|
---|
239 | uint32_t *piOrdinal)
|
---|
240 | {
|
---|
241 | RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
|
---|
242 | Assert(!pszSymbol[cchSymbol]); NOREF(cchSymbol);
|
---|
243 | return RTDbgModSymbolAdd(hCnt, pszSymbol, iSeg, off, cb, fFlags, piOrdinal);
|
---|
244 | }
|
---|
245 |
|
---|
246 |
|
---|
247 | /** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentByIndex} */
|
---|
248 | static DECLCALLBACK(int) rtDbgModMapSym_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
|
---|
249 | {
|
---|
250 | RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
|
---|
251 | return RTDbgModSegmentByIndex(hCnt, iSeg, pSegInfo);
|
---|
252 | }
|
---|
253 |
|
---|
254 |
|
---|
255 | /** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentCount} */
|
---|
256 | static DECLCALLBACK(RTDBGSEGIDX) rtDbgModMapSym_SegmentCount(PRTDBGMODINT pMod)
|
---|
257 | {
|
---|
258 | RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
|
---|
259 | return RTDbgModSegmentCount(hCnt);
|
---|
260 | }
|
---|
261 |
|
---|
262 |
|
---|
263 | /** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentAdd} */
|
---|
264 | static DECLCALLBACK(int) rtDbgModMapSym_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName,
|
---|
265 | size_t cchName, uint32_t fFlags, PRTDBGSEGIDX piSeg)
|
---|
266 | {
|
---|
267 | RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
|
---|
268 | Assert(!pszName[cchName]); NOREF(cchName);
|
---|
269 | return RTDbgModSegmentAdd(hCnt, uRva, cb, pszName, fFlags, piSeg);
|
---|
270 | }
|
---|
271 |
|
---|
272 |
|
---|
273 | /** @interface_method_impl{RTDBGMODVTDBG,pfnImageSize} */
|
---|
274 | static DECLCALLBACK(RTUINTPTR) rtDbgModMapSym_ImageSize(PRTDBGMODINT pMod)
|
---|
275 | {
|
---|
276 | RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
|
---|
277 | return RTDbgModImageSize(hCnt);
|
---|
278 | }
|
---|
279 |
|
---|
280 |
|
---|
281 | /** @interface_method_impl{RTDBGMODVTDBG,pfnRvaToSegOff} */
|
---|
282 | static DECLCALLBACK(RTDBGSEGIDX) rtDbgModMapSym_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
|
---|
283 | {
|
---|
284 | RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
|
---|
285 | return RTDbgModRvaToSegOff(hCnt, uRva, poffSeg);
|
---|
286 | }
|
---|
287 |
|
---|
288 |
|
---|
289 | /** @interface_method_impl{RTDBGMODVTDBG,pfnClose} */
|
---|
290 | static DECLCALLBACK(int) rtDbgModMapSym_Close(PRTDBGMODINT pMod)
|
---|
291 | {
|
---|
292 | RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
|
---|
293 | RTDbgModRelease(hCnt);
|
---|
294 | pMod->pvDbgPriv = NULL;
|
---|
295 | return VINF_SUCCESS;
|
---|
296 | }
|
---|
297 |
|
---|
298 |
|
---|
299 | /**
|
---|
300 | * Validate the module header.
|
---|
301 | *
|
---|
302 | * @returns true if valid, false if not.
|
---|
303 | * @param pHdr The header.
|
---|
304 | * @param cbAvail How much we've actually read.
|
---|
305 | * @param cbFile The file size (relative to module header).
|
---|
306 | */
|
---|
307 | static bool rtDbgModMapSymIsValidHeader(MAPSYMHDR const *pHdr, size_t cbAvail, uint64_t cbFile)
|
---|
308 | {
|
---|
309 | if (cbAvail <= RT_UOFFSETOF(MAPSYMHDR, achModule))
|
---|
310 | return false;
|
---|
311 |
|
---|
312 | if (pHdr->cSegs == 0)
|
---|
313 | return false;
|
---|
314 | if (pHdr->cSegs > RTDBGMODMAPSYM_MAX_SEGMENTS)
|
---|
315 | return false;
|
---|
316 |
|
---|
317 | if (pHdr->off16SegDef == 0)
|
---|
318 | return false;
|
---|
319 | if (pHdr->off16SegDef * (uint32_t)16 >= cbFile)
|
---|
320 | return false;
|
---|
321 |
|
---|
322 | if (pHdr->cchModule == 0)
|
---|
323 | return false;
|
---|
324 | if (pHdr->cchModule > 128) /* Note must be smaller than abPadding below in caller */
|
---|
325 | return false;
|
---|
326 |
|
---|
327 | size_t cchMaxName = cbAvail - RT_UOFFSETOF(MAPSYMHDR, achModule);
|
---|
328 | if (pHdr->cchModule > cchMaxName)
|
---|
329 | return false;
|
---|
330 |
|
---|
331 | for (uint32_t i = 0; i < pHdr->cchModule; i++)
|
---|
332 | {
|
---|
333 | unsigned char const uch = pHdr->achModule[i];
|
---|
334 | if ( uch < 0x20
|
---|
335 | || uch >= 0x7f)
|
---|
336 | return false;
|
---|
337 | }
|
---|
338 |
|
---|
339 | return true;
|
---|
340 | }
|
---|
341 |
|
---|
342 |
|
---|
343 | /**
|
---|
344 | * Validate the given segment definition.
|
---|
345 | *
|
---|
346 | * @returns true if valid, false if not.
|
---|
347 | * @param pSegDef The segment definition structure.
|
---|
348 | * @param cbMax Host many bytes are available starting with pSegDef.
|
---|
349 | */
|
---|
350 | static bool rtDbgModMapSymIsValidSegDef(MAPSYMSEGDEF const *pSegDef, size_t cbMax)
|
---|
351 | {
|
---|
352 | if (RT_UOFFSETOF(MAPSYMSEGDEF, achSegName) > cbMax)
|
---|
353 | return false;
|
---|
354 | if (pSegDef->cSymbols)
|
---|
355 | {
|
---|
356 | if (pSegDef->cSymbols > _32K)
|
---|
357 | {
|
---|
358 | Log(("rtDbgModMapSymIsValidSegDef: Too many symbols: %#x\n", pSegDef->cSymbols));
|
---|
359 | return false;
|
---|
360 | }
|
---|
361 |
|
---|
362 | if (pSegDef->offSymbolOffsets + (uint32_t)2 * pSegDef->cSymbols > cbMax)
|
---|
363 | {
|
---|
364 | Log(("rtDbgModMapSymIsValidSegDef: Bad symbol offset/count: %#x/%#x\n", pSegDef->offSymbolOffsets, pSegDef->cSymbols));
|
---|
365 | return false;
|
---|
366 | }
|
---|
367 | }
|
---|
368 |
|
---|
369 | size_t cchMaxName = cbMax - RT_UOFFSETOF(MAPSYMHDR, achModule);
|
---|
370 | if (pSegDef->cchSegName > cchMaxName)
|
---|
371 | {
|
---|
372 | Log(("rtDbgModMapSymIsValidSegDef: Bad segment name length\n"));
|
---|
373 | return false;
|
---|
374 | }
|
---|
375 |
|
---|
376 | for (uint32_t i = 0; i < pSegDef->cchSegName; i++)
|
---|
377 | {
|
---|
378 | unsigned char uch = pSegDef->achSegName[i];
|
---|
379 | if ( uch < 0x20
|
---|
380 | || uch >= 0x7f)
|
---|
381 | {
|
---|
382 | Log(("rtDbgModMapSymIsValidSegDef: Bad segment name: %.*Rhxs\n", pSegDef->cchSegName, pSegDef->achSegName));
|
---|
383 | return false;
|
---|
384 | }
|
---|
385 | }
|
---|
386 |
|
---|
387 | return true;
|
---|
388 | }
|
---|
389 |
|
---|
390 |
|
---|
391 | /**
|
---|
392 | * Fills @a hCnt with segments and symbols from the MAPSYM file.
|
---|
393 | *
|
---|
394 | * @note We only support reading the first module, right now.
|
---|
395 | */
|
---|
396 | static int rtDbgModMapSymReadIt(RTDBGMOD hCnt, uint8_t const *pbFile, size_t cbFile)
|
---|
397 | {
|
---|
398 | /*
|
---|
399 | * Revalidate the header.
|
---|
400 | */
|
---|
401 | MAPSYMHDR const *pHdr = (MAPSYMHDR const *)pbFile;
|
---|
402 | if (!rtDbgModMapSymIsValidHeader(pHdr, cbFile, cbFile))
|
---|
403 | return VERR_DBG_NO_MATCHING_INTERPRETER;
|
---|
404 | Log(("rtDbgModMapSymReadIt: szModule='%.*s' cSegs=%u off16NextMap=%#x\n",
|
---|
405 | pHdr->cchModule, pHdr->achModule, pHdr->cSegs, pHdr->off16NextMap));
|
---|
406 |
|
---|
407 | /*
|
---|
408 | * Load each segment.
|
---|
409 | */
|
---|
410 | uint32_t uRva = 0;
|
---|
411 | uint32_t const cSegs = pHdr->cSegs;
|
---|
412 | uint32_t offSegment = pHdr->off16SegDef * (uint32_t)16;
|
---|
413 | for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
|
---|
414 | {
|
---|
415 | if (offSegment >= cbFile)
|
---|
416 | return VERR_DBG_NO_MATCHING_INTERPRETER;
|
---|
417 |
|
---|
418 | size_t const cbMax = cbFile - offSegment;
|
---|
419 | MAPSYMSEGDEF const *pSegDef = (MAPSYMSEGDEF const *)&pbFile[offSegment];
|
---|
420 | if (!rtDbgModMapSymIsValidSegDef(pSegDef, cbMax))
|
---|
421 | return VERR_DBG_NO_MATCHING_INTERPRETER;
|
---|
422 |
|
---|
423 | Log(("rtDbgModMapSymReadIt: Segment #%u: flags=%#x name='%.*s' symbols=%#x @ %#x next=%#x lines=@%#x (reserved: %#x %#x %#x %#x %#x %#x)\n",
|
---|
424 | iSeg, pSegDef->bFlags, pSegDef->cchSegName, pSegDef->achSegName, pSegDef->cSymbols, pSegDef->offSymbolOffsets,
|
---|
425 | pSegDef->off16NextSeg, pSegDef->offLineDef, pSegDef->au16Reserved0[0], pSegDef->au16Reserved0[1],
|
---|
426 | pSegDef->au16Reserved0[2], pSegDef->au16Reserved0[3], pSegDef->bReserved1, pSegDef->u16Reserved2));
|
---|
427 |
|
---|
428 | /*
|
---|
429 | * First symbol pass finds the largest symbol and uses that as the segment size.
|
---|
430 | */
|
---|
431 | uint32_t cbSegmentEst = 0;
|
---|
432 | uint32_t const cSymbols = pSegDef->cSymbols;
|
---|
433 | uint16_t const * const paoffSymbols = (uint16_t const *)&pbFile[offSegment + pSegDef->offSymbolOffsets];
|
---|
434 | bool const fIs32Bit = RT_BOOL(pSegDef->bFlags & MAPSYMSEGDEF_F_32BIT);
|
---|
435 | uint32_t const cbSymDef = fIs32Bit ? 4 + 1 : 2 + 1;
|
---|
436 | for (uint32_t iSymbol = 0; iSymbol < cSymbols; iSymbol++)
|
---|
437 | {
|
---|
438 | uint32_t off = paoffSymbols[iSymbol] + offSegment;
|
---|
439 | if (off + cbSymDef <= cbFile)
|
---|
440 | {
|
---|
441 | uint32_t uValue = fIs32Bit ? *(uint32_t const *)&pbFile[off] : (uint32_t)*(uint16_t const *)&pbFile[off];
|
---|
442 | if (uValue > cbSegmentEst)
|
---|
443 | cbSegmentEst = uValue;
|
---|
444 | }
|
---|
445 | else
|
---|
446 | Log(("rtDbgModMapSymReadIt: Bad symbol offset %#x\n", off));
|
---|
447 | }
|
---|
448 |
|
---|
449 | /*
|
---|
450 | * Add the segment.
|
---|
451 | */
|
---|
452 | char szName[256];
|
---|
453 | memcpy(szName, pSegDef->achSegName, pSegDef->cchSegName);
|
---|
454 | szName[pSegDef->cchSegName] = '\0';
|
---|
455 | if (!pSegDef->cchSegName)
|
---|
456 | RTStrPrintf(szName, sizeof(szName), "seg%02u", iSeg);
|
---|
457 |
|
---|
458 | RTDBGSEGIDX idxDbgSeg = iSeg;
|
---|
459 | int rc = RTDbgModSegmentAdd(hCnt, uRva, cbSegmentEst, szName, 0 /*fFlags*/, &idxDbgSeg);
|
---|
460 | if (RT_FAILURE(rc))
|
---|
461 | return rc;
|
---|
462 |
|
---|
463 | uRva += cbSegmentEst;
|
---|
464 |
|
---|
465 | /*
|
---|
466 | * The second symbol pass loads the symbol values and names.
|
---|
467 | */
|
---|
468 | for (uint32_t iSymbol = 0; iSymbol < cSymbols; iSymbol++)
|
---|
469 | {
|
---|
470 | uint32_t off = paoffSymbols[iSymbol] + offSegment;
|
---|
471 | if (off + cbSymDef <= cbFile)
|
---|
472 | {
|
---|
473 | /* Get value: */
|
---|
474 | uint32_t uValue = RT_MAKE_U16(pbFile[off], pbFile[off + 1]);
|
---|
475 | off += 2;
|
---|
476 | if (fIs32Bit)
|
---|
477 | {
|
---|
478 | uValue |= RT_MAKE_U32_FROM_U8(0, 0, pbFile[off], pbFile[off + 1]);
|
---|
479 | off += 2;
|
---|
480 | }
|
---|
481 |
|
---|
482 | /* Get name: */
|
---|
483 | uint8_t cchName = pbFile[off++];
|
---|
484 | if (off + cchName <= cbFile)
|
---|
485 | {
|
---|
486 | memcpy(szName, &pbFile[off], cchName);
|
---|
487 | szName[cchName] = '\0';
|
---|
488 | RTStrPurgeEncoding(szName);
|
---|
489 | }
|
---|
490 | else
|
---|
491 | cchName = 0;
|
---|
492 | if (cchName == 0)
|
---|
493 | RTStrPrintf(szName, sizeof(szName), "unknown_%u_%u", iSeg, iSymbol);
|
---|
494 |
|
---|
495 | /* Try add it: */
|
---|
496 | rc = RTDbgModSymbolAdd(hCnt, szName, idxDbgSeg, uValue, 0 /*cb*/, 0 /*fFlags*/, NULL /*piOrdinal*/);
|
---|
497 | if (RT_SUCCESS(rc))
|
---|
498 | Log7(("rtDbgModMapSymReadIt: %02x:%06x %s\n", idxDbgSeg, uValue, szName));
|
---|
499 | else if ( rc == VERR_DBG_DUPLICATE_SYMBOL
|
---|
500 | || rc == VERR_DBG_ADDRESS_CONFLICT
|
---|
501 | || rc == VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE)
|
---|
502 | Log(("rtDbgModMapSymReadIt: %02x:%06x %s\n", idxDbgSeg, uValue, szName));
|
---|
503 | else
|
---|
504 | {
|
---|
505 | Log(("rtDbgModMapSymReadIt: Unexpected RTDbgModSymbolAdd failure: %Rrc - %02x:%06x %s\n",
|
---|
506 | rc, idxDbgSeg, uValue, szName));
|
---|
507 | return rc;
|
---|
508 | }
|
---|
509 | }
|
---|
510 | }
|
---|
511 |
|
---|
512 | /* Next segment */
|
---|
513 | offSegment = pSegDef->off16NextSeg * (uint32_t)16;
|
---|
514 | }
|
---|
515 | return VINF_SUCCESS;
|
---|
516 | }
|
---|
517 |
|
---|
518 |
|
---|
519 | /** @interface_method_impl{RTDBGMODVTDBG,pfnTryOpen} */
|
---|
520 | static DECLCALLBACK(int) rtDbgModMapSym_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch, RTDBGCFG hDbgCfg)
|
---|
521 | {
|
---|
522 | NOREF(enmArch); RT_NOREF_PV(hDbgCfg);
|
---|
523 |
|
---|
524 | /*
|
---|
525 | * Fend off images.
|
---|
526 | */
|
---|
527 | if ( !pMod->pszDbgFile
|
---|
528 | || pMod->pImgVt)
|
---|
529 | return VERR_DBG_NO_MATCHING_INTERPRETER;
|
---|
530 | pMod->pvDbgPriv = NULL;
|
---|
531 |
|
---|
532 | /*
|
---|
533 | * Try open the file and check out the first header.
|
---|
534 | */
|
---|
535 | RTFILE hFile;
|
---|
536 | int rc = RTFileOpen(&hFile, pMod->pszDbgFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
|
---|
537 | if (RT_SUCCESS(rc))
|
---|
538 | {
|
---|
539 | uint64_t cbFile = 0;
|
---|
540 | rc = RTFileQuerySize(hFile, &cbFile);
|
---|
541 | if ( RT_SUCCESS(rc)
|
---|
542 | && cbFile < _2M)
|
---|
543 | {
|
---|
544 | union
|
---|
545 | {
|
---|
546 | MAPSYMHDR Hdr;
|
---|
547 | char abPadding[sizeof(MAPSYMHDR) + 257]; /* rtDbgModMapSymIsValidHeader makes size assumptions. */
|
---|
548 | } uBuf;
|
---|
549 | size_t cbToRead = (size_t)RT_MIN(cbFile, sizeof(uBuf));
|
---|
550 | rc = RTFileReadAt(hFile, 0, &uBuf, RT_MIN(cbFile, sizeof(uBuf)), NULL);
|
---|
551 | if (RT_SUCCESS(rc))
|
---|
552 | {
|
---|
553 | if (rtDbgModMapSymIsValidHeader(&uBuf.Hdr, cbToRead, cbFile))
|
---|
554 | {
|
---|
555 | uBuf.Hdr.achModule[uBuf.Hdr.cchModule] = '\0';
|
---|
556 |
|
---|
557 | /*
|
---|
558 | * Read the whole thing into memory, create an
|
---|
559 | * instance/container and load it with symbols.
|
---|
560 | */
|
---|
561 | void *pvFile = NULL;
|
---|
562 | size_t cbFile2 = 0;
|
---|
563 | rc = RTFileReadAllByHandle(hFile, &pvFile, &cbFile2);
|
---|
564 | if (RT_SUCCESS(rc))
|
---|
565 | {
|
---|
566 | RTDBGMOD hCnt;
|
---|
567 | rc = RTDbgModCreate(&hCnt, uBuf.Hdr.achModule, 0 /*cbSeg*/, 0 /*fFlags*/);
|
---|
568 | if (RT_SUCCESS(rc))
|
---|
569 | {
|
---|
570 | rc = rtDbgModMapSymReadIt(hCnt, (uint8_t const *)pvFile, cbFile2);
|
---|
571 | if (RT_SUCCESS(rc))
|
---|
572 | pMod->pvDbgPriv = hCnt;
|
---|
573 | else
|
---|
574 | RTDbgModRelease(hCnt);
|
---|
575 | }
|
---|
576 | RTFileReadAllFree(pvFile, cbFile2);
|
---|
577 | }
|
---|
578 | }
|
---|
579 | else
|
---|
580 | rc = VERR_DBG_NO_MATCHING_INTERPRETER;
|
---|
581 | }
|
---|
582 | }
|
---|
583 | else
|
---|
584 | rc = VERR_DBG_NO_MATCHING_INTERPRETER;
|
---|
585 | RTFileClose(hFile);
|
---|
586 | }
|
---|
587 | Log(("rtDbgModMapSym_TryOpen: %s -> %Rrc, %p\n", pMod->pszDbgFile, rc, pMod->pvDbgPriv));
|
---|
588 | return rc;
|
---|
589 | }
|
---|
590 |
|
---|
591 |
|
---|
592 |
|
---|
593 | /** Virtual function table for the MAPSYM file reader. */
|
---|
594 | DECL_HIDDEN_CONST(RTDBGMODVTDBG) const g_rtDbgModVtDbgMapSym =
|
---|
595 | {
|
---|
596 | /*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
|
---|
597 | /*.fSupports = */ RT_DBGTYPE_SYM,
|
---|
598 | /*.pszName = */ "mapsym",
|
---|
599 | /*.pfnTryOpen = */ rtDbgModMapSym_TryOpen,
|
---|
600 | /*.pfnClose = */ rtDbgModMapSym_Close,
|
---|
601 |
|
---|
602 | /*.pfnRvaToSegOff = */ rtDbgModMapSym_RvaToSegOff,
|
---|
603 | /*.pfnImageSize = */ rtDbgModMapSym_ImageSize,
|
---|
604 |
|
---|
605 | /*.pfnSegmentAdd = */ rtDbgModMapSym_SegmentAdd,
|
---|
606 | /*.pfnSegmentCount = */ rtDbgModMapSym_SegmentCount,
|
---|
607 | /*.pfnSegmentByIndex = */ rtDbgModMapSym_SegmentByIndex,
|
---|
608 |
|
---|
609 | /*.pfnSymbolAdd = */ rtDbgModMapSym_SymbolAdd,
|
---|
610 | /*.pfnSymbolCount = */ rtDbgModMapSym_SymbolCount,
|
---|
611 | /*.pfnSymbolByOrdinal = */ rtDbgModMapSym_SymbolByOrdinal,
|
---|
612 | /*.pfnSymbolByName = */ rtDbgModMapSym_SymbolByName,
|
---|
613 | /*.pfnSymbolByAddr = */ rtDbgModMapSym_SymbolByAddr,
|
---|
614 |
|
---|
615 | /*.pfnLineAdd = */ rtDbgModMapSym_LineAdd,
|
---|
616 | /*.pfnLineCount = */ rtDbgModMapSym_LineCount,
|
---|
617 | /*.pfnLineByOrdinal = */ rtDbgModMapSym_LineByOrdinal,
|
---|
618 | /*.pfnLineByAddr = */ rtDbgModMapSym_LineByAddr,
|
---|
619 |
|
---|
620 | /*.pfnUnwindFrame = */ rtDbgModMapSym_UnwindFrame,
|
---|
621 |
|
---|
622 | /*.u32EndMagic = */ RTDBGMODVTDBG_MAGIC
|
---|
623 | };
|
---|
624 |
|
---|