VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageDebugVM.cpp@ 57745

Last change on this file since 57745 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.5 KB
Line 
1/* $Id: VBoxManageDebugVM.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * VBoxManage - Implementation of the debugvm command.
4 */
5
6/*
7 * Copyright (C) 2012 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#include <VBox/com/com.h>
23#include <VBox/com/string.h>
24#include <VBox/com/Guid.h>
25#include <VBox/com/array.h>
26#include <VBox/com/ErrorInfo.h>
27#include <VBox/com/errorprint.h>
28#include <VBox/com/VirtualBox.h>
29
30#include <iprt/ctype.h>
31#include <VBox/err.h>
32#include <iprt/getopt.h>
33#include <iprt/path.h>
34#include <iprt/param.h>
35#include <iprt/stream.h>
36#include <iprt/string.h>
37#include <iprt/uuid.h>
38#include <VBox/log.h>
39
40#include "VBoxManage.h"
41
42
43/**
44 * Handles the getregisters sub-command.
45 *
46 * @returns Suitable exit code.
47 * @param pArgs The handler arguments.
48 * @param pDebugger Pointer to the debugger interface.
49 */
50static RTEXITCODE handleDebugVM_GetRegisters(HandlerArg *pArgs, IMachineDebugger *pDebugger)
51{
52 /*
53 * We take a list of register names (case insensitive). If 'all' is
54 * encountered we'll dump all registers.
55 */
56 ULONG idCpu = 0;
57 unsigned cRegisters = 0;
58
59 RTGETOPTSTATE GetState;
60 RTGETOPTUNION ValueUnion;
61 static const RTGETOPTDEF s_aOptions[] =
62 {
63 { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
64 };
65 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
66 AssertRCReturn(rc, RTEXITCODE_FAILURE);
67
68 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
69 {
70 switch (rc)
71 {
72 case 'c':
73 idCpu = ValueUnion.u32;
74 break;
75
76 case VINF_GETOPT_NOT_OPTION:
77 if (!RTStrICmp(ValueUnion.psz, "all"))
78 {
79 com::SafeArray<BSTR> aBstrNames;
80 com::SafeArray<BSTR> aBstrValues;
81 CHECK_ERROR2I_RET(pDebugger, GetRegisters(idCpu, ComSafeArrayAsOutParam(aBstrNames),
82 ComSafeArrayAsOutParam(aBstrValues)),
83 RTEXITCODE_FAILURE);
84 Assert(aBstrNames.size() == aBstrValues.size());
85
86 size_t cchMaxName = 8;
87 for (size_t i = 0; i < aBstrNames.size(); i++)
88 {
89 size_t cchName = RTUtf16Len(aBstrNames[i]);
90 if (cchName > cchMaxName)
91 cchMaxName = cchName;
92 }
93
94 for (size_t i = 0; i < aBstrNames.size(); i++)
95 RTPrintf("%-*ls = %ls\n", cchMaxName, aBstrNames[i], aBstrValues[i]);
96 }
97 else
98 {
99 com::Bstr bstrName = ValueUnion.psz;
100 com::Bstr bstrValue;
101 CHECK_ERROR2I_RET(pDebugger, GetRegister(idCpu, bstrName.raw(), bstrValue.asOutParam()), RTEXITCODE_FAILURE);
102 RTPrintf("%s = %ls\n", ValueUnion.psz, bstrValue.raw());
103 }
104 cRegisters++;
105 break;
106
107 default:
108 return errorGetOpt(rc, &ValueUnion);
109 }
110 }
111
112 if (!cRegisters)
113 return errorSyntax("The getregisters sub-command takes at least one register name");
114 return RTEXITCODE_SUCCESS;
115}
116
117/**
118 * Handles the info sub-command.
119 *
120 * @returns Suitable exit code.
121 * @param pArgs The handler arguments.
122 * @param pDebugger Pointer to the debugger interface.
123 */
124static RTEXITCODE handleDebugVM_Info(HandlerArg *pArgs, IMachineDebugger *pDebugger)
125{
126 /*
127 * Parse arguments.
128 */
129 const char *pszInfo = NULL;
130 const char *pszArgs = NULL;
131 RTGETOPTSTATE GetState;
132 RTGETOPTUNION ValueUnion;
133 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, NULL, 0, 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
134 AssertRCReturn(rc, RTEXITCODE_FAILURE);
135
136 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
137 {
138 switch (rc)
139 {
140 case VINF_GETOPT_NOT_OPTION:
141 if (!pszInfo)
142 pszInfo = ValueUnion.psz;
143 else if (!pszArgs)
144 pszArgs = ValueUnion.psz;
145 else
146 return errorTooManyParameters(&pArgs->argv[GetState.iNext - 1]);
147 break;
148 default:
149 return errorGetOpt(rc, &ValueUnion);
150 }
151 }
152
153 if (!pszInfo)
154 return errorSyntax("Must specify info item to display");
155
156 /*
157 * Do the work.
158 */
159 com::Bstr bstrName(pszInfo);
160 com::Bstr bstrArgs(pszArgs);
161 com::Bstr bstrInfo;
162 CHECK_ERROR2I_RET(pDebugger, Info(bstrName.raw(), bstrArgs.raw(), bstrInfo.asOutParam()), RTEXITCODE_FAILURE);
163 RTPrintf("%ls", bstrInfo.raw());
164 return RTEXITCODE_SUCCESS;
165}
166
167/**
168 * Handles the inject sub-command.
169 *
170 * @returns Suitable exit code.
171 * @param a The handler arguments.
172 * @param pDebugger Pointer to the debugger interface.
173 */
174static RTEXITCODE handleDebugVM_InjectNMI(HandlerArg *a, IMachineDebugger *pDebugger)
175{
176 if (a->argc != 2)
177 return errorTooManyParameters(&a->argv[1]);
178 CHECK_ERROR2I_RET(pDebugger, InjectNMI(), RTEXITCODE_FAILURE);
179 return RTEXITCODE_SUCCESS;
180}
181
182/**
183 * Handles the log sub-command.
184 *
185 * @returns Suitable exit code.
186 * @param pArgs The handler arguments.
187 * @param pDebugger Pointer to the debugger interface.
188 * @param pszSubCmd The sub command.
189 */
190static RTEXITCODE handleDebugVM_LogXXXX(HandlerArg *pArgs, IMachineDebugger *pDebugger, const char *pszSubCmd)
191{
192 /*
193 * Parse arguments.
194 */
195 bool fRelease = false;
196 com::Utf8Str strSettings;
197
198 RTGETOPTSTATE GetState;
199 RTGETOPTUNION ValueUnion;
200
201 /*
202 * NB: don't use short options to prevent log specifications like
203 * "-drv_foo" from being interpreted as options.
204 */
205# define DEBUGVM_LOG_DEBUG (VINF_GETOPT_NOT_OPTION + 'd')
206# define DEBUGVM_LOG_RELEASE (VINF_GETOPT_NOT_OPTION + 'r')
207
208 static const RTGETOPTDEF s_aOptions[] =
209 {
210 { "--debug", DEBUGVM_LOG_DEBUG, RTGETOPT_REQ_NOTHING },
211 { "--release", DEBUGVM_LOG_RELEASE, RTGETOPT_REQ_NOTHING }
212 };
213 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
214 AssertRCReturn(rc, RTEXITCODE_FAILURE);
215
216 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
217 {
218 switch (rc)
219 {
220 case DEBUGVM_LOG_RELEASE:
221 fRelease = true;
222 break;
223
224 case DEBUGVM_LOG_DEBUG:
225 fRelease = false;
226 break;
227
228 /* Because log strings can start with "-" (like "-all+dev_foo")
229 * we have to take everything we got as a setting and apply it.
230 * IPRT will take care of the validation afterwards. */
231 default:
232 if (strSettings.length() == 0)
233 strSettings = ValueUnion.psz;
234 else
235 {
236 strSettings.append(' ');
237 strSettings.append(ValueUnion.psz);
238 }
239 break;
240 }
241 }
242
243 if (fRelease)
244 {
245 com::Utf8Str strTmp(strSettings);
246 strSettings = "release: ";
247 strSettings.append(strTmp);
248 }
249
250 com::Bstr bstrSettings(strSettings);
251 if (!strcmp(pszSubCmd, "log"))
252 CHECK_ERROR2I_RET(pDebugger, ModifyLogGroups(bstrSettings.raw()), RTEXITCODE_FAILURE);
253 else if (!strcmp(pszSubCmd, "logdest"))
254 CHECK_ERROR2I_RET(pDebugger, ModifyLogDestinations(bstrSettings.raw()), RTEXITCODE_FAILURE);
255 else if (!strcmp(pszSubCmd, "logflags"))
256 CHECK_ERROR2I_RET(pDebugger, ModifyLogFlags(bstrSettings.raw()), RTEXITCODE_FAILURE);
257 else
258 AssertFailedReturn(RTEXITCODE_FAILURE);
259
260 return RTEXITCODE_SUCCESS;
261}
262
263
264/**
265 * Handles the inject sub-command.
266 *
267 * @returns Suitable exit code.
268 * @param pArgs The handler arguments.
269 * @param pDebugger Pointer to the debugger interface.
270 */
271static RTEXITCODE handleDebugVM_DumpVMCore(HandlerArg *pArgs, IMachineDebugger *pDebugger)
272{
273 /*
274 * Parse arguments.
275 */
276 const char *pszFilename = NULL;
277 const char *pszCompression = NULL;
278
279 RTGETOPTSTATE GetState;
280 RTGETOPTUNION ValueUnion;
281 static const RTGETOPTDEF s_aOptions[] =
282 {
283 { "--filename", 'f', RTGETOPT_REQ_STRING },
284 { "--compression", 'c', RTGETOPT_REQ_STRING }
285 };
286 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, 0 /*fFlags*/);
287 AssertRCReturn(rc, RTEXITCODE_FAILURE);
288
289 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
290 {
291 switch (rc)
292 {
293 case 'c':
294 if (pszCompression)
295 return errorSyntax("The --compression option has already been given");
296 pszCompression = ValueUnion.psz;
297 break;
298 case 'f':
299 if (pszFilename)
300 return errorSyntax("The --filename option has already been given");
301 pszFilename = ValueUnion.psz;
302 break;
303 default:
304 return errorGetOpt(rc, &ValueUnion);
305 }
306 }
307
308 if (!pszFilename)
309 return errorSyntax("The --filename option is required");
310
311 /*
312 * Make the filename absolute before handing it on to the API.
313 */
314 char szAbsFilename[RTPATH_MAX];
315 rc = RTPathAbs(pszFilename, szAbsFilename, sizeof(szAbsFilename));
316 if (RT_FAILURE(rc))
317 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs failed on '%s': %Rrc", pszFilename, rc);
318
319 com::Bstr bstrFilename(szAbsFilename);
320 com::Bstr bstrCompression(pszCompression);
321 CHECK_ERROR2I_RET(pDebugger, DumpGuestCore(bstrFilename.raw(), bstrCompression.raw()), RTEXITCODE_FAILURE);
322 return RTEXITCODE_SUCCESS;
323}
324
325/**
326 * Handles the osdetect sub-command.
327 *
328 * @returns Suitable exit code.
329 * @param a The handler arguments.
330 * @param pDebugger Pointer to the debugger interface.
331 */
332static RTEXITCODE handleDebugVM_OSDetect(HandlerArg *a, IMachineDebugger *pDebugger)
333{
334 if (a->argc != 2)
335 return errorTooManyParameters(&a->argv[1]);
336
337 com::Bstr bstrIgnore;
338 com::Bstr bstrAll("all");
339 CHECK_ERROR2I_RET(pDebugger, LoadPlugIn(bstrAll.raw(), bstrIgnore.asOutParam()), RTEXITCODE_FAILURE);
340
341 com::Bstr bstrName;
342 CHECK_ERROR2I_RET(pDebugger, DetectOS(bstrName.asOutParam()), RTEXITCODE_FAILURE);
343 RTPrintf("Detected: %ls\n", bstrName.raw());
344 return RTEXITCODE_SUCCESS;
345}
346
347/**
348 * Handles the osinfo sub-command.
349 *
350 * @returns Suitable exit code.
351 * @param a The handler arguments.
352 * @param pDebugger Pointer to the debugger interface.
353 */
354static RTEXITCODE handleDebugVM_OSInfo(HandlerArg *a, IMachineDebugger *pDebugger)
355{
356 if (a->argc != 2)
357 return errorTooManyParameters(&a->argv[1]);
358
359 com::Bstr bstrName;
360 CHECK_ERROR2I_RET(pDebugger, COMGETTER(OSName)(bstrName.asOutParam()), RTEXITCODE_FAILURE);
361 com::Bstr bstrVersion;
362 CHECK_ERROR2I_RET(pDebugger, COMGETTER(OSVersion)(bstrVersion.asOutParam()), RTEXITCODE_FAILURE);
363 RTPrintf("Name: %ls\n", bstrName.raw());
364 RTPrintf("Version: %ls\n", bstrVersion.raw());
365 return RTEXITCODE_SUCCESS;
366}
367
368/**
369 * Handles the osdmsg sub-command.
370 *
371 * @returns Suitable exit code.
372 * @param pArgs The handler arguments.
373 * @param pDebugger Pointer to the debugger interface.
374 */
375static RTEXITCODE handleDebugVM_OSDmesg(HandlerArg *pArgs, IMachineDebugger *pDebugger)
376{
377 /*
378 * Parse argument.
379 */
380 uint32_t uMaxMessages = 0;
381 RTGETOPTSTATE GetState;
382 RTGETOPTUNION ValueUnion;
383 static const RTGETOPTDEF s_aOptions[] =
384 {
385 { "--lines", 'n', RTGETOPT_REQ_UINT32 },
386 };
387 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
388 AssertRCReturn(rc, RTEXITCODE_FAILURE);
389 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
390 switch (rc)
391 {
392 case 'n': uMaxMessages = ValueUnion.u32; break;
393 default: return errorGetOpt(rc, &ValueUnion);
394 }
395
396 /*
397 * Do it.
398 */
399 com::Bstr bstrDmesg;
400 CHECK_ERROR2I_RET(pDebugger, QueryOSKernelLog(uMaxMessages, bstrDmesg.asOutParam()), RTEXITCODE_FAILURE);
401 RTPrintf("%ls\n", bstrDmesg.raw());
402 return RTEXITCODE_SUCCESS;
403}
404
405/**
406 * Handles the setregisters sub-command.
407 *
408 * @returns Suitable exit code.
409 * @param pArgs The handler arguments.
410 * @param pDebugger Pointer to the debugger interface.
411 */
412static RTEXITCODE handleDebugVM_SetRegisters(HandlerArg *pArgs, IMachineDebugger *pDebugger)
413{
414 /*
415 * We take a list of register assignments, that is register=value.
416 */
417 ULONG idCpu = 0;
418 com::SafeArray<IN_BSTR> aBstrNames;
419 com::SafeArray<IN_BSTR> aBstrValues;
420
421 RTGETOPTSTATE GetState;
422 RTGETOPTUNION ValueUnion;
423 static const RTGETOPTDEF s_aOptions[] =
424 {
425 { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
426 };
427 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
428 AssertRCReturn(rc, RTEXITCODE_FAILURE);
429
430 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
431 {
432 switch (rc)
433 {
434 case 'c':
435 idCpu = ValueUnion.u32;
436 break;
437
438 case VINF_GETOPT_NOT_OPTION:
439 {
440 const char *pszEqual = strchr(ValueUnion.psz, '=');
441 if (!pszEqual)
442 return errorSyntax("setregisters expects input on the form 'register=value' got '%s'", ValueUnion.psz);
443 try
444 {
445 com::Bstr bstrName(ValueUnion.psz, pszEqual - ValueUnion.psz);
446 com::Bstr bstrValue(pszEqual + 1);
447 if ( !aBstrNames.push_back(bstrName.raw())
448 || !aBstrValues.push_back(bstrValue.raw()))
449 throw std::bad_alloc();
450 }
451 catch (std::bad_alloc)
452 {
453 RTMsgError("Out of memory\n");
454 return RTEXITCODE_FAILURE;
455 }
456 break;
457 }
458
459 default:
460 return errorGetOpt(rc, &ValueUnion);
461 }
462 }
463
464 if (!aBstrNames.size())
465 return errorSyntax("The setregisters sub-command takes at least one register name");
466
467 /*
468 * If it is only one register, use the single register method just so
469 * we expose it and can test it from the command line.
470 */
471 if (aBstrNames.size() == 1)
472 {
473 CHECK_ERROR2I_RET(pDebugger, SetRegister(idCpu, aBstrNames[0], aBstrValues[0]), RTEXITCODE_FAILURE);
474 RTPrintf("Successfully set %ls\n", aBstrNames[0]);
475 }
476 else
477 {
478 CHECK_ERROR2I_RET(pDebugger, SetRegisters(idCpu, ComSafeArrayAsInParam(aBstrNames), ComSafeArrayAsInParam(aBstrValues)),
479 RTEXITCODE_FAILURE);
480 RTPrintf("Successfully set %u registers\n", aBstrNames.size());
481 }
482
483 return RTEXITCODE_SUCCESS;
484}
485
486/** @name debugvm show flags
487 * @{ */
488#define DEBUGVM_SHOW_FLAGS_HUMAN_READABLE UINT32_C(0x00000000)
489#define DEBUGVM_SHOW_FLAGS_SH_EXPORT UINT32_C(0x00000001)
490#define DEBUGVM_SHOW_FLAGS_SH_EVAL UINT32_C(0x00000002)
491#define DEBUGVM_SHOW_FLAGS_CMD_SET UINT32_C(0x00000003)
492#define DEBUGVM_SHOW_FLAGS_FMT_MASK UINT32_C(0x00000003)
493/** @} */
494
495/**
496 * Prints a variable according to the @a fFlags.
497 *
498 * @param pszVar The variable name.
499 * @param pbstrValue The variable value.
500 * @param fFlags The debugvm show flags.
501 */
502static void handleDebugVM_Show_PrintVar(const char *pszVar, com::Bstr const *pbstrValue, uint32_t fFlags)
503{
504 switch (fFlags & DEBUGVM_SHOW_FLAGS_FMT_MASK)
505 {
506 case DEBUGVM_SHOW_FLAGS_HUMAN_READABLE: RTPrintf(" %27s=%ls\n", pszVar, pbstrValue->raw()); break;
507 case DEBUGVM_SHOW_FLAGS_SH_EXPORT: RTPrintf("export %s='%ls'\n", pszVar, pbstrValue->raw()); break;
508 case DEBUGVM_SHOW_FLAGS_SH_EVAL: RTPrintf("%s='%ls'\n", pszVar, pbstrValue->raw()); break;
509 case DEBUGVM_SHOW_FLAGS_CMD_SET: RTPrintf("set %s=%ls\n", pszVar, pbstrValue->raw()); break;
510 default: AssertFailed();
511 }
512}
513
514/**
515 * Handles logdbg-settings.
516 *
517 * @returns Exit code.
518 * @param pDebugger The debugger interface.
519 * @param fFlags The debugvm show flags.
520 */
521static RTEXITCODE handleDebugVM_Show_LogDbgSettings(IMachineDebugger *pDebugger, uint32_t fFlags)
522{
523 if ((fFlags & DEBUGVM_SHOW_FLAGS_FMT_MASK) == DEBUGVM_SHOW_FLAGS_HUMAN_READABLE)
524 RTPrintf("Debug logger settings:\n");
525
526 com::Bstr bstr;
527 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogDbgFlags)(bstr.asOutParam()), RTEXITCODE_FAILURE);
528 handleDebugVM_Show_PrintVar("VBOX_LOG", &bstr, fFlags);
529
530 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogDbgGroups)(bstr.asOutParam()), RTEXITCODE_FAILURE);
531 handleDebugVM_Show_PrintVar("VBOX_LOG_FLAGS", &bstr, fFlags);
532
533 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogDbgDestinations)(bstr.asOutParam()), RTEXITCODE_FAILURE);
534 handleDebugVM_Show_PrintVar("VBOX_LOG_DEST", &bstr, fFlags);
535 return RTEXITCODE_SUCCESS;
536}
537
538/**
539 * Handles logrel-settings.
540 *
541 * @returns Exit code.
542 * @param pDebugger The debugger interface.
543 * @param fFlags The debugvm show flags.
544 */
545static RTEXITCODE handleDebugVM_Show_LogRelSettings(IMachineDebugger *pDebugger, uint32_t fFlags)
546{
547 if ((fFlags & DEBUGVM_SHOW_FLAGS_FMT_MASK) == DEBUGVM_SHOW_FLAGS_HUMAN_READABLE)
548 RTPrintf("Release logger settings:\n");
549
550 com::Bstr bstr;
551 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogRelFlags)(bstr.asOutParam()), RTEXITCODE_FAILURE);
552 handleDebugVM_Show_PrintVar("VBOX_RELEASE_LOG", &bstr, fFlags);
553
554 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogRelGroups)(bstr.asOutParam()), RTEXITCODE_FAILURE);
555 handleDebugVM_Show_PrintVar("VBOX_RELEASE_LOG_FLAGS", &bstr, fFlags);
556
557 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogRelDestinations)(bstr.asOutParam()), RTEXITCODE_FAILURE);
558 handleDebugVM_Show_PrintVar("VBOX_RELEASE_LOG_DEST", &bstr, fFlags);
559 return RTEXITCODE_SUCCESS;
560}
561
562/**
563 * Handles the show sub-command.
564 *
565 * @returns Suitable exit code.
566 * @param pArgs The handler arguments.
567 * @param pDebugger Pointer to the debugger interface.
568 */
569static RTEXITCODE handleDebugVM_Show(HandlerArg *pArgs, IMachineDebugger *pDebugger)
570{
571 /*
572 * Parse arguments and what to show. Order dependent.
573 */
574 uint32_t fFlags = DEBUGVM_SHOW_FLAGS_HUMAN_READABLE;
575
576 RTGETOPTSTATE GetState;
577 RTGETOPTUNION ValueUnion;
578 static const RTGETOPTDEF s_aOptions[] =
579 {
580 { "--human-readable", 'H', RTGETOPT_REQ_NOTHING },
581 { "--sh-export", 'e', RTGETOPT_REQ_NOTHING },
582 { "--sh-eval", 'E', RTGETOPT_REQ_NOTHING },
583 { "--cmd-set", 's', RTGETOPT_REQ_NOTHING },
584 };
585 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, 0 /*fFlags*/);
586 AssertRCReturn(rc, RTEXITCODE_FAILURE);
587
588 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
589 {
590 switch (rc)
591 {
592 case 'H':
593 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_HUMAN_READABLE;
594 break;
595
596 case 'e':
597 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_SH_EXPORT;
598 break;
599
600 case 'E':
601 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_SH_EVAL;
602 break;
603
604 case 's':
605 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_CMD_SET;
606 break;
607
608 case VINF_GETOPT_NOT_OPTION:
609 {
610 RTEXITCODE rcExit;
611 if (!strcmp(ValueUnion.psz, "log-settings"))
612 {
613 rcExit = handleDebugVM_Show_LogDbgSettings(pDebugger, fFlags);
614 if (rcExit == RTEXITCODE_SUCCESS)
615 rcExit = handleDebugVM_Show_LogRelSettings(pDebugger, fFlags);
616 }
617 else if (!strcmp(ValueUnion.psz, "logdbg-settings"))
618 rcExit = handleDebugVM_Show_LogDbgSettings(pDebugger, fFlags);
619 else if (!strcmp(ValueUnion.psz, "logrel-settings"))
620 rcExit = handleDebugVM_Show_LogRelSettings(pDebugger, fFlags);
621 else
622 rcExit = errorSyntax("The show sub-command has no idea what '%s' might be", ValueUnion.psz);
623 if (rcExit != RTEXITCODE_SUCCESS)
624 return rcExit;
625 break;
626 }
627
628 default:
629 return errorGetOpt(rc, &ValueUnion);
630 }
631 }
632 return RTEXITCODE_SUCCESS;
633}
634
635/**
636 * Handles the statistics sub-command.
637 *
638 * @returns Suitable exit code.
639 * @param pArgs The handler arguments.
640 * @param pDebugger Pointer to the debugger interface.
641 */
642static RTEXITCODE handleDebugVM_Statistics(HandlerArg *pArgs, IMachineDebugger *pDebugger)
643{
644 /*
645 * Parse arguments.
646 */
647 bool fWithDescriptions = false;
648 const char *pszPattern = NULL; /* all */
649 bool fReset = false;
650
651 RTGETOPTSTATE GetState;
652 RTGETOPTUNION ValueUnion;
653 static const RTGETOPTDEF s_aOptions[] =
654 {
655 { "--descriptions", 'd', RTGETOPT_REQ_NOTHING },
656 { "--pattern", 'p', RTGETOPT_REQ_STRING },
657 { "--reset", 'r', RTGETOPT_REQ_NOTHING },
658 };
659 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, 0 /*fFlags*/);
660 AssertRCReturn(rc, RTEXITCODE_FAILURE);
661
662 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
663 {
664 switch (rc)
665 {
666 case 'd':
667 fWithDescriptions = true;
668 break;
669
670 case 'p':
671 if (pszPattern)
672 return errorSyntax("Multiple --pattern options are not permitted");
673 pszPattern = ValueUnion.psz;
674 break;
675
676 case 'r':
677 fReset = true;
678 break;
679
680 default:
681 return errorGetOpt(rc, &ValueUnion);
682 }
683 }
684
685 if (fReset && fWithDescriptions)
686 return errorSyntax("The --reset and --descriptions options does not mix");
687
688 /*
689 * Execute the order.
690 */
691 com::Bstr bstrPattern(pszPattern);
692 if (fReset)
693 CHECK_ERROR2I_RET(pDebugger, ResetStats(bstrPattern.raw()), RTEXITCODE_FAILURE);
694 else
695 {
696 com::Bstr bstrStats;
697 CHECK_ERROR2I_RET(pDebugger, GetStats(bstrPattern.raw(), fWithDescriptions, bstrStats.asOutParam()),
698 RTEXITCODE_FAILURE);
699 /* if (fFormatted)
700 { big mess }
701 else
702 */
703 RTPrintf("%ls\n", bstrStats.raw());
704 }
705
706 return RTEXITCODE_SUCCESS;
707}
708
709RTEXITCODE handleDebugVM(HandlerArg *pArgs)
710{
711 RTEXITCODE rcExit = RTEXITCODE_FAILURE;
712
713 /*
714 * The first argument is the VM name or UUID. Open a session to it.
715 */
716 if (pArgs->argc < 2)
717 return errorNoSubcommand();
718 ComPtr<IMachine> ptrMachine;
719 CHECK_ERROR2I_RET(pArgs->virtualBox, FindMachine(com::Bstr(pArgs->argv[0]).raw(), ptrMachine.asOutParam()), RTEXITCODE_FAILURE);
720 CHECK_ERROR2I_RET(ptrMachine, LockMachine(pArgs->session, LockType_Shared), RTEXITCODE_FAILURE);
721
722 /*
723 * Get the associated console and machine debugger.
724 */
725 HRESULT rc;
726 ComPtr<IConsole> ptrConsole;
727 CHECK_ERROR(pArgs->session, COMGETTER(Console)(ptrConsole.asOutParam()));
728 if (SUCCEEDED(rc))
729 {
730 if (ptrConsole.isNotNull())
731 {
732 ComPtr<IMachineDebugger> ptrDebugger;
733 CHECK_ERROR(ptrConsole, COMGETTER(Debugger)(ptrDebugger.asOutParam()));
734 if (SUCCEEDED(rc))
735 {
736 /*
737 * String switch on the sub-command.
738 */
739 const char *pszSubCmd = pArgs->argv[1];
740 if (!strcmp(pszSubCmd, "dumpvmcore"))
741 {
742 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_DUMPVMCORE);
743 rcExit = handleDebugVM_DumpVMCore(pArgs, ptrDebugger);
744 }
745 else if (!strcmp(pszSubCmd, "getregisters"))
746 {
747 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_GETREGISTERS);
748 rcExit = handleDebugVM_GetRegisters(pArgs, ptrDebugger);
749 }
750 else if (!strcmp(pszSubCmd, "info"))
751 {
752 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_INFO);
753 rcExit = handleDebugVM_Info(pArgs, ptrDebugger);
754 }
755 else if (!strcmp(pszSubCmd, "injectnmi"))
756 {
757 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_INJECTNMI);
758 rcExit = handleDebugVM_InjectNMI(pArgs, ptrDebugger);
759 }
760 else if (!strcmp(pszSubCmd, "log"))
761 {
762 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_LOG);
763 rcExit = handleDebugVM_LogXXXX(pArgs, ptrDebugger, pszSubCmd);
764 }
765 else if (!strcmp(pszSubCmd, "logdest"))
766 {
767 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_LOGDEST);
768 rcExit = handleDebugVM_LogXXXX(pArgs, ptrDebugger, pszSubCmd);
769 }
770 else if (!strcmp(pszSubCmd, "logflags"))
771 {
772 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_LOGFLAGS);
773 rcExit = handleDebugVM_LogXXXX(pArgs, ptrDebugger, pszSubCmd);
774 }
775 else if (!strcmp(pszSubCmd, "osdetect"))
776 {
777 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_OSDETECT);
778 rcExit = handleDebugVM_OSDetect(pArgs, ptrDebugger);
779 }
780 else if (!strcmp(pszSubCmd, "osinfo"))
781 {
782 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_OSINFO);
783 rcExit = handleDebugVM_OSInfo(pArgs, ptrDebugger);
784 }
785 else if (!strcmp(pszSubCmd, "osdmesg"))
786 {
787 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_OSDMESG);
788 rcExit = handleDebugVM_OSDmesg(pArgs, ptrDebugger);
789 }
790 else if (!strcmp(pszSubCmd, "setregisters"))
791 {
792 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_SETREGISTERS);
793 rcExit = handleDebugVM_SetRegisters(pArgs, ptrDebugger);
794 }
795 else if (!strcmp(pszSubCmd, "show"))
796 {
797 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_SHOW);
798 rcExit = handleDebugVM_Show(pArgs, ptrDebugger);
799 }
800 else if (!strcmp(pszSubCmd, "statistics"))
801 {
802 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_STATISTICS);
803 rcExit = handleDebugVM_Statistics(pArgs, ptrDebugger);
804 }
805 else
806 errorUnknownSubcommand(pszSubCmd);
807 }
808 }
809 else
810 RTMsgError("Machine '%s' is not currently running.\n", pArgs->argv[0]);
811 }
812
813 pArgs->session->UnlockMachine();
814
815 return rcExit;
816}
817
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