DBGConsole.cpp revision 3009d189e498dc1af8c7024cd02d358aa3e60bd9
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk/* $Id$ */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk/** @file
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * DBGC - Debugger Console.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk/*
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Copyright (C) 2006-2011 Oracle Corporation
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * This file is part of VirtualBox Open Source Edition (OSE), as
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * available from http://www.virtualbox.org. This file is free software;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * you can redistribute it and/or modify it under the terms of the GNU
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * General Public License (GPL) as published by the Free Software
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Foundation, in version 2 as it comes in the "COPYING" file of the
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk/** @page pg_dbgc DBGC - The Debug Console
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * The debugger console is an early attempt to make some interactive
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * debugging facilities for the VirtualBox VMM. It was initially only
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * accessible thru a telnet session in debug builds. Later it was hastily built
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * into the VBoxDbg module with a very simple Qt wrapper around it.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * The current state is that it's by default shipped with all standard
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * VirtualBox builds. The GUI component is by default accessible in all
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * non-release builds, while release builds require extra data, environment or
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * command line options to make it visible.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Now, even if we ship it with all standard builds we would like it to remain
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * an optional feature that can be omitted when building VirtualBox. Therefore,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * all external code interfacing DBGC need to be enclosed in
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * \#ifdef VBOX_WITH_DEBUGGER blocks. This is mandatory for components that
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * register external commands.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @section sec_dbgc_op Operation
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * The console will process commands in a manner similar to the OS/2 and Windows
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * kernel debuggers. This means ';' is a command separator and that when
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * possible we'll use the same command names as these two uses. As an
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * alternative we intent to provide a set of gdb-like commands as well and let
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * the user decide which should take precedence.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @subsection sec_dbg_op_numbers Numbers
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Numbers are hexadecimal unless specified with a prefix indicating
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * elsewise. Prefixes:
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * - '0x' - hexadecimal.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * - '0n' - decimal
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * - '0t' - octal.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * - '0y' - binary.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Some of the prefixes are a bit uncommon, the reason for this that the
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * typical binary prefix '0b' can also be a hexadecimal value since no prefix or
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * suffix is required for such values. Ditto for '0n' and '0' for decimal and
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * octal.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * The '`' can be used in the numeric value to separate parts as the user
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * wishes. Generally, though the debugger may use it in output as thousand
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * separator in decimal numbers and 32-bit separator in hex numbers.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * For historical reasons, a 'h' suffix is suffered on hex numbers. Unlike most
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * assemblers, a leading 0 before a-f is not required with the 'h' suffix.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * The prefix '0i' can be used instead of '0n', as it was the early decimal
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * prefix employed by DBGC. It's being deprecated and may be removed later.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @subsection sec_dbg_op_strings Strings and Symbols
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * The debugger will try to guess, convert or promote what the type of an
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * argument to a command, function or operator based on the input description of
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * the receiver. If the user wants to make it clear to the debugger that
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * something is a string, put it inside double quotes. Symbols should use
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * single quotes, though we're current still a bit flexible on this point.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * If you need to put a quote character inside the quoted text, you escape it by
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * repating it once: echo "printf(""hello world"");"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @subsection sec_dbg_op_address Addressing modes
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * - Default is flat. For compatibility '%' also means flat.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * - Segmented addresses are specified selector:offset.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * - Physical addresses are specified using '%%'.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * - The default target for the addressing is the guest context, the '#'
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * will override this and set it to the host.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Note that several operations won't work on host addresses.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * The '%', '%%' and '#' prefixes is implemented as unary operators, while ':'
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * is a binary operator. Operator precedence takes care of evaluation order.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @subsection sec_dbg_op_c_operators C/C++ Operators
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Most unary and binary arithmetic, comparison, logical and bitwise C/C++
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * operators are supported by the debugger, with the same precedence rules of
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * course. There is one notable change made due to the unary '%' and '%%'
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * operators, and that is that the modulo (remainder) operator is called 'mod'
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * instead of '%'. This saves a lot of trouble separating argument.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * There are no assignment operators. Instead some simple global variable space
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * is provided thru the 'set' and 'unset' commands and the unary '$' operator.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @subsection sec_dbg_op_registers Registers
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * All registers and their sub-fields exposed by the DBGF API are accessible via
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * the '\@' operator. A few CPU register are accessible directly (as symbols)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * without using the '\@' operator. Hypervisor registers are accessible by
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * prefixing the register name with a dot ('.').
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @subsection sec_dbg_op_commands Commands
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Commands names are case sensitive. By convention they are lower cased, starts
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * with a letter but may contain digits and underscores afterwards. Operators
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * are not allowed in the name (not even part of it), as we would risk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * misunderstanding it otherwise.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Commands returns a status code.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * The '.' prefix indicates the set of external commands. External commands are
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * command registered by VMM components.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @subsection sec_dbg_op_functions Functions
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Functions are similar to commands, but return a variable and can only be used
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * as part of an expression making up the argument of a command, function,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * operator or language statement (if we get around to implement that).
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @section sec_dbgc_logging Logging
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * The idea is to be able to pass thru debug and release logs to the console
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * if the user so wishes. This feature requires some kind of hook into the
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * logger instance and while this was sketched it hasn't yet been implemented
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * (dbgcProcessLog and DBGC::fLog).
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * This feature has not materialized and probably never will.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @section sec_dbgc_linking Linking and API
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * The DBGC code is linked into the VBoxVMM module.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * IMachineDebugger may one day be extended with a DBGC interface so we can work
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * with DBGC remotely without requiring TCP. Some questions about callbacks
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * (for output) and security (you may wish to restrict users from debugging a
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * VM) needs to be answered first though.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk/*******************************************************************************
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk* Header Files *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk*******************************************************************************/
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#define LOG_GROUP LOG_GROUP_DBGC
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include <VBox/dbg.h>
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include <VBox/vmm/dbgf.h>
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include <VBox/err.h>
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include <VBox/log.h>
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include <iprt/asm.h>
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include <iprt/assert.h>
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include <iprt/mem.h>
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include <iprt/string.h>
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include "DBGCInternal.h"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk#include "DBGPlugIns.h"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk/*******************************************************************************
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk* Internal Functions *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk*******************************************************************************/
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkstatic int dbgcProcessLog(PDBGC pDbgc);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk/**
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Resolves a symbol (or tries to do so at least).
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @returns 0 on success.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @returns VBox status on failure.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @param pDbgc The debug console instance.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @param pszSymbol The symbol name.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @param enmType The result type. Specifying DBGCVAR_TYPE_GC_FAR may
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * cause failure, avoid it.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @param pResult Where to store the result.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkint dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk{
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk int rc;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /*
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Builtin?
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk PCDBGCSYM pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (pSymDesc)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (!pSymDesc->pfnGet)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return VERR_DBGC_PARSE_WRITEONLY_SYMBOL;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /*
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * A typical register? (Guest only)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk static const char s_szSixLetterRegisters[] =
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "rflags;eflags;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk ;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk static const char s_szThreeLetterRegisters[] =
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "eax;rax;" "r10;" "r8d;r8w;r8b;" "cr0;" "dr0;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "ebx;rbx;" "r11;" "r9d;r9w;r8b;" "dr1;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "ecx;rcx;" "r12;" "cr2;" "dr2;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "edx;rdx;" "r13;" "cr3;" "dr3;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "edi;rdi;dil;" "r14;" "cr4;" "dr4;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "esi;rsi;sil;" "r15;" "cr8;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "ebp;rbp;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "esp;rsp;" "dr6;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "rip;eip;" "dr7;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "efl;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk ;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk static const char s_szTwoLetterRegisters[] =
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "ax;al;ah;" "r8;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "bx;bl;bh;" "r9;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "cx;cl;ch;" "cs;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "dx;dl;dh;" "ds;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "di;" "es;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "si;" "fs;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "bp;" "gs;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "sp;" "ss;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk "ip;"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk ;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk size_t const cchSymbol = strlen(pszSymbol);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if ( (cchSymbol == 2 && strstr(s_szTwoLetterRegisters, pszSymbol))
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk || (cchSymbol == 3 && strstr(s_szThreeLetterRegisters, pszSymbol))
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk || (cchSymbol == 6 && strstr(s_szSixLetterRegisters, pszSymbol)))
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (!strchr(pszSymbol, ';'))
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk DBGCVAR Var;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk DBGCVAR_INIT_STRING(&Var, pszSymbol);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk rc = dbgcOpRegister(pDbgc, &Var, DBGCVAR_CAT_ANY, pResult);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (RT_SUCCESS(rc))
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return DBGCCmdHlpConvert(&pDbgc->CmdHlp, pResult, enmType, false /*fConvSyms*/, pResult);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /*
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Ask PDM.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /** @todo resolve symbols using PDM. */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /*
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Ask the debug info manager.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk RTDBGSYMBOL Symbol;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk rc = DBGFR3AsSymbolByName(pDbgc->pVM, pDbgc->hDbgAs, pszSymbol, &Symbol, NULL);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (RT_SUCCESS(rc))
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /*
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Default return is a flat gc address.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk DBGCVAR_INIT_GC_FLAT(pResult, Symbol.Value);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (Symbol.cb)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk DBGCVAR_SET_RANGE(pResult, DBGCVAR_RANGE_BYTES, Symbol.cb);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk switch (enmType)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /* nothing to do. */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk case DBGCVAR_TYPE_GC_FLAT:
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk case DBGCVAR_TYPE_ANY:
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return VINF_SUCCESS;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /* impossible at the moment. */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk case DBGCVAR_TYPE_GC_FAR:
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return VERR_DBGC_PARSE_CONVERSION_FAILED;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /* simply make it numeric. */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk case DBGCVAR_TYPE_NUMBER:
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pResult->enmType = DBGCVAR_TYPE_NUMBER;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pResult->u.u64Number = Symbol.Value;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return VINF_SUCCESS;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /* cast it. */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk case DBGCVAR_TYPE_GC_PHYS:
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk case DBGCVAR_TYPE_HC_FLAT:
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk case DBGCVAR_TYPE_HC_PHYS:
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return DBGCCmdHlpConvert(&pDbgc->CmdHlp, pResult, enmType, false /*fConvSyms*/, pResult);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk default:
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk AssertMsgFailed(("Internal error enmType=%d\n", enmType));
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return VERR_INVALID_PARAMETER;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return VERR_DBGC_PARSE_NOT_IMPLEMENTED;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk}
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk/**
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Process all commands currently in the buffer.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @returns VBox status code. Any error indicates the termination of the console session.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @param pDbgc Debugger console instance data.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @param fNoExecute Indicates that no commands should actually be executed.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkstatic int dbgcProcessCommands(PDBGC pDbgc, bool fNoExecute)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk{
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /** @todo Replace this with a sh/ksh/csh/rexx like toplevel language that
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * allows doing function, loops, if, cases, and such. */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk int rc = VINF_SUCCESS;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk while (pDbgc->cInputLines)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /*
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Empty the log buffer if we're hooking the log.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (pDbgc->fLog)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk rc = dbgcProcessLog(pDbgc);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (RT_FAILURE(rc))
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk break;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (pDbgc->iRead == pDbgc->iWrite)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pDbgc->cInputLines = 0;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return 0;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /*
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Copy the command to the parse buffer.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk char ch;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk char *psz = &pDbgc->achInput[pDbgc->iRead];
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk char *pszTrg = &pDbgc->achScratch[0];
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk psz = &pDbgc->achInput[0];
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (psz == &pDbgc->achInput[pDbgc->iWrite])
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pDbgc->cInputLines = 0;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return 0;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pszTrg++;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *pszTrg = '\0';
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /*
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Advance the buffer.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pDbgc->iRead = psz - &pDbgc->achInput[0];
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (ch == '\n')
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pDbgc->cInputLines--;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /*
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Parse and execute this command.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pDbgc->pszScratch = psz;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pDbgc->iArg = 0;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk rc = dbgcEvalCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1, fNoExecute);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if ( rc == VERR_DBGC_QUIT
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk || rc == VWRN_DBGC_CMD_PENDING)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk break;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk rc = VINF_SUCCESS; /* ignore other statuses */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return rc;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk}
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk/**
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Handle input buffer overflow.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Will read any available input looking for a '\n' to reset the buffer on.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @returns VBox status.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @param pDbgc Debugger console instance data.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkstatic int dbgcInputOverflow(PDBGC pDbgc)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk{
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /*
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Assert overflow status and reset the input buffer.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (!pDbgc->fInputOverflow)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pDbgc->fInputOverflow = true;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pDbgc->iRead = pDbgc->iWrite = 0;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pDbgc->cInputLines = 0;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /*
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Eat input till no more or there is a '\n'.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * When finding a '\n' we'll continue normal processing.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk size_t cbRead;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (RT_FAILURE(rc))
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return rc;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if (psz)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk {
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pDbgc->fInputOverflow = false;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pDbgc->iWrite = (unsigned)cbRead;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk pDbgc->cInputLines = 0;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk break;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk }
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk return 0;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk}
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk/**
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Read input and do some preprocessing.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk *
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @returns VBox status.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * In addition to the iWrite and achInput, cInputLines is maintained.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * In case of an input overflow the fInputOverflow flag will be set.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * @param pDbgc Debugger console instance data.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkstatic int dbgcInputRead(PDBGC pDbgc)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk{
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk /*
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * We have ready input.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk * Read it till we don't have any or we have a full input buffer.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk */
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk int rc = 0;
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk do
{
/*
* More available buffer space?
*/
size_t cbLeft;
if (pDbgc->iWrite > pDbgc->iRead)
cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);
else
cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;
if (!cbLeft)
{
/* overflow? */
if (!pDbgc->cInputLines)
rc = dbgcInputOverflow(pDbgc);
break;
}
/*
* Read one char and interpret it.
*/
char achRead[128];
size_t cbRead;
rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);
if (RT_FAILURE(rc))
return rc;
char *psz = &achRead[0];
while (cbRead-- > 0)
{
char ch = *psz++;
switch (ch)
{
/*
* Ignore.
*/
case '\0':
case '\r':
case '\a':
break;
/*
* Backspace.
*/
case '\b':
Log2(("DBGC: backspace\n"));
if (pDbgc->iRead != pDbgc->iWrite)
{
unsigned iWriteUndo = pDbgc->iWrite;
if (pDbgc->iWrite)
pDbgc->iWrite--;
else
pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;
if (pDbgc->achInput[pDbgc->iWrite] == '\n')
pDbgc->iWrite = iWriteUndo;
}
break;
/*
* Add char to buffer.
*/
case '\t':
case '\n':
case ';':
switch (ch)
{
case '\t': ch = ' '; break;
case '\n': pDbgc->cInputLines++; break;
}
default:
Log2(("DBGC: ch=%02x\n", (unsigned char)ch));
pDbgc->achInput[pDbgc->iWrite] = ch;
if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))
pDbgc->iWrite = 0;
break;
}
}
/* Terminate it to make it easier to read in the debugger. */
pDbgc->achInput[pDbgc->iWrite] = '\0';
} while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));
return rc;
}
/**
* Reads input, parses it and executes commands on '\n'.
*
* @returns VBox status.
* @param pDbgc Debugger console instance data.
* @param fNoExecute Indicates that no commands should actually be executed.
*/
int dbgcProcessInput(PDBGC pDbgc, bool fNoExecute)
{
/*
* We know there's input ready, so let's read it first.
*/
int rc = dbgcInputRead(pDbgc);
if (RT_FAILURE(rc))
return rc;
/*
* Now execute any ready commands.
*/
if (pDbgc->cInputLines)
{
pDbgc->pBack->pfnSetReady(pDbgc->pBack, false);
pDbgc->fReady = false;
rc = dbgcProcessCommands(pDbgc, fNoExecute);
if (RT_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)
pDbgc->fReady = true;
if ( RT_SUCCESS(rc)
&& pDbgc->iRead == pDbgc->iWrite
&& pDbgc->fReady)
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
if ( RT_SUCCESS(rc)
&& pDbgc->fReady)
pDbgc->pBack->pfnSetReady(pDbgc->pBack, true);
}
else
/* Received nonsense; just skip it. */
pDbgc->iRead = pDbgc->iWrite;
return rc;
}
/**
* Gets the event context identifier string.
* @returns Read only string.
* @param enmCtx The context.
*/
static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)
{
switch (enmCtx)
{
case DBGFEVENTCTX_RAW: return "raw";
case DBGFEVENTCTX_REM: return "rem";
case DBGFEVENTCTX_HWACCL: return "hwaccl";
case DBGFEVENTCTX_HYPER: return "hyper";
case DBGFEVENTCTX_OTHER: return "other";
case DBGFEVENTCTX_INVALID: return "!Invalid Event Ctx!";
default:
AssertMsgFailed(("enmCtx=%d\n", enmCtx));
return "!Unknown Event Ctx!";
}
}
/**
* Processes debugger events.
*
* @returns VBox status.
* @param pDbgc DBGC Instance data.
* @param pEvent Pointer to event data.
*/
static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)
{
/*
* Flush log first.
*/
if (pDbgc->fLog)
{
int rc = dbgcProcessLog(pDbgc);
if (RT_FAILURE(rc))
return rc;
}
/*
* Process the event.
*/
pDbgc->pszScratch = &pDbgc->achInput[0];
pDbgc->iArg = 0;
bool fPrintPrompt = true;
int rc = VINF_SUCCESS;
switch (pEvent->enmType)
{
/*
* The first part is events we have initiated with commands.
*/
case DBGFEVENT_HALT_DONE:
{
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */
if (RT_SUCCESS(rc))
rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
break;
}
/*
* The second part is events which can occur at any time.
*/
case DBGFEVENT_FATAL_ERROR:
{
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
dbgcGetEventCtx(pEvent->enmCtx));
pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */
if (RT_SUCCESS(rc))
rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
break;
}
case DBGFEVENT_BREAKPOINT:
case DBGFEVENT_BREAKPOINT_HYPER:
{
bool fRegCtxGuest = pDbgc->fRegCtxGuest;
pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;
rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
switch (rc)
{
case VERR_DBGC_BP_NOT_FOUND:
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
break;
case VINF_DBGC_BP_NO_COMMAND:
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
break;
case VINF_BUFFER_OVERFLOW:
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
break;
default:
break;
}
if (RT_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))
rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
else
pDbgc->fRegCtxGuest = fRegCtxGuest;
break;
}
case DBGFEVENT_STEPPED:
case DBGFEVENT_STEPPED_HYPER:
{
pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
if (RT_SUCCESS(rc))
rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
break;
}
case DBGFEVENT_ASSERTION_HYPER:
{
pDbgc->fRegCtxGuest = false;
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
"\ndbgf event: Hypervisor Assertion! (%s)\n"
"%s"
"%s"
"\n",
dbgcGetEventCtx(pEvent->enmCtx),
pEvent->u.Assert.pszMsg1,
pEvent->u.Assert.pszMsg2);
if (RT_SUCCESS(rc))
rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
break;
}
case DBGFEVENT_DEV_STOP:
{
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
"\n"
"dbgf event: DBGFSTOP (%s)\n"
"File: %s\n"
"Line: %d\n"
"Function: %s\n",
dbgcGetEventCtx(pEvent->enmCtx),
pEvent->u.Src.pszFile,
pEvent->u.Src.uLine,
pEvent->u.Src.pszFunction);
if (RT_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
"Message: %s\n",
pEvent->u.Src.pszMessage);
if (RT_SUCCESS(rc))
rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
break;
}
case DBGFEVENT_INVALID_COMMAND:
{
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
break;
}
case DBGFEVENT_TERMINATING:
{
pDbgc->fReady = false;
pDbgc->pBack->pfnSetReady(pDbgc->pBack, false);
pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");
fPrintPrompt = false;
rc = VERR_GENERAL_FAILURE;
break;
}
default:
{
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
break;
}
}
/*
* Prompt, anyone?
*/
if (fPrintPrompt && RT_SUCCESS(rc))
{
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
pDbgc->fReady = true;
if (RT_SUCCESS(rc))
pDbgc->pBack->pfnSetReady(pDbgc->pBack, true);
}
return rc;
}
/**
* Prints any log lines from the log buffer.
*
* The caller must not call function this unless pDbgc->fLog is set.
*
* @returns VBox status. (output related)
* @param pDbgc Debugger console instance data.
*/
static int dbgcProcessLog(PDBGC pDbgc)
{
/** @todo */
NOREF(pDbgc);
return 0;
}
/**
* Run the debugger console.
*
* @returns VBox status.
* @param pDbgc Pointer to the debugger console instance data.
*/
int dbgcRun(PDBGC pDbgc)
{
/*
* We're ready for commands now.
*/
pDbgc->fReady = true;
pDbgc->pBack->pfnSetReady(pDbgc->pBack, true);
/*
* Main Debugger Loop.
*
* This loop will either block on waiting for input or on waiting on
* debug events. If we're forwarding the log we cannot wait for long
* before we must flush the log.
*/
int rc = VINF_SUCCESS;
for (;;)
{
if ( pDbgc->pVM
&& DBGFR3CanWait(pDbgc->pVM))
{
/*
* Wait for a debug event.
*/
PCDBGFEVENT pEvent;
rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);
if (RT_SUCCESS(rc))
{
rc = dbgcProcessEvent(pDbgc, pEvent);
if (RT_FAILURE(rc))
break;
}
else if (rc != VERR_TIMEOUT)
break;
/*
* Check for input.
*/
if (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
{
rc = dbgcProcessInput(pDbgc, false /* fNoExecute */);
if (RT_FAILURE(rc))
break;
}
}
else
{
/*
* Wait for input. If Logging is enabled we'll only wait very briefly.
*/
if (pDbgc->pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))
{
rc = dbgcProcessInput(pDbgc, false /* fNoExecute */);
if (RT_FAILURE(rc))
break;
}
}
/*
* Forward log output.
*/
if (pDbgc->fLog)
{
rc = dbgcProcessLog(pDbgc);
if (RT_FAILURE(rc))
break;
}
}
return rc;
}
/**
* Creates a a new instance.
*
* @returns VBox status code.
* @param ppDbgc Where to store the pointer to the instance data.
* @param pBack Pointer to the backend.
* @param fFlags The flags.
*/
int dbgcCreate(PDBGC *ppDbgc, PDBGCBACK pBack, unsigned fFlags)
{
/*
* Validate input.
*/
AssertPtrReturn(pBack, VERR_INVALID_POINTER);
AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
/*
* Allocate and initialize.
*/
PDBGC pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
if (!pDbgc)
return VERR_NO_MEMORY;
dbgcInitCmdHlp(pDbgc);
pDbgc->pBack = pBack;
pDbgc->pVM = NULL;
pDbgc->idCpu = 0;
pDbgc->hDbgAs = DBGF_AS_GLOBAL;
pDbgc->pszEmulation = "CodeView/WinDbg";
pDbgc->paEmulationCmds = &g_aCmdsCodeView[0];
pDbgc->cEmulationCmds = g_cCmdsCodeView;
pDbgc->paEmulationFuncs = &g_aFuncsCodeView[0];
pDbgc->cEmulationFuncs = g_cFuncsCodeView;
//pDbgc->fLog = false;
pDbgc->fRegCtxGuest = true;
pDbgc->fRegTerse = true;
//pDbgc->cPagingHierarchyDumps = 0;
//pDbgc->DisasmPos = {0};
//pDbgc->SourcePos = {0};
//pDbgc->DumpPos = {0};
pDbgc->pLastPos = &pDbgc->DisasmPos;
//pDbgc->cbDumpElement = 0;
//pDbgc->cVars = 0;
//pDbgc->paVars = NULL;
//pDbgc->pPlugInHead = NULL;
//pDbgc->pFirstBp = NULL;
//pDbgc->abSearch = {0};
//pDbgc->cbSearch = 0;
pDbgc->cbSearchUnit = 1;
pDbgc->cMaxSearchHits = 1;
//pDbgc->SearchAddr = {0};
//pDbgc->cbSearchRange = 0;
//pDbgc->uInputZero = 0;
//pDbgc->iRead = 0;
//pDbgc->iWrite = 0;
//pDbgc->cInputLines = 0;
//pDbgc->fInputOverflow = false;
pDbgc->fReady = true;
pDbgc->pszScratch = &pDbgc->achScratch[0];
//pDbgc->iArg = 0;
//pDbgc->rcOutput = 0;
//pDbgc->rcCmd = 0;
dbgcEvalInit();
*ppDbgc = pDbgc;
return VINF_SUCCESS;
}
/**
* Destroys a DBGC instance created by dbgcCreate.
*
* @param pDbgc Pointer to the debugger console instance data.
*/
void dbgcDestroy(PDBGC pDbgc)
{
AssertPtr(pDbgc);
/* Disable log hook. */
if (pDbgc->fLog)
{
}
/* Unload all plug-ins. */
dbgcPlugInUnloadAll(pDbgc);
/* Detach from the VM. */
if (pDbgc->pVM)
DBGFR3Detach(pDbgc->pVM);
/* finally, free the instance memory. */
RTMemFree(pDbgc);
}
/**
* Make a console instance.
*
* This will not return until either an 'exit' command is issued or a error code
* indicating connection loss is encountered.
*
* @returns VINF_SUCCESS if console termination caused by the 'exit' command.
* @returns The VBox status code causing the console termination.
*
* @param pVM VM Handle.
* @param pBack Pointer to the backend structure. This must contain
* a full set of function pointers to service the console.
* @param fFlags Reserved, must be zero.
* @remark A forced termination of the console is easiest done by forcing the
* callbacks to return fatal failures.
*/
DBGDECL(int) DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)
{
/*
* Validate input.
*/
AssertPtrNullReturn(pVM, VERR_INVALID_POINTER);
/*
* Allocate and initialize instance data
*/
PDBGC pDbgc;
int rc = dbgcCreate(&pDbgc, pBack, fFlags);
if (RT_FAILURE(rc))
return rc;
/*
* Print welcome message.
*/
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
"Welcome to the VirtualBox Debugger!\n");
/*
* Attach to the specified VM.
*/
if (RT_SUCCESS(rc) && pVM)
{
rc = DBGFR3Attach(pVM);
if (RT_SUCCESS(rc))
{
pDbgc->pVM = pVM;
pDbgc->idCpu = 0;
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
"Current VM is %08x, CPU #%u\n" /** @todo get and print the VM name! */
, pDbgc->pVM, pDbgc->idCpu);
}
else
rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
}
/*
* Load plugins.
*/
if (RT_SUCCESS(rc))
{
if (pVM)
dbgcPlugInAutoLoad(pDbgc);
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
}
else
pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nDBGCCreate error: %Rrc\n", rc);
/*
* Run the debugger main loop.
*/
if (RT_SUCCESS(rc))
rc = dbgcRun(pDbgc);
/*
* Cleanup console debugger session.
*/
dbgcDestroy(pDbgc);
return rc == VERR_DBGC_QUIT ? VINF_SUCCESS : rc;
}