VirtualBox

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

Last change on this file since 57991 was 57991, checked in by vboxsync, 10 years ago

VBoxManage/VBoxManageDebugVM.cpp: Fixed hang when processing log groups starting with "h", e.g. "VBoxManage debugvm <VM Name> log --debug -hex".

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.9 KB
Line 
1/* $Id: VBoxManageDebugVM.cpp 57991 2015-10-01 19:28:46Z 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.215389.xyz. 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,
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);
220 AssertRCReturn(rc, RTEXITCODE_FAILURE);
221
222 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
223 {
224 switch (rc)
225 {
226 case DEBUGVM_LOG_RELEASE:
227 fRelease = true;
228 break;
229
230 case DEBUGVM_LOG_DEBUG:
231 fRelease = false;
232 break;
233
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:
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);
252 strSettings = "release: ";
253 strSettings.append(strTmp);
254 }
255
256
257
258 com::Bstr bstrSettings(strSettings);
259 if (!strcmp(pszSubCmd, "log"))
260 CHECK_ERROR2I_RET(pDebugger, ModifyLogGroups(bstrSettings.raw()), RTEXITCODE_FAILURE);
261 else if (!strcmp(pszSubCmd, "logdest"))
262 CHECK_ERROR2I_RET(pDebugger, ModifyLogDestinations(bstrSettings.raw()), RTEXITCODE_FAILURE);
263 else if (!strcmp(pszSubCmd, "logflags"))
264 CHECK_ERROR2I_RET(pDebugger, ModifyLogFlags(bstrSettings.raw()), RTEXITCODE_FAILURE);
265 else
266 AssertFailedReturn(RTEXITCODE_FAILURE);
267
268 return RTEXITCODE_SUCCESS;
269}
270
271
272/**
273 * Handles the inject sub-command.
274 *
275 * @returns Suitable exit code.
276 * @param pArgs The handler arguments.
277 * @param pDebugger Pointer to the debugger interface.
278 */
279static RTEXITCODE handleDebugVM_DumpVMCore(HandlerArg *pArgs, IMachineDebugger *pDebugger)
280{
281 /*
282 * Parse arguments.
283 */
284 const char *pszFilename = NULL;
285 const char *pszCompression = NULL;
286
287 RTGETOPTSTATE GetState;
288 RTGETOPTUNION ValueUnion;
289 static const RTGETOPTDEF s_aOptions[] =
290 {
291 { "--filename", 'f', RTGETOPT_REQ_STRING },
292 { "--compression", 'c', RTGETOPT_REQ_STRING }
293 };
294 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, 0 /*fFlags*/);
295 AssertRCReturn(rc, RTEXITCODE_FAILURE);
296
297 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
298 {
299 switch (rc)
300 {
301 case 'c':
302 if (pszCompression)
303 return errorSyntax("The --compression option has already been given");
304 pszCompression = ValueUnion.psz;
305 break;
306 case 'f':
307 if (pszFilename)
308 return errorSyntax("The --filename option has already been given");
309 pszFilename = ValueUnion.psz;
310 break;
311 default:
312 return errorGetOpt(rc, &ValueUnion);
313 }
314 }
315
316 if (!pszFilename)
317 return errorSyntax("The --filename option is required");
318
319 /*
320 * Make the filename absolute before handing it on to the API.
321 */
322 char szAbsFilename[RTPATH_MAX];
323 rc = RTPathAbs(pszFilename, szAbsFilename, sizeof(szAbsFilename));
324 if (RT_FAILURE(rc))
325 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs failed on '%s': %Rrc", pszFilename, rc);
326
327 com::Bstr bstrFilename(szAbsFilename);
328 com::Bstr bstrCompression(pszCompression);
329 CHECK_ERROR2I_RET(pDebugger, DumpGuestCore(bstrFilename.raw(), bstrCompression.raw()), RTEXITCODE_FAILURE);
330 return RTEXITCODE_SUCCESS;
331}
332
333/**
334 * Handles the osdetect sub-command.
335 *
336 * @returns Suitable exit code.
337 * @param a The handler arguments.
338 * @param pDebugger Pointer to the debugger interface.
339 */
340static RTEXITCODE handleDebugVM_OSDetect(HandlerArg *a, IMachineDebugger *pDebugger)
341{
342 if (a->argc != 2)
343 return errorTooManyParameters(&a->argv[1]);
344
345 com::Bstr bstrIgnore;
346 com::Bstr bstrAll("all");
347 CHECK_ERROR2I_RET(pDebugger, LoadPlugIn(bstrAll.raw(), bstrIgnore.asOutParam()), RTEXITCODE_FAILURE);
348
349 com::Bstr bstrName;
350 CHECK_ERROR2I_RET(pDebugger, DetectOS(bstrName.asOutParam()), RTEXITCODE_FAILURE);
351 RTPrintf("Detected: %ls\n", bstrName.raw());
352 return RTEXITCODE_SUCCESS;
353}
354
355/**
356 * Handles the osinfo sub-command.
357 *
358 * @returns Suitable exit code.
359 * @param a The handler arguments.
360 * @param pDebugger Pointer to the debugger interface.
361 */
362static RTEXITCODE handleDebugVM_OSInfo(HandlerArg *a, IMachineDebugger *pDebugger)
363{
364 if (a->argc != 2)
365 return errorTooManyParameters(&a->argv[1]);
366
367 com::Bstr bstrName;
368 CHECK_ERROR2I_RET(pDebugger, COMGETTER(OSName)(bstrName.asOutParam()), RTEXITCODE_FAILURE);
369 com::Bstr bstrVersion;
370 CHECK_ERROR2I_RET(pDebugger, COMGETTER(OSVersion)(bstrVersion.asOutParam()), RTEXITCODE_FAILURE);
371 RTPrintf("Name: %ls\n", bstrName.raw());
372 RTPrintf("Version: %ls\n", bstrVersion.raw());
373 return RTEXITCODE_SUCCESS;
374}
375
376/**
377 * Handles the osdmsg sub-command.
378 *
379 * @returns Suitable exit code.
380 * @param pArgs The handler arguments.
381 * @param pDebugger Pointer to the debugger interface.
382 */
383static RTEXITCODE handleDebugVM_OSDmesg(HandlerArg *pArgs, IMachineDebugger *pDebugger)
384{
385 /*
386 * Parse argument.
387 */
388 uint32_t uMaxMessages = 0;
389 RTGETOPTSTATE GetState;
390 RTGETOPTUNION ValueUnion;
391 static const RTGETOPTDEF s_aOptions[] =
392 {
393 { "--lines", 'n', RTGETOPT_REQ_UINT32 },
394 };
395 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
396 AssertRCReturn(rc, RTEXITCODE_FAILURE);
397 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
398 switch (rc)
399 {
400 case 'n': uMaxMessages = ValueUnion.u32; break;
401 default: return errorGetOpt(rc, &ValueUnion);
402 }
403
404 /*
405 * Do it.
406 */
407 com::Bstr bstrDmesg;
408 CHECK_ERROR2I_RET(pDebugger, QueryOSKernelLog(uMaxMessages, bstrDmesg.asOutParam()), RTEXITCODE_FAILURE);
409 RTPrintf("%ls\n", bstrDmesg.raw());
410 return RTEXITCODE_SUCCESS;
411}
412
413/**
414 * Handles the setregisters sub-command.
415 *
416 * @returns Suitable exit code.
417 * @param pArgs The handler arguments.
418 * @param pDebugger Pointer to the debugger interface.
419 */
420static RTEXITCODE handleDebugVM_SetRegisters(HandlerArg *pArgs, IMachineDebugger *pDebugger)
421{
422 /*
423 * We take a list of register assignments, that is register=value.
424 */
425 ULONG idCpu = 0;
426 com::SafeArray<IN_BSTR> aBstrNames;
427 com::SafeArray<IN_BSTR> aBstrValues;
428
429 RTGETOPTSTATE GetState;
430 RTGETOPTUNION ValueUnion;
431 static const RTGETOPTDEF s_aOptions[] =
432 {
433 { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
434 };
435 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
436 AssertRCReturn(rc, RTEXITCODE_FAILURE);
437
438 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
439 {
440 switch (rc)
441 {
442 case 'c':
443 idCpu = ValueUnion.u32;
444 break;
445
446 case VINF_GETOPT_NOT_OPTION:
447 {
448 const char *pszEqual = strchr(ValueUnion.psz, '=');
449 if (!pszEqual)
450 return errorSyntax("setregisters expects input on the form 'register=value' got '%s'", ValueUnion.psz);
451 try
452 {
453 com::Bstr bstrName(ValueUnion.psz, pszEqual - ValueUnion.psz);
454 com::Bstr bstrValue(pszEqual + 1);
455 if ( !aBstrNames.push_back(bstrName.raw())
456 || !aBstrValues.push_back(bstrValue.raw()))
457 throw std::bad_alloc();
458 }
459 catch (std::bad_alloc)
460 {
461 RTMsgError("Out of memory\n");
462 return RTEXITCODE_FAILURE;
463 }
464 break;
465 }
466
467 default:
468 return errorGetOpt(rc, &ValueUnion);
469 }
470 }
471
472 if (!aBstrNames.size())
473 return errorSyntax("The setregisters sub-command takes at least one register name");
474
475 /*
476 * If it is only one register, use the single register method just so
477 * we expose it and can test it from the command line.
478 */
479 if (aBstrNames.size() == 1)
480 {
481 CHECK_ERROR2I_RET(pDebugger, SetRegister(idCpu, aBstrNames[0], aBstrValues[0]), RTEXITCODE_FAILURE);
482 RTPrintf("Successfully set %ls\n", aBstrNames[0]);
483 }
484 else
485 {
486 CHECK_ERROR2I_RET(pDebugger, SetRegisters(idCpu, ComSafeArrayAsInParam(aBstrNames), ComSafeArrayAsInParam(aBstrValues)),
487 RTEXITCODE_FAILURE);
488 RTPrintf("Successfully set %u registers\n", aBstrNames.size());
489 }
490
491 return RTEXITCODE_SUCCESS;
492}
493
494/** @name debugvm show flags
495 * @{ */
496#define DEBUGVM_SHOW_FLAGS_HUMAN_READABLE UINT32_C(0x00000000)
497#define DEBUGVM_SHOW_FLAGS_SH_EXPORT UINT32_C(0x00000001)
498#define DEBUGVM_SHOW_FLAGS_SH_EVAL UINT32_C(0x00000002)
499#define DEBUGVM_SHOW_FLAGS_CMD_SET UINT32_C(0x00000003)
500#define DEBUGVM_SHOW_FLAGS_FMT_MASK UINT32_C(0x00000003)
501/** @} */
502
503/**
504 * Prints a variable according to the @a fFlags.
505 *
506 * @param pszVar The variable name.
507 * @param pbstrValue The variable value.
508 * @param fFlags The debugvm show flags.
509 */
510static void handleDebugVM_Show_PrintVar(const char *pszVar, com::Bstr const *pbstrValue, uint32_t fFlags)
511{
512 switch (fFlags & DEBUGVM_SHOW_FLAGS_FMT_MASK)
513 {
514 case DEBUGVM_SHOW_FLAGS_HUMAN_READABLE: RTPrintf(" %27s=%ls\n", pszVar, pbstrValue->raw()); break;
515 case DEBUGVM_SHOW_FLAGS_SH_EXPORT: RTPrintf("export %s='%ls'\n", pszVar, pbstrValue->raw()); break;
516 case DEBUGVM_SHOW_FLAGS_SH_EVAL: RTPrintf("%s='%ls'\n", pszVar, pbstrValue->raw()); break;
517 case DEBUGVM_SHOW_FLAGS_CMD_SET: RTPrintf("set %s=%ls\n", pszVar, pbstrValue->raw()); break;
518 default: AssertFailed();
519 }
520}
521
522/**
523 * Handles logdbg-settings.
524 *
525 * @returns Exit code.
526 * @param pDebugger The debugger interface.
527 * @param fFlags The debugvm show flags.
528 */
529static RTEXITCODE handleDebugVM_Show_LogDbgSettings(IMachineDebugger *pDebugger, uint32_t fFlags)
530{
531 if ((fFlags & DEBUGVM_SHOW_FLAGS_FMT_MASK) == DEBUGVM_SHOW_FLAGS_HUMAN_READABLE)
532 RTPrintf("Debug logger settings:\n");
533
534 com::Bstr bstr;
535 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogDbgFlags)(bstr.asOutParam()), RTEXITCODE_FAILURE);
536 handleDebugVM_Show_PrintVar("VBOX_LOG", &bstr, fFlags);
537
538 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogDbgGroups)(bstr.asOutParam()), RTEXITCODE_FAILURE);
539 handleDebugVM_Show_PrintVar("VBOX_LOG_FLAGS", &bstr, fFlags);
540
541 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogDbgDestinations)(bstr.asOutParam()), RTEXITCODE_FAILURE);
542 handleDebugVM_Show_PrintVar("VBOX_LOG_DEST", &bstr, fFlags);
543 return RTEXITCODE_SUCCESS;
544}
545
546/**
547 * Handles logrel-settings.
548 *
549 * @returns Exit code.
550 * @param pDebugger The debugger interface.
551 * @param fFlags The debugvm show flags.
552 */
553static RTEXITCODE handleDebugVM_Show_LogRelSettings(IMachineDebugger *pDebugger, uint32_t fFlags)
554{
555 if ((fFlags & DEBUGVM_SHOW_FLAGS_FMT_MASK) == DEBUGVM_SHOW_FLAGS_HUMAN_READABLE)
556 RTPrintf("Release logger settings:\n");
557
558 com::Bstr bstr;
559 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogRelFlags)(bstr.asOutParam()), RTEXITCODE_FAILURE);
560 handleDebugVM_Show_PrintVar("VBOX_RELEASE_LOG", &bstr, fFlags);
561
562 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogRelGroups)(bstr.asOutParam()), RTEXITCODE_FAILURE);
563 handleDebugVM_Show_PrintVar("VBOX_RELEASE_LOG_FLAGS", &bstr, fFlags);
564
565 CHECK_ERROR2I_RET(pDebugger, COMGETTER(LogRelDestinations)(bstr.asOutParam()), RTEXITCODE_FAILURE);
566 handleDebugVM_Show_PrintVar("VBOX_RELEASE_LOG_DEST", &bstr, fFlags);
567 return RTEXITCODE_SUCCESS;
568}
569
570/**
571 * Handles the show sub-command.
572 *
573 * @returns Suitable exit code.
574 * @param pArgs The handler arguments.
575 * @param pDebugger Pointer to the debugger interface.
576 */
577static RTEXITCODE handleDebugVM_Show(HandlerArg *pArgs, IMachineDebugger *pDebugger)
578{
579 /*
580 * Parse arguments and what to show. Order dependent.
581 */
582 uint32_t fFlags = DEBUGVM_SHOW_FLAGS_HUMAN_READABLE;
583
584 RTGETOPTSTATE GetState;
585 RTGETOPTUNION ValueUnion;
586 static const RTGETOPTDEF s_aOptions[] =
587 {
588 { "--human-readable", 'H', RTGETOPT_REQ_NOTHING },
589 { "--sh-export", 'e', RTGETOPT_REQ_NOTHING },
590 { "--sh-eval", 'E', RTGETOPT_REQ_NOTHING },
591 { "--cmd-set", 's', RTGETOPT_REQ_NOTHING },
592 };
593 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, 0 /*fFlags*/);
594 AssertRCReturn(rc, RTEXITCODE_FAILURE);
595
596 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
597 {
598 switch (rc)
599 {
600 case 'H':
601 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_HUMAN_READABLE;
602 break;
603
604 case 'e':
605 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_SH_EXPORT;
606 break;
607
608 case 'E':
609 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_SH_EVAL;
610 break;
611
612 case 's':
613 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_CMD_SET;
614 break;
615
616 case VINF_GETOPT_NOT_OPTION:
617 {
618 RTEXITCODE rcExit;
619 if (!strcmp(ValueUnion.psz, "log-settings"))
620 {
621 rcExit = handleDebugVM_Show_LogDbgSettings(pDebugger, fFlags);
622 if (rcExit == RTEXITCODE_SUCCESS)
623 rcExit = handleDebugVM_Show_LogRelSettings(pDebugger, fFlags);
624 }
625 else if (!strcmp(ValueUnion.psz, "logdbg-settings"))
626 rcExit = handleDebugVM_Show_LogDbgSettings(pDebugger, fFlags);
627 else if (!strcmp(ValueUnion.psz, "logrel-settings"))
628 rcExit = handleDebugVM_Show_LogRelSettings(pDebugger, fFlags);
629 else
630 rcExit = errorSyntax("The show sub-command has no idea what '%s' might be", ValueUnion.psz);
631 if (rcExit != RTEXITCODE_SUCCESS)
632 return rcExit;
633 break;
634 }
635
636 default:
637 return errorGetOpt(rc, &ValueUnion);
638 }
639 }
640 return RTEXITCODE_SUCCESS;
641}
642
643/**
644 * Handles the statistics sub-command.
645 *
646 * @returns Suitable exit code.
647 * @param pArgs The handler arguments.
648 * @param pDebugger Pointer to the debugger interface.
649 */
650static RTEXITCODE handleDebugVM_Statistics(HandlerArg *pArgs, IMachineDebugger *pDebugger)
651{
652 /*
653 * Parse arguments.
654 */
655 bool fWithDescriptions = false;
656 const char *pszPattern = NULL; /* all */
657 bool fReset = false;
658
659 RTGETOPTSTATE GetState;
660 RTGETOPTUNION ValueUnion;
661 static const RTGETOPTDEF s_aOptions[] =
662 {
663 { "--descriptions", 'd', RTGETOPT_REQ_NOTHING },
664 { "--pattern", 'p', RTGETOPT_REQ_STRING },
665 { "--reset", 'r', RTGETOPT_REQ_NOTHING },
666 };
667 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, 0 /*fFlags*/);
668 AssertRCReturn(rc, RTEXITCODE_FAILURE);
669
670 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
671 {
672 switch (rc)
673 {
674 case 'd':
675 fWithDescriptions = true;
676 break;
677
678 case 'p':
679 if (pszPattern)
680 return errorSyntax("Multiple --pattern options are not permitted");
681 pszPattern = ValueUnion.psz;
682 break;
683
684 case 'r':
685 fReset = true;
686 break;
687
688 default:
689 return errorGetOpt(rc, &ValueUnion);
690 }
691 }
692
693 if (fReset && fWithDescriptions)
694 return errorSyntax("The --reset and --descriptions options does not mix");
695
696 /*
697 * Execute the order.
698 */
699 com::Bstr bstrPattern(pszPattern);
700 if (fReset)
701 CHECK_ERROR2I_RET(pDebugger, ResetStats(bstrPattern.raw()), RTEXITCODE_FAILURE);
702 else
703 {
704 com::Bstr bstrStats;
705 CHECK_ERROR2I_RET(pDebugger, GetStats(bstrPattern.raw(), fWithDescriptions, bstrStats.asOutParam()),
706 RTEXITCODE_FAILURE);
707 /* if (fFormatted)
708 { big mess }
709 else
710 */
711 RTPrintf("%ls\n", bstrStats.raw());
712 }
713
714 return RTEXITCODE_SUCCESS;
715}
716
717RTEXITCODE handleDebugVM(HandlerArg *pArgs)
718{
719 RTEXITCODE rcExit = RTEXITCODE_FAILURE;
720
721 /*
722 * The first argument is the VM name or UUID. Open a session to it.
723 */
724 if (pArgs->argc < 2)
725 return errorNoSubcommand();
726 ComPtr<IMachine> ptrMachine;
727 CHECK_ERROR2I_RET(pArgs->virtualBox, FindMachine(com::Bstr(pArgs->argv[0]).raw(), ptrMachine.asOutParam()), RTEXITCODE_FAILURE);
728 CHECK_ERROR2I_RET(ptrMachine, LockMachine(pArgs->session, LockType_Shared), RTEXITCODE_FAILURE);
729
730 /*
731 * Get the associated console and machine debugger.
732 */
733 HRESULT rc;
734 ComPtr<IConsole> ptrConsole;
735 CHECK_ERROR(pArgs->session, COMGETTER(Console)(ptrConsole.asOutParam()));
736 if (SUCCEEDED(rc))
737 {
738 if (ptrConsole.isNotNull())
739 {
740 ComPtr<IMachineDebugger> ptrDebugger;
741 CHECK_ERROR(ptrConsole, COMGETTER(Debugger)(ptrDebugger.asOutParam()));
742 if (SUCCEEDED(rc))
743 {
744 /*
745 * String switch on the sub-command.
746 */
747 const char *pszSubCmd = pArgs->argv[1];
748 if (!strcmp(pszSubCmd, "dumpvmcore"))
749 {
750 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_DUMPVMCORE);
751 rcExit = handleDebugVM_DumpVMCore(pArgs, ptrDebugger);
752 }
753 else if (!strcmp(pszSubCmd, "getregisters"))
754 {
755 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_GETREGISTERS);
756 rcExit = handleDebugVM_GetRegisters(pArgs, ptrDebugger);
757 }
758 else if (!strcmp(pszSubCmd, "info"))
759 {
760 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_INFO);
761 rcExit = handleDebugVM_Info(pArgs, ptrDebugger);
762 }
763 else if (!strcmp(pszSubCmd, "injectnmi"))
764 {
765 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_INJECTNMI);
766 rcExit = handleDebugVM_InjectNMI(pArgs, ptrDebugger);
767 }
768 else if (!strcmp(pszSubCmd, "log"))
769 {
770 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_LOG);
771 rcExit = handleDebugVM_LogXXXX(pArgs, ptrDebugger, pszSubCmd);
772 }
773 else if (!strcmp(pszSubCmd, "logdest"))
774 {
775 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_LOGDEST);
776 rcExit = handleDebugVM_LogXXXX(pArgs, ptrDebugger, pszSubCmd);
777 }
778 else if (!strcmp(pszSubCmd, "logflags"))
779 {
780 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_LOGFLAGS);
781 rcExit = handleDebugVM_LogXXXX(pArgs, ptrDebugger, pszSubCmd);
782 }
783 else if (!strcmp(pszSubCmd, "osdetect"))
784 {
785 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_OSDETECT);
786 rcExit = handleDebugVM_OSDetect(pArgs, ptrDebugger);
787 }
788 else if (!strcmp(pszSubCmd, "osinfo"))
789 {
790 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_OSINFO);
791 rcExit = handleDebugVM_OSInfo(pArgs, ptrDebugger);
792 }
793 else if (!strcmp(pszSubCmd, "osdmesg"))
794 {
795 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_OSDMESG);
796 rcExit = handleDebugVM_OSDmesg(pArgs, ptrDebugger);
797 }
798 else if (!strcmp(pszSubCmd, "setregisters"))
799 {
800 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_SETREGISTERS);
801 rcExit = handleDebugVM_SetRegisters(pArgs, ptrDebugger);
802 }
803 else if (!strcmp(pszSubCmd, "show"))
804 {
805 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_SHOW);
806 rcExit = handleDebugVM_Show(pArgs, ptrDebugger);
807 }
808 else if (!strcmp(pszSubCmd, "statistics"))
809 {
810 setCurrentSubcommand(HELP_SCOPE_DEBUGVM_STATISTICS);
811 rcExit = handleDebugVM_Statistics(pArgs, ptrDebugger);
812 }
813 else
814 errorUnknownSubcommand(pszSubCmd);
815 }
816 }
817 else
818 RTMsgError("Machine '%s' is not currently running.\n", pArgs->argv[0]);
819 }
820
821 pArgs->session->UnlockMachine();
822
823 return rcExit;
824}
825
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette