VirtualBox

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

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

VBoxManage debugvm osdetect: Load all plug-ins first.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.9 KB
Line 
1/* $Id: VBoxManageDebugVM.cpp 55884 2015-05-16 01:25:08Z 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_ERROR2_RET(pDebugger, GetRegisters(idCpu, ComSafeArrayAsOutParam(aBstrNames), ComSafeArrayAsOutParam(aBstrValues)),
82 RTEXITCODE_FAILURE);
83 Assert(aBstrNames.size() == aBstrValues.size());
84
85 size_t cchMaxName = 8;
86 for (size_t i = 0; i < aBstrNames.size(); i++)
87 {
88 size_t cchName = RTUtf16Len(aBstrNames[i]);
89 if (cchName > cchMaxName)
90 cchMaxName = cchName;
91 }
92
93 for (size_t i = 0; i < aBstrNames.size(); i++)
94 RTPrintf("%-*ls = %ls\n", cchMaxName, aBstrNames[i], aBstrValues[i]);
95 }
96 else
97 {
98 com::Bstr bstrName = ValueUnion.psz;
99 com::Bstr bstrValue;
100 CHECK_ERROR2_RET(pDebugger, GetRegister(idCpu, bstrName.raw(), bstrValue.asOutParam()), RTEXITCODE_FAILURE);
101 RTPrintf("%s = %ls\n", ValueUnion.psz, bstrValue.raw());
102 }
103 cRegisters++;
104 break;
105
106 default:
107 return errorGetOpt(USAGE_DEBUGVM, rc, &ValueUnion);
108 }
109 }
110
111 if (!cRegisters)
112 return errorSyntax(USAGE_DEBUGVM, "The getregisters sub-command takes at least one register name");
113 return RTEXITCODE_SUCCESS;
114}
115
116/**
117 * Handles the info sub-command.
118 *
119 * @returns Suitable exit code.
120 * @param a The handler arguments.
121 * @param pDebugger Pointer to the debugger interface.
122 */
123static RTEXITCODE handleDebugVM_Info(HandlerArg *a, IMachineDebugger *pDebugger)
124{
125 if (a->argc < 3 || a->argc > 4)
126 return errorSyntax(USAGE_DEBUGVM, "The inject sub-command takes at one or two arguments");
127
128 com::Bstr bstrName(a->argv[2]);
129 com::Bstr bstrArgs(a->argv[3]);
130 com::Bstr bstrInfo;
131 CHECK_ERROR2_RET(pDebugger, Info(bstrName.raw(), bstrArgs.raw(), bstrInfo.asOutParam()), RTEXITCODE_FAILURE);
132 RTPrintf("%ls", bstrInfo.raw());
133 return RTEXITCODE_SUCCESS;
134}
135
136/**
137 * Handles the inject sub-command.
138 *
139 * @returns Suitable exit code.
140 * @param a The handler arguments.
141 * @param pDebugger Pointer to the debugger interface.
142 */
143static RTEXITCODE handleDebugVM_InjectNMI(HandlerArg *a, IMachineDebugger *pDebugger)
144{
145 if (a->argc != 2)
146 return errorSyntax(USAGE_DEBUGVM, "The inject sub-command does not take any arguments");
147 CHECK_ERROR2_RET(pDebugger, InjectNMI(), RTEXITCODE_FAILURE);
148 return RTEXITCODE_SUCCESS;
149}
150
151/**
152 * Handles the log sub-command.
153 *
154 * @returns Suitable exit code.
155 * @param pArgs The handler arguments.
156 * @param pDebugger Pointer to the debugger interface.
157 * @param pszSubCmd The sub command.
158 */
159static RTEXITCODE handleDebugVM_LogXXXX(HandlerArg *pArgs, IMachineDebugger *pDebugger, const char *pszSubCmd)
160{
161 /*
162 * Parse arguments.
163 */
164 bool fRelease = false;
165 com::Utf8Str strSettings;
166
167 RTGETOPTSTATE GetState;
168 RTGETOPTUNION ValueUnion;
169
170 /*
171 * NB: don't use short options to prevent log specifications like
172 * "-drv_foo" from being interpreted as options.
173 */
174# define DEBUGVM_LOG_DEBUG (VINF_GETOPT_NOT_OPTION + 'd')
175# define DEBUGVM_LOG_RELEASE (VINF_GETOPT_NOT_OPTION + 'r')
176
177 static const RTGETOPTDEF s_aOptions[] =
178 {
179 { "--debug", DEBUGVM_LOG_DEBUG, RTGETOPT_REQ_NOTHING },
180 { "--release", DEBUGVM_LOG_RELEASE, RTGETOPT_REQ_NOTHING }
181 };
182 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
183 AssertRCReturn(rc, RTEXITCODE_FAILURE);
184
185 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
186 {
187 switch (rc)
188 {
189 case DEBUGVM_LOG_RELEASE:
190 fRelease = true;
191 break;
192
193 case DEBUGVM_LOG_DEBUG:
194 fRelease = false;
195 break;
196
197 /* Because log strings can start with "-" (like "-all+dev_foo")
198 * we have to take everything we got as a setting and apply it.
199 * IPRT will take care of the validation afterwards. */
200 default:
201 if (strSettings.length() == 0)
202 strSettings = ValueUnion.psz;
203 else
204 {
205 strSettings.append(' ');
206 strSettings.append(ValueUnion.psz);
207 }
208 break;
209 }
210 }
211
212 if (fRelease)
213 {
214 com::Utf8Str strTmp(strSettings);
215 strSettings = "release: ";
216 strSettings.append(strTmp);
217 }
218
219 com::Bstr bstrSettings(strSettings);
220 if (!strcmp(pszSubCmd, "log"))
221 CHECK_ERROR2_RET(pDebugger, ModifyLogGroups(bstrSettings.raw()), RTEXITCODE_FAILURE);
222 else if (!strcmp(pszSubCmd, "logdest"))
223 CHECK_ERROR2_RET(pDebugger, ModifyLogDestinations(bstrSettings.raw()), RTEXITCODE_FAILURE);
224 else if (!strcmp(pszSubCmd, "logflags"))
225 CHECK_ERROR2_RET(pDebugger, ModifyLogFlags(bstrSettings.raw()), RTEXITCODE_FAILURE);
226 else
227 AssertFailedReturn(RTEXITCODE_FAILURE);
228
229 return RTEXITCODE_SUCCESS;
230}
231
232
233/**
234 * Handles the inject sub-command.
235 *
236 * @returns Suitable exit code.
237 * @param pArgs The handler arguments.
238 * @param pDebugger Pointer to the debugger interface.
239 */
240static RTEXITCODE handleDebugVM_DumpVMCore(HandlerArg *pArgs, IMachineDebugger *pDebugger)
241{
242 /*
243 * Parse arguments.
244 */
245 const char *pszFilename = NULL;
246 const char *pszCompression = NULL;
247
248 RTGETOPTSTATE GetState;
249 RTGETOPTUNION ValueUnion;
250 static const RTGETOPTDEF s_aOptions[] =
251 {
252 { "--filename", 'f', RTGETOPT_REQ_STRING },
253 { "--compression", 'c', RTGETOPT_REQ_STRING }
254 };
255 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, 0 /*fFlags*/);
256 AssertRCReturn(rc, RTEXITCODE_FAILURE);
257
258 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
259 {
260 switch (rc)
261 {
262 case 'c':
263 if (pszCompression)
264 return errorSyntax(USAGE_DEBUGVM, "The --compression option has already been given");
265 pszCompression = ValueUnion.psz;
266 break;
267 case 'f':
268 if (pszFilename)
269 return errorSyntax(USAGE_DEBUGVM, "The --filename option has already been given");
270 pszFilename = ValueUnion.psz;
271 break;
272 default:
273 return errorGetOpt(USAGE_DEBUGVM, rc, &ValueUnion);
274 }
275 }
276
277 if (!pszFilename)
278 return errorSyntax(USAGE_DEBUGVM, "The --filename option is required");
279
280 /*
281 * Make the filename absolute before handing it on to the API.
282 */
283 char szAbsFilename[RTPATH_MAX];
284 rc = RTPathAbs(pszFilename, szAbsFilename, sizeof(szAbsFilename));
285 if (RT_FAILURE(rc))
286 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs failed on '%s': %Rrc", pszFilename, rc);
287
288 com::Bstr bstrFilename(szAbsFilename);
289 com::Bstr bstrCompression(pszCompression);
290 CHECK_ERROR2_RET(pDebugger, DumpGuestCore(bstrFilename.raw(), bstrCompression.raw()), RTEXITCODE_FAILURE);
291 return RTEXITCODE_SUCCESS;
292}
293
294/**
295 * Handles the os sub-command.
296 *
297 * @returns Suitable exit code.
298 * @param a The handler arguments.
299 * @param pDebugger Pointer to the debugger interface.
300 */
301static RTEXITCODE handleDebugVM_OSDetect(HandlerArg *a, IMachineDebugger *pDebugger)
302{
303 if (a->argc != 2)
304 return errorSyntax(USAGE_DEBUGVM, "The osdetect sub-command does not take any arguments");
305
306 com::Bstr bstrIgnore;
307 com::Bstr bstrAll("all");
308 CHECK_ERROR2_RET(pDebugger, LoadPlugIn(bstrAll.raw(), bstrIgnore.asOutParam()), RTEXITCODE_FAILURE);
309
310 com::Bstr bstrName;
311 CHECK_ERROR2_RET(pDebugger, DetectOS(bstrName.asOutParam()), RTEXITCODE_FAILURE);
312 RTPrintf("Detected: %ls\n", bstrName.raw());
313 return RTEXITCODE_SUCCESS;
314}
315
316/**
317 * Handles the os sub-command.
318 *
319 * @returns Suitable exit code.
320 * @param a The handler arguments.
321 * @param pDebugger Pointer to the debugger interface.
322 */
323static RTEXITCODE handleDebugVM_OSInfo(HandlerArg *a, IMachineDebugger *pDebugger)
324{
325 if (a->argc != 2)
326 return errorSyntax(USAGE_DEBUGVM, "The osinfo sub-command does not take any arguments");
327
328 com::Bstr bstrName;
329 CHECK_ERROR2_RET(pDebugger, COMGETTER(OSName)(bstrName.asOutParam()), RTEXITCODE_FAILURE);
330 com::Bstr bstrVersion;
331 CHECK_ERROR2_RET(pDebugger, COMGETTER(OSVersion)(bstrVersion.asOutParam()), RTEXITCODE_FAILURE);
332 RTPrintf("Name: %ls\n", bstrName.raw());
333 RTPrintf("Version: %ls\n", bstrVersion.raw());
334 return RTEXITCODE_SUCCESS;
335}
336
337/**
338 * Handles the setregisters sub-command.
339 *
340 * @returns Suitable exit code.
341 * @param pArgs The handler arguments.
342 * @param pDebugger Pointer to the debugger interface.
343 */
344static RTEXITCODE handleDebugVM_SetRegisters(HandlerArg *pArgs, IMachineDebugger *pDebugger)
345{
346 /*
347 * We take a list of register assignments, that is register=value.
348 */
349 ULONG idCpu = 0;
350 com::SafeArray<IN_BSTR> aBstrNames;
351 com::SafeArray<IN_BSTR> aBstrValues;
352
353 RTGETOPTSTATE GetState;
354 RTGETOPTUNION ValueUnion;
355 static const RTGETOPTDEF s_aOptions[] =
356 {
357 { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
358 };
359 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
360 AssertRCReturn(rc, RTEXITCODE_FAILURE);
361
362 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
363 {
364 switch (rc)
365 {
366 case 'c':
367 idCpu = ValueUnion.u32;
368 break;
369
370 case VINF_GETOPT_NOT_OPTION:
371 {
372 const char *pszEqual = strchr(ValueUnion.psz, '=');
373 if (!pszEqual)
374 return errorSyntax(USAGE_DEBUGVM, "setregisters expects input on the form 'register=value' got '%s'", ValueUnion.psz);
375 try
376 {
377 com::Bstr bstrName(ValueUnion.psz, pszEqual - ValueUnion.psz);
378 com::Bstr bstrValue(pszEqual + 1);
379 if ( !aBstrNames.push_back(bstrName.raw())
380 || !aBstrValues.push_back(bstrValue.raw()))
381 throw std::bad_alloc();
382 }
383 catch (std::bad_alloc)
384 {
385 RTMsgError("Out of memory\n");
386 return RTEXITCODE_FAILURE;
387 }
388 break;
389 }
390
391 default:
392 return errorGetOpt(USAGE_DEBUGVM, rc, &ValueUnion);
393 }
394 }
395
396 if (!aBstrNames.size())
397 return errorSyntax(USAGE_DEBUGVM, "The setregisters sub-command takes at least one register name");
398
399 /*
400 * If it is only one register, use the single register method just so
401 * we expose it and can test it from the command line.
402 */
403 if (aBstrNames.size() == 1)
404 {
405 CHECK_ERROR2_RET(pDebugger, SetRegister(idCpu, aBstrNames[0], aBstrValues[0]), RTEXITCODE_FAILURE);
406 RTPrintf("Successfully set %ls\n", aBstrNames[0]);
407 }
408 else
409 {
410 CHECK_ERROR2_RET(pDebugger, SetRegisters(idCpu, ComSafeArrayAsInParam(aBstrNames), ComSafeArrayAsInParam(aBstrValues)), RTEXITCODE_FAILURE);
411 RTPrintf("Successfully set %u registers\n", aBstrNames.size());
412 }
413
414 return RTEXITCODE_SUCCESS;
415}
416
417/** @name debugvm show flags
418 * @{ */
419#define DEBUGVM_SHOW_FLAGS_HUMAN_READABLE UINT32_C(0x00000000)
420#define DEBUGVM_SHOW_FLAGS_SH_EXPORT UINT32_C(0x00000001)
421#define DEBUGVM_SHOW_FLAGS_SH_EVAL UINT32_C(0x00000002)
422#define DEBUGVM_SHOW_FLAGS_CMD_SET UINT32_C(0x00000003)
423#define DEBUGVM_SHOW_FLAGS_FMT_MASK UINT32_C(0x00000003)
424/** @} */
425
426/**
427 * Prints a variable according to the @a fFlags.
428 *
429 * @param pszVar The variable name.
430 * @param pbstrValue The variable value.
431 * @param fFlags The debugvm show flags.
432 */
433static void handleDebugVM_Show_PrintVar(const char *pszVar, com::Bstr const *pbstrValue, uint32_t fFlags)
434{
435 switch (fFlags & DEBUGVM_SHOW_FLAGS_FMT_MASK)
436 {
437 case DEBUGVM_SHOW_FLAGS_HUMAN_READABLE: RTPrintf(" %27s=%ls\n", pszVar, pbstrValue->raw()); break;
438 case DEBUGVM_SHOW_FLAGS_SH_EXPORT: RTPrintf("export %s='%ls'\n", pszVar, pbstrValue->raw()); break;
439 case DEBUGVM_SHOW_FLAGS_SH_EVAL: RTPrintf("%s='%ls'\n", pszVar, pbstrValue->raw()); break;
440 case DEBUGVM_SHOW_FLAGS_CMD_SET: RTPrintf("set %s=%ls\n", pszVar, pbstrValue->raw()); break;
441 default: AssertFailed();
442 }
443}
444
445/**
446 * Handles logdbg-settings.
447 *
448 * @returns Exit code.
449 * @param pDebugger The debugger interface.
450 * @param fFlags The debugvm show flags.
451 */
452static RTEXITCODE handleDebugVM_Show_LogDbgSettings(IMachineDebugger *pDebugger, uint32_t fFlags)
453{
454 if ((fFlags & DEBUGVM_SHOW_FLAGS_FMT_MASK) == DEBUGVM_SHOW_FLAGS_HUMAN_READABLE)
455 RTPrintf("Debug logger settings:\n");
456
457 com::Bstr bstr;
458 CHECK_ERROR2_RET(pDebugger, COMGETTER(LogDbgFlags)(bstr.asOutParam()), RTEXITCODE_FAILURE);
459 handleDebugVM_Show_PrintVar("VBOX_LOG", &bstr, fFlags);
460
461 CHECK_ERROR2_RET(pDebugger, COMGETTER(LogDbgGroups)(bstr.asOutParam()), RTEXITCODE_FAILURE);
462 handleDebugVM_Show_PrintVar("VBOX_LOG_FLAGS", &bstr, fFlags);
463
464 CHECK_ERROR2_RET(pDebugger, COMGETTER(LogDbgDestinations)(bstr.asOutParam()), RTEXITCODE_FAILURE);
465 handleDebugVM_Show_PrintVar("VBOX_LOG_DEST", &bstr, fFlags);
466 return RTEXITCODE_SUCCESS;
467}
468
469/**
470 * Handles logrel-settings.
471 *
472 * @returns Exit code.
473 * @param pDebugger The debugger interface.
474 * @param fFlags The debugvm show flags.
475 */
476static RTEXITCODE handleDebugVM_Show_LogRelSettings(IMachineDebugger *pDebugger, uint32_t fFlags)
477{
478 if ((fFlags & DEBUGVM_SHOW_FLAGS_FMT_MASK) == DEBUGVM_SHOW_FLAGS_HUMAN_READABLE)
479 RTPrintf("Release logger settings:\n");
480
481 com::Bstr bstr;
482 CHECK_ERROR2_RET(pDebugger, COMGETTER(LogRelFlags)(bstr.asOutParam()), RTEXITCODE_FAILURE);
483 handleDebugVM_Show_PrintVar("VBOX_RELEASE_LOG", &bstr, fFlags);
484
485 CHECK_ERROR2_RET(pDebugger, COMGETTER(LogRelGroups)(bstr.asOutParam()), RTEXITCODE_FAILURE);
486 handleDebugVM_Show_PrintVar("VBOX_RELEASE_LOG_FLAGS", &bstr, fFlags);
487
488 CHECK_ERROR2_RET(pDebugger, COMGETTER(LogRelDestinations)(bstr.asOutParam()), RTEXITCODE_FAILURE);
489 handleDebugVM_Show_PrintVar("VBOX_RELEASE_LOG_DEST", &bstr, fFlags);
490 return RTEXITCODE_SUCCESS;
491}
492
493/**
494 * Handles the show sub-command.
495 *
496 * @returns Suitable exit code.
497 * @param pArgs The handler arguments.
498 * @param pDebugger Pointer to the debugger interface.
499 */
500static RTEXITCODE handleDebugVM_Show(HandlerArg *pArgs, IMachineDebugger *pDebugger)
501{
502 /*
503 * Parse arguments and what to show. Order dependent.
504 */
505 uint32_t fFlags = DEBUGVM_SHOW_FLAGS_HUMAN_READABLE;
506
507 RTGETOPTSTATE GetState;
508 RTGETOPTUNION ValueUnion;
509 static const RTGETOPTDEF s_aOptions[] =
510 {
511 { "--human-readable", 'H', RTGETOPT_REQ_NOTHING },
512 { "--sh-export", 'e', RTGETOPT_REQ_NOTHING },
513 { "--sh-eval", 'E', RTGETOPT_REQ_NOTHING },
514 { "--cmd-set", 's', RTGETOPT_REQ_NOTHING },
515 };
516 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, 0 /*fFlags*/);
517 AssertRCReturn(rc, RTEXITCODE_FAILURE);
518
519 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
520 {
521 switch (rc)
522 {
523 case 'H':
524 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_HUMAN_READABLE;
525 break;
526
527 case 'e':
528 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_SH_EXPORT;
529 break;
530
531 case 'E':
532 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_SH_EVAL;
533 break;
534
535 case 's':
536 fFlags = (fFlags & ~DEBUGVM_SHOW_FLAGS_FMT_MASK) | DEBUGVM_SHOW_FLAGS_CMD_SET;
537 break;
538
539 case VINF_GETOPT_NOT_OPTION:
540 {
541 RTEXITCODE rcExit;
542 if (!strcmp(ValueUnion.psz, "log-settings"))
543 {
544 rcExit = handleDebugVM_Show_LogDbgSettings(pDebugger, fFlags);
545 if (rcExit == RTEXITCODE_SUCCESS)
546 rcExit = handleDebugVM_Show_LogRelSettings(pDebugger, fFlags);
547 }
548 else if (!strcmp(ValueUnion.psz, "logdbg-settings"))
549 rcExit = handleDebugVM_Show_LogDbgSettings(pDebugger, fFlags);
550 else if (!strcmp(ValueUnion.psz, "logrel-settings"))
551 rcExit = handleDebugVM_Show_LogRelSettings(pDebugger, fFlags);
552 else
553 rcExit = errorSyntax(USAGE_DEBUGVM, "The show sub-command has no idea what '%s' might be", ValueUnion.psz);
554 if (rcExit != RTEXITCODE_SUCCESS)
555 return rcExit;
556 break;
557 }
558
559 default:
560 return errorGetOpt(USAGE_DEBUGVM, rc, &ValueUnion);
561 }
562 }
563 return RTEXITCODE_SUCCESS;
564}
565
566/**
567 * Handles the statistics sub-command.
568 *
569 * @returns Suitable exit code.
570 * @param pArgs The handler arguments.
571 * @param pDebugger Pointer to the debugger interface.
572 */
573static RTEXITCODE handleDebugVM_Statistics(HandlerArg *pArgs, IMachineDebugger *pDebugger)
574{
575 /*
576 * Parse arguments.
577 */
578 bool fWithDescriptions = false;
579 const char *pszPattern = NULL; /* all */
580 bool fReset = false;
581
582 RTGETOPTSTATE GetState;
583 RTGETOPTUNION ValueUnion;
584 static const RTGETOPTDEF s_aOptions[] =
585 {
586 { "--descriptions", 'd', RTGETOPT_REQ_NOTHING },
587 { "--pattern", 'p', RTGETOPT_REQ_STRING },
588 { "--reset", 'r', RTGETOPT_REQ_NOTHING },
589 };
590 int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, 0 /*fFlags*/);
591 AssertRCReturn(rc, RTEXITCODE_FAILURE);
592
593 while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
594 {
595 switch (rc)
596 {
597 case 'd':
598 fWithDescriptions = true;
599 break;
600
601 case 'p':
602 if (pszPattern)
603 return errorSyntax(USAGE_DEBUGVM, "Multiple --pattern options are not permitted");
604 pszPattern = ValueUnion.psz;
605 break;
606
607 case 'r':
608 fReset = true;
609 break;
610
611 default:
612 return errorGetOpt(USAGE_DEBUGVM, rc, &ValueUnion);
613 }
614 }
615
616 if (fReset && fWithDescriptions)
617 return errorSyntax(USAGE_DEBUGVM, "The --reset and --descriptions options does not mix");
618
619 /*
620 * Execute the order.
621 */
622 com::Bstr bstrPattern(pszPattern);
623 if (fReset)
624 CHECK_ERROR2_RET(pDebugger, ResetStats(bstrPattern.raw()), RTEXITCODE_FAILURE);
625 else
626 {
627 com::Bstr bstrStats;
628 CHECK_ERROR2_RET(pDebugger, GetStats(bstrPattern.raw(), fWithDescriptions, bstrStats.asOutParam()),
629 RTEXITCODE_FAILURE);
630 /* if (fFormatted)
631 { big mess }
632 else
633 */
634 RTPrintf("%ls\n", bstrStats.raw());
635 }
636
637 return RTEXITCODE_SUCCESS;
638}
639
640int handleDebugVM(HandlerArg *pArgs)
641{
642 RTEXITCODE rcExit = RTEXITCODE_FAILURE;
643
644 /*
645 * The first argument is the VM name or UUID. Open a session to it.
646 */
647 if (pArgs->argc < 2)
648 return errorSyntax(USAGE_DEBUGVM, "Too few parameters");
649 ComPtr<IMachine> ptrMachine;
650 CHECK_ERROR2_RET(pArgs->virtualBox, FindMachine(com::Bstr(pArgs->argv[0]).raw(), ptrMachine.asOutParam()), RTEXITCODE_FAILURE);
651 CHECK_ERROR2_RET(ptrMachine, LockMachine(pArgs->session, LockType_Shared), RTEXITCODE_FAILURE);
652
653 /*
654 * Get the associated console and machine debugger.
655 */
656 HRESULT rc;
657 ComPtr<IConsole> ptrConsole;
658 CHECK_ERROR(pArgs->session, COMGETTER(Console)(ptrConsole.asOutParam()));
659 if (SUCCEEDED(rc))
660 {
661 ComPtr<IMachineDebugger> ptrDebugger;
662 CHECK_ERROR(ptrConsole, COMGETTER(Debugger)(ptrDebugger.asOutParam()));
663 if (SUCCEEDED(rc))
664 {
665 /*
666 * String switch on the sub-command.
667 */
668 const char *pszSubCmd = pArgs->argv[1];
669 if (!strcmp(pszSubCmd, "dumpguestcore"))
670 rcExit = handleDebugVM_DumpVMCore(pArgs, ptrDebugger);
671 else if (!strcmp(pszSubCmd, "getregisters"))
672 rcExit = handleDebugVM_GetRegisters(pArgs, ptrDebugger);
673 else if (!strcmp(pszSubCmd, "info"))
674 rcExit = handleDebugVM_Info(pArgs, ptrDebugger);
675 else if (!strcmp(pszSubCmd, "injectnmi"))
676 rcExit = handleDebugVM_InjectNMI(pArgs, ptrDebugger);
677 else if (!strcmp(pszSubCmd, "log"))
678 rcExit = handleDebugVM_LogXXXX(pArgs, ptrDebugger, pszSubCmd);
679 else if (!strcmp(pszSubCmd, "logdest"))
680 rcExit = handleDebugVM_LogXXXX(pArgs, ptrDebugger, pszSubCmd);
681 else if (!strcmp(pszSubCmd, "logflags"))
682 rcExit = handleDebugVM_LogXXXX(pArgs, ptrDebugger, pszSubCmd);
683 else if (!strcmp(pszSubCmd, "osdetect"))
684 rcExit = handleDebugVM_OSDetect(pArgs, ptrDebugger);
685 else if (!strcmp(pszSubCmd, "osinfo"))
686 rcExit = handleDebugVM_OSInfo(pArgs, ptrDebugger);
687 else if (!strcmp(pszSubCmd, "setregisters"))
688 rcExit = handleDebugVM_SetRegisters(pArgs, ptrDebugger);
689 else if (!strcmp(pszSubCmd, "show"))
690 rcExit = handleDebugVM_Show(pArgs, ptrDebugger);
691 else if (!strcmp(pszSubCmd, "statistics"))
692 rcExit = handleDebugVM_Statistics(pArgs, ptrDebugger);
693 else
694 errorSyntax(USAGE_DEBUGVM, "Invalid parameter '%s'", pArgs->argv[1]);
695 }
696 }
697
698 pArgs->session->UnlockMachine();
699
700 return rcExit;
701}
702
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