VirtualBox

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

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

gcc warning

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