/** @file
 * Debugger Interfaces. (VBoxDbg)
 *
 * This header covers all external interfaces of the Debugger module.
 * However, it does not cover the DBGF interface since that part of the
 * VMM. Use dbgf.h for that.
 */

/*
 * Copyright (C) 2006-2007 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 *
 * The contents of this file may alternatively be used under the terms
 * of the Common Development and Distribution License Version 1.0
 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
 * VirtualBox OSE distribution, in which case the provisions of the
 * CDDL are applicable instead of those of the GPL.
 *
 * You may elect to license modified versions of this file under the
 * terms and conditions of either the GPL or the CDDL or both.
 */

#ifndef ___VBox_dbg_h
#define ___VBox_dbg_h

#include <VBox/cdefs.h>
#include <VBox/types.h>
#include <VBox/vmm/dbgf.h>

#include <iprt/stdarg.h>
#ifdef IN_RING3
# include <iprt/err.h>
#endif

RT_C_DECLS_BEGIN

#ifdef IN_RING3 /* The debugger stuff is ring-3 only. */

/** @def VBOX_WITH_DEBUGGER
 * The build is with debugger module. Test if this is defined before registering
 * external debugger commands. This is normally defined in Config.kmk.
 */
#ifdef DOXYGEN_RUNNING
# define VBOX_WITH_DEBUGGER
#endif


/**
 * DBGC variable category.
 *
 * Used to describe an argument to a command or function and a functions
 * return value.
 */
typedef enum DBGCVARCAT
{
    /** Any type is fine. */
    DBGCVAR_CAT_ANY = 0,
    /** Any kind of pointer or number. */
    DBGCVAR_CAT_POINTER_NUMBER,
    /** Any kind of pointer or number, no range. */
    DBGCVAR_CAT_POINTER_NUMBER_NO_RANGE,
    /** Any kind of pointer. */
    DBGCVAR_CAT_POINTER,
    /** Any kind of pointer with no range option. */
    DBGCVAR_CAT_POINTER_NO_RANGE,
    /** GC pointer. */
    DBGCVAR_CAT_GC_POINTER,
    /** GC pointer with no range option. */
    DBGCVAR_CAT_GC_POINTER_NO_RANGE,
    /** Numeric argument. */
    DBGCVAR_CAT_NUMBER,
    /** Numeric argument with no range option. */
    DBGCVAR_CAT_NUMBER_NO_RANGE,
    /** String. */
    DBGCVAR_CAT_STRING,
    /** Symbol. */
    DBGCVAR_CAT_SYMBOL,
    /** Option. */
    DBGCVAR_CAT_OPTION,
    /** Option + string. */
    DBGCVAR_CAT_OPTION_STRING,
    /** Option + number. */
    DBGCVAR_CAT_OPTION_NUMBER
} DBGCVARCAT;


/**
 * DBGC variable type.
 */
typedef enum DBGCVARTYPE
{
    /** unknown... */
    DBGCVAR_TYPE_UNKNOWN = 0,
    /** Flat GC pointer. */
    DBGCVAR_TYPE_GC_FLAT,
    /** Segmented GC pointer. */
    DBGCVAR_TYPE_GC_FAR,
    /** Physical GC pointer. */
    DBGCVAR_TYPE_GC_PHYS,
    /** Flat HC pointer. */
    DBGCVAR_TYPE_HC_FLAT,
    /** Physical HC pointer. */
    DBGCVAR_TYPE_HC_PHYS,
    /** String. */
    DBGCVAR_TYPE_STRING,
    /** Number. */
    DBGCVAR_TYPE_NUMBER,
    /** Symbol.
     * @todo drop this   */
    DBGCVAR_TYPE_SYMBOL,
    /** Special type used when querying symbols. */
    DBGCVAR_TYPE_ANY
} DBGCVARTYPE;

/** @todo Rename to DBGCVAR_IS_xyz. */

/** Checks if the specified variable type is of a pointer persuasion. */
#define DBGCVAR_ISPOINTER(enmType)      ((enmType) >= DBGCVAR_TYPE_GC_FLAT && enmType <= DBGCVAR_TYPE_HC_PHYS)
/** Checks if the specified variable type is of a pointer persuasion. */
#define DBGCVAR_IS_FAR_PTR(enmType)     ((enmType) == DBGCVAR_TYPE_GC_FAR)
/** Checks if the specified variable type is of a pointer persuasion and of the guest context sort. */
#define DBGCVAR_ISGCPOINTER(enmType)    ((enmType) >= DBGCVAR_TYPE_GC_FLAT && (enmType) <= DBGCVAR_TYPE_GC_PHYS)
/** Checks if the specified variable type is of a pointer persuasion and of the host context sort. */
#define DBGCVAR_ISHCPOINTER(enmType)    ((enmType) >= DBGCVAR_TYPE_HC_FLAT && (enmType) <= DBGCVAR_TYPE_HC_PHYS)


