~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Frontends/VBoxManage/VBoxManageDebugVM.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: VBoxManageDebugVM.cpp 35550 2011-01-13 18:08:54Z 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
 */
 
52
static 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
 */
 
125
static 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
 */
 
145
static 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 inject sub-command.
 
155
 *
 
156
 * @returns Suitable exit code.
 
157
 * @param   pArgs               The handler arguments.
 
158
 * @param   pDebugger           Pointer to the debugger interface.
 
159
 */
 
160
static RTEXITCODE handleDebugVM_DumpVMCore(HandlerArg *pArgs, IMachineDebugger *pDebugger)
 
161
{
 
162
    /*
 
163
     * Parse arguments.
 
164
     */
 
165
    const char                 *pszFilename = NULL;
 
166
    const char                 *pszCompression = NULL;
 
167
 
 
168
    RTGETOPTSTATE               GetState;
 
169
    RTGETOPTUNION               ValueUnion;
 
170
    static const RTGETOPTDEF    s_aOptions[] =
 
171
    {
 
172
        { "--filename",     'f', RTGETOPT_REQ_STRING },
 
173
        { "--compression",  'c', RTGETOPT_REQ_STRING }
 
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 'c':
 
183
                if (pszCompression)
 
184
                    return errorSyntax(USAGE_DEBUGVM, "The --compression option has already been given");
 
185
                pszCompression = ValueUnion.psz;
 
186
                break;
 
187
            case 'f':
 
188
                if (pszFilename)
 
189
                    return errorSyntax(USAGE_DEBUGVM, "The --filename option has already been given");
 
190
                pszFilename = ValueUnion.psz;
 
191
                break;
 
192
            default:
 
193
                return errorGetOpt(USAGE_DEBUGVM, rc, &ValueUnion);
 
194
        }
 
195
    }
 
196
 
 
197
    if (!pszFilename)
 
198
        return errorSyntax(USAGE_DEBUGVM, "The --filename option is required");
 
199
 
 
200
    /*
 
201
     * Make the filename absolute before handing it on to the API.
 
202
     */
 
203
    char szAbsFilename[RTPATH_MAX];
 
204
    rc = RTPathAbs(pszFilename, szAbsFilename, sizeof(szAbsFilename));
 
205
    if (RT_FAILURE(rc))
 
206
        return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs failed on '%s': %Rrc", pszFilename, rc);
 
207
 
 
208
    com::Bstr bstrFilename(szAbsFilename);
 
209
    com::Bstr bstrCompression(pszCompression);
 
210
    CHECK_ERROR2_RET(pDebugger, DumpGuestCore(bstrFilename.raw(), bstrCompression.raw()), RTEXITCODE_FAILURE);
 
211
    return RTEXITCODE_SUCCESS;
 
212
}
 
213
 
 
214
/**
 
215
 * Handles the os sub-command.
 
216
 *
 
217
 * @returns Suitable exit code.
 
218
 * @param   a                   The handler arguments.
 
219
 * @param   pDebugger           Pointer to the debugger interface.
 
220
 */
 
221
static RTEXITCODE handleDebugVM_OSDetect(HandlerArg *a, IMachineDebugger *pDebugger)
 
222
{
 
223
    if (a->argc != 2)
 
224
        return errorSyntax(USAGE_DEBUGVM, "The osdetect sub-command does not take any arguments");
 
225
 
 
226
    com::Bstr bstrName;
 
227
    CHECK_ERROR2_RET(pDebugger, DetectOS(bstrName.asOutParam()), RTEXITCODE_FAILURE);
 
228
    RTPrintf("Detected: %ls\n", bstrName.raw());
 
229
    return RTEXITCODE_SUCCESS;
 
230
}
 
231
 
 
232
/**
 
233
 * Handles the os sub-command.
 
234
 *
 
235
 * @returns Suitable exit code.
 
236
 * @param   a                   The handler arguments.
 
237
 * @param   pDebugger           Pointer to the debugger interface.
 
238
 */
 
239
static RTEXITCODE handleDebugVM_OSInfo(HandlerArg *a, IMachineDebugger *pDebugger)
 
240
{
 
241
    if (a->argc != 2)
 
242
        return errorSyntax(USAGE_DEBUGVM, "The osinfo sub-command does not take any arguments");
 
243
 
 
244
    com::Bstr bstrName;
 
245
    CHECK_ERROR2_RET(pDebugger, COMGETTER(OSName)(bstrName.asOutParam()), RTEXITCODE_FAILURE);
 
246
    com::Bstr bstrVersion;
 
247
    CHECK_ERROR2_RET(pDebugger, COMGETTER(OSVersion)(bstrVersion.asOutParam()), RTEXITCODE_FAILURE);
 
248
    RTPrintf("Name:    %ls\n", bstrName.raw());
 
249
    RTPrintf("Version: %ls\n", bstrVersion.raw());
 
250
    return RTEXITCODE_SUCCESS;
 
251
}
 
