VirtualBox

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

Last change on this file since 22346 was 22108, checked in by vboxsync, 15 years ago

DBGC: plug-ins in the works.

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