[9277] | 1 | /* $Id: DBGFAddrSpace.cpp 50407 2014-02-11 01:58:32Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
[12677] | 3 | * DBGF - Debugger Facility, Address Space Management.
|
---|
[9277] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[44399] | 7 | * Copyright (C) 2008-2013 Oracle Corporation
|
---|
[9277] | 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 |
|
---|
[12541] | 19 | /** @page pg_dbgf_addr_space DBGFAddrSpace - Address Space Management
|
---|
[9277] | 20 | *
|
---|
| 21 | * What's an address space? It's mainly a convenient way of stuffing
|
---|
| 22 | * module segments and ad-hoc symbols together. It will also help out
|
---|
| 23 | * when the debugger gets extended to deal with user processes later.
|
---|
| 24 | *
|
---|
| 25 | * There are two standard address spaces that will always be present:
|
---|
| 26 | * - The physical address space.
|
---|
| 27 | * - The global virtual address space.
|
---|
| 28 | *
|
---|
| 29 | * Additional address spaces will be added and removed at runtime for
|
---|
| 30 | * guest processes. The global virtual address space will be used to
|
---|
| 31 | * track the kernel parts of the OS, or at least the bits of the kernel
|
---|
| 32 | * that is part of all address spaces (mac os x and 4G/4G patched linux).
|
---|
| 33 | *
|
---|
| 34 | */
|
---|
| 35 |
|
---|
[19757] | 36 | /*******************************************************************************
|
---|
| 37 | * Header Files *
|
---|
| 38 | *******************************************************************************/
|
---|
| 39 | #define LOG_GROUP LOG_GROUP_DBGF
|
---|
[35346] | 40 | #include <VBox/vmm/dbgf.h>
|
---|
[46135] | 41 | #include <VBox/vmm/hm.h>
|
---|
[35346] | 42 | #include <VBox/vmm/pdmapi.h>
|
---|
| 43 | #include <VBox/vmm/mm.h>
|
---|
[46135] | 44 | #ifdef VBOX_WITH_RAW_MODE
|
---|
| 45 | # include <VBox/vmm/patm.h>
|
---|
| 46 | #endif
|
---|
[19757] | 47 | #include "DBGFInternal.h"
|
---|
[44399] | 48 | #include <VBox/vmm/uvm.h>
|
---|
[35346] | 49 | #include <VBox/vmm/vm.h>
|
---|
[19757] | 50 | #include <VBox/err.h>
|
---|
| 51 | #include <VBox/log.h>
|
---|
[9277] | 52 |
|
---|
[29250] | 53 | #include <iprt/asm.h>
|
---|
[19757] | 54 | #include <iprt/assert.h>
|
---|
| 55 | #include <iprt/ctype.h>
|
---|
| 56 | #include <iprt/env.h>
|
---|
[46135] | 57 | #include <iprt/mem.h>
|
---|
[19757] | 58 | #include <iprt/path.h>
|
---|
| 59 | #include <iprt/param.h>
|
---|
| 60 |
|
---|
| 61 |
|
---|
| 62 | /*******************************************************************************
|
---|
| 63 | * Structures and Typedefs *
|
---|
| 64 | *******************************************************************************/
|
---|
| 65 | /**
|
---|
| 66 | * Address space database node.
|
---|
| 67 | */
|
---|
| 68 | typedef struct DBGFASDBNODE
|
---|
| 69 | {
|
---|
| 70 | /** The node core for DBGF::AsHandleTree, the key is the address space handle. */
|
---|
| 71 | AVLPVNODECORE HandleCore;
|
---|
| 72 | /** The node core for DBGF::AsPidTree, the key is the process id. */
|
---|
| 73 | AVLU32NODECORE PidCore;
|
---|
| 74 | /** The node core for DBGF::AsNameSpace, the string is the address space name. */
|
---|
| 75 | RTSTRSPACECORE NameCore;
|
---|
| 76 |
|
---|
| 77 | } DBGFASDBNODE;
|
---|
| 78 | /** Pointer to an address space database node. */
|
---|
| 79 | typedef DBGFASDBNODE *PDBGFASDBNODE;
|
---|
| 80 |
|
---|
| 81 |
|
---|
| 82 | /**
|
---|
| 83 | * For dbgfR3AsLoadImageOpenData and dbgfR3AsLoadMapOpenData.
|
---|
| 84 | */
|
---|
| 85 | typedef struct DBGFR3ASLOADOPENDATA
|
---|
| 86 | {
|
---|
[44399] | 87 | const char *pszModName;
|
---|
| 88 | RTGCUINTPTR uSubtrahend;
|
---|
| 89 | uint32_t fFlags;
|
---|
| 90 | RTDBGMOD hMod;
|
---|
[19757] | 91 | } DBGFR3ASLOADOPENDATA;
|
---|
| 92 |
|
---|
| 93 | /**
|
---|
| 94 | * Callback for dbgfR3AsSearchPath and dbgfR3AsSearchEnvPath.
|
---|
| 95 | *
|
---|
| 96 | * @returns VBox status code. If success, then the search is completed.
|
---|
| 97 | * @param pszFilename The file name under evaluation.
|
---|
| 98 | * @param pvUser The user argument.
|
---|
| 99 | */
|
---|
| 100 | typedef int FNDBGFR3ASSEARCHOPEN(const char *pszFilename, void *pvUser);
|
---|
| 101 | /** Pointer to a FNDBGFR3ASSEARCHOPEN. */
|
---|
| 102 | typedef FNDBGFR3ASSEARCHOPEN *PFNDBGFR3ASSEARCHOPEN;
|
---|
| 103 |
|
---|
| 104 |
|
---|
| 105 | /*******************************************************************************
|
---|
| 106 | * Defined Constants And Macros *
|
---|
| 107 | *******************************************************************************/
|
---|
| 108 | /** Locks the address space database for writing. */
|
---|
[44399] | 109 | #define DBGF_AS_DB_LOCK_WRITE(pUVM) \
|
---|
[19757] | 110 | do { \
|
---|
[44399] | 111 | int rcSem = RTSemRWRequestWrite((pUVM)->dbgf.s.hAsDbLock, RT_INDEFINITE_WAIT); \
|
---|
[19757] | 112 | AssertRC(rcSem); \
|
---|
| 113 | } while (0)
|
---|
| 114 |
|
---|
| 115 | /** Unlocks the address space database after writing. */
|
---|
[44399] | 116 | #define DBGF_AS_DB_UNLOCK_WRITE(pUVM) \
|
---|
[19757] | 117 | do { \
|
---|
[44399] | 118 | int rcSem = RTSemRWReleaseWrite((pUVM)->dbgf.s.hAsDbLock); \
|
---|
[19757] | 119 | AssertRC(rcSem); \
|
---|
| 120 | } while (0)
|
---|
| 121 |
|
---|
| 122 | /** Locks the address space database for reading. */
|
---|
[44399] | 123 | #define DBGF_AS_DB_LOCK_READ(pUVM) \
|
---|
[19757] | 124 | do { \
|
---|
[44399] | 125 | int rcSem = RTSemRWRequestRead((pUVM)->dbgf.s.hAsDbLock, RT_INDEFINITE_WAIT); \
|
---|
[19757] | 126 | AssertRC(rcSem); \
|
---|
| 127 | } while (0)
|
---|
| 128 |
|
---|
| 129 | /** Unlocks the address space database after reading. */
|
---|
[44399] | 130 | #define DBGF_AS_DB_UNLOCK_READ(pUVM) \
|
---|
[19757] | 131 | do { \
|
---|
[44399] | 132 | int rcSem = RTSemRWReleaseRead((pUVM)->dbgf.s.hAsDbLock); \
|
---|
[19757] | 133 | AssertRC(rcSem); \
|
---|
| 134 | } while (0)
|
---|
| 135 |
|
---|
| 136 |
|
---|
| 137 |
|
---|
| 138 | /**
|
---|
| 139 | * Initializes the address space parts of DBGF.
|
---|
| 140 | *
|
---|
| 141 | * @returns VBox status code.
|
---|
[44399] | 142 | * @param pUVM The user mode VM handle.
|
---|
[19757] | 143 | */
|
---|
[44399] | 144 | int dbgfR3AsInit(PUVM pUVM)
|
---|
[19757] | 145 | {
|
---|
[45984] | 146 | Assert(pUVM->pVM);
|
---|
| 147 |
|
---|
[19757] | 148 | /*
|
---|
| 149 | * Create the semaphore.
|
---|
| 150 | */
|
---|
[44399] | 151 | int rc = RTSemRWCreate(&pUVM->dbgf.s.hAsDbLock);
|
---|
[19757] | 152 | AssertRCReturn(rc, rc);
|
---|
| 153 |
|
---|
| 154 | /*
|
---|
[46110] | 155 | * Create the debugging config instance and set it up, defaulting to
|
---|
| 156 | * deferred loading in order to keep things fast.
|
---|
[45984] | 157 | */
|
---|
[46050] | 158 | rc = RTDbgCfgCreate(&pUVM->dbgf.s.hDbgCfg, NULL, true /*fNativePaths*/);
|
---|
[45984] | 159 | AssertRCReturn(rc, rc);
|
---|
[46110] | 160 | rc = RTDbgCfgChangeUInt(pUVM->dbgf.s.hDbgCfg, RTDBGCFGPROP_FLAGS, RTDBGCFGOP_PREPEND,
|
---|
| 161 | RTDBGCFG_FLAGS_DEFERRED);
|
---|
| 162 | AssertRCReturn(rc, rc);
|
---|
[45984] | 163 |
|
---|
| 164 | static struct
|
---|
| 165 | {
|
---|
| 166 | RTDBGCFGPROP enmProp;
|
---|
| 167 | const char *pszEnvName;
|
---|
| 168 | const char *pszCfgName;
|
---|
| 169 | } const s_aProps[] =
|
---|
| 170 | {
|
---|
| 171 | { RTDBGCFGPROP_FLAGS, "VBOXDBG_FLAGS", "Flags" },
|
---|
| 172 | { RTDBGCFGPROP_PATH, "VBOXDBG_PATH", "Path" },
|
---|
| 173 | { RTDBGCFGPROP_SUFFIXES, "VBOXDBG_SUFFIXES", "Suffixes" },
|
---|
| 174 | { RTDBGCFGPROP_SRC_PATH, "VBOXDBG_SRC_PATH", "SrcPath" },
|
---|
| 175 | };
|
---|
| 176 | PCFGMNODE pCfgDbgf = CFGMR3GetChild(CFGMR3GetRootU(pUVM), "/DBGF");
|
---|
| 177 | for (unsigned i = 0; i < RT_ELEMENTS(s_aProps); i++)
|
---|
| 178 | {
|
---|
[50406] | 179 | char szEnvValue[8192];
|
---|
[50407] | 180 | rc = RTEnvGetEx(RTENV_DEFAULT, s_aProps[i].pszEnvName, szEnvValue, sizeof(szEnvValue), NULL);
|
---|
[50406] | 181 | if (RT_SUCCESS(rc))
|
---|
[45984] | 182 | {
|
---|
[50406] | 183 | rc = RTDbgCfgChangeString(pUVM->dbgf.s.hDbgCfg, s_aProps[i].enmProp, RTDBGCFGOP_PREPEND, szEnvValue);
|
---|
[45984] | 184 | if (RT_FAILURE(rc))
|
---|
| 185 | return VMR3SetError(pUVM, rc, RT_SRC_POS,
|
---|
[50406] | 186 | "DBGF Config Error: %s=%s -> %Rrc", s_aProps[i].pszEnvName, szEnvValue, rc);
|
---|
[45984] | 187 | }
|
---|
[50406] | 188 | else if (rc != VERR_ENV_VAR_NOT_FOUND)
|
---|
| 189 | return VMR3SetError(pUVM, rc, RT_SRC_POS,
|
---|
| 190 | "DBGF Config Error: Error querying env.var. %s: %Rrc", s_aProps[i].pszEnvName, rc);
|
---|
[45984] | 191 |
|
---|
| 192 | char *pszCfgValue;
|
---|
[45987] | 193 | rc = CFGMR3QueryStringAllocDef(pCfgDbgf, s_aProps[i].pszCfgName, &pszCfgValue, NULL);
|
---|
[45984] | 194 | if (RT_FAILURE(rc))
|
---|
| 195 | return VMR3SetError(pUVM, rc, RT_SRC_POS,
|
---|
| 196 | "DBGF Config Error: Querying /DBGF/%s -> %Rrc", s_aProps[i].pszCfgName, rc);
|
---|
| 197 | if (pszCfgValue)
|
---|
| 198 | {
|
---|
| 199 | rc = RTDbgCfgChangeString(pUVM->dbgf.s.hDbgCfg, s_aProps[i].enmProp, RTDBGCFGOP_PREPEND, pszCfgValue);
|
---|
| 200 | if (RT_FAILURE(rc))
|
---|
| 201 | return VMR3SetError(pUVM, rc, RT_SRC_POS,
|
---|
| 202 | "DBGF Config Error: /DBGF/%s=%s -> %Rrc", s_aProps[i].pszCfgName, pszCfgValue, rc);
|
---|
| 203 | }
|
---|
| 204 | }
|
---|
| 205 |
|
---|
| 206 | /*
|
---|
[47825] | 207 | * Prepend the NoArch and VBoxDbgSyms directories to the path.
|
---|
[46946] | 208 | */
|
---|
| 209 | char szPath[RTPATH_MAX];
|
---|
| 210 | rc = RTPathAppPrivateNoArch(szPath, sizeof(szPath));
|
---|
| 211 | AssertRCReturn(rc, rc);
|
---|
| 212 | #ifdef RT_OS_DARWIN
|
---|
| 213 | rc = RTPathAppend(szPath, sizeof(szPath), "../Resources/VBoxDbgSyms/");
|
---|
| 214 | #else
|
---|
[47825] | 215 | rc = RTDbgCfgChangeString(pUVM->dbgf.s.hDbgCfg, RTDBGCFGPROP_PATH, RTDBGCFGOP_PREPEND, szPath);
|
---|
| 216 | AssertRCReturn(rc, rc);
|
---|
| 217 |
|
---|
[46946] | 218 | rc = RTPathAppend(szPath, sizeof(szPath), "VBoxDbgSyms/");
|
---|
| 219 | #endif
|
---|
| 220 | AssertRCReturn(rc, rc);
|
---|
| 221 | rc = RTDbgCfgChangeString(pUVM->dbgf.s.hDbgCfg, RTDBGCFGPROP_PATH, RTDBGCFGOP_PREPEND, szPath);
|
---|
| 222 | AssertRCReturn(rc, rc);
|
---|
| 223 |
|
---|
| 224 | /*
|
---|
[19757] | 225 | * Create the standard address spaces.
|
---|
| 226 | */
|
---|
| 227 | RTDBGAS hDbgAs;
|
---|
[21108] | 228 | rc = RTDbgAsCreate(&hDbgAs, 0, RTGCPTR_MAX, "Global");
|
---|
[19757] | 229 | AssertRCReturn(rc, rc);
|
---|
[44399] | 230 | rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
|
---|
[19757] | 231 | AssertRCReturn(rc, rc);
|
---|
| 232 | RTDbgAsRetain(hDbgAs);
|
---|
[44399] | 233 | pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_GLOBAL)] = hDbgAs;
|
---|
[19757] | 234 |
|
---|
| 235 | RTDbgAsRetain(hDbgAs);
|
---|
[44399] | 236 | pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_KERNEL)] = hDbgAs;
|
---|
[19757] | 237 |
|
---|
[21108] | 238 | rc = RTDbgAsCreate(&hDbgAs, 0, RTGCPHYS_MAX, "Physical");
|
---|
[19757] | 239 | AssertRCReturn(rc, rc);
|
---|
[44399] | 240 | rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
|
---|
[19757] | 241 | AssertRCReturn(rc, rc);
|
---|
| 242 | RTDbgAsRetain(hDbgAs);
|
---|
[44399] | 243 | pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_PHYS)] = hDbgAs;
|
---|
[19757] | 244 |
|
---|
| 245 | rc = RTDbgAsCreate(&hDbgAs, 0, RTRCPTR_MAX, "HyperRawMode");
|
---|
| 246 | AssertRCReturn(rc, rc);
|
---|
[44399] | 247 | rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
|
---|
[19757] | 248 | AssertRCReturn(rc, rc);
|
---|
| 249 | RTDbgAsRetain(hDbgAs);
|
---|
[44399] | 250 | pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC)] = hDbgAs;
|
---|
[19757] | 251 | RTDbgAsRetain(hDbgAs);
|
---|
[44399] | 252 | pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC_AND_GC_GLOBAL)] = hDbgAs;
|
---|
[19757] | 253 |
|
---|
[21108] | 254 | rc = RTDbgAsCreate(&hDbgAs, 0, RTR0PTR_MAX, "HyperRing0");
|
---|
[19757] | 255 | AssertRCReturn(rc, rc);
|
---|
[44399] | 256 | rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
|
---|
[19757] | 257 | AssertRCReturn(rc, rc);
|
---|
| 258 | RTDbgAsRetain(hDbgAs);
|
---|
[44399] | 259 | pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_R0)] = hDbgAs;
|
---|
[19757] | 260 |
|
---|
| 261 | return VINF_SUCCESS;
|
---|
| 262 | }
|
---|
| 263 |
|
---|
| 264 |
|
---|
| 265 | /**
|
---|
| 266 | * Callback used by dbgfR3AsTerm / RTAvlPVDestroy to release an address space.
|
---|
| 267 | *
|
---|
| 268 | * @returns 0.
|
---|
| 269 | * @param pNode The address space database node.
|
---|
| 270 | * @param pvIgnore NULL.
|
---|
| 271 | */
|
---|
| 272 | static DECLCALLBACK(int) dbgfR3AsTermDestroyNode(PAVLPVNODECORE pNode, void *pvIgnore)
|
---|
| 273 | {
|
---|
| 274 | PDBGFASDBNODE pDbNode = (PDBGFASDBNODE)pNode;
|
---|
| 275 | RTDbgAsRelease((RTDBGAS)pDbNode->HandleCore.Key);
|
---|
| 276 | pDbNode->HandleCore.Key = NIL_RTDBGAS;
|
---|
| 277 | /* Don't bother freeing it here as MM will free it soon and MM is much at
|
---|
| 278 | it when doing it wholesale instead of piecemeal. */
|
---|
| 279 | NOREF(pvIgnore);
|
---|
| 280 | return 0;
|
---|
| 281 | }
|
---|
| 282 |
|
---|
| 283 |
|
---|
| 284 | /**
|
---|
| 285 | * Terminates the address space parts of DBGF.
|
---|
| 286 | *
|
---|
[44399] | 287 | * @param pUVM The user mode VM handle.
|
---|
[19757] | 288 | */
|
---|
[44399] | 289 | void dbgfR3AsTerm(PUVM pUVM)
|
---|
[19757] | 290 | {
|
---|
| 291 | /*
|
---|
| 292 | * Create the semaphore.
|
---|
| 293 | */
|
---|
[44399] | 294 | int rc = RTSemRWDestroy(pUVM->dbgf.s.hAsDbLock);
|
---|
[19757] | 295 | AssertRC(rc);
|
---|
[44399] | 296 | pUVM->dbgf.s.hAsDbLock = NIL_RTSEMRW;
|
---|
[19757] | 297 |
|
---|
| 298 | /*
|
---|
| 299 | * Release all the address spaces.
|
---|
| 300 | */
|
---|
[44399] | 301 | RTAvlPVDestroy(&pUVM->dbgf.s.AsHandleTree, dbgfR3AsTermDestroyNode, NULL);
|
---|
| 302 | for (size_t i = 0; i < RT_ELEMENTS(pUVM->dbgf.s.ahAsAliases); i++)
|
---|
[19757] | 303 | {
|
---|
[44399] | 304 | RTDbgAsRelease(pUVM->dbgf.s.ahAsAliases[i]);
|
---|
| 305 | pUVM->dbgf.s.ahAsAliases[i] = NIL_RTDBGAS;
|
---|
[19757] | 306 | }
|
---|
| 307 | }
|
---|
| 308 |
|
---|
| 309 |
|
---|
| 310 | /**
|
---|
| 311 | * Relocates the RC address space.
|
---|
| 312 | *
|
---|
[44399] | 313 | * @param pUVM The user mode VM handle.
|
---|
| 314 | * @param offDelta The relocation delta.
|
---|
[19757] | 315 | */
|
---|
[44399] | 316 | void dbgfR3AsRelocate(PUVM pUVM, RTGCUINTPTR offDelta)
|
---|
[19757] | 317 | {
|
---|
[46135] | 318 | /*
|
---|
| 319 | * We will relocate the raw-mode context modules by offDelta if they have
|
---|
| 320 | * been injected into the the DBGF_AS_RC map.
|
---|
| 321 | */
|
---|
| 322 | if ( pUVM->dbgf.s.afAsAliasPopuplated[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC)]
|
---|
| 323 | && offDelta != 0)
|
---|
| 324 | {
|
---|
| 325 | RTDBGAS hAs = pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC)];
|
---|
| 326 |
|
---|
| 327 | /* Take a snapshot of the modules as we might have overlapping
|
---|
| 328 | addresses between the previous and new mapping. */
|
---|
[46137] | 329 | RTDbgAsLockExcl(hAs);
|
---|
[46135] | 330 | uint32_t cModules = RTDbgAsModuleCount(hAs);
|
---|
| 331 | if (cModules > 0 && cModules < _4K)
|
---|
| 332 | {
|
---|
| 333 | struct DBGFASRELOCENTRY
|
---|
| 334 | {
|
---|
| 335 | RTDBGMOD hDbgMod;
|
---|
| 336 | RTRCPTR uOldAddr;
|
---|
| 337 | } *paEntries = (struct DBGFASRELOCENTRY *)RTMemTmpAllocZ(sizeof(paEntries[0]) * cModules);
|
---|
| 338 | if (paEntries)
|
---|
| 339 | {
|
---|
| 340 | /* Snapshot. */
|
---|
| 341 | for (uint32_t i = 0; i < cModules; i++)
|
---|
| 342 | {
|
---|
| 343 | paEntries[i].hDbgMod = RTDbgAsModuleByIndex(hAs, i);
|
---|
| 344 | AssertLogRelMsg(paEntries[i].hDbgMod != NIL_RTDBGMOD, ("iModule=%#x\n", i));
|
---|
| 345 |
|
---|
| 346 | RTDBGASMAPINFO aMappings[1] = { { 0, 0 } };
|
---|
| 347 | uint32_t cMappings = 1;
|
---|
| 348 | int rc = RTDbgAsModuleQueryMapByIndex(hAs, i, &aMappings[0], &cMappings, 0 /*fFlags*/);
|
---|
| 349 | if (RT_SUCCESS(rc) && cMappings == 1 && aMappings[0].iSeg == NIL_RTDBGSEGIDX)
|
---|
| 350 | paEntries[i].uOldAddr = (RTRCPTR)aMappings[0].Address;
|
---|
| 351 | else
|
---|
| 352 | AssertLogRelMsgFailed(("iModule=%#x rc=%Rrc cMappings=%#x.\n", i, rc, cMappings));
|
---|
| 353 | }
|
---|
| 354 |
|
---|
| 355 | /* Unlink them. */
|
---|
| 356 | for (uint32_t i = 0; i < cModules; i++)
|
---|
| 357 | {
|
---|
| 358 | int rc = RTDbgAsModuleUnlink(hAs, paEntries[i].hDbgMod);
|
---|
| 359 | AssertLogRelMsg(RT_SUCCESS(rc), ("iModule=%#x rc=%Rrc hDbgMod=%p\n", i, rc, paEntries[i].hDbgMod));
|
---|
| 360 | }
|
---|
| 361 |
|
---|
| 362 | /* Link them at the new locations. */
|
---|
| 363 | for (uint32_t i = 0; i < cModules; i++)
|
---|
| 364 | {
|
---|
| 365 | RTRCPTR uNewAddr = paEntries[i].uOldAddr + offDelta;
|
---|
| 366 | int rc = RTDbgAsModuleLink(hAs, paEntries[i].hDbgMod, uNewAddr,
|
---|
| 367 | RTDBGASLINK_FLAGS_REPLACE);
|
---|
| 368 | AssertLogRelMsg(RT_SUCCESS(rc),
|
---|
| 369 | ("iModule=%#x rc=%Rrc hDbgMod=%p %RRv -> %RRv\n", i, rc, paEntries[i].hDbgMod,
|
---|
| 370 | paEntries[i].uOldAddr, uNewAddr));
|
---|
| 371 | RTDbgModRelease(paEntries[i].hDbgMod);
|
---|
| 372 | }
|
---|
| 373 |
|
---|
| 374 | RTMemTmpFree(paEntries);
|
---|
| 375 | }
|
---|
| 376 | else
|
---|
| 377 | AssertLogRelMsgFailed(("No memory for %#x modules.\n", cModules));
|
---|
| 378 | }
|
---|
| 379 | else
|
---|
| 380 | AssertLogRelMsgFailed(("cModules=%#x\n", cModules));
|
---|
[46137] | 381 | RTDbgAsUnlockExcl(hAs);
|
---|
[46135] | 382 | }
|
---|
[19757] | 383 | }
|
---|
| 384 |
|
---|
| 385 |
|
---|
| 386 | /**
|
---|
[45993] | 387 | * Gets the IPRT debugging configuration handle (no refs retained).
|
---|
| 388 | *
|
---|
| 389 | * @returns Config handle or NIL_RTDBGCFG.
|
---|
| 390 | * @param pUVM The user mode VM handle.
|
---|
| 391 | */
|
---|
| 392 | VMMR3DECL(RTDBGCFG) DBGFR3AsGetConfig(PUVM pUVM)
|
---|
| 393 | {
|
---|
| 394 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, NIL_RTDBGCFG);
|
---|
| 395 | return pUVM->dbgf.s.hDbgCfg;
|
---|
| 396 | }
|
---|
| 397 |
|
---|
| 398 |
|
---|
| 399 | /**
|
---|
[19757] | 400 | * Adds the address space to the database.
|
---|
| 401 | *
|
---|
| 402 | * @returns VBox status code.
|
---|
[44399] | 403 | * @param pUVM The user mode VM handle.
|
---|
| 404 | * @param hDbgAs The address space handle. The reference of the caller
|
---|
| 405 | * will NOT be consumed.
|
---|
| 406 | * @param ProcId The process id or NIL_RTPROCESS.
|
---|
[19757] | 407 | */
|
---|
[44399] | 408 | VMMR3DECL(int) DBGFR3AsAdd(PUVM pUVM, RTDBGAS hDbgAs, RTPROCESS ProcId)
|
---|
[19757] | 409 | {
|
---|
| 410 | /*
|
---|
| 411 | * Input validation.
|
---|
| 412 | */
|
---|
[44399] | 413 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
|
---|
[19757] | 414 | const char *pszName = RTDbgAsName(hDbgAs);
|
---|
| 415 | if (!pszName)
|
---|
| 416 | return VERR_INVALID_HANDLE;
|
---|
| 417 | uint32_t cRefs = RTDbgAsRetain(hDbgAs);
|
---|
| 418 | if (cRefs == UINT32_MAX)
|
---|
| 419 | return VERR_INVALID_HANDLE;
|
---|
| 420 |
|
---|
| 421 | /*
|
---|
| 422 | * Allocate a tracking node.
|
---|
| 423 | */
|
---|
| 424 | int rc = VERR_NO_MEMORY;
|
---|
[44399] | 425 | PDBGFASDBNODE pDbNode = (PDBGFASDBNODE)MMR3HeapAllocU(pUVM, MM_TAG_DBGF_AS, sizeof(*pDbNode));
|
---|
[19757] | 426 | if (pDbNode)
|
---|
| 427 | {
|
---|
[39078] | 428 | pDbNode->HandleCore.Key = hDbgAs;
|
---|
| 429 | pDbNode->PidCore.Key = ProcId;
|
---|
[19757] | 430 | pDbNode->NameCore.pszString = pszName;
|
---|
| 431 | pDbNode->NameCore.cchString = strlen(pszName);
|
---|
[44399] | 432 | DBGF_AS_DB_LOCK_WRITE(pUVM);
|
---|
| 433 | if (RTStrSpaceInsert(&pUVM->dbgf.s.AsNameSpace, &pDbNode->NameCore))
|
---|
[19757] | 434 | {
|
---|
[44399] | 435 | if (RTAvlPVInsert(&pUVM->dbgf.s.AsHandleTree, &pDbNode->HandleCore))
|
---|
[19757] | 436 | {
|
---|
[44399] | 437 | DBGF_AS_DB_UNLOCK_WRITE(pUVM);
|
---|
[19757] | 438 | return VINF_SUCCESS;
|
---|
| 439 | }
|
---|
| 440 |
|
---|
| 441 | /* bail out */
|
---|
[44399] | 442 | RTStrSpaceRemove(&pUVM->dbgf.s.AsNameSpace, pszName);
|
---|
[19757] | 443 | }
|
---|
[44399] | 444 | DBGF_AS_DB_UNLOCK_WRITE(pUVM);
|
---|
[19757] | 445 | MMR3HeapFree(pDbNode);
|
---|
| 446 | }
|
---|
| 447 | RTDbgAsRelease(hDbgAs);
|
---|
| 448 | return rc;
|
---|
| 449 | }
|
---|
| 450 |
|
---|
| 451 |
|
---|
| 452 | /**
|
---|
| 453 | * Delete an address space from the database.
|
---|
| 454 | *
|
---|
| 455 | * The address space must not be engaged as any of the standard aliases.
|
---|
| 456 | *
|
---|
| 457 | * @returns VBox status code.
|
---|
| 458 | * @retval VERR_SHARING_VIOLATION if in use as an alias.
|
---|
| 459 | * @retval VERR_NOT_FOUND if not found in the address space database.
|
---|
| 460 | *
|
---|
[44399] | 461 | * @param pUVM The user mode VM handle.
|
---|
| 462 | * @param hDbgAs The address space handle. Aliases are not allowed.
|
---|
[19757] | 463 | */
|
---|
[44399] | 464 | VMMR3DECL(int) DBGFR3AsDelete(PUVM pUVM, RTDBGAS hDbgAs)
|
---|
[19757] | 465 | {
|
---|
| 466 | /*
|
---|
| 467 | * Input validation. Retain the address space so it can be released outside
|
---|
| 468 | * the lock as well as validated.
|
---|
| 469 | */
|
---|
[44399] | 470 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
|
---|
[19757] | 471 | if (hDbgAs == NIL_RTDBGAS)
|
---|
| 472 | return VINF_SUCCESS;
|
---|
| 473 | uint32_t cRefs = RTDbgAsRetain(hDbgAs);
|
---|
| 474 | if (cRefs == UINT32_MAX)
|
---|
| 475 | return VERR_INVALID_HANDLE;
|
---|
| 476 | RTDbgAsRelease(hDbgAs);
|
---|
| 477 |
|
---|
[44399] | 478 | DBGF_AS_DB_LOCK_WRITE(pUVM);
|
---|
[19757] | 479 |
|
---|
| 480 | /*
|
---|
| 481 | * You cannot delete any of the aliases.
|
---|
| 482 | */
|
---|
[44399] | 483 | for (size_t i = 0; i < RT_ELEMENTS(pUVM->dbgf.s.ahAsAliases); i++)
|
---|
| 484 | if (pUVM->dbgf.s.ahAsAliases[i] == hDbgAs)
|
---|
[19757] | 485 | {
|
---|
[44399] | 486 | DBGF_AS_DB_UNLOCK_WRITE(pUVM);
|
---|
[19757] | 487 | return VERR_SHARING_VIOLATION;
|
---|
| 488 | }
|
---|
| 489 |
|
---|
| 490 | /*
|
---|
| 491 | * Ok, try remove it from the database.
|
---|
| 492 | */
|
---|
[44399] | 493 | PDBGFASDBNODE pDbNode = (PDBGFASDBNODE)RTAvlPVRemove(&pUVM->dbgf.s.AsHandleTree, hDbgAs);
|
---|
[19757] | 494 | if (!pDbNode)
|
---|
| 495 | {
|
---|
[44399] | 496 | DBGF_AS_DB_UNLOCK_WRITE(pUVM);
|
---|
[19757] | 497 | return VERR_NOT_FOUND;
|
---|
| 498 | }
|
---|
[44399] | 499 | RTStrSpaceRemove(&pUVM->dbgf.s.AsNameSpace, pDbNode->NameCore.pszString);
|
---|
[19757] | 500 | if (pDbNode->PidCore.Key != NIL_RTPROCESS)
|
---|
[44399] | 501 | RTAvlU32Remove(&pUVM->dbgf.s.AsPidTree, pDbNode->PidCore.Key);
|
---|
[19757] | 502 |
|
---|
[44399] | 503 | DBGF_AS_DB_UNLOCK_WRITE(pUVM);
|
---|
[19757] | 504 |
|
---|
| 505 | /*
|
---|
| 506 | * Free the resources.
|
---|
| 507 | */
|
---|
| 508 | RTDbgAsRelease(hDbgAs);
|
---|
| 509 | MMR3HeapFree(pDbNode);
|
---|
| 510 |
|
---|
| 511 | return VINF_SUCCESS;
|
---|
| 512 | }
|
---|
| 513 |
|
---|
| 514 |
|
---|
| 515 | /**
|
---|
| 516 | * Changes an alias to point to a new address space.
|
---|
| 517 | *
|
---|
| 518 | * Not all the aliases can be changed, currently it's only DBGF_AS_GLOBAL
|
---|
| 519 | * and DBGF_AS_KERNEL.
|
---|
| 520 | *
|
---|
| 521 | * @returns VBox status code.
|
---|
[44399] | 522 | * @param pUVM The user mode VM handle.
|
---|
| 523 | * @param hAlias The alias to change.
|
---|
| 524 | * @param hAliasFor The address space hAlias should be an alias for. This
|
---|
| 525 | * can be an alias. The caller's reference to this address
|
---|
| 526 | * space will NOT be consumed.
|
---|
[19757] | 527 | */
|
---|
[44399] | 528 | VMMR3DECL(int) DBGFR3AsSetAlias(PUVM pUVM, RTDBGAS hAlias, RTDBGAS hAliasFor)
|
---|
[19757] | 529 | {
|
---|
| 530 | /*
|
---|
| 531 | * Input validation.
|
---|
| 532 | */
|
---|
[44399] | 533 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
|
---|
[22112] | 534 | AssertMsgReturn(DBGF_AS_IS_ALIAS(hAlias), ("%p\n", hAlias), VERR_INVALID_PARAMETER);
|
---|
[19757] | 535 | AssertMsgReturn(!DBGF_AS_IS_FIXED_ALIAS(hAlias), ("%p\n", hAlias), VERR_INVALID_PARAMETER);
|
---|
[44399] | 536 | RTDBGAS hRealAliasFor = DBGFR3AsResolveAndRetain(pUVM, hAliasFor);
|
---|
[19757] | 537 | if (hRealAliasFor == NIL_RTDBGAS)
|
---|
| 538 | return VERR_INVALID_HANDLE;
|
---|
| 539 |
|
---|
| 540 | /*
|
---|
| 541 | * Make sure the handle has is already in the database.
|
---|
| 542 | */
|
---|
| 543 | int rc = VERR_NOT_FOUND;
|
---|
[44399] | 544 | DBGF_AS_DB_LOCK_WRITE(pUVM);
|
---|
| 545 | if (RTAvlPVGet(&pUVM->dbgf.s.AsHandleTree, hRealAliasFor))
|
---|
[19757] | 546 | {
|
---|
| 547 | /*
|
---|
| 548 | * Update the alias table and release the current address space.
|
---|
| 549 | */
|
---|
| 550 | RTDBGAS hAsOld;
|
---|
[44399] | 551 | ASMAtomicXchgHandle(&pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(hAlias)], hRealAliasFor, &hAsOld);
|
---|
[19757] | 552 | uint32_t cRefs = RTDbgAsRelease(hAsOld);
|
---|
[39034] | 553 | Assert(cRefs > 0); Assert(cRefs != UINT32_MAX); NOREF(cRefs);
|
---|
[19757] | 554 | rc = VINF_SUCCESS;
|
---|
| 555 | }
|
---|
[44399] | 556 | DBGF_AS_DB_UNLOCK_WRITE(pUVM);
|
---|
[19757] | 557 |
|
---|
| 558 | return rc;
|
---|
| 559 | }
|
---|
| 560 |
|
---|
| 561 |
|
---|
| 562 | /**
|
---|
[30078] | 563 | * @callback_method_impl{FNPDMR3ENUM}
|
---|
| 564 | */
|
---|
| 565 | static DECLCALLBACK(int) dbgfR3AsLazyPopulateR0Callback(PVM pVM, const char *pszFilename, const char *pszName,
|
---|
[46915] | 566 | RTUINTPTR ImageBase, size_t cbImage, PDMLDRCTX enmCtx, void *pvArg)
|
---|
[30078] | 567 | {
|
---|
[39078] | 568 | NOREF(pVM); NOREF(cbImage);
|
---|
| 569 |
|
---|
[30078] | 570 | /* Only ring-0 modules. */
|
---|
[46915] | 571 | if (enmCtx == PDMLDRCTX_RING_0)
|
---|
[30078] | 572 | {
|
---|
| 573 | RTDBGMOD hDbgMod;
|
---|
[46161] | 574 | int rc = RTDbgModCreateFromImage(&hDbgMod, pszFilename, pszName, RTLDRARCH_HOST, pVM->pUVM->dbgf.s.hDbgCfg);
|
---|
[30078] | 575 | if (RT_SUCCESS(rc))
|
---|
| 576 | {
|
---|
| 577 | rc = RTDbgAsModuleLink((RTDBGAS)pvArg, hDbgMod, ImageBase, 0 /*fFlags*/);
|
---|
| 578 | if (RT_FAILURE(rc))
|
---|
| 579 | LogRel(("DBGF: Failed to link module \"%s\" into DBGF_AS_R0 at %RTptr: %Rrc\n",
|
---|
| 580 | pszName, ImageBase, rc));
|
---|
| 581 | }
|
---|
| 582 | else
|
---|
| 583 | LogRel(("DBGF: RTDbgModCreateFromImage failed with rc=%Rrc for module \"%s\" (%s)\n",
|
---|
| 584 | rc, pszName, pszFilename));
|
---|
| 585 | }
|
---|
| 586 | return VINF_SUCCESS;
|
---|
| 587 | }
|
---|
| 588 |
|
---|
| 589 |
|
---|
| 590 | /**
|
---|
[46135] | 591 | * @callback_method_impl{FNPDMR3ENUM}
|
---|
| 592 | */
|
---|
| 593 | static DECLCALLBACK(int) dbgfR3AsLazyPopulateRCCallback(PVM pVM, const char *pszFilename, const char *pszName,
|
---|
[46915] | 594 | RTUINTPTR ImageBase, size_t cbImage, PDMLDRCTX enmCtx, void *pvArg)
|
---|
[46135] | 595 | {
|
---|
| 596 | NOREF(pVM); NOREF(cbImage);
|
---|
| 597 |
|
---|
| 598 | /* Only raw-mode modules. */
|
---|
[46915] | 599 | if (enmCtx == PDMLDRCTX_RAW_MODE)
|
---|
[46135] | 600 | {
|
---|
| 601 | RTDBGMOD hDbgMod;
|
---|
[46161] | 602 | int rc = RTDbgModCreateFromImage(&hDbgMod, pszFilename, pszName, RTLDRARCH_X86_32, pVM->pUVM->dbgf.s.hDbgCfg);
|
---|
[46135] | 603 | if (RT_SUCCESS(rc))
|
---|
| 604 | {
|
---|
| 605 | rc = RTDbgAsModuleLink((RTDBGAS)pvArg, hDbgMod, ImageBase, 0 /*fFlags*/);
|
---|
| 606 | if (RT_FAILURE(rc))
|
---|
| 607 | LogRel(("DBGF: Failed to link module \"%s\" into DBGF_AS_RC at %RTptr: %Rrc\n",
|
---|
| 608 | pszName, ImageBase, rc));
|
---|
| 609 | }
|
---|
| 610 | else
|
---|
| 611 | LogRel(("DBGF: RTDbgModCreateFromImage failed with rc=%Rrc for module \"%s\" (%s)\n",
|
---|
| 612 | rc, pszName, pszFilename));
|
---|
| 613 | }
|
---|
| 614 | return VINF_SUCCESS;
|
---|
| 615 | }
|
---|
| 616 |
|
---|
| 617 |
|
---|
| 618 | /**
|
---|
[30078] | 619 | * Lazily populates the specified address space.
|
---|
| 620 | *
|
---|
[44399] | 621 | * @param pUVM The user mode VM handle.
|
---|
| 622 | * @param hAlias The alias.
|
---|
[30078] | 623 | */
|
---|
[44399] | 624 | static void dbgfR3AsLazyPopulate(PUVM pUVM, RTDBGAS hAlias)
|
---|
[30078] | 625 | {
|
---|
[44399] | 626 | DBGF_AS_DB_LOCK_WRITE(pUVM);
|
---|
[30078] | 627 | uintptr_t iAlias = DBGF_AS_ALIAS_2_INDEX(hAlias);
|
---|
[44399] | 628 | if (!pUVM->dbgf.s.afAsAliasPopuplated[iAlias])
|
---|
[30078] | 629 | {
|
---|
[46135] | 630 | RTDBGAS hDbgAs = pUVM->dbgf.s.ahAsAliases[iAlias];
|
---|
[44399] | 631 | if (hAlias == DBGF_AS_R0 && pUVM->pVM)
|
---|
[46135] | 632 | PDMR3LdrEnumModules(pUVM->pVM, dbgfR3AsLazyPopulateR0Callback, hDbgAs);
|
---|
| 633 | else if (hAlias == DBGF_AS_RC && pUVM->pVM && !HMIsEnabled(pUVM->pVM))
|
---|
| 634 | {
|
---|
| 635 | LogRel(("DBGF: Lazy init of RC address space\n"));
|
---|
| 636 | PDMR3LdrEnumModules(pUVM->pVM, dbgfR3AsLazyPopulateRCCallback, hDbgAs);
|
---|
| 637 | #ifdef VBOX_WITH_RAW_MODE
|
---|
[46137] | 638 | PATMR3DbgPopulateAddrSpace(pUVM->pVM, hDbgAs);
|
---|
[46135] | 639 | #endif
|
---|
| 640 | }
|
---|
[46946] | 641 | else if (hAlias == DBGF_AS_PHYS && pUVM->pVM)
|
---|
| 642 | {
|
---|
| 643 | /** @todo Lazy load pc and vga bios symbols or the EFI stuff. */
|
---|
| 644 | }
|
---|
[30078] | 645 |
|
---|
[44399] | 646 | pUVM->dbgf.s.afAsAliasPopuplated[iAlias] = true;
|
---|
[30078] | 647 | }
|
---|
[44399] | 648 | DBGF_AS_DB_UNLOCK_WRITE(pUVM);
|
---|
[30078] | 649 | }
|
---|
| 650 |
|
---|
| 651 |
|
---|
| 652 | /**
|
---|
[19757] | 653 | * Resolves the address space handle into a real handle if it's an alias.
|
---|
| 654 | *
|
---|
| 655 | * @returns Real address space handle. NIL_RTDBGAS if invalid handle.
|
---|
| 656 | *
|
---|
[44399] | 657 | * @param pUVM The user mode VM handle.
|
---|
| 658 | * @param hAlias The possibly address space alias.
|
---|
[19757] | 659 | *
|
---|
| 660 | * @remarks Doesn't take any locks.
|
---|
| 661 | */
|
---|
[44399] | 662 | VMMR3DECL(RTDBGAS) DBGFR3AsResolve(PUVM pUVM, RTDBGAS hAlias)
|
---|
[19757] | 663 | {
|
---|
[44399] | 664 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
|
---|
[30257] | 665 | AssertCompileNS(NIL_RTDBGAS == (RTDBGAS)0);
|
---|
[19757] | 666 |
|
---|
| 667 | uintptr_t iAlias = DBGF_AS_ALIAS_2_INDEX(hAlias);
|
---|
| 668 | if (iAlias < DBGF_AS_COUNT)
|
---|
[44399] | 669 | ASMAtomicReadHandle(&pUVM->dbgf.s.ahAsAliases[iAlias], &hAlias);
|
---|
[19757] | 670 | return hAlias;
|
---|
| 671 | }
|
---|
| 672 |
|
---|
| 673 |
|
---|
| 674 | /**
|
---|
| 675 | * Resolves the address space handle into a real handle if it's an alias,
|
---|
| 676 | * and retains whatever it is.
|
---|
| 677 | *
|
---|
| 678 | * @returns Real address space handle. NIL_RTDBGAS if invalid handle.
|
---|
| 679 | *
|
---|
[44399] | 680 | * @param pUVM The user mode VM handle.
|
---|
| 681 | * @param hAlias The possibly address space alias.
|
---|
[19757] | 682 | */
|
---|
[44399] | 683 | VMMR3DECL(RTDBGAS) DBGFR3AsResolveAndRetain(PUVM pUVM, RTDBGAS hAlias)
|
---|
[19757] | 684 | {
|
---|
[44399] | 685 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
|
---|
[30257] | 686 | AssertCompileNS(NIL_RTDBGAS == (RTDBGAS)0);
|
---|
[19757] | 687 |
|
---|
| 688 | uint32_t cRefs;
|
---|
| 689 | uintptr_t iAlias = DBGF_AS_ALIAS_2_INDEX(hAlias);
|
---|
| 690 | if (iAlias < DBGF_AS_COUNT)
|
---|
| 691 | {
|
---|
| 692 | if (DBGF_AS_IS_FIXED_ALIAS(hAlias))
|
---|
| 693 | {
|
---|
[30078] | 694 | /* Perform lazy address space population. */
|
---|
[44399] | 695 | if (!pUVM->dbgf.s.afAsAliasPopuplated[iAlias])
|
---|
| 696 | dbgfR3AsLazyPopulate(pUVM, hAlias);
|
---|
[30078] | 697 |
|
---|
[19757] | 698 | /* Won't ever change, no need to grab the lock. */
|
---|
[44399] | 699 | hAlias = pUVM->dbgf.s.ahAsAliases[iAlias];
|
---|
[19757] | 700 | cRefs = RTDbgAsRetain(hAlias);
|
---|
| 701 | }
|
---|
| 702 | else
|
---|
| 703 | {
|
---|
| 704 | /* May change, grab the lock so we can read it safely. */
|
---|
[44399] | 705 | DBGF_AS_DB_LOCK_READ(pUVM);
|
---|
| 706 | hAlias = pUVM->dbgf.s.ahAsAliases[iAlias];
|
---|
[19757] | 707 | cRefs = RTDbgAsRetain(hAlias);
|
---|
[44399] | 708 | DBGF_AS_DB_UNLOCK_READ(pUVM);
|
---|
[19757] | 709 | }
|
---|
| 710 | }
|
---|
| 711 | else
|
---|
| 712 | /* Not an alias, just retain it. */
|
---|
| 713 | cRefs = RTDbgAsRetain(hAlias);
|
---|
| 714 |
|
---|
| 715 | return cRefs != UINT32_MAX ? hAlias : NIL_RTDBGAS;
|
---|
| 716 | }
|
---|
| 717 |
|
---|
| 718 |
|
---|
| 719 | /**
|
---|
| 720 | * Query an address space by name.
|
---|
| 721 | *
|
---|
| 722 | * @returns Retained address space handle if found, NIL_RTDBGAS if not.
|
---|
| 723 | *
|
---|
[44399] | 724 | * @param pUVM The user mode VM handle.
|
---|
[19757] | 725 | * @param pszName The name.
|
---|
| 726 | */
|
---|
[44399] | 727 | VMMR3DECL(RTDBGAS) DBGFR3AsQueryByName(PUVM pUVM, const char *pszName)
|
---|
[19757] | 728 | {
|
---|
| 729 | /*
|
---|
| 730 | * Validate the input.
|
---|
| 731 | */
|
---|
[44399] | 732 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, NIL_RTDBGAS);
|
---|
[19757] | 733 | AssertPtrReturn(pszName, NIL_RTDBGAS);
|
---|
| 734 | AssertReturn(*pszName, NIL_RTDBGAS);
|
---|
| 735 |
|
---|
| 736 | /*
|
---|
| 737 | * Look it up in the string space and retain the result.
|
---|
| 738 | */
|
---|
| 739 | RTDBGAS hDbgAs = NIL_RTDBGAS;
|
---|
[44399] | 740 | DBGF_AS_DB_LOCK_READ(pUVM);
|
---|
[19757] | 741 |
|
---|
[44399] | 742 | PRTSTRSPACECORE pNode = RTStrSpaceGet(&pUVM->dbgf.s.AsNameSpace, pszName);
|
---|
[19757] | 743 | if (pNode)
|
---|
| 744 | {
|
---|
| 745 | PDBGFASDBNODE pDbNode = RT_FROM_MEMBER(pNode, DBGFASDBNODE, NameCore);
|
---|
| 746 | hDbgAs = (RTDBGAS)pDbNode->HandleCore.Key;
|
---|
| 747 | uint32_t cRefs = RTDbgAsRetain(hDbgAs);
|
---|
| 748 | if (RT_UNLIKELY(cRefs == UINT32_MAX))
|
---|
| 749 | hDbgAs = NIL_RTDBGAS;
|
---|
| 750 | }
|
---|
| 751 |
|
---|
[44399] | 752 | DBGF_AS_DB_UNLOCK_READ(pUVM);
|
---|
[19757] | 753 | return hDbgAs;
|
---|
| 754 | }
|
---|
| 755 |
|
---|
| 756 |
|
---|
| 757 | /**
|
---|
| 758 | * Query an address space by process ID.
|
---|
| 759 | *
|
---|
| 760 | * @returns Retained address space handle if found, NIL_RTDBGAS if not.
|
---|
| 761 | *
|
---|
[44399] | 762 | * @param pUVM The user mode VM handle.
|
---|
[19757] | 763 | * @param ProcId The process ID.
|
---|
| 764 | */
|
---|
[44399] | 765 | VMMR3DECL(RTDBGAS) DBGFR3AsQueryByPid(PUVM pUVM, RTPROCESS ProcId)
|
---|
[19757] | 766 | {
|
---|
| 767 | /*
|
---|
| 768 | * Validate the input.
|
---|
| 769 | */
|
---|
[44399] | 770 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, NIL_RTDBGAS);
|
---|
[19757] | 771 | AssertReturn(ProcId != NIL_RTPROCESS, NIL_RTDBGAS);
|
---|
| 772 |
|
---|
| 773 | /*
|
---|
| 774 | * Look it up in the PID tree and retain the result.
|
---|
| 775 | */
|
---|
| 776 | RTDBGAS hDbgAs = NIL_RTDBGAS;
|
---|
[44399] | 777 | DBGF_AS_DB_LOCK_READ(pUVM);
|
---|
[19757] | 778 |
|
---|
[44399] | 779 | PAVLU32NODECORE pNode = RTAvlU32Get(&pUVM->dbgf.s.AsPidTree, ProcId);
|
---|
[19757] | 780 | if (pNode)
|
---|
| 781 | {
|
---|
| 782 | PDBGFASDBNODE pDbNode = RT_FROM_MEMBER(pNode, DBGFASDBNODE, PidCore);
|
---|
| 783 | hDbgAs = (RTDBGAS)pDbNode->HandleCore.Key;
|
---|
| 784 | uint32_t cRefs = RTDbgAsRetain(hDbgAs);
|
---|
| 785 | if (RT_UNLIKELY(cRefs == UINT32_MAX))
|
---|
| 786 | hDbgAs = NIL_RTDBGAS;
|
---|
| 787 | }
|
---|
[44399] | 788 | DBGF_AS_DB_UNLOCK_READ(pUVM);
|
---|
[19757] | 789 |
|
---|
| 790 | return hDbgAs;
|
---|
| 791 | }
|
---|
| 792 |
|
---|
| 793 |
|
---|
| 794 | /**
|
---|
| 795 | * Searches for the file in the path.
|
---|
| 796 | *
|
---|
| 797 | * The file is first tested without any path modification, then we walk the path
|
---|
| 798 | * looking in each directory.
|
---|
| 799 | *
|
---|
| 800 | * @returns VBox status code.
|
---|
| 801 | * @param pszFilename The file to search for.
|
---|
| 802 | * @param pszPath The search path.
|
---|
| 803 | * @param pfnOpen The open callback function.
|
---|
| 804 | * @param pvUser User argument for the callback.
|
---|
| 805 | */
|
---|
| 806 | static int dbgfR3AsSearchPath(const char *pszFilename, const char *pszPath, PFNDBGFR3ASSEARCHOPEN pfnOpen, void *pvUser)
|
---|
| 807 | {
|
---|
| 808 | char szFound[RTPATH_MAX];
|
---|
| 809 |
|
---|
| 810 | /* Check the filename length. */
|
---|
| 811 | size_t const cchFilename = strlen(pszFilename);
|
---|
| 812 | if (cchFilename >= sizeof(szFound))
|
---|
| 813 | return VERR_FILENAME_TOO_LONG;
|
---|
| 814 | const char *pszName = RTPathFilename(pszFilename);
|
---|
| 815 | if (!pszName)
|
---|
| 816 | return VERR_IS_A_DIRECTORY;
|
---|
| 817 | size_t const cchName = strlen(pszName);
|
---|
| 818 |
|
---|
| 819 | /*
|
---|
| 820 | * Try default location first.
|
---|
| 821 | */
|
---|
| 822 | memcpy(szFound, pszFilename, cchFilename + 1);
|
---|
| 823 | int rc = pfnOpen(szFound, pvUser);
|
---|
| 824 | if (RT_SUCCESS(rc))
|
---|
| 825 | return rc;
|
---|
| 826 |
|
---|
| 827 | /*
|
---|
| 828 | * Walk the search path.
|
---|
| 829 | */
|
---|
| 830 | const char *psz = pszPath;
|
---|
| 831 | while (*psz)
|
---|
| 832 | {
|
---|
| 833 | /* Skip leading blanks - no directories with leading spaces, thank you. */
|
---|
| 834 | while (RT_C_IS_BLANK(*psz))
|
---|
| 835 | psz++;
|
---|
| 836 |
|
---|
[22108] | 837 | /* Find the end of this element. */
|
---|
[19757] | 838 | const char *pszNext;
|
---|
| 839 | const char *pszEnd = strchr(psz, ';');
|
---|
| 840 | if (!pszEnd)
|
---|
| 841 | pszEnd = pszNext = strchr(psz, '\0');
|
---|
| 842 | else
|
---|
| 843 | pszNext = pszEnd + 1;
|
---|
| 844 | if (pszEnd != psz)
|
---|
| 845 | {
|
---|
| 846 | size_t const cch = pszEnd - psz;
|
---|
| 847 | if (cch + 1 + cchName < sizeof(szFound))
|
---|
| 848 | {
|
---|
| 849 | /** @todo RTPathCompose, RTPathComposeN(). This code isn't right
|
---|
| 850 | * for 'E:' on DOS systems. It may also create unwanted double slashes. */
|
---|
| 851 | memcpy(szFound, psz, cch);
|
---|
| 852 | szFound[cch] = '/';
|
---|
| 853 | memcpy(szFound + cch + 1, pszName, cchName + 1);
|
---|
| 854 | int rc2 = pfnOpen(szFound, pvUser);
|
---|
| 855 | if (RT_SUCCESS(rc2))
|
---|
| 856 | return rc2;
|
---|
| 857 | if ( rc2 != rc
|
---|
| 858 | && ( rc == VERR_FILE_NOT_FOUND
|
---|
| 859 | || rc == VERR_OPEN_FAILED))
|
---|
| 860 | rc = rc2;
|
---|
| 861 | }
|
---|
| 862 | }
|
---|
| 863 |
|
---|
| 864 | /* advance */
|
---|
| 865 | psz = pszNext;
|
---|
| 866 | }
|
---|
| 867 |
|
---|
| 868 | /*
|
---|
| 869 | * Walk the path once again, this time do a depth search.
|
---|
| 870 | */
|
---|
| 871 | /** @todo do a depth search using the specified path. */
|
---|
| 872 |
|
---|
| 873 | /* failed */
|
---|
| 874 | return rc;
|
---|
| 875 | }
|
---|
| 876 |
|
---|
| 877 |
|
---|
| 878 | /**
|
---|
| 879 | * Same as dbgfR3AsSearchEnv, except that the path is taken from the environment.
|
---|
| 880 | *
|
---|
[39477] | 881 | * If the environment variable doesn't exist, the current directory is searched
|
---|
| 882 | * instead.
|
---|
[19757] | 883 | *
|
---|
| 884 | * @returns VBox status code.
|
---|
| 885 | * @param pszFilename The filename.
|
---|
| 886 | * @param pszEnvVar The environment variable name.
|
---|
| 887 | * @param pfnOpen The open callback function.
|
---|
| 888 | * @param pvUser User argument for the callback.
|
---|
| 889 | */
|
---|
| 890 | static int dbgfR3AsSearchEnvPath(const char *pszFilename, const char *pszEnvVar, PFNDBGFR3ASSEARCHOPEN pfnOpen, void *pvUser)
|
---|
| 891 | {
|
---|
[25942] | 892 | int rc;
|
---|
| 893 | char *pszPath = RTEnvDupEx(RTENV_DEFAULT, pszEnvVar);
|
---|
| 894 | if (pszPath)
|
---|
| 895 | {
|
---|
| 896 | rc = dbgfR3AsSearchPath(pszFilename, pszPath, pfnOpen, pvUser);
|
---|
| 897 | RTStrFree(pszPath);
|
---|
| 898 | }
|
---|
| 899 | else
|
---|
| 900 | rc = dbgfR3AsSearchPath(pszFilename, ".", pfnOpen, pvUser);
|
---|
| 901 | return rc;
|
---|
[19757] | 902 | }
|
---|
| 903 |
|
---|
| 904 |
|
---|
| 905 | /**
|
---|
[39477] | 906 | * Same as dbgfR3AsSearchEnv, except that the path is taken from the DBGF config
|
---|
| 907 | * (CFGM).
|
---|
| 908 | *
|
---|
| 909 | * Nothing is done if the CFGM variable isn't set.
|
---|
| 910 | *
|
---|
| 911 | * @returns VBox status code.
|
---|
[44399] | 912 | * @param pUVM The user mode VM handle.
|
---|
[39477] | 913 | * @param pszFilename The filename.
|
---|
| 914 | * @param pszCfgValue The name of the config variable (under /DBGF/).
|
---|
| 915 | * @param pfnOpen The open callback function.
|
---|
| 916 | * @param pvUser User argument for the callback.
|
---|
| 917 | */
|
---|
[44399] | 918 | static int dbgfR3AsSearchCfgPath(PUVM pUVM, const char *pszFilename, const char *pszCfgValue,
|
---|
| 919 | PFNDBGFR3ASSEARCHOPEN pfnOpen, void *pvUser)
|
---|
[39477] | 920 | {
|
---|
| 921 | char *pszPath;
|
---|
[44399] | 922 | int rc = CFGMR3QueryStringAllocDef(CFGMR3GetChild(CFGMR3GetRootU(pUVM), "/DBGF"), pszCfgValue, &pszPath, NULL);
|
---|
[39477] | 923 | if (RT_FAILURE(rc))
|
---|
| 924 | return rc;
|
---|
| 925 | if (!pszPath)
|
---|
| 926 | return VERR_FILE_NOT_FOUND;
|
---|
| 927 | rc = dbgfR3AsSearchPath(pszFilename, pszPath, pfnOpen, pvUser);
|
---|
| 928 | MMR3HeapFree(pszPath);
|
---|
| 929 | return rc;
|
---|
| 930 | }
|
---|
| 931 |
|
---|
| 932 |
|
---|
| 933 | /**
|
---|
[19757] | 934 | * Load symbols from an executable module into the specified address space.
|
---|
| 935 | *
|
---|
| 936 | * If an module exist at the specified address it will be replaced by this
|
---|
| 937 | * call, otherwise a new module is created.
|
---|
| 938 | *
|
---|
| 939 | * @returns VBox status code.
|
---|
| 940 | *
|
---|
[44399] | 941 | * @param pUVM The user mode VM handle.
|
---|
[19757] | 942 | * @param hDbgAs The address space.
|
---|
| 943 | * @param pszFilename The filename of the executable module.
|
---|
| 944 | * @param pszModName The module name. If NULL, then then the file name
|
---|
| 945 | * base is used (no extension or nothing).
|
---|
[48694] | 946 | * @param enmArch The desired architecture, use RTLDRARCH_WHATEVER if
|
---|
| 947 | * it's not relevant or known.
|
---|
[19757] | 948 | * @param pModAddress The load address of the module.
|
---|
| 949 | * @param iModSeg The segment to load, pass NIL_RTDBGSEGIDX to load
|
---|
| 950 | * the whole image.
|
---|
| 951 | * @param fFlags Flags reserved for future extensions, must be 0.
|
---|
| 952 | */
|
---|
[48694] | 953 | VMMR3DECL(int) DBGFR3AsLoadImage(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, RTLDRARCH enmArch,
|
---|
| 954 | PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags)
|
---|
[19757] | 955 | {
|
---|
| 956 | /*
|
---|
| 957 | * Validate input
|
---|
| 958 | */
|
---|
[44399] | 959 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
|
---|
[19757] | 960 | AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
|
---|
| 961 | AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
|
---|
[44399] | 962 | AssertReturn(DBGFR3AddrIsValid(pUVM, pModAddress), VERR_INVALID_PARAMETER);
|
---|
[19757] | 963 | AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER);
|
---|
[44399] | 964 | RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
|
---|
[19757] | 965 | if (hRealAS == NIL_RTDBGAS)
|
---|
| 966 | return VERR_INVALID_HANDLE;
|
---|
| 967 |
|
---|
[45984] | 968 | RTDBGMOD hDbgMod;
|
---|
[48694] | 969 | int rc = RTDbgModCreateFromImage(&hDbgMod, pszFilename, pszModName, enmArch, pUVM->dbgf.s.hDbgCfg);
|
---|
[19757] | 970 | if (RT_SUCCESS(rc))
|
---|
| 971 | {
|
---|
[45984] | 972 | rc = DBGFR3AsLinkModule(pUVM, hRealAS, hDbgMod, pModAddress, iModSeg, 0);
|
---|
[19757] | 973 | if (RT_FAILURE(rc))
|
---|
[45984] | 974 | RTDbgModRelease(hDbgMod);
|
---|
[19757] | 975 | }
|
---|
| 976 |
|
---|
| 977 | RTDbgAsRelease(hRealAS);
|
---|
| 978 | return rc;
|
---|
| 979 | }
|
---|
| 980 |
|
---|
| 981 |
|
---|
| 982 | /**
|
---|
| 983 | * Load symbols from a map file into a module at the specified address space.
|
---|
| 984 | *
|
---|
| 985 | * If an module exist at the specified address it will be replaced by this
|
---|
| 986 | * call, otherwise a new module is created.
|
---|
| 987 | *
|
---|
| 988 | * @returns VBox status code.
|
---|
| 989 | *
|
---|
[44399] | 990 | * @param pUVM The user mode VM handle.
|
---|
[19757] | 991 | * @param hDbgAs The address space.
|
---|
| 992 | * @param pszFilename The map file.
|
---|
| 993 | * @param pszModName The module name. If NULL, then then the file name
|
---|
| 994 | * base is used (no extension or nothing).
|
---|
| 995 | * @param pModAddress The load address of the module.
|
---|
| 996 | * @param iModSeg The segment to load, pass NIL_RTDBGSEGIDX to load
|
---|
| 997 | * the whole image.
|
---|
| 998 | * @param uSubtrahend Value to to subtract from the symbols in the map
|
---|
| 999 | * file. This is useful for the linux System.map and
|
---|
| 1000 | * /proc/kallsyms.
|
---|
| 1001 | * @param fFlags Flags reserved for future extensions, must be 0.
|
---|
| 1002 | */
|
---|
[44399] | 1003 | VMMR3DECL(int) DBGFR3AsLoadMap(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName,
|
---|
[19757] | 1004 | PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, RTGCUINTPTR uSubtrahend, uint32_t fFlags)
|
---|
| 1005 | {
|
---|
| 1006 | /*
|
---|
| 1007 | * Validate input
|
---|
| 1008 | */
|
---|
[44399] | 1009 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
|
---|
[19757] | 1010 | AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
|
---|
| 1011 | AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
|
---|
[44399] | 1012 | AssertReturn(DBGFR3AddrIsValid(pUVM, pModAddress), VERR_INVALID_PARAMETER);
|
---|
[19757] | 1013 | AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER);
|
---|
[44399] | 1014 | RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
|
---|
[19757] | 1015 | if (hRealAS == NIL_RTDBGAS)
|
---|
| 1016 | return VERR_INVALID_HANDLE;
|
---|
| 1017 |
|
---|
[45984] | 1018 | RTDBGMOD hDbgMod;
|
---|
| 1019 | int rc = RTDbgModCreateFromMap(&hDbgMod, pszFilename, pszModName, uSubtrahend, pUVM->dbgf.s.hDbgCfg);
|
---|
[19757] | 1020 | if (RT_SUCCESS(rc))
|
---|
| 1021 | {
|
---|
[45984] | 1022 | rc = DBGFR3AsLinkModule(pUVM, hRealAS, hDbgMod, pModAddress, iModSeg, 0);
|
---|
[19757] | 1023 | if (RT_FAILURE(rc))
|
---|
[45984] | 1024 | RTDbgModRelease(hDbgMod);
|
---|
[19757] | 1025 | }
|
---|
| 1026 |
|
---|
| 1027 | RTDbgAsRelease(hRealAS);
|
---|
| 1028 | return rc;
|
---|
| 1029 | }
|
---|
| 1030 |
|
---|
| 1031 |
|
---|
| 1032 | /**
|
---|
| 1033 | * Wrapper around RTDbgAsModuleLink, RTDbgAsModuleLinkSeg and DBGFR3AsResolve.
|
---|
| 1034 | *
|
---|
| 1035 | * @returns VBox status code.
|
---|
[44399] | 1036 | * @param pUVM The user mode VM handle.
|
---|
[19757] | 1037 | * @param hDbgAs The address space handle.
|
---|
| 1038 | * @param hMod The module handle.
|
---|
| 1039 | * @param pModAddress The link address.
|
---|
| 1040 | * @param iModSeg The segment to link, NIL_RTDBGSEGIDX for the entire image.
|
---|
| 1041 | * @param fFlags Flags to pass to the link functions, see RTDBGASLINK_FLAGS_*.
|
---|
| 1042 | */
|
---|
[44399] | 1043 | VMMR3DECL(int) DBGFR3AsLinkModule(PUVM pUVM, RTDBGAS hDbgAs, RTDBGMOD hMod, PCDBGFADDRESS pModAddress,
|
---|
| 1044 | RTDBGSEGIDX iModSeg, uint32_t fFlags)
|
---|
[19757] | 1045 | {
|
---|
| 1046 | /*
|
---|
| 1047 | * Input validation.
|
---|
| 1048 | */
|
---|
[44399] | 1049 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
|
---|
| 1050 | AssertReturn(DBGFR3AddrIsValid(pUVM, pModAddress), VERR_INVALID_PARAMETER);
|
---|
| 1051 | RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
|
---|
[19757] | 1052 | if (hRealAS == NIL_RTDBGAS)
|
---|
| 1053 | return VERR_INVALID_HANDLE;
|
---|
| 1054 |
|
---|
| 1055 | /*
|
---|
| 1056 | * Do the job.
|
---|
| 1057 | */
|
---|
| 1058 | int rc;
|
---|
| 1059 | if (iModSeg == NIL_RTDBGSEGIDX)
|
---|
| 1060 | rc = RTDbgAsModuleLink(hRealAS, hMod, pModAddress->FlatPtr, fFlags);
|
---|
| 1061 | else
|
---|
| 1062 | rc = RTDbgAsModuleLinkSeg(hRealAS, hMod, iModSeg, pModAddress->FlatPtr, fFlags);
|
---|
| 1063 |
|
---|
| 1064 | RTDbgAsRelease(hRealAS);
|
---|
| 1065 | return rc;
|
---|
| 1066 | }
|
---|
| 1067 |
|
---|
[21111] | 1068 |
|
---|
| 1069 | /**
|
---|
[48694] | 1070 | * Wrapper around RTDbgAsModuleByName and RTDbgAsModuleUnlink.
|
---|
| 1071 | *
|
---|
| 1072 | * Unlinks all mappings matching the given module name.
|
---|
| 1073 | *
|
---|
| 1074 | * @returns VBox status code.
|
---|
| 1075 | * @param pUVM The user mode VM handle.
|
---|
| 1076 | * @param hDbgAs The address space handle.
|
---|
| 1077 | * @param pszModName The name of the module to unlink.
|
---|
| 1078 | */
|
---|
| 1079 | VMMR3DECL(int) DBGFR3AsUnlinkModuleByName(PUVM pUVM, RTDBGAS hDbgAs, const char *pszModName)
|
---|
| 1080 | {
|
---|
| 1081 | /*
|
---|
| 1082 | * Input validation.
|
---|
| 1083 | */
|
---|
| 1084 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
|
---|
| 1085 | RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
|
---|
| 1086 | if (hRealAS == NIL_RTDBGAS)
|
---|
| 1087 | return VERR_INVALID_HANDLE;
|
---|
| 1088 |
|
---|
| 1089 | /*
|
---|
| 1090 | * Do the job.
|
---|
| 1091 | */
|
---|
| 1092 | RTDBGMOD hMod;
|
---|
| 1093 | int rc = RTDbgAsModuleByName(hRealAS, pszModName, 0, &hMod);
|
---|
| 1094 | if (RT_SUCCESS(rc))
|
---|
| 1095 | {
|
---|
| 1096 | for (;;)
|
---|
| 1097 | {
|
---|
| 1098 | rc = RTDbgAsModuleUnlink(hRealAS, hMod);
|
---|
| 1099 | RTDbgModRelease(hMod);
|
---|
| 1100 | if (RT_FAILURE(rc))
|
---|
| 1101 | break;
|
---|
| 1102 | rc = RTDbgAsModuleByName(hRealAS, pszModName, 0, &hMod);
|
---|
| 1103 | if (RT_FAILURE_NP(rc))
|
---|
| 1104 | {
|
---|
| 1105 | if (rc == VERR_NOT_FOUND)
|
---|
| 1106 | rc = VINF_SUCCESS;
|
---|
| 1107 | break;
|
---|
| 1108 | }
|
---|
| 1109 | }
|
---|
| 1110 | }
|
---|
| 1111 |
|
---|
| 1112 | RTDbgAsRelease(hRealAS);
|
---|
| 1113 | return rc;
|
---|
| 1114 | }
|
---|
| 1115 |
|
---|
| 1116 |
|
---|
| 1117 | /**
|
---|
[21111] | 1118 | * Adds the module name to the symbol name.
|
---|
| 1119 | *
|
---|
| 1120 | * @param pSymbol The symbol info (in/out).
|
---|
| 1121 | * @param hMod The module handle.
|
---|
| 1122 | */
|
---|
| 1123 | static void dbgfR3AsSymbolJoinNames(PRTDBGSYMBOL pSymbol, RTDBGMOD hMod)
|
---|
| 1124 | {
|
---|
| 1125 | /* Figure the lengths, adjust them if the result is too long. */
|
---|
| 1126 | const char *pszModName = RTDbgModName(hMod);
|
---|
| 1127 | size_t cchModName = strlen(pszModName);
|
---|
| 1128 | size_t cchSymbol = strlen(pSymbol->szName);
|
---|
| 1129 | if (cchModName + 1 + cchSymbol >= sizeof(pSymbol->szName))
|
---|
| 1130 | {
|
---|
| 1131 | if (cchModName >= sizeof(pSymbol->szName) / 4)
|
---|
| 1132 | cchModName = sizeof(pSymbol->szName) / 4;
|
---|
| 1133 | if (cchModName + 1 + cchSymbol >= sizeof(pSymbol->szName))
|
---|
| 1134 | cchSymbol = sizeof(pSymbol->szName) - cchModName - 2;
|
---|
| 1135 | Assert(cchModName + 1 + cchSymbol < sizeof(pSymbol->szName));
|
---|
| 1136 | }
|
---|
| 1137 |
|
---|
| 1138 | /* Do the moving and copying. */
|
---|
| 1139 | memmove(&pSymbol->szName[cchModName + 1], &pSymbol->szName[0], cchSymbol + 1);
|
---|
| 1140 | memcpy(&pSymbol->szName[0], pszModName, cchModName);
|
---|
| 1141 | pSymbol->szName[cchModName] = '!';
|
---|
| 1142 | }
|
---|
| 1143 |
|
---|
| 1144 |
|
---|
| 1145 | /** Temporary symbol conversion function. */
|
---|
| 1146 | static void dbgfR3AsSymbolConvert(PRTDBGSYMBOL pSymbol, PCDBGFSYMBOL pDbgfSym)
|
---|
| 1147 | {
|
---|
| 1148 | pSymbol->offSeg = pSymbol->Value = pDbgfSym->Value;
|
---|
| 1149 | pSymbol->cb = pDbgfSym->cb;
|
---|
| 1150 | pSymbol->iSeg = 0;
|
---|
| 1151 | pSymbol->fFlags = 0;
|
---|
| 1152 | pSymbol->iOrdinal = UINT32_MAX;
|
---|
| 1153 | strcpy(pSymbol->szName, pDbgfSym->szName);
|
---|
| 1154 | }
|
---|
| 1155 |
|
---|
| 1156 |
|
---|
| 1157 | /**
|
---|
| 1158 | * Query a symbol by address.
|
---|
| 1159 | *
|
---|
| 1160 | * The returned symbol is the one we consider closes to the specified address.
|
---|
| 1161 | *
|
---|
| 1162 | * @returns VBox status code. See RTDbgAsSymbolByAddr.
|
---|
| 1163 | *
|
---|
[44399] | 1164 | * @param pUVM The user mode VM handle.
|
---|
| 1165 | * @param hDbgAs The address space handle.
|
---|
| 1166 | * @param pAddress The address to lookup.
|
---|
[46155] | 1167 | * @param fFlags One of the RTDBGSYMADDR_FLAGS_XXX flags.
|
---|
[44399] | 1168 | * @param poffDisp Where to return the distance between the returned
|
---|
| 1169 | * symbol and pAddress. Optional.
|
---|
| 1170 | * @param pSymbol Where to return the symbol information. The returned
|
---|
| 1171 | * symbol name will be prefixed by the module name as
|
---|
| 1172 | * far as space allows.
|
---|
| 1173 | * @param phMod Where to return the module handle. Optional.
|
---|
[21111] | 1174 | */
|
---|
[46155] | 1175 | VMMR3DECL(int) DBGFR3AsSymbolByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, uint32_t fFlags,
|
---|
[21111] | 1176 | PRTGCINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
|
---|
| 1177 | {
|
---|
| 1178 | /*
|
---|
| 1179 | * Implement the special address space aliases the lazy way.
|
---|
| 1180 | */
|
---|
| 1181 | if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL)
|
---|
| 1182 | {
|
---|
[46155] | 1183 | int rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_RC, pAddress, fFlags, poffDisp, pSymbol, phMod);
|
---|
[21111] | 1184 | if (RT_FAILURE(rc))
|
---|
[46155] | 1185 | rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_GLOBAL, pAddress, fFlags, poffDisp, pSymbol, phMod);
|
---|
[21111] | 1186 | return rc;
|
---|
| 1187 | }
|
---|
| 1188 |
|
---|
| 1189 | /*
|
---|
| 1190 | * Input validation.
|
---|
| 1191 | */
|
---|
[44399] | 1192 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
|
---|
| 1193 | AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER);
|
---|
[21111] | 1194 | AssertPtrNullReturn(poffDisp, VERR_INVALID_POINTER);
|
---|
| 1195 | AssertPtrReturn(pSymbol, VERR_INVALID_POINTER);
|
---|
| 1196 | AssertPtrNullReturn(phMod, VERR_INVALID_POINTER);
|
---|
| 1197 | if (poffDisp)
|
---|
| 1198 | *poffDisp = 0;
|
---|
| 1199 | if (phMod)
|
---|
| 1200 | *phMod = NIL_RTDBGMOD;
|
---|
[44399] | 1201 | RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
|
---|
[21111] | 1202 | if (hRealAS == NIL_RTDBGAS)
|
---|
| 1203 | return VERR_INVALID_HANDLE;
|
---|
| 1204 |
|
---|
| 1205 | /*
|
---|
| 1206 | * Do the lookup.
|
---|
| 1207 | */
|
---|
| 1208 | RTDBGMOD hMod;
|
---|
[46155] | 1209 | int rc = RTDbgAsSymbolByAddr(hRealAS, pAddress->FlatPtr, fFlags, poffDisp, pSymbol, &hMod);
|
---|
[21111] | 1210 | if (RT_SUCCESS(rc))
|
---|
| 1211 | {
|
---|
| 1212 | dbgfR3AsSymbolJoinNames(pSymbol, hMod);
|
---|
| 1213 | if (!phMod)
|
---|
| 1214 | RTDbgModRelease(hMod);
|
---|
| 1215 | }
|
---|
| 1216 |
|
---|
| 1217 | return rc;
|
---|
| 1218 | }
|
---|
| 1219 |
|
---|
| 1220 |
|
---|
| 1221 | /**
|
---|
[22112] | 1222 | * Convenience function that combines RTDbgSymbolDup and DBGFR3AsSymbolByAddr.
|
---|
| 1223 | *
|
---|
| 1224 | * @returns Pointer to the symbol on success. This must be free using
|
---|
| 1225 | * RTDbgSymbolFree(). NULL is returned if not found or any error
|
---|
| 1226 | * occurs.
|
---|
| 1227 | *
|
---|
[44399] | 1228 | * @param pUVM The user mode VM handle.
|
---|
| 1229 | * @param hDbgAs See DBGFR3AsSymbolByAddr.
|
---|
| 1230 | * @param pAddress See DBGFR3AsSymbolByAddr.
|
---|
[46155] | 1231 | * @param fFlags See DBGFR3AsSymbolByAddr.
|
---|
[44399] | 1232 | * @param poffDisp See DBGFR3AsSymbolByAddr.
|
---|
| 1233 | * @param phMod See DBGFR3AsSymbolByAddr.
|
---|
[22112] | 1234 | */
|
---|
[46155] | 1235 | VMMR3DECL(PRTDBGSYMBOL) DBGFR3AsSymbolByAddrA(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, uint32_t fFlags,
|
---|
| 1236 | PRTGCINTPTR poffDisp, PRTDBGMOD phMod)
|
---|
[22112] | 1237 | {
|
---|
| 1238 | RTDBGSYMBOL SymInfo;
|
---|
[46155] | 1239 | int rc = DBGFR3AsSymbolByAddr(pUVM, hDbgAs, pAddress, fFlags, poffDisp, &SymInfo, phMod);
|
---|
[22112] | 1240 | if (RT_SUCCESS(rc))
|
---|
| 1241 | return RTDbgSymbolDup(&SymInfo);
|
---|
| 1242 | return NULL;
|
---|
| 1243 | }
|
---|
| 1244 |
|
---|
| 1245 |
|
---|
| 1246 | /**
|
---|
[21111] | 1247 | * Query a symbol by name.
|
---|
| 1248 | *
|
---|
| 1249 | * The symbol can be prefixed by a module name pattern to scope the search. The
|
---|
| 1250 | * pattern is a simple string pattern with '*' and '?' as wild chars. See
|
---|
| 1251 | * RTStrSimplePatternMatch().
|
---|
| 1252 | *
|
---|
| 1253 | * @returns VBox status code. See RTDbgAsSymbolByAddr.
|
---|
| 1254 | *
|
---|
[44399] | 1255 | * @param pUVM The user mode VM handle.
|
---|
| 1256 | * @param hDbgAs The address space handle.
|
---|
| 1257 | * @param pszSymbol The symbol to search for, maybe prefixed by a
|
---|
| 1258 | * module pattern.
|
---|
| 1259 | * @param pSymbol Where to return the symbol information.
|
---|
| 1260 | * The returned symbol name will be prefixed by
|
---|
| 1261 | * the module name as far as space allows.
|
---|
| 1262 | * @param phMod Where to return the module handle. Optional.
|
---|
[21111] | 1263 | */
|
---|
[44399] | 1264 | VMMR3DECL(int) DBGFR3AsSymbolByName(PUVM pUVM, RTDBGAS hDbgAs, const char *pszSymbol,
|
---|
[21111] | 1265 | PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
|
---|
| 1266 | {
|
---|
| 1267 | /*
|
---|
| 1268 | * Implement the special address space aliases the lazy way.
|
---|
| 1269 | */
|
---|
| 1270 | if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL)
|
---|
| 1271 | {
|
---|
[44399] | 1272 | int rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_RC, pszSymbol, pSymbol, phMod);
|
---|
[21111] | 1273 | if (RT_FAILURE(rc))
|
---|
[44399] | 1274 | rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_GLOBAL, pszSymbol, pSymbol, phMod);
|
---|
[21111] | 1275 | return rc;
|
---|
| 1276 | }
|
---|
| 1277 |
|
---|
| 1278 | /*
|
---|
| 1279 | * Input validation.
|
---|
| 1280 | */
|
---|
[44399] | 1281 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
|
---|
[21111] | 1282 | AssertPtrReturn(pSymbol, VERR_INVALID_POINTER);
|
---|
| 1283 | AssertPtrNullReturn(phMod, VERR_INVALID_POINTER);
|
---|
| 1284 | if (phMod)
|
---|
| 1285 | *phMod = NIL_RTDBGMOD;
|
---|
[44399] | 1286 | RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
|
---|
[21111] | 1287 | if (hRealAS == NIL_RTDBGAS)
|
---|
| 1288 | return VERR_INVALID_HANDLE;
|
---|
| 1289 |
|
---|
| 1290 |
|
---|
| 1291 | /*
|
---|
| 1292 | * Do the lookup.
|
---|
| 1293 | */
|
---|
| 1294 | RTDBGMOD hMod;
|
---|
| 1295 | int rc = RTDbgAsSymbolByName(hRealAS, pszSymbol, pSymbol, &hMod);
|
---|
| 1296 | if (RT_SUCCESS(rc))
|
---|
| 1297 | {
|
---|
| 1298 | dbgfR3AsSymbolJoinNames(pSymbol, hMod);
|
---|
| 1299 | if (!phMod)
|
---|
| 1300 | RTDbgModRelease(hMod);
|
---|
| 1301 | }
|
---|
| 1302 |
|
---|
| 1303 | return rc;
|
---|
| 1304 | }
|
---|
| 1305 |
|
---|
[46165] | 1306 |
|
---|
| 1307 | VMMR3DECL(int) DBGFR3AsLineByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress,
|
---|
| 1308 | PRTGCINTPTR poffDisp, PRTDBGLINE pLine, PRTDBGMOD phMod)
|
---|
| 1309 | {
|
---|
| 1310 | /*
|
---|
| 1311 | * Implement the special address space aliases the lazy way.
|
---|
| 1312 | */
|
---|
| 1313 | if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL)
|
---|
| 1314 | {
|
---|
| 1315 | int rc = DBGFR3AsLineByAddr(pUVM, DBGF_AS_RC, pAddress, poffDisp, pLine, phMod);
|
---|
| 1316 | if (RT_FAILURE(rc))
|
---|
| 1317 | rc = DBGFR3AsLineByAddr(pUVM, DBGF_AS_GLOBAL, pAddress, poffDisp, pLine, phMod);
|
---|
| 1318 | return rc;
|
---|
| 1319 | }
|
---|
| 1320 |
|
---|
| 1321 | /*
|
---|
| 1322 | * Input validation.
|
---|
| 1323 | */
|
---|
| 1324 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
|
---|
| 1325 | AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER);
|
---|
| 1326 | AssertPtrNullReturn(poffDisp, VERR_INVALID_POINTER);
|
---|
| 1327 | AssertPtrReturn(pLine, VERR_INVALID_POINTER);
|
---|
| 1328 | AssertPtrNullReturn(phMod, VERR_INVALID_POINTER);
|
---|
| 1329 | if (poffDisp)
|
---|
| 1330 | *poffDisp = 0;
|
---|
| 1331 | if (phMod)
|
---|
| 1332 | *phMod = NIL_RTDBGMOD;
|
---|
| 1333 | RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
|
---|
| 1334 | if (hRealAS == NIL_RTDBGAS)
|
---|
| 1335 | return VERR_INVALID_HANDLE;
|
---|
| 1336 |
|
---|
| 1337 | /*
|
---|
| 1338 | * Do the lookup.
|
---|
| 1339 | */
|
---|
| 1340 | return RTDbgAsLineByAddr(hRealAS, pAddress->FlatPtr, poffDisp, pLine, phMod);
|
---|
| 1341 | }
|
---|
| 1342 |
|
---|
| 1343 |
|
---|
| 1344 | VMMR3DECL(PRTDBGLINE) DBGFR3AsLineByAddrA(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress,
|
---|
| 1345 | PRTGCINTPTR poffDisp, PRTDBGMOD phMod)
|
---|
| 1346 | {
|
---|
| 1347 | RTDBGLINE Line;
|
---|
| 1348 | int rc = DBGFR3AsLineByAddr(pUVM, hDbgAs, pAddress, poffDisp, &Line, phMod);
|
---|
| 1349 | if (RT_SUCCESS(rc))
|
---|
| 1350 | return RTDbgLineDup(&Line);
|
---|
| 1351 | return NULL;
|
---|
| 1352 | }
|
---|
| 1353 |
|
---|