VirtualBox

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

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

VBoxManage/DebugVM: Fixed "--debug" parameter, fixed parameter settings for log, logdest and logflags.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use