/**
 * DBGC variable range type.
 */
typedef enum DBGCVARRANGETYPE
{
    /** No range appliable or no range specified. */
    DBGCVAR_RANGE_NONE = 0,
    /** Number of elements. */
    DBGCVAR_RANGE_ELEMENTS,
    /** Number of bytes. */
    DBGCVAR_RANGE_BYTES
} DBGCVARRANGETYPE;


/**
 * Variable descriptor.
 */
typedef struct DBGCVARDESC
{
    /** The minimal number of times this argument may occur.
     * Use 0 here to inidicate that the argument is optional. */
    unsigned    cTimesMin;
    /** Maximum number of occurrences.
     * Use ~0 here to indicate infinite. */
    unsigned    cTimesMax;
    /** Argument category. */
    DBGCVARCAT  enmCategory;
    /** Flags, DBGCVD_FLAGS_* */
    unsigned    fFlags;
    /** Argument name. */
    const char *pszName;
    /** Argument name. */
    const char *pszDescription;
} DBGCVARDESC;
/** Pointer to an argument descriptor. */
typedef DBGCVARDESC *PDBGCVARDESC;
/** Pointer to a const argument descriptor. */
typedef const DBGCVARDESC *PCDBGCVARDESC;

/** Variable descriptor flags.
 * @{ */
/** Indicates that the variable depends on the previous being present. */
#define DBGCVD_FLAGS_DEP_PREV       RT_BIT(1)
/** @} */


/**
 * DBGC variable.
 */
typedef struct DBGCVAR
{
    /** Pointer to the argument descriptor. */
    PCDBGCVARDESC   pDesc;
    /** Pointer to the next argument. */
    struct DBGCVAR *pNext;

    /** Argument type. */
    DBGCVARTYPE     enmType;
    /** Type specific. */
    union
    {
        /** Flat GC Address.        (DBGCVAR_TYPE_GC_FLAT) */
        RTGCPTR         GCFlat;
        /** Far (16:32) GC Address. (DBGCVAR_TYPE_GC_FAR) */
        RTFAR32         GCFar;
        /** Physical GC Address.    (DBGCVAR_TYPE_GC_PHYS) */
        RTGCPHYS        GCPhys;
        /** Flat HC Address.        (DBGCVAR_TYPE_HC_FLAT) */
        void           *pvHCFlat;
        /** Physical GC Address.    (DBGCVAR_TYPE_HC_PHYS) */
        RTHCPHYS        HCPhys;
        /** String.                 (DBGCVAR_TYPE_STRING)
         * The basic idea is the the this is a pointer to the expression we're
         * parsing, so no messing with freeing. */
        const char     *pszString;
        /** Number.                 (DBGCVAR_TYPE_NUMBER) */
        uint64_t        u64Number;
    } u;

    /** Range type. */
    DBGCVARRANGETYPE    enmRangeType;
    /** Range. The use of the content depends on the enmRangeType. */
    uint64_t            u64Range;
} DBGCVAR;
/** Pointer to a command argument. */
typedef DBGCVAR *PDBGCVAR;
/** Pointer to a const command argument. */
typedef const DBGCVAR *PCDBGCVAR;


/**
 * Macro for initializing a DBGC variable with defaults.
 * The result is an unknown variable type without any range.
 */
#define DBGCVAR_INIT(pVar) \
        do { \
            (pVar)->pDesc = NULL;\
            (pVar)->pNext = NULL; \
            (pVar)->enmType = DBGCVAR_TYPE_UNKNOWN; \
            (pVar)->u.u64Number = 0; \
            (pVar)->enmRangeType = DBGCVAR_RANGE_NONE; \
            (pVar)->u64Range = 0; \
        } while (0)

/**
 * Macro for initializing a DBGC variable with a HC physical address.
 */
#define DBGCVAR_INIT_HC_PHYS(pVar, Phys) \
        do { \
            DBGCVAR_INIT(pVar); \
            (pVar)->enmType = DBGCVAR_TYPE_HC_PHYS; \
            (pVar)->u.HCPhys = (Phys); \
        } while (0)

/**
 * Macro for initializing a DBGC variable with a HC flat address.
 */
#define DBGCVAR_INIT_HC_FLAT(pVar, Flat) \
        do { \
            DBGCVAR_INIT(pVar); \
            (pVar)->enmType = DBGCVAR_TYPE_HC_FLAT; \
            (pVar)->u.pvHCFlat = (Flat); \
        } while (0)