252
 
 
253
/**
 
254
 * Handles the setregisters sub-command.
 
255
 *
 
256
 * @returns Suitable exit code.
 
257
 * @param   pArgs               The handler arguments.
 
258
 * @param   pDebugger           Pointer to the debugger interface.
 
259
 */
 
260
static RTEXITCODE handleDebugVM_SetRegisters(HandlerArg *pArgs, IMachineDebugger *pDebugger)
 
261
{
 
262
    /*
 
263
     * We take a list of register assignments, that is register=value.
 
264
     */
 
265
    ULONG                       idCpu = 0;
 
266
    com::SafeArray<IN_BSTR>     aBstrNames;
 
267
    com::SafeArray<IN_BSTR>     aBstrValues;
 
268
 
 
269
    RTGETOPTSTATE               GetState;
 
270
    RTGETOPTUNION               ValueUnion;
 
271
    static const RTGETOPTDEF    s_aOptions[] =
 
272
    {
 
273
        { "--cpu", 'c', RTGETOPT_REQ_UINT32 },
 
274
    };
 
275
    int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, RTGETOPTINIT_FLAGS_OPTS_FIRST);
 
276
    AssertRCReturn(rc, RTEXITCODE_FAILURE);
 
277
 
 
278
    while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
 
279
    {
 
280
        switch (rc)
 
281
        {
 
282
            case 'c':
 
283
                idCpu = ValueUnion.u32;
 
284
                break;
 
285
 
 
286
            case VINF_GETOPT_NOT_OPTION:
 
287
            {
 
288
                const char *pszEqual = strchr(ValueUnion.psz, '=');
 
289
                if (!pszEqual)
 
290
                    return errorSyntax(USAGE_DEBUGVM, "setregisters expects input on the form 'register=value' got '%s'", ValueUnion.psz);
 
291
                try
 
292
                {
 
293
                    com::Bstr bstrName(ValueUnion.psz, pszEqual - ValueUnion.psz);
 
294
                    com::Bstr bstrValue(pszEqual + 1);
 
295
                    if (   !aBstrNames.push_back(bstrName.raw())
 
296
                        || !aBstrValues.push_back(bstrValue.raw()))
 
297
                        throw std::bad_alloc();
 
298
                }
 
299
                catch (std::bad_alloc)
 
300
                {
 
301
                    RTMsgError("Out of memory\n");
 
302
                    return RTEXITCODE_FAILURE;
 
303
                }
 
304
                break;
 
305
            }
 
306
 
 
307
            default:
 
308
                return errorGetOpt(USAGE_DEBUGVM, rc, &ValueUnion);
 
309
        }
 
310
    }
 
311
 
 
312
    if (!aBstrNames.size())
 
313
        return errorSyntax(USAGE_DEBUGVM, "The setregisters sub-command takes at least one register name");
 
314
 
 
315
    /*
 
316
     * If it is only one register, use the single register method just so
 
317
     * we expose it and can test it from the command line.
 
318
     */
 
319
    if (aBstrNames.size() == 1)
 
320
    {
 
321
        CHECK_ERROR2_RET(pDebugger, SetRegister(idCpu, aBstrNames[0], aBstrValues[0]), RTEXITCODE_FAILURE);
 
322
        RTPrintf("Successfully set %ls\n", aBstrNames[0]);
 
323
    }
 
324
    else
 
325
    {
 
326
        CHECK_ERROR2_RET(pDebugger, SetRegisters(idCpu, ComSafeArrayAsInParam(aBstrNames), ComSafeArrayAsInParam(aBstrValues)), RTEXITCODE_FAILURE);
 
327
        RTPrintf("Successfully set %u registers\n", aBstrNames.size());
 
328
    }
 
329
 
 
330
    return RTEXITCODE_SUCCESS;
 
331
}
 
332
 
 
333
/**
 
334
 * Handles the statistics sub-command.
 
335
 *
 
336
 * @returns Suitable exit code.
 
337
 * @param   pArgs               The handler arguments.
 
338
 * @param   pDebugger           Pointer to the debugger interface.
 
339
 */
 
340
static RTEXITCODE handleDebugVM_Statistics(HandlerArg *pArgs, IMachineDebugger *pDebugger)
 
341
{
 
342
    /*
 
343
     * Parse arguments.
 
344
     */
 
345
    bool                        fWithDescriptions   = false;
 
346
    const char                 *pszPattern          = NULL; /* all */
 
347
    bool                        fReset              = false;
 
348
 
 
349
    RTGETOPTSTATE               GetState;
 
350
    RTGETOPTUNION               ValueUnion;
 
351
    static const RTGETOPTDEF    s_aOptions[] =
 
352
    {
 
353
        { "--descriptions", 'd', RTGETOPT_REQ_NOTHING },
 
354
        { "--pattern",      'p', RTGETOPT_REQ_STRING  },
 
355
        { "--reset",        'r', RTGETOPT_REQ_NOTHING  },
 
356
    };
 
357
    int rc = RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 2, 0 /*fFlags*/);
 
358
    AssertRCReturn(rc, RTEXITCODE_FAILURE);
 
359
 
 
360
    while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
 
