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