VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFSym.cpp@ 45907

Last change on this file since 45907 was 45753, checked in by vboxsync, 12 years ago

Don't call MMHyperIsInsideArea if we're using HM to execute code, it will return bogus results!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 36.6 KB
Line 
1/* $Id: DBGFSym.cpp 45753 2013-04-26 01:33:30Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Symbol Management.
4 */
5
6/*
7 * Copyright (C) 2006-2013 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
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DBGF
23#if defined(RT_OS_WINDOWS) && 0 //defined(DEBUG_bird) // enabled this is you want to debug win32 guests, the hypervisor of EFI.
24# include <Windows.h>
25# define _IMAGEHLP64
26# include <DbgHelp.h>
27# define HAVE_DBGHELP /* if doing guest stuff, this can be nice. */
28#endif
29/** @todo Only use DBGHELP for reading modules since it doesn't do all we want (relocations), or is way to slow in some cases (add symbol)! */
30#include <VBox/vmm/dbgf.h>
31#include <VBox/vmm/mm.h>
32#include <VBox/vmm/hm.h>
33#include <VBox/vmm/pdmapi.h>
34#include "DBGFInternal.h"
35#include <VBox/vmm/vm.h>
36#include <VBox/vmm/uvm.h>
37#include <VBox/err.h>
38#include <VBox/log.h>
39
40#include <iprt/assert.h>
41#include <iprt/path.h>
42#include <iprt/ctype.h>
43#include <iprt/env.h>
44#include <iprt/param.h>
45#ifndef HAVE_DBGHELP
46# include <iprt/avl.h>
47# include <iprt/string.h>
48#endif
49
50#include <stdio.h> /* for fopen(). */ /** @todo use iprt/stream.h! */
51#include <stdlib.h>
52
53
54/*******************************************************************************
55* Internal Functions *
56*******************************************************************************/
57#ifdef HAVE_DBGHELP
58static DECLCALLBACK(int) dbgfR3EnumModules(PVM pVM, const char *pszFilename, const char *pszName,
59 RTUINTPTR ImageBase, size_t cbImage, bool fRC, void *pvArg);
60static int win32Error(PVM pVM);
61#endif
62
63
64/*******************************************************************************
65* Structures and Typedefs *
66*******************************************************************************/
67#ifndef HAVE_DBGHELP
68/* later */
69typedef struct DBGFMOD *PDBGFMOD;
70
71/**
72 * Internal representation of a symbol.
73 */
74typedef struct DBGFSYM
75{
76 /** Node core with the symbol address range. */
77 AVLRGCPTRNODECORE Core;
78 /** Pointer to the module this symbol is associated with. */
79 PDBGFMOD pModule;
80 /** Pointer to the next symbol in with this name. */
81 struct DBGFSYM *pNext;
82 /** Symbol name. */
83 char szName[1];
84} DBGFSYM, *PDBGFSYM;
85
86/**
87 * Symbol name space node.
88 */
89typedef struct DBGFSYMSPACE
90{
91 /** Node core with the symbol name.
92 * (it's allocated in the same block as this struct) */
93 RTSTRSPACECORE Core;
94 /** Pointer to the first symbol with this name (LIFO). */
95 PDBGFSYM pSym;
96} DBGFSYMSPACE, *PDBGFSYMSPACE;
97
98#endif
99
100
101
102/*******************************************************************************
103* Internal Functions *
104*******************************************************************************/
105#ifndef HAVE_DBGHELP
106
107/**
108 * Initializes the symbol tree.
109 */
110static int dbgfR3SymbolInit(PVM pVM)
111{
112 PDBGFSYM pSym = (PDBGFSYM)MMR3HeapAlloc(pVM, MM_TAG_DBGF_SYMBOL, sizeof(*pSym));
113 if (pSym)
114 {
115 pSym->Core.Key = 0;
116 pSym->Core.KeyLast = ~0;
117 pSym->pModule = NULL;
118 pSym->szName[0] = '\0';
119 if (RTAvlrGCPtrInsert(&pVM->dbgf.s.SymbolTree, &pSym->Core))
120 return VINF_SUCCESS;
121 AssertReleaseMsgFailed(("Failed to insert %RGv-%RGv!\n", pSym->Core.Key, pSym->Core.KeyLast));
122 return VERR_INTERNAL_ERROR;
123 }
124 return VERR_NO_MEMORY;
125}
126
127
128/**
129 * Insert a record into the symbol tree.
130 */
131static int dbgfR3SymbolInsert(PVM pVM, const char *pszName, RTGCPTR Address, size_t cb, PDBGFMOD pModule)
132{
133 /*
134 * Make the address space node.
135 */
136 size_t cchName = strlen(pszName) + 1;
137 PDBGFSYM pSym = (PDBGFSYM)MMR3HeapAlloc(pVM, MM_TAG_DBGF_SYMBOL, RT_OFFSETOF(DBGFSYM, szName[cchName]));
138 if (pSym)
139 {
140 pSym->Core.Key = Address;
141 pSym->Core.KeyLast = Address + cb;
142 pSym->pModule = pModule;
143 memcpy(pSym->szName, pszName, cchName);
144
145 PDBGFSYM pOld = (PDBGFSYM)RTAvlrGCPtrRangeGet(&pVM->dbgf.s.SymbolTree, (RTGCPTR)Address);
146 if (pOld)
147 {
148 pSym->Core.KeyLast = pOld->Core.KeyLast;
149 if (pOld->Core.Key == pSym->Core.Key)
150 {
151 pOld = (PDBGFSYM)RTAvlrGCPtrRemove(&pVM->dbgf.s.SymbolTree, (RTGCPTR)Address);
152 AssertRelease(pOld);
153 MMR3HeapFree(pOld);
154 }
155 else
156 pOld->Core.KeyLast = Address - 1;
157 if (RTAvlrGCPtrInsert(&pVM->dbgf.s.SymbolTree, &pSym->Core))
158 {
159 /*
160 * Make the name space node.
161 */
162 PDBGFSYMSPACE pName = (PDBGFSYMSPACE)RTStrSpaceGet(pVM->dbgf.s.pSymbolSpace, pszName);
163 if (!pName)
164 {
165 /* make new symbol space node. */
166 pName = (PDBGFSYMSPACE)MMR3HeapAlloc(pVM, MM_TAG_DBGF_SYMBOL, sizeof(*pName) + cchName);
167 if (pName)
168 {
169 pName->Core.pszString = (char *)memcpy(pName + 1, pszName, cchName);
170 pName->pSym = pSym;
171 if (RTStrSpaceInsert(pVM->dbgf.s.pSymbolSpace, &pName->Core))
172 return VINF_SUCCESS;
173 }
174 else
175 return VINF_SUCCESS;
176 }
177 else
178 {
179 /* Add to existing symbol name. */
180 pSym->pNext = pName->pSym;
181 pName->pSym = pSym;
182 return VINF_SUCCESS;
183 }
184 }
185 AssertReleaseMsgFailed(("Failed to insert %RGv-%RGv!\n", pSym->Core.Key, pSym->Core.KeyLast));
186 }
187 else
188 AssertMsgFailed(("pOld! %RGv %s\n", pSym->Core.Key, pszName));
189 return VERR_INTERNAL_ERROR;
190
191 }
192 return VERR_NO_MEMORY;
193}
194
195
196/**
197 * Get nearest symbol.
198 * @returns NULL if no symbol was the for that address.
199 */
200static PDBGFSYM dbgfR3SymbolGetAddr(PVM pVM, RTGCPTR Address)
201{
202 PDBGFSYM pSym = (PDBGFSYM)RTAvlrGCPtrRangeGet(&pVM->dbgf.s.SymbolTree, Address);
203 Assert(pSym);
204 if (pSym && pSym->szName[0])
205 return pSym;
206 return NULL;
207}
208
209
210/**
211 * Get first symbol.
212 * @returns NULL if no symbol by that name.
213 */
214static PDBGFSYM dbgfR3SymbolGetName(PVM pVM, const char *pszSymbol)
215{
216 PDBGFSYMSPACE pName = (PDBGFSYMSPACE)RTStrSpaceGet(pVM->dbgf.s.pSymbolSpace, pszSymbol);
217 if (pName)
218 return pName->pSym;
219 return NULL;
220}
221
222#endif
223
224
225/**
226 * Strips all kind of spaces from head and tail of a string.
227 */
228static char *dbgfR3Strip(char *psz)
229{
230 while (*psz && RT_C_IS_SPACE(*psz))
231 psz++;
232 char *psz2 = strchr(psz, '\0') - 1;
233 while (psz2 >= psz && RT_C_IS_SPACE(*psz2))
234 *psz2-- = '\0';
235 return psz;
236}
237
238
239/**
240 * Initialize the debug info for a VM.
241 *
242 * This will check the CFGM for any symbols or symbol files
243 * which needs loading.
244 *
245 * @returns VBox status code.
246 * @param pVM Pointer to the VM.
247 */
248int dbgfR3SymInit(PVM pVM)
249{
250 int rc;
251
252 /*
253 * Initialize the symbol table.
254 */
255 pVM->dbgf.s.pSymbolSpace = (PRTSTRSPACE)MMR3HeapAllocZ(pVM, MM_TAG_DBGF_SYMBOL, sizeof(*pVM->dbgf.s.pSymbolSpace));
256 AssertReturn(pVM->dbgf.s.pSymbolSpace, VERR_NO_MEMORY);
257
258#ifndef HAVE_DBGHELP
259 /* modules & lines later */
260 rc = dbgfR3SymbolInit(pVM);
261 if (RT_FAILURE(rc))
262 return rc;
263 pVM->dbgf.s.fSymInited = true;
264#endif
265
266 /** @todo symbol search path setup. */
267
268 /*
269 * Check if there are 'loadsyms' commands in the configuration.
270 */
271 PCFGMNODE pNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "/DBGF/loadsyms/");
272 if (pNode)
273 {
274 /*
275 * Enumerate the commands.
276 */
277 for (PCFGMNODE pCmdNode = CFGMR3GetFirstChild(pNode);
278 pCmdNode;
279 pCmdNode = CFGMR3GetNextChild(pCmdNode))
280 {
281 char szCmdName[128];
282 CFGMR3GetName(pCmdNode, &szCmdName[0], sizeof(szCmdName));
283
284 /* File */
285 char *pszFilename;
286 rc = CFGMR3QueryStringAlloc(pCmdNode, "Filename", &pszFilename);
287 AssertMsgRCReturn(rc, ("rc=%Rrc querying the 'File' attribute of '/DBGF/loadsyms/%s'!\n", rc, szCmdName), rc);
288
289 /* Delta (optional) */
290 RTGCINTPTR offDelta;
291 rc = CFGMR3QueryGCPtrS(pNode, "Delta", &offDelta);
292 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
293 offDelta = 0;
294 else
295 AssertMsgRCReturn(rc, ("rc=%Rrc querying the 'Delta' attribute of '/DBGF/loadsyms/%s'!\n", rc, szCmdName), rc);
296
297 /* Module (optional) */
298 char *pszModule;
299 rc = CFGMR3QueryStringAlloc(pCmdNode, "Module", &pszModule);
300 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
301 pszModule = NULL;
302 else
303 AssertMsgRCReturn(rc, ("rc=%Rrc querying the 'Module' attribute of '/DBGF/loadsyms/%s'!\n", rc, szCmdName), rc);
304
305 /* Module (optional) */
306 RTGCUINTPTR ModuleAddress;
307 rc = CFGMR3QueryGCPtrU(pNode, "ModuleAddress", &ModuleAddress);
308 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
309 ModuleAddress = 0;
310 else
311 AssertMsgRCReturn(rc, ("rc=%Rrc querying the 'ModuleAddress' attribute of '/DBGF/loadsyms/%s'!\n", rc, szCmdName), rc);
312
313 /* Image size (optional) */
314 RTGCUINTPTR cbModule;
315 rc = CFGMR3QueryGCPtrU(pNode, "ModuleSize", &cbModule);
316 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
317 cbModule = 0;
318 else
319 AssertMsgRCReturn(rc, ("rc=%Rrc querying the 'ModuleAddress' attribute of '/DBGF/loadsyms/%s'!\n", rc, szCmdName), rc);
320
321
322 /*
323 * Execute the command.
324 */
325 rc = DBGFR3ModuleLoad(pVM->pUVM, pszFilename, offDelta, pszModule, ModuleAddress, cbModule);
326 AssertMsgRCReturn(rc, ("pszFilename=%s offDelta=%RGv pszModule=%s ModuleAddress=%RGv cbModule=%RGv\n",
327 pszFilename, offDelta, pszModule, ModuleAddress, cbModule), rc);
328
329 MMR3HeapFree(pszModule);
330 MMR3HeapFree(pszFilename);
331 }
332 }
333
334 /*
335 * Check if there are 'loadmap' commands in the configuration.
336 */
337 pNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "/DBGF/loadmap/");
338 if (pNode)
339 {
340 /*
341 * Enumerate the commands.
342 */
343 for (PCFGMNODE pCmdNode = CFGMR3GetFirstChild(pNode);
344 pCmdNode;
345 pCmdNode = CFGMR3GetNextChild(pCmdNode))
346 {
347 char szCmdName[128];
348 CFGMR3GetName(pCmdNode, &szCmdName[0], sizeof(szCmdName));
349
350 /* File */
351 char *pszFilename;
352 rc = CFGMR3QueryStringAlloc(pCmdNode, "Filename", &pszFilename);
353 AssertMsgRCReturn(rc, ("rc=%Rrc querying the 'File' attribute of '/DBGF/loadsyms/%s'!\n", rc, szCmdName), rc);
354
355 /* Address. */
356 RTGCPTR GCPtrAddr;
357 rc = CFGMR3QueryGCPtrUDef(pNode, "Address", &GCPtrAddr, 0);
358 AssertMsgRCReturn(rc, ("rc=%Rrc querying the 'Address' attribute of '/DBGF/loadsyms/%s'!\n", rc, szCmdName), rc);
359 DBGFADDRESS ModAddr;
360 DBGFR3AddrFromFlat(pVM->pUVM, &ModAddr, GCPtrAddr);
361
362 /* Name (optional) */
363 char *pszModName;
364 rc = CFGMR3QueryStringAllocDef(pCmdNode, "Name", &pszModName, NULL);
365 AssertMsgRCReturn(rc, ("rc=%Rrc querying the 'Name' attribute of '/DBGF/loadsyms/%s'!\n", rc, szCmdName), rc);
366
367 /* Subtrahend (optional) */
368 RTGCPTR offSubtrahend;
369 rc = CFGMR3QueryGCPtrDef(pNode, "Subtrahend", &offSubtrahend, 0);
370 AssertMsgRCReturn(rc, ("rc=%Rrc querying the 'Subtrahend' attribute of '/DBGF/loadsyms/%s'!\n", rc, szCmdName), rc);
371
372 /* Segment (optional) */
373 uint32_t iSeg;
374 rc = CFGMR3QueryU32Def(pNode, "Segment", &iSeg, UINT32_MAX);
375 AssertMsgRCReturn(rc, ("rc=%Rrc querying the 'Segment' attribute of '/DBGF/loadsyms/%s'!\n", rc, szCmdName), rc);
376
377 /*
378 * Execute the command.
379 */
380 rc = DBGFR3AsLoadMap(pVM->pUVM, DBGF_AS_GLOBAL, pszFilename, pszModName, &ModAddr,
381 iSeg == UINT32_MAX ? NIL_RTDBGSEGIDX : iSeg, offSubtrahend, 0 /*fFlags*/);
382 AssertMsgRCReturn(rc, ("pszFilename=%s pszModName=%s ModAddr=%RGv offSubtrahend=%#x iSeg=%#x\n",
383 pszFilename, pszModName, ModAddr.FlatPtr, offSubtrahend, iSeg), rc);
384
385 MMR3HeapFree(pszModName);
386 MMR3HeapFree(pszFilename);
387 }
388 }
389
390 /*
391 * Check if there are any 'symadd' commands in the configuration.
392 */
393
394 return VINF_SUCCESS;
395}
396
397
398/**
399 * We delay certain
400 * Initialize the debug info for a VM.
401 */
402int dbgfR3SymLazyInit(PVM pVM)
403{
404 if (pVM->dbgf.s.fSymInited)
405 return VINF_SUCCESS;
406#ifdef HAVE_DBGHELP
407 if (SymInitialize(pVM, NULL, FALSE))
408 {
409 pVM->dbgf.s.fSymInited = true;
410 SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
411
412 /*
413 * Enumerate all modules loaded by PDM and add them to the symbol database.
414 */
415 PDMR3LdrEnumModules(pVM, dbgfR3EnumModules, NULL);
416 return VINF_SUCCESS;
417 }
418 return win32Error(pVM);
419#else
420 return VINF_SUCCESS;
421#endif
422}
423
424
425#ifdef HAVE_DBGHELP
426/**
427 * Module enumeration callback function.
428 *
429 * @returns VBox status.
430 * Failure will stop the search and return the return code.
431 * Warnings will be ignored and not returned.
432 * @param pVM Pointer to the VM.
433 * @param pszFilename Module filename.
434 * @param pszName Module name. (short and unique)
435 * @param ImageBase Address where to executable image is loaded.
436 * @param cbImage Size of the executable image.
437 * @param fRC Set if guest context, clear if host context.
438 * @param pvArg User argument.
439 */
440static DECLCALLBACK(int) dbgfR3EnumModules(PVM pVM, const char *pszFilename, const char *pszName,
441 RTUINTPTR ImageBase, size_t cbImage, bool fRC, void *pvArg)
442{
443 DWORD64 LoadedImageBase = SymLoadModule64(pVM, NULL, (char *)(void *)pszFilename,
444 (char *)(void *)pszName, ImageBase, (DWORD)cbImage);
445 if (!LoadedImageBase)
446 Log(("SymLoadModule64(,,%s,,) -> lasterr=%d\n", pszFilename, GetLastError()));
447 else
448 Log(("Loaded debuginfo for %s - %s %llx\n", pszName, pszFilename, LoadedImageBase));
449
450 return VINF_SUCCESS;
451}
452#endif
453
454
455/**
456 * Terminate the debug info repository for the specified VM.
457 *
458 * @returns VBox status.
459 * @param pVM Pointer to the VM.
460 */
461int dbgfR3SymTerm(PVM pVM)
462{
463#ifdef HAVE_DBGHELP
464 if (pVM->dbgf.s.fSymInited)
465 SymCleanup(pVM);
466 pVM->dbgf.s.fSymInited = false;
467 return VINF_SUCCESS;
468#else
469 pVM->dbgf.s.SymbolTree = 0; /* MM cleans up allocations */
470 pVM->dbgf.s.fSymInited = false;
471 return VINF_SUCCESS;
472#endif
473}
474
475
476/** Symbol file type.. */
477typedef enum SYMFILETYPE
478{
479 SYMFILETYPE_UNKNOWN,
480 SYMFILETYPE_LD_MAP,
481 SYMFILETYPE_MS_MAP,
482 SYMFILETYPE_OBJDUMP,
483 SYMFILETYPE_LINUX_SYSTEM_MAP,
484 SYMFILETYPE_PDB,
485 SYMFILETYPE_DBG,
486 SYMFILETYPE_MZ,
487 SYMFILETYPE_ELF
488} SYMFILETYPE, *PSYMFILETYPE;
489
490
491
492/**
493 * Probe the type of a symbol information file.
494 *
495 * @returns The file type.
496 * @param pFile File handle.
497 */
498SYMFILETYPE dbgfR3ModuleProbe(FILE *pFile)
499{
500 char szHead[4096];
501 size_t cchHead = fread(szHead, 1, sizeof(szHead) - 1, pFile);
502 if (cchHead > 0)
503 {
504 szHead[cchHead] = '\0';
505 if (strstr(szHead, "Preferred load address is"))
506 return SYMFILETYPE_MS_MAP;
507
508 if ( strstr(szHead, "Archive member included because of")
509 || strstr(szHead, "Memory Configuration")
510 || strstr(szHead, "Linker script and memory map"))
511 return SYMFILETYPE_LD_MAP;
512
513 if ( RT_C_IS_XDIGIT(szHead[0])
514 && RT_C_IS_XDIGIT(szHead[1])
515 && RT_C_IS_XDIGIT(szHead[2])
516 && RT_C_IS_XDIGIT(szHead[3])
517 && RT_C_IS_XDIGIT(szHead[4])
518 && RT_C_IS_XDIGIT(szHead[5])
519 && RT_C_IS_XDIGIT(szHead[6])
520 && RT_C_IS_XDIGIT(szHead[7])
521 && szHead[8] == ' '
522 && RT_C_IS_ALPHA(szHead[9])
523 && szHead[10] == ' '
524 && (RT_C_IS_ALPHA(szHead[11]) || szHead[11] == '_' || szHead[11] == '$')
525 )
526 return SYMFILETYPE_LINUX_SYSTEM_MAP;
527
528 if ( RT_C_IS_XDIGIT(szHead[0])
529 && RT_C_IS_XDIGIT(szHead[1])
530 && RT_C_IS_XDIGIT(szHead[2])
531 && RT_C_IS_XDIGIT(szHead[3])
532 && RT_C_IS_XDIGIT(szHead[4])
533 && RT_C_IS_XDIGIT(szHead[5])
534 && RT_C_IS_XDIGIT(szHead[6])
535 && RT_C_IS_XDIGIT(szHead[7])
536 && RT_C_IS_XDIGIT(szHead[8])
537 && RT_C_IS_XDIGIT(szHead[9])
538 && RT_C_IS_XDIGIT(szHead[10])
539 && RT_C_IS_XDIGIT(szHead[11])
540 && RT_C_IS_XDIGIT(szHead[12])
541 && RT_C_IS_XDIGIT(szHead[13])
542 && RT_C_IS_XDIGIT(szHead[14])
543 && RT_C_IS_XDIGIT(szHead[15])
544 && szHead[16] == ' '
545 && RT_C_IS_ALPHA(szHead[17])
546 && szHead[18] == ' '
547 && (RT_C_IS_ALPHA(szHead[19]) || szHead[19] == '_' || szHead[19] == '$')
548 )
549 return SYMFILETYPE_LINUX_SYSTEM_MAP;
550
551 if (strstr(szHead, "Microsoft C/C++ MSF") == szHead)
552 return SYMFILETYPE_PDB;
553
554 if (strstr(szHead, "ELF") == szHead + 1)
555 return SYMFILETYPE_ELF;
556
557 if ( strstr(szHead, "MZ") == szHead
558 || strstr(szHead, "PE") == szHead
559 || strstr(szHead, "LE") == szHead
560 || strstr(szHead, "LX") == szHead
561 || strstr(szHead, "NE") == szHead)
562 return SYMFILETYPE_MZ;
563
564
565 if (strstr(szHead, "file format"))
566 return SYMFILETYPE_OBJDUMP;
567 }
568
569 return SYMFILETYPE_UNKNOWN;
570}
571
572
573static int dbgfR3LoadLinuxSystemMap(PVM pVM, FILE *pFile, RTGCUINTPTR ModuleAddress, RTGCUINTPTR AddressDelta)
574{
575 char szLine[4096];
576 while (fgets(szLine, sizeof(szLine), pFile))
577 {
578 /* parse the line: <address> <type> <name> */
579 const char *psz = dbgfR3Strip(szLine);
580 char *pszEnd = NULL;
581 uint64_t u64Address;
582 int rc = RTStrToUInt64Ex(psz, &pszEnd, 16, &u64Address);
583 RTGCUINTPTR Address = u64Address;
584 if ( RT_SUCCESS(rc)
585 && (*pszEnd == ' ' || *pszEnd == '\t')
586 && Address == u64Address
587 && u64Address != 0
588 && u64Address != (RTGCUINTPTR)~0)
589 {
590 pszEnd++;
591 if ( RT_C_IS_ALPHA(*pszEnd)
592 && (pszEnd[1] == ' ' || pszEnd[1] == '\t'))
593 {
594 psz = dbgfR3Strip(pszEnd + 2);
595 if (*psz)
596 {
597 int rc2 = DBGFR3SymbolAdd(pVM, ModuleAddress, Address + AddressDelta, 0, psz);
598 if (RT_FAILURE(rc2))
599 Log2(("DBGFR3SymbolAdd(,, %RGv, 0, '%s') -> %Rrc\n", Address, psz, rc2));
600 }
601 }
602 }
603 }
604 return VINF_SUCCESS;
605}
606
607/**
608 * Tries to open the file using the image search paths.
609 *
610 * This is currently a quick hack and the only way to specifying the path is by setting
611 * VBOXDBG_IMAGE_PATH in the environment. It uses semicolon as separator everywhere.
612 *
613 * @returns VBox status code.
614 * @param pVM Pointer to the VM.
615 * @param pszFilename The name of the file to locate and open.
616 * @param pszFound Where to return the actual filename.
617 * @param cchFound The buffer size.
618 * @param ppFile Where to return the opened file.
619 */
620int dbgfR3ModuleLocateAndOpen(PVM pVM, const char *pszFilename, char *pszFound, size_t cchFound, FILE **ppFile)
621{
622 NOREF(pVM);
623
624 /* Check the filename length. */
625 size_t const cchFilename = strlen(pszFilename);
626 if (cchFilename >= cchFound)
627 return VERR_FILENAME_TOO_LONG;
628 const char *pszName = RTPathFilename(pszFilename);
629 if (!pszName)
630 return VERR_IS_A_DIRECTORY;
631 size_t const cchName = strlen(pszName);
632
633 /*
634 * Try default location first.
635 */
636 memcpy(pszFound, pszFilename, cchFilename + 1);
637 FILE *pFile = *ppFile = fopen(pszFound, "rb");
638 if (pFile)
639 return VINF_SUCCESS;
640
641 /*
642 * Walk the search path.
643 */
644 char *pszFreeMe = RTEnvDupEx(RTENV_DEFAULT, "VBOXDBG_IMAGE_PATH");
645 const char *psz = pszFreeMe ? pszFreeMe : ".";
646 while (*psz)
647 {
648 /* Skip leading blanks - no directories with leading spaces, thank you. */
649 while (RT_C_IS_BLANK(*psz))
650 psz++;
651
652 /* Fine the end of this element. */
653 const char *pszNext;
654 const char *pszEnd = strchr(psz, ';');
655 if (!pszEnd)
656 pszEnd = pszNext = strchr(psz, '\0');
657 else
658 pszNext = pszEnd + 1;
659 if (pszEnd != psz)
660 {
661 size_t const cch = pszEnd - psz;
662 if (cch + 1 + cchName < cchFound)
663 {
664 /** @todo RTPathCompose, RTPathComposeN(). This code isn't right
665 * for 'E:' on DOS systems. It may also create unwanted double slashes. */
666 memcpy(pszFound, psz, cch);
667 pszFound[cch] = '/';
668 memcpy(pszFound + cch + 1, pszName, cchName + 1);
669 *ppFile = pFile = fopen(pszFound, "rb");
670 if (pFile)
671 {
672 RTStrFree(pszFreeMe);
673 return VINF_SUCCESS;
674 }
675 }
676
677 /** @todo do a depth search using the specified path. */
678 }
679
680 /* advance */
681 psz = pszNext;
682 }
683
684 /* not found */
685 RTStrFree(pszFreeMe);
686 return VERR_OPEN_FAILED;
687}
688
689
690/**
691 * Load debug info, optionally related to a specific module.
692 *
693 * @returns VBox status.
694 * @param pUVM The user mode VM handle.
695 * @param pszFilename Path to the file containing the symbol information.
696 * This can be the executable image, a flat symbol file of some kind or stripped debug info.
697 * @param AddressDelta The value to add to the loaded symbols.
698 * @param pszName Short hand name for the module. If not related to a module specify NULL.
699 * @param ModuleAddress Address which the image is loaded at. This will be used to reference the module other places in the api.
700 * Ignored when pszName is NULL.
701 * @param cbImage Size of the image.
702 * Ignored when pszName is NULL.
703 */
704VMMR3DECL(int) DBGFR3ModuleLoad(PUVM pUVM, const char *pszFilename, RTGCUINTPTR AddressDelta, const char *pszName,
705 RTGCUINTPTR ModuleAddress, unsigned cbImage)
706{
707 NOREF(cbImage);
708
709 /*
710 * Lazy init.
711 */
712 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
713 PVM pVM = pUVM->pVM;
714 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
715 if (!pVM->dbgf.s.fSymInited)
716 {
717 int rc = dbgfR3SymLazyInit(pVM);
718 if (RT_FAILURE(rc))
719 return rc;
720 }
721
722 /*
723 * Open the load file.
724 */
725 FILE *pFile = NULL;
726 char szFoundFile[RTPATH_MAX];
727 int rc = dbgfR3ModuleLocateAndOpen(pVM, pszFilename, szFoundFile, sizeof(szFoundFile), &pFile);
728 if (pFile)
729 {
730 /*
731 * Probe the file type.
732 */
733 SYMFILETYPE enmType = dbgfR3ModuleProbe(pFile);
734 if (enmType != SYMFILETYPE_UNKNOWN)
735 {
736 /*
737 * Add the module.
738 */
739 if (pszName)
740 {
741 #ifdef HAVE_DBGHELP
742 /** @todo arg! checkout the inserting of modules and then loading them again.... Or just the module representation.... */
743 DWORD64 ImageBase = SymLoadModule64(pVM, NULL, (char *)(void *)szFoundFile, (char *)(void *)pszName, ModuleAddress, cbImage);
744 if (!ImageBase)
745 ImageBase = SymLoadModule64(pVM, NULL, (char *)(void *)pszName, (char *)(void *)pszName, ModuleAddress, cbImage);
746 if (ImageBase)
747 {
748 AssertMsg(ModuleAddress == 0 || ModuleAddress == ImageBase, ("ModuleAddres=%RGv ImageBase=%llx\n", ModuleAddress, ImageBase));
749 ModuleAddress = ImageBase;
750 }
751 else
752 rc = win32Error(pVM);
753 #else
754 rc = VERR_NOT_IMPLEMENTED;
755 #endif
756 }
757 if (RT_SUCCESS(rc))
758 {
759 /*
760 * Seek to the start of the file.
761 */
762 rc = fseek(pFile, 0, SEEK_SET);
763 Assert(!rc);
764
765 /*
766 * Process the specific.
767 */
768 switch (enmType)
769 {
770 case SYMFILETYPE_LINUX_SYSTEM_MAP:
771 rc = dbgfR3LoadLinuxSystemMap(pVM, pFile, ModuleAddress, AddressDelta);
772 break;
773
774 case SYMFILETYPE_PDB:
775 case SYMFILETYPE_DBG:
776 case SYMFILETYPE_MZ:
777 #ifdef HAVE_DBGHELP
778 /* done it all above! */
779 break;
780 #endif
781 case SYMFILETYPE_LD_MAP:
782 case SYMFILETYPE_MS_MAP:
783 case SYMFILETYPE_OBJDUMP:
784 case SYMFILETYPE_ELF:
785 rc = VERR_NOT_SUPPORTED;
786 break;
787
788 default:
789 AssertFailed();
790 rc = VERR_INTERNAL_ERROR;
791 break;
792 } /* file switch. */
793 } /* module added successfully. */
794 } /* format identified */
795 else
796 rc = VERR_NOT_SUPPORTED;
797 /** @todo check for read errors */
798 fclose(pFile);
799 }
800 return rc;
801}
802
803
804/**
805 * Interface used by PDMR3LdrRelocate for telling us that a GC module has been relocated.
806 *
807 * @param pVM Pointer to the VM.
808 * @param OldImageBase The old image base.
809 * @param NewImageBase The new image base.
810 * @param cbImage The image size.
811 * @param pszFilename The image filename.
812 * @param pszName The module name.
813 */
814VMMR3_INT_DECL(void) DBGFR3ModuleRelocate(PVM pVM, RTGCUINTPTR OldImageBase, RTGCUINTPTR NewImageBase, RTGCUINTPTR cbImage,
815 const char *pszFilename, const char *pszName)
816{
817#ifdef HAVE_DBGHELP
818 if (pVM->dbgf.s.fSymInited)
819 {
820 if (!SymUnloadModule64(pVM, OldImageBase))
821 Log(("SymUnloadModule64(,%RGv) failed, lasterr=%d\n", OldImageBase, GetLastError()));
822
823 DWORD ImageSize = (DWORD)cbImage; Assert(ImageSize == cbImage);
824 DWORD64 LoadedImageBase = SymLoadModule64(pVM, NULL, (char *)(void *)pszFilename, (char *)(void *)pszName, NewImageBase, ImageSize);
825 if (!LoadedImageBase)
826 Log(("SymLoadModule64(,,%s,,) -> lasterr=%d (relocate)\n", pszFilename, GetLastError()));
827 else
828 Log(("Reloaded debuginfo for %s - %s %llx\n", pszName, pszFilename, LoadedImageBase));
829 }
830#else
831 NOREF(pVM); NOREF(OldImageBase); NOREF(NewImageBase); NOREF(cbImage); NOREF(pszFilename); NOREF(pszName);
832#endif
833}
834
835
836/**
837 * Adds a symbol to the debug info manager.
838 *
839 * @returns VBox status.
840 * @param pVM Pointer to the VM.
841 * @param ModuleAddress Module address. Use 0 if no module.
842 * @param SymbolAddress Symbol address
843 * @param cbSymbol Size of the symbol. Use 0 if info not available.
844 * @param pszSymbol Symbol name.
845 */
846VMMR3_INT_DECL(int) DBGFR3SymbolAdd(PVM pVM, RTGCUINTPTR ModuleAddress, RTGCUINTPTR SymbolAddress, RTUINT cbSymbol,
847 const char *pszSymbol)
848{
849 /*
850 * Validate.
851 */
852 if (!pszSymbol || !*pszSymbol)
853 {
854 AssertMsgFailed(("No symbol name!\n"));
855 return VERR_INVALID_PARAMETER;
856 }
857
858 /*
859 * Lazy init.
860 */
861 if (!pVM->dbgf.s.fSymInited)
862 {
863 int rc = dbgfR3SymLazyInit(pVM);
864 if (RT_FAILURE(rc))
865 return rc;
866 }
867
868#ifdef HAVE_DBGHELP
869 if (SymAddSymbol(pVM, ModuleAddress, (char *)(void *)pszSymbol, SymbolAddress, cbSymbol, 0))
870 return VINF_SUCCESS;
871 return win32Error(pVM);
872#else
873 NOREF(ModuleAddress); /** @todo module lookup. */
874 return dbgfR3SymbolInsert(pVM, pszSymbol, SymbolAddress, cbSymbol, NULL);
875#endif
876}
877
878
879/**
880 * Find symbol by address (nearest).
881 *
882 * @returns VBox status.
883 * @param pVM Pointer to the VM.
884 * @param Address Address.
885 * @param poffDisplacement Where to store the symbol displacement from Address.
886 * @param pSymbol Where to store the symbol info.
887 */
888VMMR3_INT_DECL(int) DBGFR3SymbolByAddr(PVM pVM, RTGCUINTPTR Address, PRTGCINTPTR poffDisplacement, PDBGFSYMBOL pSymbol)
889{
890 /*
891 * Lazy init.
892 */
893 if (!pVM->dbgf.s.fSymInited)
894 {
895 int rc = dbgfR3SymLazyInit(pVM);
896 if (RT_FAILURE(rc))
897 return rc;
898 }
899
900 /*
901 * Look it up.
902 */
903#ifdef HAVE_DBGHELP
904 char achBuffer[sizeof(IMAGEHLP_SYMBOL64) + DBGF_SYMBOL_NAME_LENGTH * sizeof(TCHAR) + sizeof(ULONG64)];
905 PIMAGEHLP_SYMBOL64 pSym = (PIMAGEHLP_SYMBOL64)&achBuffer[0];
906 pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
907 pSym->MaxNameLength = DBGF_SYMBOL_NAME_LENGTH;
908
909 if (SymGetSymFromAddr64(pVM, Address, (PDWORD64)poffDisplacement, pSym))
910 {
911 pSymbol->Value = (RTGCUINTPTR)pSym->Address;
912 pSymbol->cb = pSym->Size;
913 pSymbol->fFlags = pSym->Flags;
914 strcpy(pSymbol->szName, pSym->Name);
915 return VINF_SUCCESS;
916 }
917 //return win32Error(pVM);
918
919#else
920
921 PDBGFSYM pSym = dbgfR3SymbolGetAddr(pVM, Address);
922 if (pSym)
923 {
924 pSymbol->Value = pSym->Core.Key;
925 pSymbol->cb = pSym->Core.KeyLast - pSym->Core.Key + 1;
926 pSymbol->fFlags = 0;
927 pSymbol->szName[0] = '\0';
928 strncat(pSymbol->szName, pSym->szName, sizeof(pSymbol->szName) - 1);
929 if (poffDisplacement)
930 *poffDisplacement = Address - pSymbol->Value;
931 return VINF_SUCCESS;
932 }
933
934#endif
935
936 /*
937 * Try PDM.
938 */
939 if ( !HMIsEnabled(pVM)
940 && MMHyperIsInsideArea(pVM, Address))
941 {
942 char szModName[64];
943 RTRCPTR RCPtrMod;
944 char szNearSym1[260];
945 RTRCPTR RCPtrNearSym1;
946 char szNearSym2[260];
947 RTRCPTR RCPtrNearSym2;
948 int rc = PDMR3LdrQueryRCModFromPC(pVM, Address,
949 &szModName[0], sizeof(szModName), &RCPtrMod,
950 &szNearSym1[0], sizeof(szNearSym1), &RCPtrNearSym1,
951 &szNearSym2[0], sizeof(szNearSym2), &RCPtrNearSym2);
952 if (RT_SUCCESS(rc) && szNearSym1[0])
953 {
954 pSymbol->Value = RCPtrNearSym1;
955 pSymbol->cb = RCPtrNearSym2 > RCPtrNearSym1 ? RCPtrNearSym2 - RCPtrNearSym1 : 0;
956 pSymbol->fFlags = 0;
957 pSymbol->szName[0] = '\0';
958 strncat(pSymbol->szName, szNearSym1, sizeof(pSymbol->szName) - 1);
959 if (poffDisplacement)
960 *poffDisplacement = Address - pSymbol->Value;
961 return VINF_SUCCESS;
962 }
963 }
964
965 return VERR_SYMBOL_NOT_FOUND;
966}
967
968
969/**
970 * Find symbol by name (first).
971 *
972 * @returns VBox status.
973 * @param pVM Pointer to the VM.
974 * @param pszSymbol Symbol name.
975 * @param pSymbol Where to store the symbol info.
976 */
977VMMR3_INT_DECL(int) DBGFR3SymbolByName(PVM pVM, const char *pszSymbol, PDBGFSYMBOL pSymbol)
978{
979 /*
980 * Lazy init.
981 */
982 if (!pVM->dbgf.s.fSymInited)
983 {
984 int rc = dbgfR3SymLazyInit(pVM);
985 if (RT_FAILURE(rc))
986 return rc;
987 }
988
989 /*
990 * Look it up.
991 */
992#ifdef HAVE_DBGHELP
993 char achBuffer[sizeof(IMAGEHLP_SYMBOL64) + DBGF_SYMBOL_NAME_LENGTH * sizeof(TCHAR) + sizeof(ULONG64)];
994 PIMAGEHLP_SYMBOL64 pSym = (PIMAGEHLP_SYMBOL64)&achBuffer[0];
995 pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
996 pSym->MaxNameLength = DBGF_SYMBOL_NAME_LENGTH;
997
998 if (SymGetSymFromName64(pVM, (char *)(void *)pszSymbol, pSym))
999 {
1000 pSymbol->Value = (RTGCUINTPTR)pSym->Address;
1001 pSymbol->cb = pSym->Size;
1002 pSymbol->fFlags = pSym->Flags;
1003 strcpy(pSymbol->szName, pSym->Name);
1004 return VINF_SUCCESS;
1005 }
1006 return win32Error(pVM);
1007#else
1008
1009 PDBGFSYM pSym = dbgfR3SymbolGetName(pVM, pszSymbol);
1010 if (pSym)
1011 {
1012 pSymbol->Value = pSym->Core.Key;
1013 pSymbol->cb = pSym->Core.KeyLast - pSym->Core.Key + 1;
1014 pSymbol->fFlags = 0;
1015 pSymbol->szName[0] = '\0';
1016 strncat(pSymbol->szName, pSym->szName, sizeof(pSymbol->szName) - 1);
1017 return VINF_SUCCESS;
1018 }
1019
1020 return VERR_SYMBOL_NOT_FOUND;
1021#endif
1022}
1023
1024
1025/**
1026 * Find line by address (nearest).
1027 *
1028 * @returns VBox status.
1029 * @param pUVM The user mode VM handle.
1030 * @param Address Address.
1031 * @param poffDisplacement Where to store the line displacement from Address.
1032 * @param pLine Where to store the line info.
1033 */
1034VMMR3DECL(int) DBGFR3LineByAddr(PUVM pUVM, RTGCUINTPTR Address, PRTGCINTPTR poffDisplacement, PDBGFLINE pLine)
1035{
1036 /*
1037 * Lazy init.
1038 */
1039 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1040 PVM pVM = pUVM->pVM;
1041 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1042 if (!pVM->dbgf.s.fSymInited)
1043 {
1044 int rc = dbgfR3SymLazyInit(pVM);
1045 if (RT_FAILURE(rc))
1046 return rc;
1047 }
1048
1049 /*
1050 * Look it up.
1051 */
1052#ifdef HAVE_DBGHELP
1053 IMAGEHLP_LINE64 Line = {0};
1054 DWORD off = 0;
1055 Line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
1056 if (SymGetLineFromAddr64(pVM, Address, &off, &Line))
1057 {
1058 if (poffDisplacement)
1059 *poffDisplacement = (long)off;
1060 pLine->Address = (RTGCUINTPTR)Line.Address;
1061 pLine->uLineNo = Line.LineNumber;
1062 pLine->szFilename[0] = '\0';
1063 strncat(pLine->szFilename, Line.FileName, sizeof(pLine->szFilename));
1064 return VINF_SUCCESS;
1065 }
1066 return win32Error(pVM);
1067#else
1068 NOREF(pVM); NOREF(Address); NOREF(poffDisplacement); NOREF(pLine);
1069 return VERR_NOT_IMPLEMENTED;
1070#endif
1071}
1072
1073
1074/**
1075 * Duplicates a line.
1076 *
1077 * @returns VBox status code.
1078 * @param pUVM The user mode VM handle.
1079 * @param pLine The line to duplicate.
1080 */
1081static PDBGFLINE dbgfR3LineDup(PUVM pUVM, PCDBGFLINE pLine)
1082{
1083 size_t cb = strlen(pLine->szFilename) + RT_OFFSETOF(DBGFLINE, szFilename[1]);
1084 PDBGFLINE pDup = (PDBGFLINE)MMR3HeapAllocU(pUVM, MM_TAG_DBGF_LINE_DUP, cb);
1085 if (pDup)
1086 memcpy(pDup, pLine, cb);
1087 return pDup;
1088}
1089
1090
1091/**
1092 * Find line by address (nearest), allocate return buffer.
1093 *
1094 * @returns Pointer to the line. Must be freed using DBGFR3LineFree().
1095 * @returns NULL if the line was not found or if we're out of memory.
1096 * @param pUVM The user mode VM handle.
1097 * @param Address Address.
1098 * @param poffDisplacement Where to store the line displacement from Address.
1099 */
1100VMMR3DECL(PDBGFLINE) DBGFR3LineByAddrAlloc(PUVM pUVM, RTGCUINTPTR Address, PRTGCINTPTR poffDisplacement)
1101{
1102 DBGFLINE Line;
1103 int rc = DBGFR3LineByAddr(pUVM, Address, poffDisplacement, &Line);
1104 if (RT_FAILURE(rc))
1105 return NULL;
1106 return dbgfR3LineDup(pUVM, &Line);
1107}
1108
1109
1110/**
1111 * Frees a line returned by DBGFR3LineByAddressAlloc().
1112 *
1113 * @param pLine Pointer to the line.
1114 */
1115VMMR3_INT_DECL(void) DBGFR3LineFree(PDBGFLINE pLine)
1116{
1117 if (pLine)
1118 MMR3HeapFree(pLine);
1119}
1120
1121
1122#ifdef HAVE_DBGHELP
1123
1124//static BOOL CALLBACK win32EnumModulesCallback(PSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext)
1125//{
1126// Log(("dbg: module: %08llx %s\n", ModuleName, BaseOfDll));
1127// return TRUE;
1128//}
1129
1130static int win32Error(PVM pVM)
1131{
1132 int rc = GetLastError();
1133 Log(("Lasterror=%d\n", rc));
1134
1135 //SymEnumerateModules64(pVM, win32EnumModulesCallback, NULL);
1136
1137 return VERR_GENERAL_FAILURE;
1138}
1139#endif
1140
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