/**
 * Macro for initializing a DBGC variable with a GC physical address.
 */
#define DBGCVAR_INIT_GC_PHYS(pVar, Phys) \
        do { \
            DBGCVAR_INIT(pVar); \
            (pVar)->enmType = DBGCVAR_TYPE_GC_PHYS; \
            (pVar)->u.GCPhys = (Phys); \
        } while (0)

/**
 * Macro for initializing a DBGC variable with a GC flat address.
 */
#define DBGCVAR_INIT_GC_FLAT(pVar, Flat) \
        do { \
            DBGCVAR_INIT(pVar); \
            (pVar)->enmType = DBGCVAR_TYPE_GC_FLAT; \
            (pVar)->u.GCFlat = (Flat); \
        } while (0)

/**
 * Macro for initializing a DBGC variable with a GC flat address.
 */
#define DBGCVAR_INIT_GC_FLAT_BYTE_RANGE(pVar, Flat, cbRange) \
        do { \
            DBGCVAR_INIT(pVar); \
            (pVar)->enmType = DBGCVAR_TYPE_GC_FLAT; \
            (pVar)->u.GCFlat = (Flat); \
            DBGCVAR_SET_RANGE(pVar, DBGCVAR_RANGE_BYTES, cbRange); \
        } while (0)

/**
 * Macro for initializing a DBGC variable with a GC far address.
 */
#define DBGCVAR_INIT_GC_FAR(pVar, _sel, _off) \
        do { \
            DBGCVAR_INIT(pVar); \
            (pVar)->enmType = DBGCVAR_TYPE_GC_FAR; \
            (pVar)->u.GCFar.sel = (_sel); \
            (pVar)->u.GCFar.off = (_off); \
        } while (0)

/**
 * Macro for initializing a DBGC variable with a number.
 */
#define DBGCVAR_INIT_NUMBER(pVar, Value) \
        do { \
            DBGCVAR_INIT(pVar); \
            (pVar)->enmType = DBGCVAR_TYPE_NUMBER; \
            (pVar)->u.u64Number = (Value); \
        } while (0)

/**
 * Macro for initializing a DBGC variable with a string.
 */
#define DBGCVAR_INIT_STRING(pVar, a_pszString) \
        do { \
            DBGCVAR_INIT(pVar); \
            (pVar)->enmType      = DBGCVAR_TYPE_STRING; \
            (pVar)->enmRangeType = DBGCVAR_RANGE_BYTES; \
            (pVar)->u.pszString  = (a_pszString); \
            (pVar)->u64Range     = strlen(a_pszString); \
        } while (0)


/**
 * Macro for setting the range of a DBGC variable.
 * @param   pVar            The variable.
 * @param   _enmRangeType   The range type.
 * @param   Value           The range length value.
 */
#define DBGCVAR_SET_RANGE(pVar, _enmRangeType, Value) \
    do { \
        (pVar)->enmRangeType = (_enmRangeType); \
        (pVar)->u64Range = (Value); \
    } while (0)


/**
 * Macro for setting the range of a DBGC variable.
 * @param   a_pVar          The variable.
 * @param   a_cbRange       The range, in bytes.
 */
#define DBGCVAR_SET_BYTE_RANGE(a_pVar, a_cbRange) \
    DBGCVAR_SET_RANGE(a_pVar, DBGCVAR_RANGE_BYTES, a_cbRange)


/**
 * Macro for resetting the range a DBGC variable.
 * @param   a_pVar          The variable.
 */
#define DBGCVAR_ZAP_RANGE(a_pVar) \
    do { \
        (a_pVar)->enmRangeType  = DBGCVAR_RANGE_NONE; \
        (a_pVar)->u64Range      = 0; \
    } while (0)


/**
 * Macro for assigning one DBGC variable to another.
 * @param   a_pResult       The result (target) variable.
 * @param   a_pVar          The source variable.
 */
#define DBGCVAR_ASSIGN(a_pResult, a_pVar) \
    do { \
        *(a_pResult) = *(a_pVar); \
    } while (0)


/** Pointer to command descriptor. */
typedef struct DBGCCMD *PDBGCCMD;
/** Pointer to const command descriptor. */
typedef const struct DBGCCMD *PCDBGCCMD;

/** Pointer to helper functions for commands. */
typedef struct DBGCCMDHLP *PDBGCCMDHLP;


/**
 * Helper functions for commands.
 */
