VirtualBox

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

Last change on this file since 19 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.4 KB
Line 
1/** @file
2 *
3 * VMM DBGF - Debugger Facility, Symbol Management.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_DBGF
27#if defined(__WIN32__) && defined(DEBUG_bird) // enabled this is you want to debug win32 guests or the hypervisor.
28# include <Windows.h>
29# define _IMAGEHLP64
30# include <DbgHelp.h>
31# define HAVE_DBGHELP /* if doing guest stuff, this can be nice. */
32#endif
33/** @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)! */
34#include <VBox/dbgf.h>
35#include "DBGFInternal.h"
36#include <VBox/vm.h>
37#include <VBox/mm.h>
38#include <VBox/pdm.h>
39#include <VBox/err.h>
40#include <VBox/log.h>
41#include <iprt/assert.h>
42
43#ifndef HAVE_DBGHELP
44# include <iprt/avl.h>
45# include <iprt/string.h>
46# include <string.h>
47#endif
48
49#include <ctype.h>
50#include <stdio.h>
51#include <stdlib.h>
52
53
54
55/*******************************************************************************
56* Internal Functions *
57*******************************************************************************/
58#ifdef HAVE_DBGHELP
59static DECLCALLBACK(int) dbgfR3EnumModules(PVM pVM, const char *pszFilename, const char *pszName, RTUINTPTR ImageBase, unsigned cbImage, bool fGC);
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 represenation of a symbol.
73 */
74typedef struct DBGFSYM
75{
76 /** Node core with the symbol address range. */
77 AVLROGCPTRNODECORE 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 (RTAvlroGCPtrInsert(&pVM->dbgf.s.SymbolTree, &pSym->Core))
120 return VINF_SUCCESS;
121 AssertReleaseMsgFailed(("Failed to insert %VGv-%VGv!\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)RTAvlroGCPtrRangeGet(&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)RTAvlroGCPtrRemove(&pVM->dbgf.s.SymbolTree, (RTGCPTR)Address);
152 AssertRelease(pOld);
153 MMR3HeapFree(pOld);
154 }
155 else
156 pOld->Core.KeyLast = Address - 1;
157 if (RTAvlroGCPtrInsert(&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 PDBGFSYMSPACE 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 %VGv-%VGv!\n", pSym->Core.Key, pSym->Core.KeyLast));
186 }
187 else
188 AssertMsgFailed(("pOld! %VGv %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)RTAvlroGCPtrRangeGet(&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 && isspace(*psz))
231 psz++;
232 char *psz2 = strchr(psz, '\0') - 1;
233 while (psz2 >= psz && isspace(*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 The VM handle.
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 (VBOX_FAILURE(rc))
262 return rc;
263 pVM->dbgf.s.fSymInited = true;
264#endif
265
266 /*
267 * Check if there are 'loadsyms' commands in the configuration.
268 */
269 PCFGMNODE pNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "/DBGF/loadsyms/");
270 if (pNode)
271 {
272 /*
273 * Enumerate the commands.
274 */
275 for (PCFGMNODE pCmdNode = CFGMR3GetFirstChild(pNode);
276 pCmdNode;
277 pCmdNode = CFGMR3GetNextChild(pCmdNode))
278 {
279 char szCmdName[128];
280 CFGMR3GetName(pCmdNode, &szCmdName[0], sizeof(szCmdName));
281
282 /* File */
283 char *pszFilename;
284 rc = CFGMR3QueryStringAlloc(pCmdNode, "Filename", &pszFilename);
285 AssertMsgRCReturn(rc, ("rc=%Vrc querying the 'File' attribute of '/DBGF/loadsyms/%s'!\n", rc, szCmdName), rc);
286
287 /* Delta (optional) */
288 RTGCINTPTR offDelta;
289 rc = CFGMR3QueryGCPtrS(pNode, "Delta", &offDelta);
290 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
291 offDelta = 0;
292 else
293 AssertMsgRCReturn(rc, ("rc=%Vrc querying the 'Delta' attribute of '/DBGF/loadsyms/%s'!\n", rc, szCmdName), rc);
294
295 /* Module (optional) */
296 char *pszModule;
297 rc = CFGMR3QueryStringAlloc(pCmdNode, "Module", &pszModule);
298 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
299 pszModule = NULL;
300 else
301 AssertMsgRCReturn(rc, ("rc=%Vrc querying the 'Module' attribute of '/DBGF/loadsyms/%s'!\n", rc, szCmdName), rc);
302
303 /* Module (optional) */
304 RTGCUINTPTR ModuleAddress;
305 rc = CFGMR3QueryGCPtrU(pNode, "ModuleAddress", &ModuleAddress);
306 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
307 ModuleAddress = 0;
308 else
309 AssertMsgRCReturn(rc, ("rc=%Vrc querying the 'ModuleAddress' attribute of '/DBGF/loadsyms/%s'!\n", rc, szCmdName), rc);
310
311 /* Image size (optional) */
312 RTGCUINTPTR cbModule;
313 rc = CFGMR3QueryGCPtrU(pNode, "ModuleSize", &cbModule);
314 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
315 cbModule = 0;
316 else
317 AssertMsgRCReturn(rc, ("rc=%Vrc querying the 'ModuleAddress' attribute of '/DBGF/loadsyms/%s'!\n", rc, szCmdName), rc);
318
319
320 /*
321 * Execute the command.
322 */
323 rc = DBGFR3ModuleLoad(pVM, pszFilename, offDelta, pszModule, ModuleAddress, cbModule);
324 AssertMsgRCReturn(rc, ("pszFilename=%s offDelta=%RGv pszModule=%s ModuleAddress=%RGv cbModule=%RGv\n",
325 pszFilename, offDelta, pszModule, ModuleAddress, cbModule), rc);
326
327 MMR3HeapFree(pszModule);
328 MMR3HeapFree(pszFilename);
329 }
330 }
331
332 /*
333 * Check if there are any 'symadd' commands in the configuration.
334 */
335
336 return VINF_SUCCESS;
337}
338
339
340/**
341 * We delay certain
342 * Initialize the debug info for a VM.
343 */
344int dbgfR3SymLazyInit(PVM pVM)
345{
346 if (pVM->dbgf.s.fSymInited)
347 return VINF_SUCCESS;
348#ifdef HAVE_DBGHELP
349 if (SymInitialize(pVM, NULL, FALSE))
350 {
351 pVM->dbgf.s.fSymInited = true;
352 SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
353
354 /*
355 * Enumerate all modules loaded by PDM and add them to the symbol database.
356 */
357 PDMR3EnumModules(pVM, dbgfR3EnumModules, NULL);
358 return VINF_SUCCESS;
359 }
360 return win32Error(pVM);
361#else
362 return VINF_SUCCESS;
363#endif
364}
365
366
367#ifdef HAVE_DBGHELP
368/**
369 * Module enumeration callback function.
370 *
371 * @returns VBox status.
372 * Failure will stop the search and return the return code.
373 * Warnings will be ignored and not returned.
374 * @param pVM VM Handle.
375 * @param pszFilename Module filename.
376 * @param pszName Module name. (short and unique)
377 * @param ImageBase Address where to executable image is loaded.
378 * @param cbImage Size of the executable image.
379 * @param fGC Set if guest context, clear if host context.
380 * @param pvArg User argument.
381 */
382static DECLCALLBACK(int) dbgfR3EnumModules(PVM pVM, const char *pszFilename, const char *pszName, RTUINTPTR ImageBase, unsigned cbImage, bool fGC)
383{
384 if (fGC)
385 {
386 DWORD64 LoadedImageBase = SymLoadModule64(pVM, NULL, (char *)(void *)pszFilename, (char *)(void *)pszName, ImageBase, cbImage);
387 if (!LoadedImageBase)
388 Log(("SymLoadModule64(,,%s,,) -> lasterr=%d\n", pszFilename, GetLastError()));
389 else
390 Log(("Loaded debuginfo for %s - %s %llx\n", pszName, pszFilename, LoadedImageBase));
391 }
392 return VINF_SUCCESS;
393}
394#endif
395
396
397/**
398 * Terminate the debug info repository for the specified VM.
399 *
400 * @returns VBox status.
401 * @param pVM VM Handle.
402 */
403int dbgfR3SymTerm(PVM pVM)
404{
405#ifdef HAVE_DBGHELP
406 if (pVM->dbgf.s.fSymInited)
407 SymCleanup(pVM);
408 pVM->dbgf.s.fSymInited = false;
409 return VINF_SUCCESS;
410#else
411 pVM->dbgf.s.SymbolTree = 0; /* MM cleans up allocations */
412 pVM->dbgf.s.fSymInited = false;
413 return VINF_SUCCESS;
414#endif
415}
416
417
418/** Symbol file type.. */
419typedef enum SYMFILETYPE
420{
421 SYMFILETYPE_UNKNOWN,
422 SYMFILETYPE_LD_MAP,
423 SYMFILETYPE_MS_MAP,
424 SYMFILETYPE_OBJDUMP,
425 SYMFILETYPE_LINUX_SYSTEM_MAP,
426 SYMFILETYPE_PDB,
427 SYMFILETYPE_DBG,
428 SYMFILETYPE_MZ,
429 SYMFILETYPE_ELF
430} SYMFILETYPE, *PSYMFILETYPE;
431
432
433
434/**
435 * Probe the type of a symbol information file.
436 *
437 * @returns The file type.
438 * @param pFile File handle.
439 */
440SYMFILETYPE dbgfR3ModuleProbe(FILE *pFile)
441{
442 char szHead[4096];
443 size_t cchHead = fread(szHead, 1, sizeof(szHead) - 1, pFile);
444 if (cchHead > 0)
445 {
446 szHead[cchHead] = '\0';
447 if (strstr(szHead, "Preferred load address is"))
448 return SYMFILETYPE_MS_MAP;
449
450 if ( strstr(szHead, "Archive member included because of")
451 || strstr(szHead, "Memory Configuration")
452 || strstr(szHead, "Linker script and memory map"))
453 return SYMFILETYPE_LD_MAP;
454
455 if ( isxdigit(szHead[0])
456 && isxdigit(szHead[1])
457 && isxdigit(szHead[2])
458 && isxdigit(szHead[3])
459 && isxdigit(szHead[4])
460 && isxdigit(szHead[5])
461 && isxdigit(szHead[6])
462 && isxdigit(szHead[7])
463 && szHead[8] == ' '
464 && isalpha(szHead[9])
465 && szHead[10] == ' '
466 && (isalpha(szHead[11]) || szHead[11] == '_' || szHead[11] == '$')
467 )
468 return SYMFILETYPE_LINUX_SYSTEM_MAP;
469
470 if (strstr(szHead, "Microsoft C/C++ MSF") == szHead)
471 return SYMFILETYPE_PDB;
472
473 if (strstr(szHead, "ELF") == szHead + 1)
474 return SYMFILETYPE_ELF;
475
476 if ( strstr(szHead, "MZ") == szHead
477 || strstr(szHead, "PE") == szHead
478 || strstr(szHead, "LE") == szHead
479 || strstr(szHead, "LX") == szHead
480 || strstr(szHead, "NE") == szHead)
481 return SYMFILETYPE_MZ;
482
483
484 if (strstr(szHead, "file format"))
485 return SYMFILETYPE_OBJDUMP;
486 }
487
488 return SYMFILETYPE_UNKNOWN;
489}
490
491
492static int dbgfR3LoadLinuxSystemMap(PVM pVM, FILE *pFile, RTGCUINTPTR ModuleAddress, RTGCUINTPTR AddressDelta)
493{
494 char szLine[4096];
495 while (fgets(szLine, sizeof(szLine), pFile))
496 {
497 /* parse the line: <address> <type> <name> */
498 const char *psz = dbgfR3Strip(szLine);
499 char *pszEnd = NULL;
500 RTGCUINTPTR Address = strtoul(psz, &pszEnd, 16);
501 if ( pszEnd && (*pszEnd == ' ' || *pszEnd == '\t')
502 && Address != 0
503 && Address != (RTGCUINTPTR)~0)
504 {
505 pszEnd++;
506 if ( isalpha(*pszEnd)
507 && (pszEnd[1] == ' ' || pszEnd[1] == '\t'))
508 {
509 psz = dbgfR3Strip(pszEnd + 2);
510 if (*psz)
511 {
512 int rc2 = DBGFR3SymbolAdd(pVM, ModuleAddress, Address + AddressDelta, 0, psz);
513 if (VBOX_FAILURE(rc2))
514 Log2(("DBGFR3SymbolAdd(,, %#VGv, 0, '%s') -> %VRc\n", Address, psz, rc2));
515 }
516 }
517 }
518 }
519 return VINF_SUCCESS;
520}
521
522
523/**
524 * Load debug info, optionally related to a specific module.
525 *
526 * @returns VBox status.
527 * @param pVM VM Handle.
528 * @param pszFilename Path to the file containing the symbol information.
529 * This can be the executable image, a flat symbol file of some kind or stripped debug info.
530 * @param AddressDelta The value to add to the loaded symbols.
531 * @param pszName Short hand name for the module. If not related to a module specify NULL.
532 * @param ModuleAddress Address which the image is loaded at. This will be used to reference the module other places in the api.
533 * Ignored when pszName is NULL.
534 * @param cbImage Size of the image.
535 * Ignored when pszName is NULL.
536 */
537DBGFR3DECL(int) DBGFR3ModuleLoad(PVM pVM, const char *pszFilename, RTGCUINTPTR AddressDelta, const char *pszName, RTGCUINTPTR ModuleAddress, unsigned cbImage)
538{
539 /*
540 * Lazy init.
541 */
542 if (!pVM->dbgf.s.fSymInited)
543 {
544 int rc = dbgfR3SymLazyInit(pVM);
545 if (VBOX_FAILURE(rc))
546 return rc;
547 }
548
549 /*
550 * Open the load file.
551 */
552 int rc = VINF_SUCCESS;
553 FILE *pFile = fopen(pszFilename, "rb");
554 if (pFile)
555 {
556 /*
557 * Probe the file type.
558 */
559 SYMFILETYPE enmType = dbgfR3ModuleProbe(pFile);
560 if (enmType != SYMFILETYPE_UNKNOWN)
561 {
562 /*
563 * Add the module.
564 */
565 if (pszName)
566 {
567 #ifdef HAVE_DBGHELP
568 /** @todo arg! checkout the inserting of modules and then loading them again.... Or just the module representation.... */
569 DWORD64 ImageBase = SymLoadModule64(pVM, NULL, (char *)(void *)pszFilename, (char *)(void *)pszName, ModuleAddress, cbImage);
570 if (!ImageBase)
571 ImageBase = SymLoadModule64(pVM, NULL, (char *)(void *)pszName, (char *)(void *)pszName, ModuleAddress, cbImage);
572 if (ImageBase)
573 {
574 AssertMsg(ModuleAddress == 0 || ModuleAddress == ImageBase, ("ModuleAddres=%VGv ImageBase=%llx\n", ModuleAddress, ImageBase));
575 ModuleAddress = ImageBase;
576 }
577 else
578 rc = win32Error(pVM);
579 #else
580 rc = VERR_NOT_IMPLEMENTED;
581 #endif
582 }
583 if (VBOX_SUCCESS(rc))
584 {
585 /*
586 * Seek to the start of the file.
587 */
588 rc = fseek(pFile, 0, SEEK_SET);
589 Assert(!rc);
590
591 /*
592 * Process the specific.
593 */
594 switch (enmType)
595 {
596 case SYMFILETYPE_LINUX_SYSTEM_MAP:
597 rc = dbgfR3LoadLinuxSystemMap(pVM, pFile, ModuleAddress, AddressDelta);
598 break;
599
600 case SYMFILETYPE_PDB:
601 case SYMFILETYPE_DBG:
602 case SYMFILETYPE_MZ:
603 #ifdef HAVE_DBGHELP
604 /* done it all above! */
605 break;
606 #endif
607 case SYMFILETYPE_LD_MAP:
608 case SYMFILETYPE_MS_MAP:
609 case SYMFILETYPE_OBJDUMP:
610 case SYMFILETYPE_ELF:
611 rc = VERR_NOT_SUPPORTED;
612 break;
613
614 default:
615 AssertFailed();
616 rc = VERR_INTERNAL_ERROR;
617 break;
618 } /* file switch. */
619 } /* module added successfully. */
620 } /* format identified */
621 else
622 rc = VERR_NOT_SUPPORTED;
623 /** @todo check for read errors */
624 fclose(pFile);
625 }
626 else
627 rc = VERR_OPEN_FAILED;
628 return rc;
629}
630
631
632/**
633 * Interface used by PDMR3LdrRelocate for telling us that a GC module has been relocated.
634 *
635 * @param pVM The VM handle.
636 * @param OldImageBase The old image base.
637 * @param NewImageBase The new image base.
638 * @param cbImage The image size.
639 * @param pszFilename The image filename.
640 * @param pszName The module name.
641 */
642DBGFR3DECL(void) DBGFR3ModuleRelocate(PVM pVM, RTGCUINTPTR OldImageBase, RTGCUINTPTR NewImageBase, unsigned cbImage,
643 const char *pszFilename, const char *pszName)
644{
645#ifdef HAVE_DBGHELP
646 if (pVM->dbgf.s.fSymInited)
647 {
648 if (!SymUnloadModule64(pVM, OldImageBase))
649 Log(("SymUnloadModule64(,%VGv) failed, lasterr=%d\n", OldImageBase, GetLastError()));
650
651 DWORD64 LoadedImageBase = SymLoadModule64(pVM, NULL, (char *)(void *)pszFilename, (char *)(void *)pszName, NewImageBase, cbImage);
652 if (!LoadedImageBase)
653 Log(("SymLoadModule64(,,%s,,) -> lasterr=%d (relocate)\n", pszFilename, GetLastError()));
654 else
655 Log(("Reloaded debuginfo for %s - %s %llx\n", pszName, pszFilename, LoadedImageBase));
656 }
657#else
658
659#endif
660}
661
662
663/**
664 * Adds a symbol to the debug info manager.
665 *
666 * @returns VBox status.
667 * @param pVM VM Handle.
668 * @param ModuleAddress Module address. Use 0 if no module.
669 * @param SymbolAddress Symbol address
670 * @param cbSymbol Size of the symbol. Use 0 if info not available.
671 * @param pszSymbol Symbol name.
672 */
673DBGFR3DECL(int) DBGFR3SymbolAdd(PVM pVM, RTGCUINTPTR ModuleAddress, RTGCUINTPTR SymbolAddress, RTUINT cbSymbol, const char *pszSymbol)
674{
675 /*
676 * Validate.
677 */
678 if (!pszSymbol || !*pszSymbol)
679 {
680 AssertMsgFailed(("No symbol name!\n"));
681 return VERR_INVALID_PARAMETER;
682 }
683
684 /*
685 * Lazy init.
686 */
687 if (!pVM->dbgf.s.fSymInited)
688 {
689 int rc = dbgfR3SymLazyInit(pVM);
690 if (VBOX_FAILURE(rc))
691 return rc;
692 }
693
694#ifdef HAVE_DBGHELP
695 if (SymAddSymbol(pVM, ModuleAddress, (char *)(void *)pszSymbol, SymbolAddress, cbSymbol, 0))
696 return VINF_SUCCESS;
697 return win32Error(pVM);
698#else
699 /** @todo module lookup. */
700 return dbgfR3SymbolInsert(pVM, pszSymbol, SymbolAddress, cbSymbol, NULL);
701#endif
702}
703
704
705/**
706 * Find symbol by address (nearest).
707 *
708 * @returns VBox status.
709 * @param pVM VM handle.
710 * @param Address Address.
711 * @param poffDisplacement Where to store the symbol displacement from Address.
712 * @param pSymbol Where to store the symbol info.
713 */
714DBGFR3DECL(int) DBGFR3SymbolByAddr(PVM pVM, RTGCUINTPTR Address, PRTGCINTPTR poffDisplacement, PDBGFSYMBOL pSymbol)
715{
716 /*
717 * Lazy init.
718 */
719 if (!pVM->dbgf.s.fSymInited)
720 {
721 int rc = dbgfR3SymLazyInit(pVM);
722 if (VBOX_FAILURE(rc))
723 return rc;
724 }
725
726 /*
727 * Look it up.
728 */
729#ifdef HAVE_DBGHELP
730 char achBuffer[sizeof(IMAGEHLP_SYMBOL64) + DBGF_SYMBOL_NAME_LENGTH * sizeof(TCHAR) + sizeof(ULONG64)];
731 PIMAGEHLP_SYMBOL64 pSym = (PIMAGEHLP_SYMBOL64)&achBuffer[0];
732 pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
733 pSym->MaxNameLength = DBGF_SYMBOL_NAME_LENGTH;
734
735 if (SymGetSymFromAddr64(pVM, Address, (PDWORD64)poffDisplacement, pSym))
736 {
737 pSymbol->Value = (RTGCUINTPTR)pSym->Address;
738 pSymbol->cb = pSym->Size;
739 pSymbol->fFlags = pSym->Flags;
740 strcpy(pSymbol->szName, pSym->Name);
741 return VINF_SUCCESS;
742 }
743 //return win32Error(pVM);
744
745#else
746
747 PDBGFSYM pSym = dbgfR3SymbolGetAddr(pVM, Address);
748 if (pSym)
749 {
750 pSymbol->Value = pSym->Core.Key;
751 pSymbol->cb = pSym->Core.KeyLast - pSym->Core.Key + 1;
752 pSymbol->fFlags = 0;
753 pSymbol->szName[0] = '\0';
754 strncat(pSymbol->szName, pSym->szName, sizeof(pSymbol->szName) - 1);
755 if (poffDisplacement)
756 *poffDisplacement = Address - pSymbol->Value;
757 return VINF_SUCCESS;
758 }
759
760#endif
761
762 /*
763 * Try PDM.
764 */
765 if (MMHyperIsInsideArea(pVM, Address))
766 {
767 char szModName[64];
768 RTGCPTR GCPtrMod;
769 char szNearSym1[260];
770 RTGCPTR GCPtrNearSym1;
771 char szNearSym2[260];
772 RTGCPTR GCPtrNearSym2;
773 int rc = PDMR3QueryModFromEIP(pVM, Address,
774 &szModName[0], sizeof(szModName), &GCPtrMod,
775 &szNearSym1[0], sizeof(szNearSym1), &GCPtrNearSym1,
776 &szNearSym2[0], sizeof(szNearSym2), &GCPtrNearSym2);
777 if (VBOX_SUCCESS(rc) && szNearSym1[0])
778 {
779 pSymbol->Value = GCPtrNearSym1;
780 pSymbol->cb = GCPtrNearSym2 > GCPtrNearSym1 ? GCPtrNearSym2 - GCPtrNearSym1 : 0;
781 pSymbol->fFlags = 0;
782 pSymbol->szName[0] = '\0';
783 strncat(pSymbol->szName, szNearSym1, sizeof(pSymbol->szName) - 1);
784 if (poffDisplacement)
785 *poffDisplacement = Address - pSymbol->Value;
786 return VINF_SUCCESS;
787 }
788 }
789
790 return VERR_SYMBOL_NOT_FOUND;
791}
792
793
794/**
795 * Find symbol by name (first).
796 *
797 * @returns VBox status.
798 * @param pVM VM handle.
799 * @param pszSymbol Symbol name.
800 * @param pSymbol Where to store the symbol info.
801 */
802DBGFR3DECL(int) DBGFR3SymbolByName(PVM pVM, const char *pszSymbol, PDBGFSYMBOL pSymbol)
803{
804 /*
805 * Lazy init.
806 */
807 if (!pVM->dbgf.s.fSymInited)
808 {
809 int rc = dbgfR3SymLazyInit(pVM);
810 if (VBOX_FAILURE(rc))
811 return rc;
812 }
813
814 /*
815 * Look it up.
816 */
817#ifdef HAVE_DBGHELP
818 char achBuffer[sizeof(IMAGEHLP_SYMBOL64) + DBGF_SYMBOL_NAME_LENGTH * sizeof(TCHAR) + sizeof(ULONG64)];
819 PIMAGEHLP_SYMBOL64 pSym = (PIMAGEHLP_SYMBOL64)&achBuffer[0];
820 pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
821 pSym->MaxNameLength = DBGF_SYMBOL_NAME_LENGTH;
822
823 if (SymGetSymFromName64(pVM, (char *)(void *)pszSymbol, pSym))
824 {
825 pSymbol->Value = (RTGCUINTPTR)pSym->Address;
826 pSymbol->cb = pSym->Size;
827 pSymbol->fFlags = pSym->Flags;
828 strcpy(pSymbol->szName, pSym->Name);
829 return VINF_SUCCESS;
830 }
831 return win32Error(pVM);
832#else
833
834 PDBGFSYM pSym = dbgfR3SymbolGetName(pVM, pszSymbol);
835 if (pSym)
836 {
837 pSymbol->Value = pSym->Core.Key;
838 pSymbol->cb = pSym->Core.KeyLast - pSym->Core.Key + 1;
839 pSymbol->fFlags = 0;
840 pSymbol->szName[0] = '\0';
841 strncat(pSymbol->szName, pSym->szName, sizeof(pSymbol->szName) - 1);
842 return VINF_SUCCESS;
843 }
844
845 return VERR_SYMBOL_NOT_FOUND;
846#endif
847}
848
849
850/**
851 * Duplicates a symbol.
852 *
853 * @returns Pointer to the duplicated symbol.
854 * @param pVM The VM handle.
855 * @param pSymbol The symbol to duplicate.
856 */
857static PDBGFSYMBOL dbgfR3SymbolDup(PVM pVM, PCDBGFSYMBOL pSymbol)
858{
859 size_t cb = strlen(pSymbol->szName) + RT_OFFSETOF(DBGFSYMBOL, szName[1]);
860 PDBGFSYMBOL pDup = (PDBGFSYMBOL)MMR3HeapAlloc(pVM, MM_TAG_DBGF_SYMBOL_DUP, cb);
861 if (pDup)
862 memcpy(pDup, pSymbol, cb);
863 return pDup;
864}
865
866
867/**
868 * Find symbol by address (nearest), allocate return buffer.
869 *
870 * @returns Pointer to the symbol. Must be freed using DBGFR3SymbolFree().
871 * @returns NULL if the symbol was not found or if we're out of memory.
872 * @param pVM VM handle.
873 * @param Address Address.
874 * @param poffDisplacement Where to store the symbol displacement from Address.
875 */
876DBGFR3DECL(PDBGFSYMBOL) DBGFR3SymbolByAddrAlloc(PVM pVM, RTGCUINTPTR Address, PRTGCINTPTR poffDisplacement)
877{
878 DBGFSYMBOL Symbol;
879 int rc = DBGFR3SymbolByAddr(pVM, Address, poffDisplacement, &Symbol);
880 if (VBOX_FAILURE(rc))
881 return NULL;
882 return dbgfR3SymbolDup(pVM, &Symbol);
883}
884
885
886/**
887 * Find symbol by name (first), allocate return buffer.
888 *
889 * @returns Pointer to the symbol. Must be freed using DBGFR3SymbolFree().
890 * @returns NULL if the symbol was not found or if we're out of memory.
891 * @param pVM VM handle.
892 * @param pszSymbol Symbol name.
893 */
894DBGFR3DECL(PDBGFSYMBOL) DBGFR3SymbolByNameAlloc(PVM pVM, const char *pszSymbol)
895{
896 DBGFSYMBOL Symbol;
897 int rc = DBGFR3SymbolByName(pVM, pszSymbol, &Symbol);
898 if (VBOX_FAILURE(rc))
899 return NULL;
900 return dbgfR3SymbolDup(pVM, &Symbol);
901}
902
903
904/**
905 * Frees a symbol returned by DBGFR3SymbolbyNameAlloc() or DBGFR3SymbolByAddressAlloc().
906 *
907 * @param pSymbol Pointer to the symbol.
908 */
909DBGFR3DECL(void) DBGFR3SymbolFree(PDBGFSYMBOL pSymbol)
910{
911 if (pSymbol)
912 MMR3HeapFree(pSymbol);
913}
914
915
916/**
917 * Find line by address (nearest).
918 *
919 * @returns VBox status.
920 * @param pVM VM handle.
921 * @param Address Address.
922 * @param poffDisplacement Where to store the line displacement from Address.
923 * @param pLine Where to store the line info.
924 */
925DBGFR3DECL(int) DBGFR3LineByAddr(PVM pVM, RTGCUINTPTR Address, PRTGCINTPTR poffDisplacement, PDBGFLINE pLine)
926{
927 /*
928 * Lazy init.
929 */
930 if (!pVM->dbgf.s.fSymInited)
931 {
932 int rc = dbgfR3SymLazyInit(pVM);
933 if (VBOX_FAILURE(rc))
934 return rc;
935 }
936
937 /*
938 * Look it up.
939 */
940#ifdef HAVE_DBGHELP
941 IMAGEHLP_LINE64 Line = {0};
942 DWORD off = 0;
943 Line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
944 if (SymGetLineFromAddr64(pVM, Address, &off, &Line))
945 {
946 if (poffDisplacement)
947 *poffDisplacement = (long)off;
948 pLine->Address = (RTGCUINTPTR)Line.Address;
949 pLine->uLineNo = Line.LineNumber;
950 pLine->szFilename[0] = '\0';
951 strncat(pLine->szFilename, Line.FileName, sizeof(pLine->szFilename));
952 return VINF_SUCCESS;
953 }
954 return win32Error(pVM);
955#else
956 return VERR_NOT_IMPLEMENTED;
957#endif
958}
959
960
961/**
962 * Duplicates a line.
963 *
964 * @returns VBox status code.
965 * @param pVM The VM handle.
966 * @param pLine The line to duplicate.
967 */
968static PDBGFLINE dbgfR3LineDup(PVM pVM, PCDBGFLINE pLine)
969{
970 size_t cb = strlen(pLine->szFilename) + RT_OFFSETOF(DBGFLINE, szFilename[1]);
971 PDBGFLINE pDup = (PDBGFLINE)MMR3HeapAlloc(pVM, MM_TAG_DBGF_LINE_DUP, cb);
972 if (pDup)
973 memcpy(pDup, pLine, cb);
974 return pDup;
975}
976
977
978/**
979 * Find line by address (nearest), allocate return buffer.
980 *
981 * @returns Pointer to the line. Must be freed using DBGFR3LineFree().
982 * @returns NULL if the line was not found or if we're out of memory.
983 * @param pVM VM handle.
984 * @param Address Address.
985 * @param poffDisplacement Where to store the line displacement from Address.
986 */
987DBGFR3DECL(PDBGFLINE) DBGFR3LineByAddrAlloc(PVM pVM, RTGCUINTPTR Address, PRTGCINTPTR poffDisplacement)
988{
989 DBGFLINE Line;
990 int rc = DBGFR3LineByAddr(pVM, Address, poffDisplacement, &Line);
991 if (VBOX_FAILURE(rc))
992 return NULL;
993 return dbgfR3LineDup(pVM, &Line);
994}
995
996
997/**
998 * Frees a line returned by DBGFR3LineByAddressAlloc().
999 *
1000 * @param pLine Pointer to the line.
1001 */
1002DBGFR3DECL(void) DBGFR3LineFree(PDBGFLINE pLine)
1003{
1004 if (pLine)
1005 MMR3HeapFree(pLine);
1006}
1007
1008
1009#ifdef HAVE_DBGHELP
1010
1011//static BOOL CALLBACK win32EnumModulesCallback(PSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext)
1012//{
1013// Log(("dbg: module: %08llx %s\n", ModuleName, BaseOfDll));
1014// return TRUE;
1015//}
1016
1017static int win32Error(PVM pVM)
1018{
1019 int rc = GetLastError();
1020 Log(("Lasterror=%d\n", rc));
1021
1022 //SymEnumerateModules64(pVM, win32EnumModulesCallback, NULL);
1023
1024 return VERR_GENERAL_FAILURE;
1025}
1026#endif
1027
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