VirtualBox

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

Last change on this file since 76553 was 76553, checked in by vboxsync, 5 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.2 KB
RevLine 
[34913]1/* $Id: VBoxManageDebugVM.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VBoxManage - Implementation of the debugvm command.
4 */
5
6/*
[76553]7 * Copyright (C) 2012-2019 Oracle Corporation
[34913]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*********************************************************************************************************************************/
[34913]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
[61937]30#include <VBox/types.h>
[34913]31#include <iprt/ctype.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/**
[35508]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;
[56118]81 CHECK_ERROR2I_RET(pDebugger, GetRegisters(idCpu, ComSafeArrayAsOutParam(aBstrNames),
82 ComSafeArrayAsOutParam(aBstrValues)),
83 RTEXITCODE_FAILURE);
[35508]84 Assert(aBstrNames.size() == aBstrValues.size());
85
[35550]86 size_t cchMaxName = 8;
[35508]87 for (size_t i = 0; i < aBstrNames.size(); i++)
[35550]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]);
[35508]96 }
97 else
98 {
99 com::Bstr bstrName = ValueUnion.psz;
100 com::Bstr bstrValue;
[56118]101 CHECK_ERROR2I_RET(pDebugger, GetRegister(idCpu, bstrName.raw(), bstrValue.asOutParam()), RTEXITCODE_FAILURE);
[35508]102 RTPrintf("%s = %ls\n", ValueUnion.psz, bstrValue.raw());
103 }
104 cRegisters++;
105 break;
106
107 default:
[56466]108 return errorGetOpt(rc, &ValueUnion);
[35508]109 }
110 }
111
112 if (!cRegisters)
[56466]113 return errorSyntax("The getregisters sub-command takes at least one register name");
[35508]114 return RTEXITCODE_SUCCESS;
115}
116
117/**
[35306]118 * Handles the info sub-command.
119 *
120 * @returns Suitable exit code.
[56466]121 * @param pArgs The handler arguments.
[35306]122 * @param pDebugger Pointer to the debugger interface.
123 */
[56466]124static RTEXITCODE handleDebugVM_Info(HandlerArg *pArgs, IMachineDebugger *pDebugger)
[35306]125{
[56466]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);
[35306]135
[56466]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);
[35306]161 com::Bstr bstrInfo;
[56118]162 CHECK_ERROR2I_RET(pDebugger, Info(bstrName.raw(), bstrArgs.raw(), bstrInfo.asOutParam()), RTEXITCODE_FAILURE);
[35306]163 RTPrintf("%ls", bstrInfo.raw());
164 return RTEXITCODE_SUCCESS;
165}
166
167/**
[34913]168 * Handles the inject sub-command.
[34971]169 *
[34913]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)
[56466]177 return errorTooManyParameters(&a->argv[1]);
[56118]178 CHECK_ERROR2I_RET(pDebugger, InjectNMI(), RTEXITCODE_FAILURE);
[34913]179 return RTEXITCODE_SUCCESS;
180}
181
182/**
[39650]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;
[41754]200
[52927]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
[39650]208 static const RTGETOPTDEF s_aOptions[] =
209 {
[52927]210 { "--debug", DEBUGVM_LOG_DEBUG, RTGETOPT_REQ_NOTHING },
211 { "--release", DEBUGVM_LOG_RELEASE, RTGETOPT_REQ_NOTHING }
[39650]212 };
[57991]213 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2,
214 /*
215 * Note: RTGETOPTINIT_FLAGS_NO_STD_OPTS is needed to not get into an infinite hang in the following
216 * while-loop when processing log groups starting with "h",
217 * e.g. "VBoxManage debugvm <VM Name> log --debug -hex".
218 */
219 RTGETOPTINIT_FLAGS_OPTS_FIRST | RTGETOPTINIT_FLAGS_NO_STD_OPTS);
[39650]220 AssertRCReturn(rc, RTEXITCODE_FAILURE);
221
222 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
223 {
224 switch (rc)
225 {
[52927]226 case DEBUGVM_LOG_RELEASE:
[39650]227 fRelease = true;
228 break;
229
[52927]230 case DEBUGVM_LOG_DEBUG:
[39650]231 fRelease = false;
232 break;
233
[41754]234 /* Because log strings can start with "-" (like "-all+dev_foo")
235 * we have to take everything we got as a setting and apply it.
236 * IPRT will take care of the validation afterwards. */
237 default:
[39650]238 if (strSettings.length() == 0)
239 strSettings = ValueUnion.psz;
240 else
241 {
242 strSettings.append(' ');
243 strSettings.append(ValueUnion.psz);
244 }
245 break;
246 }
247 }
248
249 if (fRelease)
250 {
251 com::Utf8Str strTmp(strSettings);
[58212]252 strSettings = "release:";
[39650]253 strSettings.append(strTmp);
254 }
255
256 com::Bstr bstrSettings(strSettings);
257 if (!strcmp(pszSubCmd, "log"))
[56118]258 CHECK_ERROR2I_RET(pDebugger, ModifyLogGroups(bstrSettings.raw()), RTEXITCODE_FAILURE);
[39650]259 else if (!strcmp(pszSubCmd, "logdest"))
[56118]260 CHECK_ERROR2I_RET(pDebugger, ModifyLogDestinations(bstrSettings.raw()), RTEXITCODE_FAILURE);
[39650]261 else if (!strcmp(pszSubCmd, "logflags"))
[56118]262 CHECK_ERROR2I_RET(pDebugger, ModifyLogFlags(bstrSettings.raw()), RTEXITCODE_FAILURE);
[39650]263 else
264 AssertFailedReturn(RTEXITCODE_FAILURE);
265
266 return RTEXITCODE_SUCCESS;
267}
268
269
270/**
[34913]271 * Handles the inject sub-command.
[34971]272 *
[34913]273 * @returns Suitable exit code.
274 * @param pArgs The handler arguments.
275 * @param pDebugger Pointer to the debugger interface.
276 */
277static RTEXITCODE handleDebugVM_DumpVMCore(HandlerArg *pArgs, IMachineDebugger *pDebugger)
278{
279 /*
280 * Parse arguments.
281 */
[35242]282 const char *pszFilename = NULL;
283 const char *pszCompression = NULL;
[34913]284
285 RTGETOPTSTATE GetState;
286 RTGETOPTUNION ValueUnion;
287 static const RTGETOPTDEF s_aOptions[] =
288 {
[35242]289 { "--filename", 'f', RTGETOPT_REQ_STRING },
290 { "--compression", 'c', RTGETOPT_REQ_STRING }
[34913]291 };
292 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, 0 /*fFlags*/);
293 AssertRCReturn(rc, RTEXITCODE_FAILURE);
294
295 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
296 {
297 switch (rc)
298 {
[35242]299 case 'c':
300 if (pszCompression)
[56466]301 return errorSyntax("The --compression option has already been given");
[35242]302 pszCompression = ValueUnion.psz;
303 break;
[34913]304 case 'f':
305 if (pszFilename)
[56466]306 return errorSyntax("The --filename option has already been given");
[34913]307 pszFilename = ValueUnion.psz;
308 break;
309 default:
[56466]310 return errorGetOpt(rc, &ValueUnion);
[34913]311 }
312 }
313
314 if (!pszFilename)
[56466]315 return errorSyntax("The --filename option is required");
[34913]316
317 /*
318 * Make the filename absolute before handing it on to the API.
319 */
320 char szAbsFilename[RTPATH_MAX];
321 rc = RTPathAbs(pszFilename, szAbsFilename, sizeof(szAbsFilename));
322 if (RT_FAILURE(rc))
323 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs failed on '%s': %Rrc", pszFilename, rc);
324
325 com::Bstr bstrFilename(szAbsFilename);
[35242]326 com::Bstr bstrCompression(pszCompression);
[56118]327 CHECK_ERROR2I_RET(pDebugger, DumpGuestCore(bstrFilename.raw(), bstrCompression.raw()), RTEXITCODE_FAILURE);
[34913]328 return RTEXITCODE_SUCCESS;
329}
330
[34971]331/**
[56090]332 * Handles the osdetect sub-command.
[35306]333 *
334 * @returns Suitable exit code.
335 * @param a The handler arguments.
336 * @param pDebugger Pointer to the debugger interface.
337 */
338static RTEXITCODE handleDebugVM_OSDetect(HandlerArg *a, IMachineDebugger *pDebugger)
339{
340 if (a->argc != 2)
[56466]341 return errorTooManyParameters(&a->argv[1]);
[35306]342
[55884]343 com::Bstr bstrIgnore;
344 com::Bstr bstrAll("all");
[56118]345 CHECK_ERROR2I_RET(pDebugger, LoadPlugIn(bstrAll.raw(), bstrIgnore.asOutParam()), RTEXITCODE_FAILURE);
[55884]346
[35306]347 com::Bstr bstrName;
[56118]348 CHECK_ERROR2I_RET(pDebugger, DetectOS(bstrName.asOutParam()), RTEXITCODE_FAILURE);
[35306]349 RTPrintf("Detected: %ls\n", bstrName.raw());
350 return RTEXITCODE_SUCCESS;
351}
352
353/**
[56090]354 * Handles the osinfo sub-command.
[35306]355 *
356 * @returns Suitable exit code.
357 * @param a The handler arguments.
358 * @param pDebugger Pointer to the debugger interface.
359 */
360static RTEXITCODE handleDebugVM_OSInfo(HandlerArg *a, IMachineDebugger *pDebugger)
361{
362 if (a->argc != 2)
[56466]363 return errorTooManyParameters(&a->argv[1]);
[35306]364
365 com::Bstr bstrName;
[56118]366 CHECK_ERROR2I_RET(pDebugger, COMGETTER(OSName)(bstrName.asOutParam()), RTEXITCODE_FAILURE);
[35306]367 com::Bstr bstrVersion;
[56118]368 CHECK_ERROR2I_RET(pDebugger, COMGETTER(OSVersion)(bstrVersion.asOutParam()), RTEXITCODE_FAILURE);
[35306]369 RTPrintf("Name: %ls\n", bstrName.raw());
370 RTPrintf("Version: %ls\n", bstrVersion.raw());
371 return RTEXITCODE_SUCCESS;
372}
373
374/**
[56090]375 * Handles the osdmsg sub-command.
376 *
377 * @returns Suitable exit code.
378 * @param pArgs The handler arguments.
379 * @param pDebugger Pointer to the debugger interface.
380 */
381static RTEXITCODE handleDebugVM_OSDmesg(HandlerArg *pArgs, IMachineDebugger *pDebugger)
382{
383 /*
384 * Parse argument.
385 */
386 uint32_t uMaxMessages = 0;
387 RTGETOPTSTATE GetState;
388 RTGETOPTUNION ValueUnion;
389 static const RTGETOPTDEF s_aOptions[] =
390 {
391 { "--lines", 'n', RTGETOPT_REQ_UINT32 },
392 };
393 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
394 AssertRCReturn(rc, RTEXITCODE_FAILURE);
395 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
396 switch (rc)
397 {
398 case 'n': uMaxMessages = ValueUnion.u32; break;
[56466]399 default: return errorGetOpt(rc, &ValueUnion);
[56090]400 }
401
402 /*
403 * Do it.
404 */
405 com::Bstr bstrDmesg;
[56118]406 CHECK_ERROR2I_RET(pDebugger, QueryOSKernelLog(uMaxMessages, bstrDmesg.asOutParam()), RTEXITCODE_FAILURE);
[56090]407 RTPrintf("%ls\n", bstrDmesg.raw());
408 return RTEXITCODE_SUCCESS;
409}
410
411/**
[35508]412 * Handles the setregisters sub-command.
413 *
414 * @returns Suitable exit code.
415 * @param pArgs The handler arguments.
416 * @param pDebugger Pointer to the debugger interface.
417 */
418static RTEXITCODE handleDebugVM_SetRegisters(HandlerArg *pArgs, IMachineDebugger *pDebugger)
419{
420 /*
421 * We take a list of register assignments, that is register=value.
422 */
423 ULONG idCpu = 0;
424 com::SafeArray<IN_BSTR> aBstrNames;
425 com::SafeArray<IN_BSTR> aBstrValues;
426
427 RTGETOPTSTATE GetState;
428 RTGETOPTUNION ValueUnion;
429 static const RTGETOPTDEF s_aOptions[] =
430 {
431 { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
432 };
433 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
434 AssertRCReturn(rc, RTEXITCODE_FAILURE);
435
436 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
437 {
438 switch (rc)
439 {
440 case 'c':
441 idCpu = ValueUnion.u32;
442 break;
443
444 case VINF_GETOPT_NOT_OPTION:
445 {
446 const char *pszEqual = strchr(ValueUnion.psz, '=');
447 if (!pszEqual)
[56466]448 return errorSyntax("setregisters expects input on the form 'register=value' got '%s'", ValueUnion.psz);
[35508]449 try
450 {
451 com::Bstr bstrName(ValueUnion.psz, pszEqual - ValueUnion.psz);
452 com::Bstr bstrValue(pszEqual + 1);
453 if ( !aBstrNames.push_back(bstrName.raw())
454 || !aBstrValues.push_back(bstrValue.raw()))
455 throw std::bad_alloc();
456 }
[73506]457 catch (std::bad_alloc &)
[35508]458 {
459 RTMsgError("Out of memory\n");
460 return RTEXITCODE_FAILURE;
461 }
462 break;
463 }
464
465 default:
[56466]466 return errorGetOpt(rc, &ValueUnion);
[35508]467 }
468 }
469
470 if (!aBstrNames.size())
[56466]471 return errorSyntax("The setregisters sub-command takes at least one register name");
[35508]472
473 /*
474 * If it is only one register, use the single register method just so
475 * we expose it and can test it from the command line.
476 */
477 if (aBstrNames.size() == 1)
478 {
[56118]479 CHECK_ERROR2I_RET(pDebugger, SetRegister(idCpu, aBstrNames[0], aBstrValues[0]), RTEXITCODE_FAILURE);
[35508]480 RTPrintf("Successfully set %ls\n", aBstrNames[0]);
481 }
482 else
483 {
[56118]484 CHECK_ERROR2I_RET(pDebugger, SetRegisters(idCpu, ComSafeArrayAsInParam(aBstrNames), ComSafeArrayAsInParam(aBstrValues)),
485 RTEXITCODE_FAILURE);
[35508]486 RTPrintf("Successfully set %u registers\n", aBstrNames.size());
487 }
488
489 return RTEXITCODE_SUCCESS;
490}
491
[39675]492/** @name debugvm show flags
493 * @{ */
494#define DEBUGVM_SHOW_FLAGS_HUMAN_READABLE UINT32_C(0x00000000)
495#define DEBUGVM_SHOW_FLAGS_SH_EXPORT UINT32_C(0x00000001)
496#define DEBUGVM_SHOW_FLAGS_SH_EVAL UINT32_C(0x00000002)
497#define DEBUGVM_SHOW_FLAGS_CMD_SET UINT32_C(0x00000003)
498#define DEBUGVM_SHOW_FLAGS_FMT_MASK UINT32_C(0x00000003)
499/** @} */
500
[35508]501/**
[39675]502 * Prints a variable according to the @a fFlags.
503 *
504 * @param pszVar The variable name.
505 * @param pbstrValue The variable value.
506 * @param fFlags The debugvm show flags.
507 */
508static void handleDebugVM_Show_PrintVar(const char *pszVar, com::Bstr const *pbstrValue, uint32_t fFlags)
509{
510 switch (fFlags & DEBUGVM_SHOW_FLAGS_FMT_MASK)
511 {
512 case DEBUGVM_SHOW_FLAGS_HUMAN_READABLE: RTPrintf(" %27s=%ls\n", pszVar, pbstrValue->raw()); break;
513 case DEBUGVM_SHOW_FLAGS_SH_EXPORT: RTPrintf("export %s='%ls'\n", pszVar, pbstrValue->raw()); break;
514 case DEBUGVM_SHOW_FLAGS_SH_EVAL: RTPrintf("%s='%ls'\n", pszVar, pbstrValue->raw()); break;
515 case DEBUGVM_SHOW_FLAGS_CMD_SET: RTPrintf("set %s=%ls\n", pszVar, pbstrValue->raw()); break;
516 default: AssertFailed();
517 }
518}
519
520/**
521 * Handles logdbg-settings.
522 *
523 * @returns Exit code.
524 * @param pDebugger The debugger interface.
525 * @param fFlags The debugvm show flags.
526 */
527static RTEXITCODE handleDebugVM_Show_LogDbgSettings(IMachineDebugger *pDebugger, uint32_t fFlags)
528{
529 if ((fFlags & DEBUGVM_SHOW_FLAGS_FMT_MASK) == DEBUGVM_SHOW_FLAGS_HUMAN_READABLE)
530 RTPrintf("Debug logger settings:\n");
531
532 com::Bstr bstr;
[57993]533 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogDbgGroups)(bstr.asOutParam()), RTEXITCODE_FAILURE);
[39675]534 handleDebugVM_Show_PrintVar("VBOX_LOG", &bstr, fFlags);
535
[57993]536 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogDbgFlags)(bstr.asOutParam()), RTEXITCODE_FAILURE);
[39675]537 handleDebugVM_Show_PrintVar("VBOX_LOG_FLAGS", &bstr, fFlags);
538
[56118]539 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogDbgDestinations)(bstr.asOutParam()), RTEXITCODE_FAILURE);
[39675]540 handleDebugVM_Show_PrintVar("VBOX_LOG_DEST", &bstr, fFlags);
541 return RTEXITCODE_SUCCESS;
542}
543
544/**
545 * Handles logrel-settings.
546 *
547 * @returns Exit code.
548 * @param pDebugger The debugger interface.
549 * @param fFlags The debugvm show flags.
550 */
551static RTEXITCODE handleDebugVM_Show_LogRelSettings(IMachineDebugger *pDebugger, uint32_t fFlags)
552{
553 if ((fFlags & DEBUGVM_SHOW_FLAGS_FMT_MASK) == DEBUGVM_SHOW_FLAGS_HUMAN_READABLE)
554 RTPrintf("Release logger settings:\n");
555
556 com::Bstr bstr;
[57993]557 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogRelGroups)(bstr.asOutParam()), RTEXITCODE_FAILURE);
[39675]558 handleDebugVM_Show_PrintVar("VBOX_RELEASE_LOG", &bstr, fFlags);
559
[57993]560 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogRelFlags)(bstr.asOutParam()), RTEXITCODE_FAILURE);
[39675]561 handleDebugVM_Show_PrintVar("VBOX_RELEASE_LOG_FLAGS", &bstr, fFlags);
562
[56118]563 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogRelDestinations)(bstr.asOutParam()), RTEXITCODE_FAILURE);
[39675]564 handleDebugVM_Show_PrintVar("VBOX_RELEASE_LOG_DEST", &bstr, fFlags);
565 return RTEXITCODE_SUCCESS;
566}
567
568/**
[39668]569 * Handles the show sub-command.
570 *
571 * @returns Suitable exit code.
572 * @param pArgs The handler arguments.
573 * @param pDebugger Pointer to the debugger interface.
574 */
575static RTEXITCODE handleDebugVM_Show(HandlerArg *pArgs, IMachineDebugger *pDebugger)
576{
[39675]577 /*
578 * Parse arguments and what to show. Order dependent.
579 */
580 uint32_t fFlags = DEBUGVM_SHOW_FLAGS_HUMAN_READABLE;
[39668]581
[39675]582 RTGETOPTSTATE GetState;
583 RTGETOPTUNION ValueUnion;
584 static const RTGETOPTDEF s_aOptions[] =
[39668]585 {
[39675]586 { "--human-readable", 'H', RTGETOPT_REQ_NOTHING },
587 { "--sh-export", 'e', RTGETOPT_REQ_NOTHING },
588 { "--sh-eval", 'E', RTGETOPT_REQ_NOTHING },
589 { "--cmd-set", 's', RTGETOPT_REQ_NOTHING },
590 };
591 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, 0 /*fFlags*/);
592 AssertRCReturn(rc, RTEXITCODE_FAILURE);
593
594 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
[39668]595 {
[39675]596 switch (rc)
597 {
598 case 'H':
599 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_HUMAN_READABLE;
600 break;
601
602 case 'e':
603 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_SH_EXPORT;
604 break;
605
606 case 'E':
607 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_SH_EVAL;
608 break;
609
610 case 's':
611 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_CMD_SET;
612 break;
613
614 case VINF_GETOPT_NOT_OPTION:
615 {
616 RTEXITCODE rcExit;
617 if (!strcmp(ValueUnion.psz, "log-settings"))
618 {
619 rcExit = handleDebugVM_Show_LogDbgSettings(pDebugger, fFlags);
620 if (rcExit == RTEXITCODE_SUCCESS)
621 rcExit = handleDebugVM_Show_LogRelSettings(pDebugger, fFlags);
622 }
623 else if (!strcmp(ValueUnion.psz, "logdbg-settings"))
624 rcExit = handleDebugVM_Show_LogDbgSettings(pDebugger, fFlags);
625 else if (!strcmp(ValueUnion.psz, "logrel-settings"))
626 rcExit = handleDebugVM_Show_LogRelSettings(pDebugger, fFlags);
627 else
[56466]628 rcExit = errorSyntax("The show sub-command has no idea what '%s' might be", ValueUnion.psz);
[39675]629 if (rcExit != RTEXITCODE_SUCCESS)
630 return rcExit;
631 break;
632 }
633
634 default:
[56466]635 return errorGetOpt(rc, &ValueUnion);
[39675]636 }
[39668]637 }
638 return RTEXITCODE_SUCCESS;
639}
640
641/**
[61937]642 * Handles the stack sub-command.
643 *
644 * @returns Suitable exit code.
645 * @param pArgs The handler arguments.
646 * @param pDebugger Pointer to the debugger interface.
647 */
648static RTEXITCODE handleDebugVM_Stack(HandlerArg *pArgs, IMachineDebugger *pDebugger)
649{
650 /*
651 * Parse arguments.
652 */
653 VMCPUID idCpu = VMCPUID_ALL;
654
655 RTGETOPTSTATE GetState;
656 RTGETOPTUNION ValueUnion;
657 static const RTGETOPTDEF s_aOptions[] =
658 {
659 { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
660 };
661 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
662 AssertRCReturn(rc, RTEXITCODE_FAILURE);
663
664 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
665 {
666 switch (rc)
667 {
668 case 'c':
669 idCpu = ValueUnion.u32;
670 break;
671
672 default:
673 return errorGetOpt(rc, &ValueUnion);
674 }
675 }
676
677 /*
678 * Dump stack.
679 */
680 com::Bstr bstrGuestStack;
681 if (idCpu != VMCPUID_ALL)
682 {
683 /* Single CPU */
684 CHECK_ERROR2I_RET(pDebugger, DumpGuestStack(idCpu, bstrGuestStack.asOutParam()), RTEXITCODE_FAILURE);
685 RTPrintf("%ls\n", bstrGuestStack.raw());
686 }
687 else
688 {
689 /* All CPUs. */
690 ComPtr<IMachine> ptrMachine;
691 CHECK_ERROR2I_RET(pArgs->session, COMGETTER(Machine)(ptrMachine.asOutParam()), RTEXITCODE_FAILURE);
692 ULONG cCpus;
693 CHECK_ERROR2I_RET(ptrMachine, COMGETTER(CPUCount)(&cCpus), RTEXITCODE_FAILURE);
694
695 for (idCpu = 0; idCpu < (VMCPUID)cCpus; idCpu++)
696 {
697 CHECK_ERROR2I_RET(pDebugger, DumpGuestStack(idCpu, bstrGuestStack.asOutParam()), RTEXITCODE_FAILURE);
698 if (cCpus > 1)
699 {
700 if (idCpu > 0)
701 RTPrintf("\n");
702 RTPrintf("====================== CPU #%u ======================\n", idCpu);
703 }
704 RTPrintf("%ls\n", bstrGuestStack.raw());
705 }
706 }
707
708
709 return RTEXITCODE_SUCCESS;
710}
711
712/**
[34971]713 * Handles the statistics sub-command.
714 *
715 * @returns Suitable exit code.
716 * @param pArgs The handler arguments.
717 * @param pDebugger Pointer to the debugger interface.
718 */
719static RTEXITCODE handleDebugVM_Statistics(HandlerArg *pArgs, IMachineDebugger *pDebugger)
720{
721 /*
722 * Parse arguments.
723 */
724 bool fWithDescriptions = false;
725 const char *pszPattern = NULL; /* all */
726 bool fReset = false;
727
728 RTGETOPTSTATE GetState;
729 RTGETOPTUNION ValueUnion;
730 static const RTGETOPTDEF s_aOptions[] =
731 {
732 { "--descriptions", 'd', RTGETOPT_REQ_NOTHING },
733 { "--pattern", 'p', RTGETOPT_REQ_STRING },
734 { "--reset", 'r', RTGETOPT_REQ_NOTHING },
735 };
736 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, 0 /*fFlags*/);
737 AssertRCReturn(rc, RTEXITCODE_FAILURE);
738
739 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
740 {
741 switch (rc)
742 {
743 case 'd':
744 fWithDescriptions = true;
745 break;
746
747 case 'p':
748 if (pszPattern)
[56466]749 return errorSyntax("Multiple --pattern options are not permitted");
[34971]750 pszPattern = ValueUnion.psz;
751 break;
752
753 case 'r':
754 fReset = true;
755 break;
756
757 default:
[56466]758 return errorGetOpt(rc, &ValueUnion);
[34971]759 }
760 }
761
762 if (fReset && fWithDescriptions)
[56466]763 return errorSyntax("The --reset and --descriptions options does not mix");
[34971]764
765 /*
766 * Execute the order.
767 */
768 com::Bstr bstrPattern(pszPattern);
769 if (fReset)
[56118]770 CHECK_ERROR2I_RET(pDebugger, ResetStats(bstrPattern.raw()), RTEXITCODE_FAILURE);
[34971]771 else
772 {
773 com::Bstr bstrStats;
[56118]774 CHECK_ERROR2I_RET(pDebugger, GetStats(bstrPattern.raw(), fWithDescriptions, bstrStats.asOutParam()),
775 RTEXITCODE_FAILURE);
[34971]776 /* if (fFormatted)
777 { big mess }
778 else
779 */
780 RTPrintf("%ls\n", bstrStats.raw());
781 }
782
783 return RTEXITCODE_SUCCESS;
784}
785
[56118]786RTEXITCODE handleDebugVM(HandlerArg *pArgs)
[34913]787{
788 RTEXITCODE rcExit = RTEXITCODE_FAILURE;
789
790 /*
791 * The first argument is the VM name or UUID. Open a session to it.
792 */
793 if (pArgs->argc < 2)
[56466]794 return errorNoSubcommand();
[34913]795 ComPtr<IMachine> ptrMachine;
[56118]796 CHECK_ERROR2I_RET(pArgs->virtualBox, FindMachine(com::Bstr(pArgs->argv[0]).raw(), ptrMachine.asOutParam()), RTEXITCODE_FAILURE);
797 CHECK_ERROR2I_RET(ptrMachine, LockMachine(pArgs->session, LockType_Shared), RTEXITCODE_FAILURE);
[34913]798
799 /*
800 * Get the associated console and machine debugger.
801 */
[61937]802 HRESULT hrc;
[34913]803 ComPtr<IConsole> ptrConsole;
[61937]804 CHECK_ERROR2(hrc, pArgs->session, COMGETTER(Console)(ptrConsole.asOutParam()));
805 if (SUCCEEDED(hrc))
[34913]806 {
[56119]807 if (ptrConsole.isNotNull())
[34913]808 {
[56119]809 ComPtr<IMachineDebugger> ptrDebugger;
[61937]810 CHECK_ERROR2(hrc, ptrConsole, COMGETTER(Debugger)(ptrDebugger.asOutParam()));
811 if (SUCCEEDED(hrc))
[56119]812 {
813 /*
814 * String switch on the sub-command.
815 */
816 const char *pszSubCmd = pArgs->argv[1];
[56466]817 if (!strcmp(pszSubCmd, "dumpvmcore"))
818 {
819 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_DUMPVMCORE);
[56119]820 rcExit = handleDebugVM_DumpVMCore(pArgs, ptrDebugger);
[56466]821 }
[56119]822 else if (!strcmp(pszSubCmd, "getregisters"))
[56466]823 {
824 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_GETREGISTERS);
[56119]825 rcExit = handleDebugVM_GetRegisters(pArgs, ptrDebugger);
[56466]826 }
[56119]827 else if (!strcmp(pszSubCmd, "info"))
[56466]828 {
829 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_INFO);
[56119]830 rcExit = handleDebugVM_Info(pArgs, ptrDebugger);
[56466]831 }
[56119]832 else if (!strcmp(pszSubCmd, "injectnmi"))
[56466]833 {
834 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_INJECTNMI);
[56119]835 rcExit = handleDebugVM_InjectNMI(pArgs, ptrDebugger);
[56466]836 }
[56119]837 else if (!strcmp(pszSubCmd, "log"))
[56466]838 {
839 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_LOG);
[56119]840 rcExit = handleDebugVM_LogXXXX(pArgs, ptrDebugger, pszSubCmd);
[56466]841 }
[56119]842 else if (!strcmp(pszSubCmd, "logdest"))
[56466]843 {
844 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_LOGDEST);
[56119]845 rcExit = handleDebugVM_LogXXXX(pArgs, ptrDebugger, pszSubCmd);
[56466]846 }
[56119]847 else if (!strcmp(pszSubCmd, "logflags"))
[56466]848 {
849 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_LOGFLAGS);
[56119]850 rcExit = handleDebugVM_LogXXXX(pArgs, ptrDebugger, pszSubCmd);
[56466]851 }
[56119]852 else if (!strcmp(pszSubCmd, "osdetect"))
[56466]853 {
854 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_OSDETECT);
[56119]855 rcExit = handleDebugVM_OSDetect(pArgs, ptrDebugger);
[56466]856 }
[56119]857 else if (!strcmp(pszSubCmd, "osinfo"))
[56466]858 {
859 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_OSINFO);
[56119]860 rcExit = handleDebugVM_OSInfo(pArgs, ptrDebugger);
[56466]861 }
[56119]862 else if (!strcmp(pszSubCmd, "osdmesg"))
[56466]863 {
864 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_OSDMESG);
[56119]865 rcExit = handleDebugVM_OSDmesg(pArgs, ptrDebugger);
[56466]866 }
[56119]867 else if (!strcmp(pszSubCmd, "setregisters"))
[56466]868 {
869 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_SETREGISTERS);
[56119]870 rcExit = handleDebugVM_SetRegisters(pArgs, ptrDebugger);
[56466]871 }
[56119]872 else if (!strcmp(pszSubCmd, "show"))
[56466]873 {
874 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_SHOW);
[56119]875 rcExit = handleDebugVM_Show(pArgs, ptrDebugger);
[56466]876 }
[61937]877 else if (!strcmp(pszSubCmd, "stack"))
878 {
879 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_STACK);
880 rcExit = handleDebugVM_Stack(pArgs, ptrDebugger);
881 }
[56119]882 else if (!strcmp(pszSubCmd, "statistics"))
[56466]883 {
884 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_STATISTICS);
[56119]885 rcExit = handleDebugVM_Statistics(pArgs, ptrDebugger);
[56466]886 }
[56119]887 else
[56466]888 errorUnknownSubcommand(pszSubCmd);
[56119]889 }
[34913]890 }
[56119]891 else
892 RTMsgError("Machine '%s' is not currently running.\n", pArgs->argv[0]);
[34913]893 }
894
895 pArgs->session->UnlockMachine();
896
897 return rcExit;
898}
899
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use