typedef struct DBGCCMDHLP
{
    /** Magic value (DBGCCMDHLP_MAGIC). */
    uint32_t                u32Magic;

    /**
     * Command helper for writing formatted text to the debug console.
     *
     * @returns VBox status.
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   pcb         Where to store the number of bytes written.
     * @param   pszFormat   The format string.
     *                      This is using the log formatter, so it's format extensions can be used.
     * @param   ...         Arguments specified in the format string.
     */
    DECLCALLBACKMEMBER(int, pfnPrintf)(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, ...);

    /**
     * Command helper for writing formatted text to the debug console.
     *
     * @returns VBox status.
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   pcb         Where to store the number of bytes written.
     * @param   pszFormat   The format string.
     *                      This is using the log formatter, so it's format extensions can be used.
     * @param   args        Arguments specified in the format string.
     */
    DECLCALLBACKMEMBER(int, pfnPrintfV)(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args);

    /**
     * Command helper for formatting and error message for a VBox status code.
     *
     * @returns VBox status code appropriate to return from a command.
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   rc          The VBox status code.
     * @param   pszFormat   Format string for additional messages. Can be NULL.
     * @param   ...         Format arguments, optional.
     */
    DECLCALLBACKMEMBER(int, pfnVBoxError)(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...);

    /**
     * Command helper for formatting and error message for a VBox status code.
     *
     * @returns VBox status code appropriate to return from a command.
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   rc          The VBox status code.
     * @param   pcb         Where to store the number of bytes written.
     * @param   pszFormat   Format string for additional messages. Can be NULL.
     * @param   args        Format arguments, optional.
     */
    DECLCALLBACKMEMBER(int, pfnVBoxErrorV)(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, va_list args);

    /**
     * Command helper for reading memory specified by a DBGC variable.
     *
     * @returns VBox status code appropriate to return from a command.
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   pVM         VM handle if GC or physical HC address.
     * @param   pvBuffer    Where to store the read data.
     * @param   cbRead      Number of bytes to read.
     * @param   pVarPointer DBGC variable specifying where to start reading.
     * @param   pcbRead     Where to store the number of bytes actually read.
     *                      This optional, but it's useful when read GC virtual memory where a
     *                      page in the requested range might not be present.
     *                      If not specified not-present failure or end of a HC physical page
     *                      will cause failure.
     */
    DECLCALLBACKMEMBER(int, pfnMemRead)(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead);

    /**
     * Command helper for writing memory specified by a DBGC variable.
     *
     * @returns VBox status code appropriate to return from a command.
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   pVM         VM handle if GC or physical HC address.
     * @param   pvBuffer    What to write.
     * @param   cbWrite     Number of bytes to write.
     * @param   pVarPointer DBGC variable specifying where to start reading.
     * @param   pcbWritten  Where to store the number of bytes written.
     *                      This is optional. If NULL be aware that some of the buffer
     *                      might have been written to the specified address.
     */
    DECLCALLBACKMEMBER(int, pfnMemWrite)(PDBGCCMDHLP pCmdHlp, PVM pVM, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten);

    /**
     * Executes command an expression.
     * (Hopefully the parser and functions are fully reentrant.)
     *
     * @returns VBox status code appropriate to return from a command.
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   pszExpr     The expression. Format string with the format DBGC extensions.
     * @param   ...         Format arguments.
     */
    DECLCALLBACKMEMBER(int, pfnExec)(PDBGCCMDHLP pCmdHlp, const char *pszExpr, ...);

    /**
     * Evaluates an expression.
     * (Hopefully the parser and functions are fully reentrant.)
     *
     * @returns VBox status code appropriate to return from a command.
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   pResult     Where to store the result.
     * @param   pszExpr     The expression. Format string with the format DBGC extensions.
     * @param   va          Format arguments.
     */
    DECLCALLBACKMEMBER(int, pfnEvalV)(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, va_list va);

    /**
     * Print an error and fail the current command.
     *
     * @returns VBox status code to pass upwards.
     *
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   pCmd        The failing command.
     * @param   pszFormat   The error message format string.
     * @param   va          Format arguments.
     */
    DECLCALLBACKMEMBER(int, pfnFailV)(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, const char *pszFormat, va_list va);

    /**
     * Print an error and fail the current command.
     *
     * @returns VBox status code to pass upwards.
     *
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   pCmd        The failing command.
     * @param   rc          The status code indicating the failure.  This will
     *                      be appended to the message after a colon (': ').
     * @param   pszFormat   The error message format string.
     * @param   va          Format arguments.
     *
     * @see     DBGCCmdHlpFailRc
     */
    DECLCALLBACKMEMBER(int, pfnFailRcV)(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, int rc, const char *pszFormat, va_list va);

    /**
     * Parser error.
     *
     * @returns VBox status code to pass upwards.
     *
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   pCmd        The failing command, can be NULL but shouldn't.
     * @param   iArg        The offending argument, -1 when lazy.
     * @param   pszExpr     The expression.
     * @param   iLine       The line number.
     */
    DECLCALLBACKMEMBER(int, pfnParserError)(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, int iArg, const char *pszExpr, unsigned iLine);

    /**
     * Converts a DBGC variable to a DBGF address structure.
     *
     * @returns VBox status code.
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   pVar        The variable to convert.
     * @param   pAddress    The target address.
     */
    DECLCALLBACKMEMBER(int, pfnVarToDbgfAddr)(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress);

    /**
     * Converts a DBGF address structure to a DBGC variable.
     *
     * @returns VBox status code.
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   pAddress    The source address.
     * @param   pResult     The result variable.
     */
    DECLCALLBACKMEMBER(int, pfnVarFromDbgfAddr)(PDBGCCMDHLP pCmdHlp, PCDBGFADDRESS pAddress, PDBGCVAR pResult);

    /**
     * Converts a DBGC variable to a 64-bit number.
     *
     * @returns VBox status code.
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   pVar        The variable to convert.
     * @param   pu64Number  Where to store the number.
     */
    DECLCALLBACKMEMBER(int, pfnVarToNumber)(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, uint64_t *pu64Number);

    /**
     * Converts a DBGC variable to a boolean.
     *
     * @returns VBox status code.
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   pVar        The variable to convert.
     * @param   pf          Where to store the boolean.
     */
    DECLCALLBACKMEMBER(int, pfnVarToBool)(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf);

    /**
     * Get the range of a variable in bytes, resolving symbols if necessary.
     *
     * @returns VBox status code.
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   pVar        The variable to convert.
     * @param   cbElement   Conversion factor for element ranges.
     * @param   cbDefault   The default range.
     * @param   pcbRange    The length of the range.
     */
    DECLCALLBACKMEMBER(int, pfnVarGetRange)(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, uint64_t cbElement, uint64_t cbDefault,
                                            uint64_t *pcbRange);

    /**
     * Converts a variable to one with the specified type.
     *
     * This preserves the range.
     *
     * @returns VBox status code.
     * @param   pCmdHlp     Pointer to the command callback structure.
     * @param   pVar        The variable to convert.
     * @param   enmToType   The target type.
     * @param   fConvSyms   If @c true, then attempt to resolve symbols.
     * @param   pResult     The output variable. Can be the same as @a pVar.
     */
    DECLCALLBACKMEMBER(int, pfnVarConvert)(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, DBGCVARTYPE enmToType, bool fConvSyms,
                                           PDBGCVAR pResult);

    /**
     * Gets a DBGF output helper that directs the output to the debugger
     * console.
     *
     * @returns Pointer to the helper structure.
     * @param   pCmdHlp     Pointer to the command callback structure.
     */
    DECLCALLBACKMEMBER(PCDBGFINFOHLP, pfnGetDbgfOutputHlp)(PDBGCCMDHLP pCmdHlp);

    /** End marker (DBGCCMDHLP_MAGIC). */
    uint32_t                u32EndMarker;
} DBGCCMDHLP;

