VirtualBox

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

Last change on this file since 38515 was 38515, checked in by vboxsync, 13 years ago

IPRT: Working on debug info again.

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