[8797] | 1 | /* $Id: DBGFOS.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
[12677] | 3 | * DBGF - Debugger Facility, Guest OS Diggers.
|
---|
[8797] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[76553] | 7 | * Copyright (C) 2008-2019 Oracle Corporation
|
---|
[8797] | 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 |
|
---|
[57358] | 19 | /*********************************************************************************************************************************
|
---|
| 20 | * Header Files *
|
---|
| 21 | *********************************************************************************************************************************/
|
---|
[8797] | 22 | #define LOG_GROUP LOG_GROUP_DBGF
|
---|
[35346] | 23 | #include <VBox/vmm/dbgf.h>
|
---|
| 24 | #include <VBox/vmm/mm.h>
|
---|
[8797] | 25 | #include "DBGFInternal.h"
|
---|
[44399] | 26 | #include <VBox/vmm/uvm.h>
|
---|
[8797] | 27 | #include <VBox/err.h>
|
---|
[22108] | 28 | #include <VBox/log.h>
|
---|
[8797] | 29 |
|
---|
[22108] | 30 | #include <iprt/assert.h>
|
---|
[8797] | 31 | #include <iprt/thread.h>
|
---|
[22108] | 32 | #include <iprt/param.h>
|
---|
[8797] | 33 |
|
---|
| 34 |
|
---|
[57358] | 35 | /*********************************************************************************************************************************
|
---|
| 36 | * Defined Constants And Macros *
|
---|
| 37 | *********************************************************************************************************************************/
|
---|
[8797] | 38 |
|
---|
[54218] | 39 | #define DBGF_OS_READ_LOCK(pUVM) \
|
---|
[55881] | 40 | do { int rcLock = RTCritSectRwEnterShared(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
|
---|
[54218] | 41 | #define DBGF_OS_READ_UNLOCK(pUVM) \
|
---|
[55881] | 42 | do { int rcLock = RTCritSectRwLeaveShared(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
|
---|
[22108] | 43 |
|
---|
[54218] | 44 | #define DBGF_OS_WRITE_LOCK(pUVM) \
|
---|
[55881] | 45 | do { int rcLock = RTCritSectRwEnterExcl(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
|
---|
[54218] | 46 | #define DBGF_OS_WRITE_UNLOCK(pUVM) \
|
---|
[55881] | 47 | do { int rcLock = RTCritSectRwLeaveExcl(&pUVM->dbgf.s.CritSect); AssertRC(rcLock); } while (0)
|
---|
[22108] | 48 |
|
---|
[54218] | 49 |
|
---|
[57358] | 50 | /*********************************************************************************************************************************
|
---|
| 51 | * Structures and Typedefs *
|
---|
| 52 | *********************************************************************************************************************************/
|
---|
[8797] | 53 | /**
|
---|
[54218] | 54 | * EMT interface wrappers.
|
---|
| 55 | *
|
---|
| 56 | * The diggers expects to be called on an EMT. To avoid the debugger+Main having
|
---|
| 57 | *
|
---|
| 58 | * Since the user (debugger/Main) shouldn't be calling directly into the digger code, but rather
|
---|
| 59 | */
|
---|
| 60 | typedef struct DBGFOSEMTWRAPPER
|
---|
| 61 | {
|
---|
| 62 | /** Pointer to the next list entry. */
|
---|
| 63 | struct DBGFOSEMTWRAPPER *pNext;
|
---|
| 64 | /** The interface type. */
|
---|
| 65 | DBGFOSINTERFACE enmIf;
|
---|
| 66 | /** The digger interface pointer. */
|
---|
| 67 | union
|
---|
| 68 | {
|
---|
| 69 | /** Generic void pointer. */
|
---|
| 70 | void *pv;
|
---|
| 71 | /** DBGFOSINTERFACE_DMESG.*/
|
---|
| 72 | PDBGFOSIDMESG pDmesg;
|
---|
| 73 | } uDigger;
|
---|
| 74 | /** The user mode VM handle. */
|
---|
| 75 | PUVM pUVM;
|
---|
| 76 | /** The wrapper interface union (consult enmIf). */
|
---|
| 77 | union
|
---|
| 78 | {
|
---|
| 79 | /** DBGFOSINTERFACE_DMESG.*/
|
---|
| 80 | DBGFOSIDMESG Dmesg;
|
---|
| 81 | } uWrapper;
|
---|
| 82 | } DBGFOSEMTWRAPPER;
|
---|
| 83 | /** Pointer to an EMT interface wrapper. */
|
---|
| 84 | typedef DBGFOSEMTWRAPPER *PDBGFOSEMTWRAPPER;
|
---|
| 85 |
|
---|
| 86 |
|
---|
| 87 | /**
|
---|
| 88 | * Internal init routine called by DBGFR3Init().
|
---|
| 89 | *
|
---|
| 90 | * @returns VBox status code.
|
---|
| 91 | * @param pUVM The user mode VM handle.
|
---|
| 92 | */
|
---|
| 93 | int dbgfR3OSInit(PUVM pUVM)
|
---|
| 94 | {
|
---|
[62638] | 95 | RT_NOREF_PV(pUVM);
|
---|
[55881] | 96 | return VINF_SUCCESS;
|
---|
[54218] | 97 | }
|
---|
| 98 |
|
---|
| 99 |
|
---|
| 100 | /**
|
---|
[73414] | 101 | * Internal cleanup routine called by DBGFR3Term(), part 1.
|
---|
[22108] | 102 | *
|
---|
[44399] | 103 | * @param pUVM The user mode VM handle.
|
---|
[22108] | 104 | */
|
---|
[73414] | 105 | void dbgfR3OSTermPart1(PUVM pUVM)
|
---|
[22108] | 106 | {
|
---|
[55881] | 107 | DBGF_OS_WRITE_LOCK(pUVM);
|
---|
[54218] | 108 |
|
---|
[22108] | 109 | /*
|
---|
| 110 | * Terminate the current one.
|
---|
| 111 | */
|
---|
[44399] | 112 | if (pUVM->dbgf.s.pCurOS)
|
---|
[22108] | 113 | {
|
---|
[44399] | 114 | pUVM->dbgf.s.pCurOS->pReg->pfnTerm(pUVM, pUVM->dbgf.s.pCurOS->abData);
|
---|
| 115 | pUVM->dbgf.s.pCurOS = NULL;
|
---|
[22108] | 116 | }
|
---|
| 117 |
|
---|
[73414] | 118 | DBGF_OS_WRITE_UNLOCK(pUVM);
|
---|
| 119 | }
|
---|
| 120 |
|
---|
| 121 |
|
---|
| 122 | /**
|
---|
| 123 | * Internal cleanup routine called by DBGFR3Term(), part 2.
|
---|
| 124 | *
|
---|
| 125 | * @param pUVM The user mode VM handle.
|
---|
| 126 | */
|
---|
| 127 | void dbgfR3OSTermPart2(PUVM pUVM)
|
---|
| 128 | {
|
---|
| 129 | DBGF_OS_WRITE_LOCK(pUVM);
|
---|
| 130 |
|
---|
| 131 | /* This shouldn't happen. */
|
---|
| 132 | AssertStmt(!pUVM->dbgf.s.pCurOS, dbgfR3OSTermPart1(pUVM));
|
---|
| 133 |
|
---|
[22108] | 134 | /*
|
---|
| 135 | * Destroy all the instances.
|
---|
| 136 | */
|
---|
[44399] | 137 | while (pUVM->dbgf.s.pOSHead)
|
---|
[22108] | 138 | {
|
---|
[44399] | 139 | PDBGFOS pOS = pUVM->dbgf.s.pOSHead;
|
---|
| 140 | pUVM->dbgf.s.pOSHead = pOS->pNext;
|
---|
[22108] | 141 | if (pOS->pReg->pfnDestruct)
|
---|
[44399] | 142 | pOS->pReg->pfnDestruct(pUVM, pOS->abData);
|
---|
[54218] | 143 |
|
---|
| 144 | PDBGFOSEMTWRAPPER pFree = pOS->pWrapperHead;
|
---|
| 145 | while ((pFree = pOS->pWrapperHead) != NULL)
|
---|
| 146 | {
|
---|
| 147 | pOS->pWrapperHead = pFree->pNext;
|
---|
| 148 | pFree->pNext = NULL;
|
---|
| 149 | MMR3HeapFree(pFree);
|
---|
| 150 | }
|
---|
| 151 |
|
---|
[22108] | 152 | MMR3HeapFree(pOS);
|
---|
| 153 | }
|
---|
[55881] | 154 |
|
---|
| 155 | DBGF_OS_WRITE_UNLOCK(pUVM);
|
---|
[22108] | 156 | }
|
---|
| 157 |
|
---|
| 158 |
|
---|
| 159 | /**
|
---|
[8800] | 160 | * EMT worker function for DBGFR3OSRegister.
|
---|
| 161 | *
|
---|
| 162 | * @returns VBox status code.
|
---|
[44399] | 163 | * @param pUVM The user mode VM handle.
|
---|
[8800] | 164 | * @param pReg The registration structure.
|
---|
| 165 | */
|
---|
[44399] | 166 | static DECLCALLBACK(int) dbgfR3OSRegister(PUVM pUVM, PDBGFOSREG pReg)
|
---|
[8800] | 167 | {
|
---|
| 168 | /* more validations. */
|
---|
[44399] | 169 | DBGF_OS_READ_LOCK(pUVM);
|
---|
[12898] | 170 | PDBGFOS pOS;
|
---|
[44399] | 171 | for (pOS = pUVM->dbgf.s.pOSHead; pOS; pOS = pOS->pNext)
|
---|
[8800] | 172 | if (!strcmp(pOS->pReg->szName, pReg->szName))
|
---|
| 173 | {
|
---|
[44399] | 174 | DBGF_OS_READ_UNLOCK(pUVM);
|
---|
[8800] | 175 | Log(("dbgfR3OSRegister: %s -> VERR_ALREADY_LOADED\n", pReg->szName));
|
---|
| 176 | return VERR_ALREADY_LOADED;
|
---|
| 177 | }
|
---|
[54218] | 178 | DBGF_OS_READ_UNLOCK(pUVM);
|
---|
[8800] | 179 |
|
---|
| 180 | /*
|
---|
| 181 | * Allocate a new structure, call the constructor and link it into the list.
|
---|
| 182 | */
|
---|
[73097] | 183 | pOS = (PDBGFOS)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_OS, RT_UOFFSETOF_DYN(DBGFOS, abData[pReg->cbData]));
|
---|
[8800] | 184 | AssertReturn(pOS, VERR_NO_MEMORY);
|
---|
| 185 | pOS->pReg = pReg;
|
---|
| 186 |
|
---|
[44399] | 187 | int rc = pOS->pReg->pfnConstruct(pUVM, pOS->abData);
|
---|
[8800] | 188 | if (RT_SUCCESS(rc))
|
---|
| 189 | {
|
---|
[44399] | 190 | DBGF_OS_WRITE_LOCK(pUVM);
|
---|
| 191 | pOS->pNext = pUVM->dbgf.s.pOSHead;
|
---|
| 192 | pUVM->dbgf.s.pOSHead = pOS;
|
---|
| 193 | DBGF_OS_WRITE_UNLOCK(pUVM);
|
---|
[8800] | 194 | }
|
---|
| 195 | else
|
---|
| 196 | {
|
---|
| 197 | if (pOS->pReg->pfnDestruct)
|
---|
[44399] | 198 | pOS->pReg->pfnDestruct(pUVM, pOS->abData);
|
---|
[8800] | 199 | MMR3HeapFree(pOS);
|
---|
| 200 | }
|
---|
| 201 |
|
---|
| 202 | return VINF_SUCCESS;
|
---|
| 203 | }
|
---|
| 204 |
|
---|
| 205 |
|
---|
| 206 | /**
|
---|
[8797] | 207 | * Registers a guest OS digger.
|
---|
| 208 | *
|
---|
| 209 | * This will instantiate an instance of the digger and add it
|
---|
| 210 | * to the list for us in the next call to DBGFR3OSDetect().
|
---|
| 211 | *
|
---|
| 212 | * @returns VBox status code.
|
---|
[44399] | 213 | * @param pUVM The user mode VM handle.
|
---|
[8797] | 214 | * @param pReg The registration structure.
|
---|
[8800] | 215 | * @thread Any.
|
---|
[8797] | 216 | */
|
---|
[44399] | 217 | VMMR3DECL(int) DBGFR3OSRegister(PUVM pUVM, PCDBGFOSREG pReg)
|
---|
[8797] | 218 | {
|
---|
| 219 | /*
|
---|
| 220 | * Validate intput.
|
---|
| 221 | */
|
---|
[44399] | 222 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
|
---|
[22108] | 223 |
|
---|
[8797] | 224 | AssertPtrReturn(pReg, VERR_INVALID_POINTER);
|
---|
| 225 | AssertReturn(pReg->u32Magic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
|
---|
| 226 | AssertReturn(pReg->u32EndMagic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
|
---|
| 227 | AssertReturn(!pReg->fFlags, VERR_INVALID_PARAMETER);
|
---|
| 228 | AssertReturn(pReg->cbData < _2G, VERR_INVALID_PARAMETER);
|
---|
[8800] | 229 | AssertReturn(pReg->szName[0], VERR_INVALID_NAME);
|
---|
[30320] | 230 | AssertReturn(RTStrEnd(&pReg->szName[0], sizeof(pReg->szName)), VERR_INVALID_NAME);
|
---|
[8797] | 231 | AssertPtrReturn(pReg->pfnConstruct, VERR_INVALID_POINTER);
|
---|
| 232 | AssertPtrNullReturn(pReg->pfnDestruct, VERR_INVALID_POINTER);
|
---|
| 233 | AssertPtrReturn(pReg->pfnProbe, VERR_INVALID_POINTER);
|
---|
| 234 | AssertPtrReturn(pReg->pfnInit, VERR_INVALID_POINTER);
|
---|
| 235 | AssertPtrReturn(pReg->pfnRefresh, VERR_INVALID_POINTER);
|
---|
| 236 | AssertPtrReturn(pReg->pfnTerm, VERR_INVALID_POINTER);
|
---|
| 237 | AssertPtrReturn(pReg->pfnQueryVersion, VERR_INVALID_POINTER);
|
---|
| 238 | AssertPtrReturn(pReg->pfnQueryInterface, VERR_INVALID_POINTER);
|
---|
| 239 |
|
---|
| 240 | /*
|
---|
[23011] | 241 | * Pass it on to EMT(0).
|
---|
[8797] | 242 | */
|
---|
[44399] | 243 | return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSRegister, 2, pUVM, pReg);
|
---|
[8797] | 244 | }
|
---|
| 245 |
|
---|
| 246 |
|
---|
| 247 | /**
|
---|
[22108] | 248 | * EMT worker function for DBGFR3OSDeregister.
|
---|
[8797] | 249 | *
|
---|
[22108] | 250 | * @returns VBox status code.
|
---|
[44399] | 251 | * @param pUVM The user mode VM handle.
|
---|
[22108] | 252 | * @param pReg The registration structure.
|
---|
[8797] | 253 | */
|
---|
[44399] | 254 | static DECLCALLBACK(int) dbgfR3OSDeregister(PUVM pUVM, PDBGFOSREG pReg)
|
---|
[8797] | 255 | {
|
---|
| 256 | /*
|
---|
[22108] | 257 | * Unlink it.
|
---|
[8797] | 258 | */
|
---|
[22108] | 259 | bool fWasCurOS = false;
|
---|
| 260 | PDBGFOS pOSPrev = NULL;
|
---|
| 261 | PDBGFOS pOS;
|
---|
[44399] | 262 | DBGF_OS_WRITE_LOCK(pUVM);
|
---|
| 263 | for (pOS = pUVM->dbgf.s.pOSHead; pOS; pOSPrev = pOS, pOS = pOS->pNext)
|
---|
[22108] | 264 | if (pOS->pReg == pReg)
|
---|
| 265 | {
|
---|
| 266 | if (pOSPrev)
|
---|
| 267 | pOSPrev->pNext = pOS->pNext;
|
---|
| 268 | else
|
---|
[44399] | 269 | pUVM->dbgf.s.pOSHead = pOS->pNext;
|
---|
| 270 | if (pUVM->dbgf.s.pCurOS == pOS)
|
---|
[22108] | 271 | {
|
---|
[44399] | 272 | pUVM->dbgf.s.pCurOS = NULL;
|
---|
[22108] | 273 | fWasCurOS = true;
|
---|
| 274 | }
|
---|
| 275 | break;
|
---|
| 276 | }
|
---|
[44399] | 277 | DBGF_OS_WRITE_UNLOCK(pUVM);
|
---|
[22108] | 278 | if (!pOS)
|
---|
[8797] | 279 | {
|
---|
[22108] | 280 | Log(("DBGFR3OSDeregister: %s -> VERR_NOT_FOUND\n", pReg->szName));
|
---|
| 281 | return VERR_NOT_FOUND;
|
---|
[8797] | 282 | }
|
---|
| 283 |
|
---|
| 284 | /*
|
---|
[22108] | 285 | * Terminate it if it was the current OS, then invoke the
|
---|
| 286 | * destructor and clean up.
|
---|
[8797] | 287 | */
|
---|
[22108] | 288 | if (fWasCurOS)
|
---|
[44399] | 289 | pOS->pReg->pfnTerm(pUVM, pOS->abData);
|
---|
[22108] | 290 | if (pOS->pReg->pfnDestruct)
|
---|
[44399] | 291 | pOS->pReg->pfnDestruct(pUVM, pOS->abData);
|
---|
[54218] | 292 |
|
---|
| 293 | PDBGFOSEMTWRAPPER pFree = pOS->pWrapperHead;
|
---|
| 294 | while ((pFree = pOS->pWrapperHead) != NULL)
|
---|
| 295 | {
|
---|
| 296 | pOS->pWrapperHead = pFree->pNext;
|
---|
| 297 | pFree->pNext = NULL;
|
---|
| 298 | MMR3HeapFree(pFree);
|
---|
| 299 | }
|
---|
| 300 |
|
---|
[22108] | 301 | MMR3HeapFree(pOS);
|
---|
| 302 |
|
---|
| 303 | return VINF_SUCCESS;
|
---|
| 304 | }
|
---|
| 305 |
|
---|
| 306 |
|
---|
| 307 | /**
|
---|
| 308 | * Deregisters a guest OS digger previously registered by DBGFR3OSRegister.
|
---|
| 309 | *
|
---|
| 310 | * @returns VBox status code.
|
---|
| 311 | *
|
---|
[44399] | 312 | * @param pUVM The user mode VM handle.
|
---|
[22108] | 313 | * @param pReg The registration structure.
|
---|
| 314 | * @thread Any.
|
---|
| 315 | */
|
---|
[44399] | 316 | VMMR3DECL(int) DBGFR3OSDeregister(PUVM pUVM, PCDBGFOSREG pReg)
|
---|
[22108] | 317 | {
|
---|
| 318 | /*
|
---|
| 319 | * Validate input.
|
---|
| 320 | */
|
---|
[44399] | 321 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
|
---|
[22108] | 322 | AssertPtrReturn(pReg, VERR_INVALID_POINTER);
|
---|
| 323 | AssertReturn(pReg->u32Magic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
|
---|
| 324 | AssertReturn(pReg->u32EndMagic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
|
---|
[30320] | 325 | AssertReturn(RTStrEnd(&pReg->szName[0], sizeof(pReg->szName)), VERR_INVALID_NAME);
|
---|
[22108] | 326 |
|
---|
[44399] | 327 | DBGF_OS_READ_LOCK(pUVM);
|
---|
[22108] | 328 | PDBGFOS pOS;
|
---|
[44399] | 329 | for (pOS = pUVM->dbgf.s.pOSHead; pOS; pOS = pOS->pNext)
|
---|
[22108] | 330 | if (pOS->pReg == pReg)
|
---|
| 331 | break;
|
---|
[54218] | 332 | DBGF_OS_READ_UNLOCK(pUVM);
|
---|
[22108] | 333 |
|
---|
| 334 | if (!pOS)
|
---|
[8797] | 335 | {
|
---|
[22108] | 336 | Log(("DBGFR3OSDeregister: %s -> VERR_NOT_FOUND\n", pReg->szName));
|
---|
| 337 | return VERR_NOT_FOUND;
|
---|
[8797] | 338 | }
|
---|
[22108] | 339 |
|
---|
| 340 | /*
|
---|
[23011] | 341 | * Pass it on to EMT(0).
|
---|
[22108] | 342 | */
|
---|
[44399] | 343 | return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSDeregister, 2, pUVM, pReg);
|
---|
[8797] | 344 | }
|
---|
| 345 |
|
---|
| 346 |
|
---|
| 347 | /**
|
---|
[8800] | 348 | * EMT worker function for DBGFR3OSDetect.
|
---|
[8797] | 349 | *
|
---|
| 350 | * @returns VBox status code.
|
---|
| 351 | * @retval VINF_SUCCESS if successfully detected.
|
---|
| 352 | * @retval VINF_DBGF_OS_NOT_DETCTED if we cannot figure it out.
|
---|
| 353 | *
|
---|
[44399] | 354 | * @param pUVM The user mode VM handle.
|
---|
[8797] | 355 | * @param pszName Where to store the OS name. Empty string if not detected.
|
---|
| 356 | * @param cchName Size of the buffer.
|
---|
| 357 | */
|
---|
[44399] | 358 | static DECLCALLBACK(int) dbgfR3OSDetect(PUVM pUVM, char *pszName, size_t cchName)
|
---|
[8797] | 359 | {
|
---|
| 360 | /*
|
---|
| 361 | * Cycle thru the detection routines.
|
---|
| 362 | */
|
---|
[54218] | 363 | DBGF_OS_WRITE_LOCK(pUVM);
|
---|
| 364 |
|
---|
[44399] | 365 | PDBGFOS const pOldOS = pUVM->dbgf.s.pCurOS;
|
---|
| 366 | pUVM->dbgf.s.pCurOS = NULL;
|
---|
[8797] | 367 |
|
---|
[44399] | 368 | for (PDBGFOS pNewOS = pUVM->dbgf.s.pOSHead; pNewOS; pNewOS = pNewOS->pNext)
|
---|
| 369 | if (pNewOS->pReg->pfnProbe(pUVM, pNewOS->abData))
|
---|
[8797] | 370 | {
|
---|
| 371 | int rc;
|
---|
[44399] | 372 | pUVM->dbgf.s.pCurOS = pNewOS;
|
---|
[8797] | 373 | if (pOldOS == pNewOS)
|
---|
[44399] | 374 | rc = pNewOS->pReg->pfnRefresh(pUVM, pNewOS->abData);
|
---|
[8797] | 375 | else
|
---|
| 376 | {
|
---|
| 377 | if (pOldOS)
|
---|
[44399] | 378 | pOldOS->pReg->pfnTerm(pUVM, pNewOS->abData);
|
---|
| 379 | rc = pNewOS->pReg->pfnInit(pUVM, pNewOS->abData);
|
---|
[8797] | 380 | }
|
---|
| 381 | if (pszName && cchName)
|
---|
| 382 | strncat(pszName, pNewOS->pReg->szName, cchName);
|
---|
[54218] | 383 |
|
---|
| 384 | DBGF_OS_WRITE_UNLOCK(pUVM);
|
---|
[8797] | 385 | return rc;
|
---|
| 386 | }
|
---|
| 387 |
|
---|
| 388 | /* not found */
|
---|
| 389 | if (pOldOS)
|
---|
[44399] | 390 | pOldOS->pReg->pfnTerm(pUVM, pOldOS->abData);
|
---|
[54218] | 391 |
|
---|
| 392 | DBGF_OS_WRITE_UNLOCK(pUVM);
|
---|
[8797] | 393 | return VINF_DBGF_OS_NOT_DETCTED;
|
---|
| 394 | }
|
---|
| 395 |
|
---|
| 396 |
|
---|
| 397 | /**
|
---|
[33540] | 398 | * Detects the guest OS and try dig out symbols and useful stuff.
|
---|
[8797] | 399 | *
|
---|
[8800] | 400 | * When called the 2nd time, symbols will be updated that if the OS
|
---|
| 401 | * is the same.
|
---|
[8797] | 402 | *
|
---|
| 403 | * @returns VBox status code.
|
---|
[8800] | 404 | * @retval VINF_SUCCESS if successfully detected.
|
---|
| 405 | * @retval VINF_DBGF_OS_NOT_DETCTED if we cannot figure it out.
|
---|
| 406 | *
|
---|
[44399] | 407 | * @param pUVM The user mode VM handle.
|
---|
[8800] | 408 | * @param pszName Where to store the OS name. Empty string if not detected.
|
---|
| 409 | * @param cchName Size of the buffer.
|
---|
| 410 | * @thread Any.
|
---|
| 411 | */
|
---|
[44399] | 412 | VMMR3DECL(int) DBGFR3OSDetect(PUVM pUVM, char *pszName, size_t cchName)
|
---|
[8800] | 413 | {
|
---|
| 414 | AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
|
---|
| 415 | if (pszName && cchName)
|
---|
| 416 | *pszName = '\0';
|
---|
[44399] | 417 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
|
---|
[8800] | 418 |
|
---|
| 419 | /*
|
---|
[23011] | 420 | * Pass it on to EMT(0).
|
---|
[8800] | 421 | */
|
---|
[44399] | 422 | return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSDetect, 3, pUVM, pszName, cchName);
|
---|
[8800] | 423 | }
|
---|
| 424 |
|
---|
| 425 |
|
---|
| 426 | /**
|
---|
| 427 | * EMT worker function for DBGFR3OSQueryNameAndVersion
|
---|
| 428 | *
|
---|
| 429 | * @returns VBox status code.
|
---|
[44399] | 430 | * @param pUVM The user mode VM handle.
|
---|
[8797] | 431 | * @param pszName Where to store the OS name. Optional.
|
---|
| 432 | * @param cchName The size of the name buffer.
|
---|
| 433 | * @param pszVersion Where to store the version string. Optional.
|
---|
| 434 | * @param cchVersion The size of the version buffer.
|
---|
| 435 | */
|
---|
[44399] | 436 | static DECLCALLBACK(int) dbgfR3OSQueryNameAndVersion(PUVM pUVM, char *pszName, size_t cchName, char *pszVersion, size_t cchVersion)
|
---|
[8797] | 437 | {
|
---|
| 438 | /*
|
---|
| 439 | * Any known OS?
|
---|
| 440 | */
|
---|
[54218] | 441 | DBGF_OS_READ_LOCK(pUVM);
|
---|
| 442 |
|
---|
[44399] | 443 | if (pUVM->dbgf.s.pCurOS)
|
---|
[8797] | 444 | {
|
---|
| 445 | int rc = VINF_SUCCESS;
|
---|
| 446 | if (pszName && cchName)
|
---|
| 447 | {
|
---|
[44399] | 448 | size_t cch = strlen(pUVM->dbgf.s.pCurOS->pReg->szName);
|
---|
[8797] | 449 | if (cchName > cch)
|
---|
[44399] | 450 | memcpy(pszName, pUVM->dbgf.s.pCurOS->pReg->szName, cch + 1);
|
---|
[8797] | 451 | else
|
---|
| 452 | {
|
---|
[44399] | 453 | memcpy(pszName, pUVM->dbgf.s.pCurOS->pReg->szName, cchName - 1);
|
---|
[8797] | 454 | pszName[cchName - 1] = '\0';
|
---|
| 455 | rc = VINF_BUFFER_OVERFLOW;
|
---|
| 456 | }
|
---|
| 457 | }
|
---|
| 458 |
|
---|
| 459 | if (pszVersion && cchVersion)
|
---|
| 460 | {
|
---|
[44399] | 461 | int rc2 = pUVM->dbgf.s.pCurOS->pReg->pfnQueryVersion(pUVM, pUVM->dbgf.s.pCurOS->abData, pszVersion, cchVersion);
|
---|
[8797] | 462 | if (RT_FAILURE(rc2) || rc == VINF_SUCCESS)
|
---|
| 463 | rc = rc2;
|
---|
| 464 | }
|
---|
[54218] | 465 |
|
---|
| 466 | DBGF_OS_READ_UNLOCK(pUVM);
|
---|
[8797] | 467 | return rc;
|
---|
| 468 | }
|
---|
| 469 |
|
---|
[54218] | 470 | DBGF_OS_READ_UNLOCK(pUVM);
|
---|
[8797] | 471 | return VERR_DBGF_OS_NOT_DETCTED;
|
---|
| 472 | }
|
---|
| 473 |
|
---|
| 474 |
|
---|
| 475 | /**
|
---|
[8800] | 476 | * Queries the name and/or version string for the guest OS.
|
---|
| 477 | *
|
---|
| 478 | * It goes without saying that this querying is done using the current
|
---|
| 479 | * guest OS digger and not additions or user configuration.
|
---|
| 480 | *
|
---|
| 481 | * @returns VBox status code.
|
---|
[44399] | 482 | * @param pUVM The user mode VM handle.
|
---|
[8800] | 483 | * @param pszName Where to store the OS name. Optional.
|
---|
| 484 | * @param cchName The size of the name buffer.
|
---|
| 485 | * @param pszVersion Where to store the version string. Optional.
|
---|
| 486 | * @param cchVersion The size of the version buffer.
|
---|
| 487 | * @thread Any.
|
---|
| 488 | */
|
---|
[44399] | 489 | VMMR3DECL(int) DBGFR3OSQueryNameAndVersion(PUVM pUVM, char *pszName, size_t cchName, char *pszVersion, size_t cchVersion)
|
---|
[8800] | 490 | {
|
---|
[44399] | 491 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
|
---|
[8800] | 492 | AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
|
---|
| 493 | AssertPtrNullReturn(pszVersion, VERR_INVALID_POINTER);
|
---|
| 494 |
|
---|
| 495 | /*
|
---|
| 496 | * Initialize the output up front.
|
---|
| 497 | */
|
---|
| 498 | if (pszName && cchName)
|
---|
| 499 | *pszName = '\0';
|
---|
| 500 | if (pszVersion && cchVersion)
|
---|
| 501 | *pszVersion = '\0';
|
---|
| 502 |
|
---|
| 503 | /*
|
---|
[23011] | 504 | * Pass it on to EMT(0).
|
---|
[8800] | 505 | */
|
---|
[44399] | 506 | return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/,
|
---|
| 507 | (PFNRT)dbgfR3OSQueryNameAndVersion, 5, pUVM, pszName, cchName, pszVersion, cchVersion);
|
---|
[8800] | 508 | }
|
---|
| 509 |
|
---|
| 510 |
|
---|
| 511 | /**
|
---|
[54218] | 512 | * @interface_method_impl{DBGFOSIDMESG,pfnQueryKernelLog, Generic EMT wrapper.}
|
---|
| 513 | */
|
---|
| 514 | static DECLCALLBACK(int) dbgfR3OSEmtIDmesg_QueryKernelLog(PDBGFOSIDMESG pThis, PUVM pUVM, uint32_t fFlags, uint32_t cMessages,
|
---|
| 515 | char *pszBuf, size_t cbBuf, size_t *pcbActual)
|
---|
| 516 | {
|
---|
| 517 | PDBGFOSEMTWRAPPER pWrapper = RT_FROM_MEMBER(pThis, DBGFOSEMTWRAPPER, uWrapper.Dmesg);
|
---|
| 518 | UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
|
---|
| 519 | AssertReturn(pUVM == pWrapper->pUVM, VERR_INVALID_VM_HANDLE);
|
---|
| 520 | AssertReturn(!fFlags, VERR_INVALID_FLAGS);
|
---|
| 521 | AssertReturn(cMessages > 0, VERR_INVALID_PARAMETER);
|
---|
| 522 | if (cbBuf)
|
---|
| 523 | AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
|
---|
| 524 | AssertPtrNullReturn(pcbActual, VERR_INVALID_POINTER);
|
---|
| 525 |
|
---|
| 526 | return VMR3ReqPriorityCallWaitU(pWrapper->pUVM, 0 /*idDstCpu*/,
|
---|
| 527 | (PFNRT)pWrapper->uDigger.pDmesg->pfnQueryKernelLog, 7,
|
---|
| 528 | pWrapper->uDigger.pDmesg, pUVM, fFlags, cMessages, pszBuf, cbBuf, pcbActual);
|
---|
| 529 |
|
---|
| 530 | }
|
---|
| 531 |
|
---|
| 532 |
|
---|
| 533 | /**
|
---|
[8800] | 534 | * EMT worker for DBGFR3OSQueryInterface.
|
---|
| 535 | *
|
---|
[44399] | 536 | * @param pUVM The user mode VM handle.
|
---|
| 537 | * @param enmIf The interface identifier.
|
---|
| 538 | * @param ppvIf Where to store the interface pointer on success.
|
---|
[8800] | 539 | */
|
---|
[44399] | 540 | static DECLCALLBACK(void) dbgfR3OSQueryInterface(PUVM pUVM, DBGFOSINTERFACE enmIf, void **ppvIf)
|
---|
[8800] | 541 | {
|
---|
[54218] | 542 | AssertPtrReturnVoid(ppvIf);
|
---|
| 543 | *ppvIf = NULL;
|
---|
| 544 | AssertReturnVoid(enmIf > DBGFOSINTERFACE_INVALID && enmIf < DBGFOSINTERFACE_END);
|
---|
| 545 | UVM_ASSERT_VALID_EXT_RETURN_VOID(pUVM);
|
---|
| 546 |
|
---|
| 547 | /*
|
---|
| 548 | * Forward the query to the current OS.
|
---|
| 549 | */
|
---|
| 550 | DBGF_OS_READ_LOCK(pUVM);
|
---|
| 551 | PDBGFOS pOS = pUVM->dbgf.s.pCurOS;
|
---|
| 552 | if (pOS)
|
---|
[8800] | 553 | {
|
---|
[54218] | 554 | void *pvDiggerIf;
|
---|
| 555 | pvDiggerIf = pOS->pReg->pfnQueryInterface(pUVM, pUVM->dbgf.s.pCurOS->abData, enmIf);
|
---|
| 556 | if (pvDiggerIf)
|
---|
[8800] | 557 | {
|
---|
[54218] | 558 | /*
|
---|
| 559 | * Do we have an EMT wrapper for this interface already?
|
---|
| 560 | *
|
---|
| 561 | * We ASSUME the interfaces are static and not dynamically allocated
|
---|
| 562 | * for each QueryInterface call.
|
---|
| 563 | */
|
---|
| 564 | PDBGFOSEMTWRAPPER pWrapper = pOS->pWrapperHead;
|
---|
| 565 | while ( pWrapper != NULL
|
---|
| 566 | && ( pWrapper->uDigger.pv != pvDiggerIf
|
---|
| 567 | && pWrapper->enmIf != enmIf) )
|
---|
| 568 | pWrapper = pWrapper->pNext;
|
---|
| 569 | if (pWrapper)
|
---|
| 570 | {
|
---|
| 571 | *ppvIf = &pWrapper->uWrapper;
|
---|
| 572 | DBGF_OS_READ_UNLOCK(pUVM);
|
---|
| 573 | return;
|
---|
| 574 | }
|
---|
| 575 | DBGF_OS_READ_UNLOCK(pUVM);
|
---|
| 576 |
|
---|
| 577 | /*
|
---|
| 578 | * Create a wrapper.
|
---|
| 579 | */
|
---|
| 580 | int rc = MMR3HeapAllocExU(pUVM, MM_TAG_DBGF_OS, sizeof(*pWrapper), (void **)&pWrapper);
|
---|
| 581 | if (RT_FAILURE(rc))
|
---|
| 582 | return;
|
---|
| 583 | pWrapper->uDigger.pv = pvDiggerIf;
|
---|
| 584 | pWrapper->pUVM = pUVM;
|
---|
| 585 | pWrapper->enmIf = enmIf;
|
---|
| 586 | switch (enmIf)
|
---|
| 587 | {
|
---|
| 588 | case DBGFOSINTERFACE_DMESG:
|
---|
| 589 | pWrapper->uWrapper.Dmesg.u32Magic = DBGFOSIDMESG_MAGIC;
|
---|
| 590 | pWrapper->uWrapper.Dmesg.pfnQueryKernelLog = dbgfR3OSEmtIDmesg_QueryKernelLog;
|
---|
| 591 | pWrapper->uWrapper.Dmesg.u32EndMagic = DBGFOSIDMESG_MAGIC;
|
---|
| 592 | break;
|
---|
| 593 | default:
|
---|
| 594 | AssertFailed();
|
---|
| 595 | MMR3HeapFree(pWrapper);
|
---|
| 596 | return;
|
---|
| 597 | }
|
---|
| 598 |
|
---|
| 599 | DBGF_OS_WRITE_LOCK(pUVM);
|
---|
| 600 | if (pUVM->dbgf.s.pCurOS == pOS)
|
---|
| 601 | {
|
---|
| 602 | pWrapper->pNext = pOS->pWrapperHead;
|
---|
| 603 | pOS->pWrapperHead = pWrapper;
|
---|
| 604 | *ppvIf = &pWrapper->uWrapper;
|
---|
| 605 | DBGF_OS_WRITE_UNLOCK(pUVM);
|
---|
| 606 | }
|
---|
| 607 | else
|
---|
| 608 | {
|
---|
| 609 | DBGF_OS_WRITE_UNLOCK(pUVM);
|
---|
| 610 | MMR3HeapFree(pWrapper);
|
---|
| 611 | }
|
---|
| 612 | return;
|
---|
[8800] | 613 | }
|
---|
| 614 | }
|
---|
[54218] | 615 | DBGF_OS_READ_UNLOCK(pUVM);
|
---|
[8800] | 616 | }
|
---|
| 617 |
|
---|
| 618 |
|
---|
| 619 | /**
|
---|
[8797] | 620 | * Query an optional digger interface.
|
---|
| 621 | *
|
---|
| 622 | * @returns Pointer to the digger interface on success, NULL if the interfaces isn't
|
---|
| 623 | * available or no active guest OS digger.
|
---|
[44399] | 624 | * @param pUVM The user mode VM handle.
|
---|
| 625 | * @param enmIf The interface identifier.
|
---|
[8800] | 626 | * @thread Any.
|
---|
[8797] | 627 | */
|
---|
[44399] | 628 | VMMR3DECL(void *) DBGFR3OSQueryInterface(PUVM pUVM, DBGFOSINTERFACE enmIf)
|
---|
[8797] | 629 | {
|
---|
| 630 | AssertMsgReturn(enmIf > DBGFOSINTERFACE_INVALID && enmIf < DBGFOSINTERFACE_END, ("%d\n", enmIf), NULL);
|
---|
[8800] | 631 |
|
---|
| 632 | /*
|
---|
[23011] | 633 | * Pass it on to an EMT.
|
---|
[8800] | 634 | */
|
---|
| 635 | void *pvIf = NULL;
|
---|
[44399] | 636 | VMR3ReqPriorityCallVoidWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3OSQueryInterface, 3, pUVM, enmIf, &pvIf);
|
---|
[8800] | 637 | return pvIf;
|
---|
[8797] | 638 | }
|
---|
| 639 |
|
---|
[73460] | 640 |
|
---|
| 641 |
|
---|
| 642 | /**
|
---|
| 643 | * Internal wrapper for calling DBGFOSREG::pfnStackUnwindAssist.
|
---|
| 644 | */
|
---|
| 645 | int dbgfR3OSStackUnwindAssist(PUVM pUVM, VMCPUID idCpu, PDBGFSTACKFRAME pFrame, PRTDBGUNWINDSTATE pState,
|
---|
| 646 | PCCPUMCTX pInitialCtx, RTDBGAS hAs, uint64_t *puScratch)
|
---|
| 647 | {
|
---|
| 648 | int rc = VINF_SUCCESS;
|
---|
| 649 | if (pUVM->dbgf.s.pCurOS)
|
---|
| 650 | {
|
---|
| 651 | ASMCompilerBarrier();
|
---|
| 652 | DBGF_OS_READ_LOCK(pUVM);
|
---|
| 653 | PDBGFOS pOS = pUVM->dbgf.s.pCurOS;
|
---|
| 654 | if (pOS)
|
---|
| 655 | rc = pOS->pReg->pfnStackUnwindAssist(pUVM, pUVM->dbgf.s.pCurOS->abData, idCpu, pFrame,
|
---|
| 656 | pState, pInitialCtx, hAs, puScratch);
|
---|
| 657 | DBGF_OS_READ_UNLOCK(pUVM);
|
---|
| 658 | }
|
---|
| 659 | return rc;
|
---|
| 660 | }
|
---|
| 661 |
|
---|