/** Magic value for DBGCCMDHLP::u32Magic. (Fyodor Mikhaylovich Dostoyevsky) */
#define DBGCCMDHLP_MAGIC    UINT32_C(18211111)


#ifdef IN_RING3

/**
 * Command helper for writing formatted text to the debug console.
 *
 * @returns VBox status.
 * @param   pCmdHlp     Pointer to the command callback structure.
 * @param   pszFormat   The format string.
 *                      This is using the log formatter, so it's format extensions can be used.
 * @param   ...         Arguments specified in the format string.
 */
DECLINLINE(int) DBGCCmdHlpPrintf(PDBGCCMDHLP pCmdHlp, const char *pszFormat, ...)
{
    va_list va;
    int     rc;

    va_start(va, pszFormat);
    rc = pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, va);
    va_end(va);

    return rc;
}

/**
 * @copydoc FNDBGCHLPVBOXERROR
 */
DECLINLINE(int) DBGCCmdHlpVBoxError(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...)
{
    va_list va;

    va_start(va, pszFormat);
    rc = pCmdHlp->pfnVBoxErrorV(pCmdHlp, rc, pszFormat, va);
    va_end(va);

    return rc;
}

/**
 * @copydoc FNDBGCHLPMEMREAD
 */
DECLINLINE(int) DBGCCmdHlpMemRead(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)
{
    return pCmdHlp->pfnMemRead(pCmdHlp, pVM, pvBuffer, cbRead, pVarPointer, pcbRead);
}

