VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFOS.cpp@ 45536

Last change on this file since 45536 was 44399, checked in by vboxsync, 12 years ago

DBGF,DBGC,++: PVM -> PUVM. Some refactoring and cleanup as well.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.6 KB
Line 
1/* $Id: DBGFOS.cpp 44399 2013-01-27 21:12:53Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Guest OS Diggers.
4 */
5
6/*
7 * Copyright (C) 2008-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DBGF
23#include <VBox/vmm/dbgf.h>
24#include <VBox/vmm/mm.h>
25#include "DBGFInternal.h"
26#include <VBox/vmm/uvm.h>
27#include <VBox/err.h>
28#include <VBox/log.h>
29
30#include <iprt/assert.h>
31#include <iprt/thread.h>
32#include <iprt/param.h>
33
34
35/*******************************************************************************
36* Defined Constants And Macros *
37*******************************************************************************/
38#define DBGF_OS_READ_LOCK(pUVM) do { } while (0)
39#define DBGF_OS_READ_UNLOCK(pUVM) do { } while (0)
40
41#define DBGF_OS_WRITE_LOCK(pUVM) do { } while (0)
42#define DBGF_OS_WRITE_UNLOCK(pUVM) do { } while (0)
43
44
45/**
46 * Internal cleanup routine called by DBGFR3Term().
47 *
48 * @param pUVM The user mode VM handle.
49 */
50void dbgfR3OSTerm(PUVM pUVM)
51{
52 /*
53 * Terminate the current one.
54 */
55 if (pUVM->dbgf.s.pCurOS)
56 {
57 pUVM->dbgf.s.pCurOS->pReg->pfnTerm(pUVM, pUVM->dbgf.s.pCurOS->abData);
58 pUVM->dbgf.s.pCurOS = NULL;
59 }
60
61 /*
62 * Destroy all the instances.
63 */
64 while (pUVM->dbgf.s.pOSHead)
65 {
66 PDBGFOS pOS = pUVM->dbgf.s.pOSHead;
67 pUVM->dbgf.s.pOSHead = pOS->pNext;
68 if (pOS->pReg->pfnDestruct)
69 pOS->pReg->pfnDestruct(pUVM, pOS->abData);
70 MMR3HeapFree(pOS);
71 }
72}
73
74
75/**
76 * EMT worker function for DBGFR3OSRegister.
77 *
78 * @returns VBox status code.
79 * @param pUVM The user mode VM handle.
80 * @param pReg The registration structure.
81 */
82static DECLCALLBACK(int) dbgfR3OSRegister(PUVM pUVM, PDBGFOSREG pReg)
83{
84 /* more validations. */
85 DBGF_OS_READ_LOCK(pUVM);
86 PDBGFOS pOS;
87 for (pOS = pUVM->dbgf.s.pOSHead; pOS; pOS = pOS->pNext)
88 if (!strcmp(pOS->pReg->szName, pReg->szName))
89 {
90 DBGF_OS_READ_UNLOCK(pUVM);
91 Log(("dbgfR3OSRegister: %s -> VERR_ALREADY_LOADED\n", pReg->szName));
92 return VERR_ALREADY_LOADED;
93 }
94
95 /*
96 * Allocate a new structure, call the constructor and link it into the list.
97 */
98 pOS = (PDBGFOS)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_OS, RT_OFFSETOF(DBGFOS, abData[pReg->cbData]));
99 AssertReturn(pOS, VERR_NO_MEMORY);
100 pOS->pReg = pReg;
101
102 int rc = pOS->pReg->pfnConstruct(pUVM, pOS->abData);
103 if (RT_SUCCESS(rc))
104 {
105 DBGF_OS_WRITE_LOCK(pUVM);
106 pOS->pNext = pUVM->dbgf.s.pOSHead;
107 pUVM->dbgf.s.pOSHead = pOS;
108 DBGF_OS_WRITE_UNLOCK(pUVM);
109 }
110 else
111 {
112 if (pOS->pReg->pfnDestruct)
113 pOS->pReg->pfnDestruct(pUVM, pOS->abData);
114 MMR3HeapFree(pOS);
115 }
116
117 return VINF_SUCCESS;
118}
119
120
121/**
122 * Registers a guest OS digger.
123 *
124 * This will instantiate an instance of the digger and add it
125 * to the list for us in the next call to DBGFR3OSDetect().
126 *
127 * @returns VBox status code.
128 * @param pUVM The user mode VM handle.
129 * @param pReg The registration structure.
130 * @thread Any.
131 */
132VMMR3DECL(int) DBGFR3OSRegister(PUVM pUVM, PCDBGFOSREG pReg)
133{
134 /*
135 * Validate intput.
136 */
137 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
138
139 AssertPtrReturn(pReg, VERR_INVALID_POINTER);
140 AssertReturn(pReg->u32Magic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
141 AssertReturn(pReg->u32EndMagic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
142 AssertReturn(!pReg->fFlags, VERR_INVALID_PARAMETER);
143 AssertReturn(pReg->cbData < _2G, VERR_INVALID_PARAMETER);
144 AssertReturn(pReg->szName[0], VERR_INVALID_NAME);
145 AssertReturn(RTStrEnd(&pReg->szName[0], sizeof(pReg->szName)), VERR_INVALID_NAME);
146 AssertPtrReturn(pReg->pfnConstruct, VERR_INVALID_POINTER);
147 AssertPtrNullReturn(pReg->pfnDestruct, VERR_INVALID_POINTER);
148 AssertPtrReturn(pReg->pfnProbe, VERR_INVALID_POINTER);
149 AssertPtrReturn(pReg->pfnInit, VERR_INVALID_POINTER);
150 AssertPtrReturn(pReg->pfnRefresh, VERR_INVALID_POINTER);
151 AssertPtrReturn(pReg->pfnTerm, VERR_INVALID_POINTER);
152 AssertPtrReturn(pReg->pfnQueryVersion, VERR_INVALID_POINTER);
153 AssertPtrReturn(pReg->pfnQueryInterface, VERR_INVALID_POINTER);
154
155 /*
156 * Pass it on to EMT(0).
157 */
158 return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSRegister, 2, pUVM, pReg);
159}
160
161
162/**
163 * EMT worker function for DBGFR3OSDeregister.
164 *
165 * @returns VBox status code.
166 * @param pUVM The user mode VM handle.
167 * @param pReg The registration structure.
168 */
169static DECLCALLBACK(int) dbgfR3OSDeregister(PUVM pUVM, PDBGFOSREG pReg)
170{
171 /*
172 * Unlink it.
173 */
174 bool fWasCurOS = false;
175 PDBGFOS pOSPrev = NULL;
176 PDBGFOS pOS;
177 DBGF_OS_WRITE_LOCK(pUVM);
178 for (pOS = pUVM->dbgf.s.pOSHead; pOS; pOSPrev = pOS, pOS = pOS->pNext)
179 if (pOS->pReg == pReg)
180 {
181 if (pOSPrev)
182 pOSPrev->pNext = pOS->pNext;
183 else
184 pUVM->dbgf.s.pOSHead = pOS->pNext;
185 if (pUVM->dbgf.s.pCurOS == pOS)
186 {
187 pUVM->dbgf.s.pCurOS = NULL;
188 fWasCurOS = true;
189 }
190 break;
191 }
192 DBGF_OS_WRITE_UNLOCK(pUVM);
193 if (!pOS)
194 {
195 Log(("DBGFR3OSDeregister: %s -> VERR_NOT_FOUND\n", pReg->szName));
196 return VERR_NOT_FOUND;
197 }
198
199 /*
200 * Terminate it if it was the current OS, then invoke the
201 * destructor and clean up.
202 */
203 if (fWasCurOS)
204 pOS->pReg->pfnTerm(pUVM, pOS->abData);
205 if (pOS->pReg->pfnDestruct)
206 pOS->pReg->pfnDestruct(pUVM, pOS->abData);
207 MMR3HeapFree(pOS);
208
209 return VINF_SUCCESS;
210}
211
212
213/**
214 * Deregisters a guest OS digger previously registered by DBGFR3OSRegister.
215 *
216 * @returns VBox status code.
217 *
218 * @param pUVM The user mode VM handle.
219 * @param pReg The registration structure.
220 * @thread Any.
221 */
222VMMR3DECL(int) DBGFR3OSDeregister(PUVM pUVM, PCDBGFOSREG pReg)
223{
224 /*
225 * Validate input.
226 */
227 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
228 AssertPtrReturn(pReg, VERR_INVALID_POINTER);
229 AssertReturn(pReg->u32Magic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
230 AssertReturn(pReg->u32EndMagic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
231 AssertReturn(RTStrEnd(&pReg->szName[0], sizeof(pReg->szName)), VERR_INVALID_NAME);
232
233 DBGF_OS_READ_LOCK(pUVM);
234 PDBGFOS pOS;
235 for (pOS = pUVM->dbgf.s.pOSHead; pOS; pOS = pOS->pNext)
236 if (pOS->pReg == pReg)
237 break;
238 DBGF_OS_READ_LOCK(pUVM);
239
240 if (!pOS)
241 {
242 Log(("DBGFR3OSDeregister: %s -> VERR_NOT_FOUND\n", pReg->szName));
243 return VERR_NOT_FOUND;
244 }
245
246 /*
247 * Pass it on to EMT(0).
248 */
249 return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSDeregister, 2, pUVM, pReg);
250}
251
252
253/**
254 * EMT worker function for DBGFR3OSDetect.
255 *
256 * @returns VBox status code.
257 * @retval VINF_SUCCESS if successfully detected.
258 * @retval VINF_DBGF_OS_NOT_DETCTED if we cannot figure it out.
259 *
260 * @param pUVM The user mode VM handle.
261 * @param pszName Where to store the OS name. Empty string if not detected.
262 * @param cchName Size of the buffer.
263 */
264static DECLCALLBACK(int) dbgfR3OSDetect(PUVM pUVM, char *pszName, size_t cchName)
265{
266 /*
267 * Cycle thru the detection routines.
268 */
269 PDBGFOS const pOldOS = pUVM->dbgf.s.pCurOS;
270 pUVM->dbgf.s.pCurOS = NULL;
271
272 for (PDBGFOS pNewOS = pUVM->dbgf.s.pOSHead; pNewOS; pNewOS = pNewOS->pNext)
273 if (pNewOS->pReg->pfnProbe(pUVM, pNewOS->abData))
274 {
275 int rc;
276 pUVM->dbgf.s.pCurOS = pNewOS;
277 if (pOldOS == pNewOS)
278 rc = pNewOS->pReg->pfnRefresh(pUVM, pNewOS->abData);
279 else
280 {
281 if (pOldOS)
282 pOldOS->pReg->pfnTerm(pUVM, pNewOS->abData);
283 rc = pNewOS->pReg->pfnInit(pUVM, pNewOS->abData);
284 }
285 if (pszName && cchName)
286 strncat(pszName, pNewOS->pReg->szName, cchName);
287 return rc;
288 }
289
290 /* not found */
291 if (pOldOS)
292 pOldOS->pReg->pfnTerm(pUVM, pOldOS->abData);
293 return VINF_DBGF_OS_NOT_DETCTED;
294}
295
296
297/**
298 * Detects the guest OS and try dig out symbols and useful stuff.
299 *
300 * When called the 2nd time, symbols will be updated that if the OS
301 * is the same.
302 *
303 * @returns VBox status code.
304 * @retval VINF_SUCCESS if successfully detected.
305 * @retval VINF_DBGF_OS_NOT_DETCTED if we cannot figure it out.
306 *
307 * @param pUVM The user mode VM handle.
308 * @param pszName Where to store the OS name. Empty string if not detected.
309 * @param cchName Size of the buffer.
310 * @thread Any.
311 */
312VMMR3DECL(int) DBGFR3OSDetect(PUVM pUVM, char *pszName, size_t cchName)
313{
314 AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
315 if (pszName && cchName)
316 *pszName = '\0';
317 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
318
319 /*
320 * Pass it on to EMT(0).
321 */
322 return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSDetect, 3, pUVM, pszName, cchName);
323}
324
325
326/**
327 * EMT worker function for DBGFR3OSQueryNameAndVersion
328 *
329 * @returns VBox status code.
330 * @param pUVM The user mode VM handle.
331 * @param pszName Where to store the OS name. Optional.
332 * @param cchName The size of the name buffer.
333 * @param pszVersion Where to store the version string. Optional.
334 * @param cchVersion The size of the version buffer.
335 */
336static DECLCALLBACK(int) dbgfR3OSQueryNameAndVersion(PUVM pUVM, char *pszName, size_t cchName, char *pszVersion, size_t cchVersion)
337{
338 /*
339 * Any known OS?
340 */
341 if (pUVM->dbgf.s.pCurOS)
342 {
343 int rc = VINF_SUCCESS;
344 if (pszName && cchName)
345 {
346 size_t cch = strlen(pUVM->dbgf.s.pCurOS->pReg->szName);
347 if (cchName > cch)
348 memcpy(pszName, pUVM->dbgf.s.pCurOS->pReg->szName, cch + 1);
349 else
350 {
351 memcpy(pszName, pUVM->dbgf.s.pCurOS->pReg->szName, cchName - 1);
352 pszName[cchName - 1] = '\0';
353 rc = VINF_BUFFER_OVERFLOW;
354 }
355 }
356
357 if (pszVersion && cchVersion)
358 {
359 int rc2 = pUVM->dbgf.s.pCurOS->pReg->pfnQueryVersion(pUVM, pUVM->dbgf.s.pCurOS->abData, pszVersion, cchVersion);
360 if (RT_FAILURE(rc2) || rc == VINF_SUCCESS)
361 rc = rc2;
362 }
363 return rc;
364 }
365
366 return VERR_DBGF_OS_NOT_DETCTED;
367}
368
369
370/**
371 * Queries the name and/or version string for the guest OS.
372 *
373 * It goes without saying that this querying is done using the current
374 * guest OS digger and not additions or user configuration.
375 *
376 * @returns VBox status code.
377 * @param pUVM The user mode VM handle.
378 * @param pszName Where to store the OS name. Optional.
379 * @param cchName The size of the name buffer.
380 * @param pszVersion Where to store the version string. Optional.
381 * @param cchVersion The size of the version buffer.
382 * @thread Any.
383 */
384VMMR3DECL(int) DBGFR3OSQueryNameAndVersion(PUVM pUVM, char *pszName, size_t cchName, char *pszVersion, size_t cchVersion)
385{
386 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
387 AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
388 AssertPtrNullReturn(pszVersion, VERR_INVALID_POINTER);
389
390 /*
391 * Initialize the output up front.
392 */
393 if (pszName && cchName)
394 *pszName = '\0';
395 if (pszVersion && cchVersion)
396 *pszVersion = '\0';
397
398 /*
399 * Pass it on to EMT(0).
400 */
401 return VMR3ReqPriorityCallWaitU(pUVM, 0 /*idDstCpu*/,
402 (PFNRT)dbgfR3OSQueryNameAndVersion, 5, pUVM, pszName, cchName, pszVersion, cchVersion);
403}
404
405
406/**
407 * EMT worker for DBGFR3OSQueryInterface.
408 *
409 * @param pUVM The user mode VM handle.
410 * @param enmIf The interface identifier.
411 * @param ppvIf Where to store the interface pointer on success.
412 */
413static DECLCALLBACK(void) dbgfR3OSQueryInterface(PUVM pUVM, DBGFOSINTERFACE enmIf, void **ppvIf)
414{
415 if (pUVM->dbgf.s.pCurOS)
416 {
417 *ppvIf = pUVM->dbgf.s.pCurOS->pReg->pfnQueryInterface(pUVM, pUVM->dbgf.s.pCurOS->abData, enmIf);
418 if (*ppvIf)
419 {
420 /** @todo Create EMT wrapper for the returned interface once we've defined one...
421 * Just keep a list of wrapper together with the OS instance. */
422 }
423 }
424 else
425 *ppvIf = NULL;
426}
427
428
429/**
430 * Query an optional digger interface.
431 *
432 * @returns Pointer to the digger interface on success, NULL if the interfaces isn't
433 * available or no active guest OS digger.
434 * @param pUVM The user mode VM handle.
435 * @param enmIf The interface identifier.
436 * @thread Any.
437 */
438VMMR3DECL(void *) DBGFR3OSQueryInterface(PUVM pUVM, DBGFOSINTERFACE enmIf)
439{
440 AssertMsgReturn(enmIf > DBGFOSINTERFACE_INVALID && enmIf < DBGFOSINTERFACE_END, ("%d\n", enmIf), NULL);
441
442 /*
443 * Pass it on to an EMT.
444 */
445 void *pvIf = NULL;
446 VMR3ReqPriorityCallVoidWaitU(pUVM, VMCPUID_ANY, (PFNRT)dbgfR3OSQueryInterface, 3, pUVM, enmIf, &pvIf);
447 return pvIf;
448}
449
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