VirtualBox

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

Last change on this file since 46658 was 46658, checked in by vboxsync, 11 years ago

include VBox/com/EventQueue only if necessary

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

© 2023 Oracle
ContactPrivacy policyTerms of Use