VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/dbg/dbgmodnm.cpp@ 25645

Last change on this file since 25645 was 25645, checked in by vboxsync, 15 years ago

IPRT,DoxyFile.Core: Mopped up the errors in the IPRT doxygen run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.8 KB
Line 
1/* $Id: dbgmodnm.cpp 25645 2010-01-05 09:29:31Z vboxsync $ */
2/** @file
3 * IPRT - Debug Map Reader For NM Like Mapfiles.
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include <iprt/dbg.h>
36#include "internal/iprt.h"
37
38#include <iprt/err.h>
39#include <iprt/ctype.h>
40#include <iprt/mem.h>
41#include <iprt/stream.h>
42#include <iprt/string.h>
43#include "internal/dbgmod.h"
44
45
46/*******************************************************************************
47* Structures and Typedefs *
48*******************************************************************************/
49/**
50 * Instance data.
51 */
52typedef struct RTDBGMODNM
53{
54 /** The debug container containing doing the real work. */
55 RTDBGMOD hCnt;
56} RTDBGMODNM;
57/** Pointer to instance data NM map reader. */
58typedef RTDBGMODNM *PRTDBGMODNM;
59
60
61
62/** @copydoc RTDBGMODVTDBG::pfnLineByAddr */
63static DECLCALLBACK(int) rtDbgModNm_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
64 PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
65{
66 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
67 return RTDbgModLineByAddr(pThis->hCnt, iSeg, off, poffDisp, pLineInfo);
68}
69
70
71/** @copydoc RTDBGMODVTDBG::pfnLineByOrdinal */
72static DECLCALLBACK(int) rtDbgModNm_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
73{
74 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
75 return RTDbgModLineByOrdinal(pThis->hCnt, iOrdinal, pLineInfo);
76}
77
78
79/** @copydoc RTDBGMODVTDBG::pfnLineCount */
80static DECLCALLBACK(uint32_t) rtDbgModNm_LineCount(PRTDBGMODINT pMod)
81{
82 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
83 return RTDbgModLineCount(pThis->hCnt);
84}
85
86
87/** @copydoc RTDBGMODVTDBG::pfnLineAdd */
88static DECLCALLBACK(int) rtDbgModNm_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
89 uint32_t iSeg, RTUINTPTR off, uint32_t *piOrdinal)
90{
91 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
92 return RTDbgModLineAdd(pThis->hCnt, pszFile, uLineNo, iSeg, off, piOrdinal);
93}
94
95
96/** @copydoc RTDBGMODVTDBG::pfnSymbolByAddr */
97static DECLCALLBACK(int) rtDbgModNm_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
98 PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
99{
100 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
101 return RTDbgModSymbolByAddr(pThis->hCnt, iSeg, off, poffDisp, pSymInfo);
102}
103
104
105/** @copydoc RTDBGMODVTDBG::pfnSymbolByName */
106static DECLCALLBACK(int) rtDbgModNm_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol, PRTDBGSYMBOL pSymInfo)
107{
108 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
109 return RTDbgModSymbolByName(pThis->hCnt, pszSymbol, pSymInfo);
110}
111
112
113/** @copydoc RTDBGMODVTDBG::pfnSymbolByOrdinal */
114static DECLCALLBACK(int) rtDbgModNm_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
115{
116 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
117 return RTDbgModSymbolByOrdinal(pThis->hCnt, iOrdinal, pSymInfo);
118}
119
120
121/** @copydoc RTDBGMODVTDBG::pfnSymbolCount */
122static DECLCALLBACK(uint32_t) rtDbgModNm_SymbolCount(PRTDBGMODINT pMod)
123{
124 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
125 return RTDbgModSymbolCount(pThis->hCnt);
126}
127
128
129/** @copydoc RTDBGMODVTDBG::pfnSymbolAdd */
130static DECLCALLBACK(int) rtDbgModNm_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
131 RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags,
132 uint32_t *piOrdinal)
133{
134 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
135 return RTDbgModSymbolAdd(pThis->hCnt, pszSymbol, iSeg, off, cb, fFlags, piOrdinal);
136}
137
138
139/** @copydoc RTDBGMODVTDBG::pfnSegmentByIndex */
140static DECLCALLBACK(int) rtDbgModNm_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
141{
142 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
143 return RTDbgModSegmentByIndex(pThis->hCnt, iSeg, pSegInfo);
144}
145
146
147/** @copydoc RTDBGMODVTDBG::pfnSegmentCount */
148static DECLCALLBACK(RTDBGSEGIDX) rtDbgModNm_SegmentCount(PRTDBGMODINT pMod)
149{
150 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
151 return RTDbgModSegmentCount(pThis->hCnt);
152}
153
154
155/** @copydoc RTDBGMODVTDBG::pfnSegmentAdd */
156static DECLCALLBACK(int) rtDbgModNm_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName, size_t cchName,
157 uint32_t fFlags, PRTDBGSEGIDX piSeg)
158{
159 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
160 return RTDbgModSegmentAdd(pThis->hCnt, uRva, cb, pszName, fFlags, piSeg);
161}
162
163
164/** @copydoc RTDBGMODVTDBG::pfnImageSize */
165static DECLCALLBACK(RTUINTPTR) rtDbgModNm_ImageSize(PRTDBGMODINT pMod)
166{
167 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
168 return RTDbgModImageSize(pThis->hCnt);
169}
170
171
172/** @copydoc RTDBGMODVTDBG::pfnRvaToSegOff */
173static DECLCALLBACK(RTDBGSEGIDX) rtDbgModNm_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
174{
175 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
176 return RTDbgModRvaToSegOff(pThis->hCnt, uRva, poffSeg);
177}
178
179
180/** @copydoc RTDBGMODVTDBG::pfnClose */
181static DECLCALLBACK(int) rtDbgModNm_Close(PRTDBGMODINT pMod)
182{
183 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
184 RTDbgModRelease(pThis->hCnt);
185 pThis->hCnt = NIL_RTDBGMOD;
186 RTMemFree(pThis);
187 return VINF_SUCCESS;
188}
189
190
191/**
192 * Scans a NM-like map file.
193 *
194 * This implements both passes to avoid code duplication.
195 *
196 * @returns IPRT status code.
197 * @param pThis The instance data.
198 * @param pStrm The stream.
199 * @param fAddSymbols false in the first pass, true in the second.
200 */
201static int rtDbgModNmScanFile(PRTDBGMODNM pThis, PRTSTREAM pStrm, bool fAddSymbols)
202{
203 /*
204 * Try parse the stream.
205 */
206 RTUINTPTR SegZeroRva = fAddSymbols ? RTDbgModSegmentRva(pThis->hCnt, 0/*iSeg*/) : 0;
207 char szSym[RTDBG_SYMBOL_NAME_LENGTH] = "";
208 size_t cchMod = 0;
209 size_t offSym = 0;
210 unsigned cchAddr = 0;
211 uint64_t u64Low = UINT64_MAX;
212 uint64_t u64High = 0;
213 char szLine[512];
214 int rc;
215 while (RT_SUCCESS(rc = RTStrmGetLine(pStrm, szLine, sizeof(szLine))))
216 {
217 char chType;
218 if (RT_C_IS_XDIGIT(szLine[0]))
219 {
220 /*
221 * This is really what C was made for, string parsing.
222 */
223 /* The the symbol value (address). */
224 uint64_t u64Addr;
225 char *psz;
226 rc = RTStrToUInt64Ex(szLine, &psz, 16, &u64Addr);
227 if (rc != VWRN_TRAILING_CHARS)
228 return VERR_DBG_NOT_NM_MAP_FILE;
229
230 /* Check the address width. */
231 if (cchAddr == 0)
232 cchAddr = psz == &szLine[8] ? 8 : 16;
233 if (psz != &szLine[cchAddr])
234 return VERR_DBG_NOT_NM_MAP_FILE;
235
236 /* Get the type and check for single space before symbol. */
237 chType = szLine[cchAddr + 1];
238 if ( RT_C_IS_BLANK(chType)
239 || !RT_C_IS_BLANK(szLine[cchAddr + 2])
240 || RT_C_IS_BLANK(szLine[cchAddr + 3]))
241 return VERR_DBG_NOT_NM_MAP_FILE;
242
243 /* Find the end of the symbol name. */
244 char *pszName = &szLine[cchAddr + 3];
245 char *pszNameEnd = pszName;
246 char ch;
247 while ((ch = *pszNameEnd) != '\0' && !RT_C_IS_SPACE(ch))
248 pszNameEnd++;
249
250 /* Any module name (linux /proc/kallsyms) following in brackets? */
251 char *pszModName = pszNameEnd;
252 char *pszModNameEnd = pszModName;
253 if (*pszModName)
254 {
255 *pszModName++ = '\0';
256 pszModNameEnd = pszModName = RTStrStripL(pszModName);
257 if (*pszModName != '\0')
258 {
259 if (*pszModName != '[')
260 return VERR_DBG_NOT_LINUX_KALLSYMS;
261 pszModNameEnd = ++pszModName;
262 while ((ch = *pszModNameEnd) != '\0' && ch != ']')
263 pszModNameEnd++;
264 if (ch != ']')
265 return VERR_DBG_NOT_LINUX_KALLSYMS;
266 char *pszEnd = pszModNameEnd + 1;
267 if ((size_t)(pszModNameEnd - pszModName) >= 128) /* lazy bird */
268 return VERR_DBG_NOT_LINUX_KALLSYMS;
269 *pszModNameEnd = '\0';
270 if (*pszEnd)
271 pszEnd = RTStrStripL(pszEnd);
272 if (*pszEnd)
273 return VERR_DBG_NOT_LINUX_KALLSYMS;
274 }
275 }
276
277 /*
278 * Did the module change? Then update the symbol prefix.
279 */
280 if ( cchMod != (size_t)(pszModNameEnd - pszModName)
281 || memcmp(pszModName, szSym, cchMod))
282 {
283 cchMod = pszModNameEnd - pszModName;
284 if (cchMod == 0)
285 offSym = 0;
286 else
287 {
288 memcpy(szSym, pszModName, cchMod);
289 szSym[cchMod] = '.';
290 offSym = cchMod + 1;
291 }
292 szSym[offSym] = '\0';
293 }
294
295 /*
296 * Validate the type and add the symbol if it's a type we care for.
297 */
298 uint32_t fFlags = 0;
299 RTDBGSEGIDX iSegSym = 0;
300 switch (chType)
301 {
302 /* absolute */
303 case 'a':
304 case '?': /* /proc/kallsyms */
305 iSegSym = RTDBGSEGIDX_ABS;
306 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
307 break;
308 case 'A':
309 iSegSym = RTDBGSEGIDX_ABS;
310 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
311 break;
312
313 case 'b':
314 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
315 break;
316 case 'B':
317 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
318 break;
319
320 case 'c':
321 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL | RTDBG_SYM_FLAGS_COMMON;
322 break;
323 case 'C':
324 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC | RTDBG_SYM_FLAGS_COMMON;
325 break;
326
327 case 'd':
328 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
329 break;
330 case 'D':
331 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
332 break;
333
334 case 'g':
335 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
336 break;
337 case 'G':
338 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
339 break;
340
341 case 'i':
342 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
343 break;
344 case 'I':
345 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
346 break;
347
348 case 'r':
349 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL | RTDBG_SYM_FLAGS_CONST;
350 break;
351 case 'R':
352 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC | RTDBG_SYM_FLAGS_CONST;
353 break;
354
355 case 's':
356 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
357 break;
358 case 'S':
359 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
360 break;
361
362 case 't':
363 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL | RTDBG_SYM_FLAGS_TEXT;
364 break;
365 case 'T':
366 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC | RTDBG_SYM_FLAGS_TEXT;
367 break;
368
369 case 'w':
370 /// @todo fFlags |= RTDBG_SYM_FLAGS_WEAK | RTDBG_SYM_FLAGS_LOCAL; //???
371 break;
372 case 'W':
373 /// @todo fFlags |= RTDBG_SYM_FLAGS_WEAK | RTDBG_SYM_FLAGS_PUBLIC;
374 break;
375
376 case 'N': /* debug */
377 case 'n':
378 case '-': /* stabs */
379 case 'u': /* undefined (/proc/kallsyms) */
380 case 'U':
381 case 'v': /* weakext */
382 case 'V':
383 iSegSym = NIL_RTDBGSEGIDX;
384 break;
385
386 default:
387 return VERR_DBG_NOT_NM_MAP_FILE;
388 }
389
390 if (iSegSym != NIL_RTDBGSEGIDX)
391 {
392 if (fAddSymbols)
393 {
394 size_t cchName = pszNameEnd - pszName;
395 if (cchName >= sizeof(szSym) - offSym)
396 cchName = sizeof(szSym) - offSym - 1;
397 memcpy(&szSym[offSym], pszName, cchName + 1);
398 if (iSegSym == 0)
399 rc = RTDbgModSymbolAdd(pThis->hCnt, szSym, iSegSym, u64Addr - SegZeroRva, 0/*cb*/, fFlags, NULL);
400 else
401 rc = RTDbgModSymbolAdd(pThis->hCnt, szSym, iSegSym, u64Addr, 0/*cb*/, fFlags, NULL);
402 if ( RT_FAILURE(rc)
403 && rc != VERR_DBG_DUPLICATE_SYMBOL
404 && rc != VERR_DBG_ADDRESS_CONFLICT) /* (don't be too strict) */
405 return rc;
406 }
407
408 /* Track segment span. */
409 if (iSegSym == 0)
410 {
411 if (u64Low > u64Addr)
412 u64Low = u64Addr;
413 if (u64High < u64Addr)
414 u64High = u64Addr;
415 }
416 }
417 }
418 else
419 {
420 /*
421 * This is either a blank line or a symbol without an address.
422 */
423 RTStrStripR(szLine);
424 if (szLine[0])
425 {
426 size_t cch = strlen(szLine);
427 if (cchAddr == 0)
428 cchAddr = cch < 16+3 || szLine[8+1] != ' ' ? 8 : 16;
429 if (cch < cchAddr+3+1)
430 return VERR_DBG_NOT_NM_MAP_FILE;
431 chType = szLine[cchAddr + 1];
432 if ( chType != 'U'
433 && chType != 'w')
434 return VERR_DBG_NOT_NM_MAP_FILE;
435 char *pszType = RTStrStripL(szLine);
436 if (pszType != &szLine[cchAddr + 1])
437 return VERR_DBG_NOT_NM_MAP_FILE;
438 if (!RT_C_IS_BLANK(szLine[cchAddr + 2]))
439 return VERR_DBG_NOT_NM_MAP_FILE;
440 }
441 /* else: blank - ignored */
442 }
443 }
444
445 /*
446 * The final segment.
447 */
448 if (rc == VERR_EOF)
449 {
450 if (fAddSymbols)
451 rc = VINF_SUCCESS;
452 else
453 {
454 if ( u64Low != UINT64_MAX
455 || u64High != 0)
456 rc = RTDbgModSegmentAdd(pThis->hCnt, u64Low, u64High - u64Low + 1, "main", 0, NULL);
457 else /* No sensible symbols... throw an error instead? */
458 rc = RTDbgModSegmentAdd(pThis->hCnt, 0, 0, "main", 0, NULL);
459 }
460 }
461
462 return rc;
463}
464
465
466/** @copydoc RTDBGMODVTDBG::pfnTryOpen */
467static DECLCALLBACK(int) rtDbgModNm_TryOpen(PRTDBGMODINT pMod)
468{
469 /*
470 * Try open the file and create an instance.
471 */
472 PRTSTREAM pStrm;
473 int rc = RTStrmOpen(pMod->pszDbgFile, "r", &pStrm);
474 if (RT_SUCCESS(rc))
475 {
476 PRTDBGMODNM pThis = (PRTDBGMODNM)RTMemAlloc(sizeof(*pThis));
477 if (pThis)
478 {
479 rc = RTDbgModCreate(&pThis->hCnt, pMod->pszName, 0 /*cbSeg*/, 0 /*fFlags*/);
480 if (RT_SUCCESS(rc))
481 {
482 /*
483 * Scan the file twice, first to figure the segment
484 * sizes, then to add the symbol.
485 */
486 rc = rtDbgModNmScanFile(pThis, pStrm, false /*fAddSymbols*/);
487 if (RT_SUCCESS(rc))
488 rc = RTStrmRewind(pStrm);
489 if (RT_SUCCESS(rc))
490 rc = rtDbgModNmScanFile(pThis, pStrm, true /*fAddSymbols*/);
491 if (RT_SUCCESS(rc))
492 {
493 RTStrmClose(pStrm);
494 pMod->pvDbgPriv = pThis;
495 return rc;
496 }
497 }
498 RTDbgModRelease(pThis->hCnt);
499 }
500 else
501 rc = VERR_NO_MEMORY;
502 RTStrmClose(pStrm);
503 }
504 return rc;
505}
506
507
508
509/** Virtual function table for the NM-like map file reader. */
510DECLHIDDEN(RTDBGMODVTDBG const) g_rtDbgModVtDbgNm =
511{
512 /*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
513 /*.fSupports = */ RT_DBGTYPE_MAP,
514 /*.pszName = */ "nm",
515 /*.pfnTryOpen = */ rtDbgModNm_TryOpen,
516 /*.pfnClose = */ rtDbgModNm_Close,
517
518 /*.pfnRvaToSegOff = */ rtDbgModNm_RvaToSegOff,
519 /*.pfnImageSize = */ rtDbgModNm_ImageSize,
520
521 /*.pfnSegmentAdd = */ rtDbgModNm_SegmentAdd,
522 /*.pfnSegmentCount = */ rtDbgModNm_SegmentCount,
523 /*.pfnSegmentByIndex = */ rtDbgModNm_SegmentByIndex,
524
525 /*.pfnSymbolAdd = */ rtDbgModNm_SymbolAdd,
526 /*.pfnSymbolCount = */ rtDbgModNm_SymbolCount,
527 /*.pfnSymbolByOrdinal = */ rtDbgModNm_SymbolByOrdinal,
528 /*.pfnSymbolByName = */ rtDbgModNm_SymbolByName,
529 /*.pfnSymbolByAddr = */ rtDbgModNm_SymbolByAddr,
530
531 /*.pfnLineAdd = */ rtDbgModNm_LineAdd,
532 /*.pfnLineCount = */ rtDbgModNm_LineCount,
533 /*.pfnLineByOrdinal = */ rtDbgModNm_LineByOrdinal,
534 /*.pfnLineByAddr = */ rtDbgModNm_LineByAddr,
535
536 /*.u32EndMagic = */ RTDBGMODVTDBG_MAGIC
537};
538
Note: See TracBrowser for help on using the repository browser.

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