VirtualBox

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

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

Don't use ISession::COMGETTER(Console) return without checking for NULL. Will crash if VM isn't running.

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