VirtualBox

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

Last change on this file since 39675 was 39675, checked in by vboxsync, 12 years ago

VBoxManage debugvm show improvemnts.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use