/**
 * Evaluates an expression.
 * (Hopefully the parser and functions are fully reentrant.)
 *
 * @returns VBox status code appropriate to return from a command.
 * @param   pCmdHlp     Pointer to the command callback structure.
 * @param   pResult     Where to store the result.
 * @param   pszExpr     The expression. Format string with the format DBGC extensions.
 * @param   ...         Format arguments.
 */
DECLINLINE(int) DBGCCmdHlpEval(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, ...)
{
    va_list va;
    int     rc;

    va_start(va, pszExpr);
    rc = pCmdHlp->pfnEvalV(pCmdHlp, pResult, pszExpr, va);
    va_end(va);

    return rc;
}

/**
 * Print an error and fail the current command.
 *
 * @returns VBox status code to pass upwards.
 *
 * @param   pCmdHlp     Pointer to the command callback structure.
 * @param   pCmd        The failing command.
 * @param   pszFormat   The error message format string.
 * @param   ...         Format arguments.
 */
DECLINLINE(int) DBGCCmdHlpFail(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, const char *pszFormat, ...)
{
    va_list va;
    int     rc;

    va_start(va, pszFormat);
    rc = pCmdHlp->pfnFailV(pCmdHlp, pCmd, pszFormat, va);
    va_end(va);

    return rc;
}

/**
 * Print an error and fail the current command.
 *
 * Usage example:
 * @code
    int rc = VMMR3Something(pVM);
    if (RT_FAILURE(rc))
        return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "VMMR3Something");
    return VINF_SUCCESS;
 * @endcode
 *
 * @returns VBox status code to pass upwards.
 *
 * @param   pCmdHlp     Pointer to the command callback structure.
 * @param   pCmd        The failing command.
 * @param   rc          The status code indicating the failure.
 * @param   pszFormat   The error message format string.
 * @param   ...         Format arguments.
 */
DECLINLINE(int) DBGCCmdHlpFailRc(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, int rc, const char *pszFormat, ...)
{
    va_list va;

    va_start(va, pszFormat);
    rc = pCmdHlp->pfnFailRcV(pCmdHlp, pCmd, rc, pszFormat, va);
    va_end(va);

    return rc;
}

/**
 * @copydoc DBGCCMDHLP::pfnParserError
 */
DECLINLINE(int) DBGCCmdHlpParserError(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, int iArg, const char *pszExpr, unsigned iLine)
{
    return pCmdHlp->pfnParserError(pCmdHlp, pCmd, iArg, pszExpr, iLine);
}

/** Assert+return like macro for checking parser sanity.
 * Returns with failure if the precodition is not met. */
#define DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, iArg, expr) \
    do { \
        if (!(expr)) \
            return DBGCCmdHlpParserError(pCmdHlp, pCmd, iArg, #expr, __LINE__); \
    } while (0)

/** Assert+return like macro that the VM handle is present.
 * Returns with failure if the VM handle is NIL.  */
#define DBGC_CMDHLP_REQ_VM_RET(pCmdHlp, pCmd, pVM) \
    do { \
        if (!(pVM)) \
            return DBGCCmdHlpFail(pCmdHlp, pCmd, "No VM selected"); \
    } while (0)

/**
 * @copydoc DBGCCMDHLP::pfnVarToDbgfAddr
 */
DECLINLINE(int) DBGCCmdHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
{
    return pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, pVar, pAddress);
}

/**
 * @copydoc DBGCCMDHLP::pfnVarToDbgfAddr
 */
DECLINLINE(int) DBGCCmdHlpVarFromDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGFADDRESS pAddress, PDBGCVAR pResult)
{
    return pCmdHlp->pfnVarFromDbgfAddr(pCmdHlp, pAddress, pResult);
}

/**
 * Converts an variable to a flat address.
 *
 * @returns VBox status code.
 * @param   pCmdHlp     Pointer to the command callback structure.
 * @param   pVar        The variable to convert.
 * @param   pFlatPtr    Where to store the flat address.
 */
DECLINLINE(int) DBGCCmdHlpVarToFlatAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PRTGCPTR pFlatPtr)
{
    DBGFADDRESS Addr;
    int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, pVar, &Addr);
    if (RT_SUCCESS(rc))
        *pFlatPtr = Addr.FlatPtr;
    return rc;
}

/**
 * @copydoc DBGCCMDHLP::pfnVarToNumber
 */
DECLINLINE(int) DBGCCmdHlpVarToNumber(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, uint64_t *pu64Number)
{
    return pCmdHlp->pfnVarToNumber(pCmdHlp, pVar, pu64Number);
}

/**
 * @copydoc DBGCCMDHLP::pfnVarToBool
 */
DECLINLINE(int) DBGCCmdHlpVarToBool(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf)
{
    return pCmdHlp->pfnVarToBool(pCmdHlp, pVar, pf);
}