361
    {
 
362
        switch (rc)
 
363
        {
 
364
            case 'd':
 
365
                fWithDescriptions = true;
 
366
                break;
 
367
 
 
368
            case 'p':
 
369
                if (pszPattern)
 
370
                    return errorSyntax(USAGE_DEBUGVM, "Multiple --pattern options are not permitted");
 
371
                pszPattern = ValueUnion.psz;
 
372
                break;
 
373
 
 
374
            case 'r':
 
375
                fReset = true;
 
376
                break;
 
377
 
 
378
            default:
 
379
                return errorGetOpt(USAGE_DEBUGVM, rc, &ValueUnion);
 
380
        }
 
381
    }
 
382
 
 
383
    if (fReset && fWithDescriptions)
 
384
        return errorSyntax(USAGE_DEBUGVM, "The --reset and --descriptions options does not mix");
 
385
 
 
386
    /*
 
387
     * Execute the order.
 
388
     */
 
389
    com::Bstr bstrPattern(pszPattern);
 
390
    if (fReset)
 
391
        CHECK_ERROR2_RET(pDebugger, ResetStats(bstrPattern.raw()), RTEXITCODE_FAILURE);
 
392
    else
 
393
    {
 
394
        com::Bstr bstrStats;
 
395
        CHECK_ERROR2_RET(pDebugger, GetStats(bstrPattern.raw(), fWithDescriptions, bstrStats.asOutParam()),
 
396
                         RTEXITCODE_FAILURE);
 
397
        /* if (fFormatted)
 
398
         { big mess }
 
399
         else
 
400
         */
 
401
        RTPrintf("%ls\n", bstrStats.raw());
 
402
    }
 
403
 
 
404
    return RTEXITCODE_SUCCESS;
 
405
}
 
406
 
 
407
int handleDebugVM(HandlerArg *pArgs)
 
408
{
 
409
    RTEXITCODE rcExit = RTEXITCODE_FAILURE;
 
410
 
 
411
    /*
 
412
     * The first argument is the VM name or UUID.  Open a session to it.
 
413
     */
 
414
    if (pArgs->argc < 2)
 
415
        return errorSyntax(USAGE_DEBUGVM, "Too few parameters");
 
416
    ComPtr<IMachine> ptrMachine;
 
417
    CHECK_ERROR2_RET(pArgs->virtualBox, FindMachine(com::Bstr(pArgs->argv[0]).raw(), ptrMachine.asOutParam()), RTEXITCODE_FAILURE);
 
418
    CHECK_ERROR2_RET(ptrMachine, LockMachine(pArgs->session, LockType_Shared), RTEXITCODE_FAILURE);
 
419
 
 
420
    /*
 
421
     * Get the associated console and machine debugger.
 
422
     */
 
423
    HRESULT rc;
 
424
    ComPtr<IConsole> ptrConsole;
 
425
    CHECK_ERROR(pArgs->session, COMGETTER(Console)(ptrConsole.asOutParam()));
 
426
    if (SUCCEEDED(rc))
 
427
    {
 
428
        ComPtr<IMachineDebugger> ptrDebugger;
 
429
        CHECK_ERROR(ptrConsole, COMGETTER(Debugger)(ptrDebugger.asOutParam()));
 
430
        if (SUCCEEDED(rc))
 
431
        {
 
432
            /*
 
433
             * String switch on the sub-command.
 
434
             */
 
435
            const char *pszSubCmd = pArgs->argv[1];
 
436
            if (!strcmp(pszSubCmd, "dumpguestcore"))
 
437
                rcExit = handleDebugVM_DumpVMCore(pArgs, ptrDebugger);
 
438
            else if (!strcmp(pszSubCmd, "getregisters"))
 
439
                rcExit = handleDebugVM_GetRegisters(pArgs, ptrDebugger);
 
440
            else if (!strcmp(pszSubCmd, "info"))
 
441
                rcExit = handleDebugVM_Info(pArgs, ptrDebugger);
 
442
            else if (!strcmp(pszSubCmd, "injectnmi"))
 
443
                rcExit = handleDebugVM_InjectNMI(pArgs, ptrDebugger);
 
444
            else if (!strcmp(pszSubCmd, "osdetect"))
 
445
                rcExit = handleDebugVM_OSDetect(pArgs, ptrDebugger);
 
446
            else if (!strcmp(pszSubCmd, "osinfo"))
 
447
                rcExit = handleDebugVM_OSInfo(pArgs, ptrDebugger);
 
448
            else if (!strcmp(pszSubCmd, "setregisters"))
 
449
                rcExit = handleDebugVM_SetRegisters(pArgs, ptrDebugger);
 
450
            else if (!strcmp(pszSubCmd, "statistics"))
 
451
                rcExit = handleDebugVM_Statistics(pArgs, ptrDebugger);
 
452
            else
 
453
                errorSyntax(USAGE_DEBUGVM, "Invalid parameter '%s'", pArgs->argv[1]);
 
454
        }
 
455
    }
 
456
 
 
457
    pArgs->session->UnlockMachine();
 
458
 
 
459
    return rcExit;
 
460
}
 
461