/**
 * @copydoc DBGCCMDHLP::pfnVarGetRange
 */
DECLINLINE(int) DBGCCmdHlpVarGetRange(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, uint64_t cbElement, uint64_t cbDefault, uint64_t *pcbRange)
{
    return pCmdHlp->pfnVarGetRange(pCmdHlp, pVar, cbElement, cbDefault, pcbRange);
}

/**
 * @copydoc DBGCCMDHLP::pfnVarConvert
 */
DECLINLINE(int) DBGCCmdHlpConvert(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, DBGCVARTYPE enmToType, bool fConvSyms, PDBGCVAR pResult)
{
    return pCmdHlp->pfnVarConvert(pCmdHlp, pVar, enmToType, fConvSyms, pResult);
}

/**
 * @copydoc DBGCCMDHLP::pfnGetDbgfOutputHlp
 */
DECLINLINE(PCDBGFINFOHLP) DBGCCmdHlpGetDbgfOutputHlp(PDBGCCMDHLP pCmdHlp)
{
    return pCmdHlp->pfnGetDbgfOutputHlp(pCmdHlp);
}

#endif /* IN_RING3 */



/**
 * Command handler.
 *
 * The console will call the handler for a command once it's finished
 * parsing the user input.  The command handler function is responsible
 * for executing the command itself.
 *
 * @returns VBox status.
 * @param   pCmd        Pointer to the command descriptor (as registered).
 * @param   pCmdHlp     Pointer to command helper functions.
 * @param   pVM         Pointer to the current VM (if any).
 * @param   paArgs      Pointer to (readonly) array of arguments.
 * @param   cArgs       Number of arguments in the array.
 */
typedef DECLCALLBACK(int) FNDBGCCMD(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
/** Pointer to a FNDBGCCMD() function. */
typedef FNDBGCCMD *PFNDBGCCMD;

/**
 * DBGC command descriptor.
 *
 * If a pResultDesc is specified the command can be called and used
 * as a function too. If it's a pure function, set fFlags to
 * DBGCCMD_FLAGS_FUNCTION.
 */
typedef struct DBGCCMD
{
    /** Command string. */
    const char     *pszCmd;
    /** Minimum number of arguments. */
    unsigned        cArgsMin;
    /** Max number of arguments. */
    unsigned        cArgsMax;
    /** Argument descriptors (array). */
    PCDBGCVARDESC   paArgDescs;
    /** Number of argument descriptors. */
    unsigned        cArgDescs;
    /** flags. (reserved for now) */
    unsigned        fFlags;
    /** Handler function. */
    PFNDBGCCMD      pfnHandler;
    /** Command syntax. */
    const char     *pszSyntax;
    /** Command description. */
    const char     *pszDescription;
} DBGCCMD;

/** DBGCCMD Flags.
 * @{
 */
/** @} */



/** Pointer to a DBGC backend. */
typedef struct DBGCBACK *PDBGCBACK;

/**
 * Checks if there is input.
 *
 * @returns true if there is input ready.
 * @returns false if there not input ready.
 * @param   pBack       Pointer to the backend structure supplied by
 *                      the backend. The backend can use this to find
 *                      it's instance data.
 * @param   cMillies    Number of milliseconds to wait on input data.
 */
typedef DECLCALLBACK(bool) FNDBGCBACKINPUT(PDBGCBACK pBack, uint32_t cMillies);
/** Pointer to a FNDBGCBACKINPUT() callback. */
typedef FNDBGCBACKINPUT *PFNDBGCBACKINPUT;

/**
 * Read input.
 *
 * @returns VBox status code.
 * @param   pBack       Pointer to the backend structure supplied by
 *                      the backend. The backend can use this to find
 *                      it's instance data.
 * @param   pvBuf       Where to put the bytes we read.
 * @param   cbBuf       Maximum nymber of bytes to read.
 * @param   pcbRead     Where to store the number of bytes actually read.
 *                      If NULL the entire buffer must be filled for a
 *                      successful return.
 */
typedef DECLCALLBACK(int) FNDBGCBACKREAD(PDBGCBACK pBack, void *pvBuf, size_t cbBuf, size_t *pcbRead);
/** Pointer to a FNDBGCBACKREAD() callback. */
typedef FNDBGCBACKREAD *PFNDBGCBACKREAD;

/**
 * Write (output).
 *
 * @returns VBox status code.
 * @param   pBack       Pointer to the backend structure supplied by
 *                      the backend. The backend can use this to find
 *                      it's instance data.
 * @param   pvBuf       What to write.
 * @param   cbBuf       Number of bytes to write.
 * @param   pcbWritten  Where to store the number of bytes actually written.
 *                      If NULL the entire buffer must be successfully written.
 */
typedef DECLCALLBACK(int) FNDBGCBACKWRITE(PDBGCBACK pBack, const void *pvBuf, size_t cbBuf, size_t *pcbWritten);
/** Pointer to a FNDBGCBACKWRITE() callback. */
typedef FNDBGCBACKWRITE *PFNDBGCBACKWRITE;

/**
 * Ready / busy notification.
 *
 * @param   pBack       Pointer to the backend structure supplied by
 *                      the backend. The backend can use this to find
 *                      it's instance data.
 * @param   fReady      Whether it's ready (true) or busy (false).
 */
typedef DECLCALLBACK(void) FNDBGCBACKSETREADY(PDBGCBACK pBack, bool fReady);
/** Pointer to a FNDBGCBACKSETREADY() callback. */
typedef FNDBGCBACKSETREADY *PFNDBGCBACKSETREADY;


/**
 * The communication backend provides the console with a number of callbacks
 * which can be used
 */
typedef struct DBGCBACK
{
    /** Check for input. */
    PFNDBGCBACKINPUT    pfnInput;
    /** Read input. */
    PFNDBGCBACKREAD     pfnRead;
    /** Write output. */
    PFNDBGCBACKWRITE    pfnWrite;
    /** Ready / busy notification. */
    PFNDBGCBACKSETREADY pfnSetReady;
} DBGCBACK;


/**
 * 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);


/**
 * Register one or more external commands.
 *
 * @returns VBox status.
 * @param   paCommands      Pointer to an array of command descriptors.
 *                          The commands must be unique. It's not possible
 *                          to register the same commands more than once.
 * @param   cCommands       Number of commands.
 */
DBGDECL(int)    DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands);


/**
 * Deregister one or more external commands previously registered by
 * DBGCRegisterCommands().
 *
 * @returns VBox status.
 * @param   paCommands      Pointer to an array of command descriptors
 *                          as given to DBGCRegisterCommands().
 * @param   cCommands       Number of commands.
 */
DBGDECL(int)    DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands);


/**
 * Spawns a new thread with a TCP based debugging console service.
 *
 * @returns VBox status.
 * @param   pVM         VM handle.
 * @param   ppvData     Where to store the pointer to instance data.
 */
DBGDECL(int)    DBGCTcpCreate(PVM pVM, void **ppvUser);

/**
 * Terminates any running TCP base debugger console service.
 *
 * @returns VBox status.
 * @param   pVM         VM handle.
 * @param   pvData      Instance data set by DBGCTcpCreate().
 */
DBGDECL(int)    DBGCTcpTerminate(PVM pVM, void *pvData);


/** @defgroup grp_dbgc_plug_in      The DBGC Plug-in Interface
 * @{
 */

/** The plug-in module name prefix. */
#define DBGC_PLUG_IN_PREFIX         "DBGCPlugIn"

/** The name of the plug-in entry point (FNDBGCPLUGIN) */
#define DBGC_PLUG_IN_ENTRYPOINT     "DBGCPlugInEntry"

/**
 * DBGC plug-in operations.
 */
typedef enum DBGCPLUGINOP
{
    /** The usual invalid first value. */
    DBGCPLUGINOP_INVALID,
    /** Initialize the plug-in, register all the stuff.
     * The plug-in will be unloaded on failure.
     * uArg: The VirtualBox version (major+minor). */
    DBGCPLUGINOP_INIT,
    /** Terminate the plug-ing, deregister all the stuff.
     * The plug-in will be unloaded after this call regardless of the return
     * code. */
    DBGCPLUGINOP_TERM,
    /** The usual 32-bit hack. */
    DBGCPLUGINOP_32BIT_HACK = 0x7fffffff
} DBGCPLUGINOP;

/**
 * DBGC plug-in main entry point.
 *
 * @returns VBox status code.
 *
 * @param   enmOperation    The operation.
 * @param   pVM             The VM handle. This may be NULL.
 * @param   uArg            Extra argument.
 */
typedef DECLCALLBACK(int) FNDBGCPLUGIN(DBGCPLUGINOP enmOperation, PVM pVM, uintptr_t uArg);
/** Pointer to a FNDBGCPLUGIN. */
typedef FNDBGCPLUGIN *PFNDBGCPLUGIN;

/** @copydoc FNDBGCPLUGIN */
DECLEXPORT(int) DBGCPlugInEntry(DBGCPLUGINOP enmOperation, PVM pVM, uintptr_t uArg);

#endif /* IN_RING3 */

/** @} */


RT_C_DECLS_END

#endif
