/* $Id: DBGCBuiltInSymbols.cpp $ */
/** @file
 * DBGC - Debugger Console, Built-In Symbols.
 */

/*
 * Copyright (C) 2006-2010 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.
 */

/*******************************************************************************
*   Header Files                                                               *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_DBGC
#include <VBox/dbg.h>
#include <VBox/vmm/dbgf.h>
#include <VBox/vmm/vm.h>
#include <VBox/vmm/vmm.h>
#include <VBox/vmm/mm.h>
#include <VBox/vmm/pgm.h>
#include <VBox/vmm/selm.h>
#include <VBox/dis.h>
#include <VBox/param.h>
#include <VBox/err.h>
#include <VBox/log.h>

#include <iprt/alloc.h>
#include <iprt/alloca.h>
#include <iprt/string.h>
#include <iprt/assert.h>
#include <iprt/ctype.h>

#include <stdlib.h>
#include <stdio.h>

#include "DBGCInternal.h"


/*******************************************************************************
*   Internal Functions                                                         *
*******************************************************************************/
static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue);


/*******************************************************************************
*   Global Variables                                                           *
*******************************************************************************/
/** Register symbol uUser value.
 * @{
 */
/** If set the register set is the hypervisor and not the guest one. */
#define SYMREG_FLAGS_HYPER      RT_BIT(20)
/** If set a far conversion of the value will use the high 16 bit for the selector.
 * If clear the low 16 bit will be used. */
#define SYMREG_FLAGS_HIGH_SEL   RT_BIT(21)
/** The shift value to calc the size of a register symbol from the uUser value. */
#define SYMREG_SIZE_SHIFT       (24)
/** Get the offset */
#define SYMREG_OFFSET(uUser)    (uUser & ((1 << 20) - 1))
/** Get the size. */
#define SYMREG_SIZE(uUser)      ((uUser >> SYMREG_SIZE_SHIFT) & 0xff)
/** 1 byte. */
#define SYMREG_SIZE_1           ( 1 << SYMREG_SIZE_SHIFT)
/** 2 byte. */
#define SYMREG_SIZE_2           ( 2 << SYMREG_SIZE_SHIFT)
/** 4 byte. */
#define SYMREG_SIZE_4           ( 4 << SYMREG_SIZE_SHIFT)
/** 6 byte. */
#define SYMREG_SIZE_6           ( 6 << SYMREG_SIZE_SHIFT)
/** 8 byte. */
#define SYMREG_SIZE_8           ( 8 << SYMREG_SIZE_SHIFT)
/** 10 bytes. */
#define SYMREG_SIZE_10          (10 << SYMREG_SIZE_SHIFT)
/** 12 byte. */
#define SYMREG_SIZE_12          (12 << SYMREG_SIZE_SHIFT)
/** 16 byte. */
#define SYMREG_SIZE_16          (16 << SYMREG_SIZE_SHIFT)
/** @} */

/** Builtin Symbols.
 * ASSUMES little endian register representation!
 */
static const DBGCSYM    g_aSyms[] =
{
    { "rax",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, rax)      | SYMREG_SIZE_8 },
    { "eax",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_4 },
    { "ax",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_2 },
    { "al",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_1 },
    { "ah",     dbgcSymGetReg,          dbgcSymSetReg,      (offsetof(CPUMCTX, eax) + 1)| SYMREG_SIZE_1 },

    { "rbx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, rbx)      | SYMREG_SIZE_8 },
    { "ebx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_4 },
    { "bx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_2 },
    { "bl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_1 },
    { "bh",     dbgcSymGetReg,          dbgcSymSetReg,      (offsetof(CPUMCTX, ebx) + 1)| SYMREG_SIZE_1 },

    { "rcx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_8 },
    { "ecx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_4 },
    { "cx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_2 },
    { "cl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_1 },
    { "ch",     dbgcSymGetReg,          dbgcSymSetReg,      (offsetof(CPUMCTX, ecx) + 1)| SYMREG_SIZE_1 },

    { "rdx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, rdx)      | SYMREG_SIZE_8 },
    { "edx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_4 },
    { "dx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_2 },
    { "dl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_1 },
    { "dh",     dbgcSymGetReg,          dbgcSymSetReg,      (offsetof(CPUMCTX, edx) + 1)| SYMREG_SIZE_1 },

    { "rdi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, rdi)      | SYMREG_SIZE_8 },
    { "edi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_4 },
    { "di",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_2 },
    { "dil",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_1 },

    { "rsi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, rsi)      | SYMREG_SIZE_8 },
    { "esi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_4 },
    { "si",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_2 },
    { "sil",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_1 },

    { "rbp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, rbp)      | SYMREG_SIZE_8 },
    { "ebp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_4 },
    { "bp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_2 },
    { "bpl",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_1 },

    { "rsp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, rsp)      | SYMREG_SIZE_8 },
    { "esp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_4 },
    { "sp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_2 },
    { "spl",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_1 },

    { "r8",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r8)       | SYMREG_SIZE_8 },
    { "r9",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r9)       | SYMREG_SIZE_8 },
    { "r10",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r10)      | SYMREG_SIZE_8 },
    { "r11",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r11)      | SYMREG_SIZE_8 },
    { "r12",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r12)      | SYMREG_SIZE_8 },
    { "r13",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r13)      | SYMREG_SIZE_8 },
    { "r14",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r14)      | SYMREG_SIZE_8 },
    { "r15",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r15)      | SYMREG_SIZE_8 },

    { "r8d",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r8)       | SYMREG_SIZE_4 },
    { "r9d",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r9)       | SYMREG_SIZE_4 },
    { "r10d",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r10)      | SYMREG_SIZE_4 },
    { "r11d",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r11)      | SYMREG_SIZE_4 },
    { "r12d",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r12)      | SYMREG_SIZE_4 },
    { "r13d",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r13)      | SYMREG_SIZE_4 },
    { "r14d",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r14)      | SYMREG_SIZE_4 },
    { "r15d",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r15)      | SYMREG_SIZE_4 },

    { "r8w",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r8)       | SYMREG_SIZE_2 },
    { "r9w",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r9)       | SYMREG_SIZE_2 },
    { "r10w",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r10)      | SYMREG_SIZE_2 },
    { "r11w",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r11)      | SYMREG_SIZE_2 },
    { "r12w",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r12)      | SYMREG_SIZE_2 },
    { "r13w",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r13)      | SYMREG_SIZE_2 },
    { "r14w",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r14)      | SYMREG_SIZE_2 },
    { "r15w",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r15)      | SYMREG_SIZE_2 },

    { "r8b",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r8)       | SYMREG_SIZE_1 },
    { "r9b",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r9)       | SYMREG_SIZE_1 },
    { "r10b",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r10)      | SYMREG_SIZE_1 },
    { "r11b",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r11)      | SYMREG_SIZE_1 },
    { "r12b",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r12)      | SYMREG_SIZE_1 },
    { "r13b",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r13)      | SYMREG_SIZE_1 },
    { "r14b",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r14)      | SYMREG_SIZE_1 },
    { "r15b",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, r15)      | SYMREG_SIZE_1 },

    { "rip",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, rip)      | SYMREG_SIZE_8 },
    { "eip",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_4 },
    { "ip",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_2 },

    { "rfl",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, rflags)   | SYMREG_SIZE_8 },
    { "rflags", dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, rflags)   | SYMREG_SIZE_8 },
    { "efl",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 },
    { "eflags", dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 },
    { "fl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 },
    { "flags",  dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 },

    { "cs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cs)       | SYMREG_SIZE_2 },
    { "ds",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ds)       | SYMREG_SIZE_2 },
    { "es",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, es)       | SYMREG_SIZE_2 },
    { "fs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, fs)       | SYMREG_SIZE_2 },
    { "gs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gs)       | SYMREG_SIZE_2 },
    { "ss",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ss)       | SYMREG_SIZE_2 },

    { "cr0",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr0)      | SYMREG_SIZE_8 },
    { "cr2",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr2)      | SYMREG_SIZE_8 },
    { "cr3",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr3)      | SYMREG_SIZE_8 },
    { "cr4",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr4)      | SYMREG_SIZE_8 },

    { "tr",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, tr)       | SYMREG_SIZE_2 },
    { "ldtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ldtr)     | SYMREG_SIZE_2 },

    { "gdtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gdtr)     | SYMREG_SIZE_10 },
    { "gdtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.cbGdt)| SYMREG_SIZE_2 },
    { "gdtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.pGdt)| SYMREG_SIZE_8 },

    { "idtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, idtr)     | SYMREG_SIZE_10 },
    { "idtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.cbIdt)| SYMREG_SIZE_2 },
    { "idtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.pIdt)| SYMREG_SIZE_8 },

    /* hypervisor */

    {".eax",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    {".ax",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    {".al",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    {".ah",     dbgcSymGetReg,          dbgcSymSetReg,      (offsetof(CPUMCTX, eax) + 1)| SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },

    {".ebx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    {".bx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    {".bl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    {".bh",     dbgcSymGetReg,          dbgcSymSetReg,      (offsetof(CPUMCTX, ebx) + 1)| SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },

    {".ecx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    {".cx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    {".cl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    {".ch",     dbgcSymGetReg,          dbgcSymSetReg,      (offsetof(CPUMCTX, ecx) + 1)| SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },

    {".edx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    {".dx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    {".dl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    {".dh",     dbgcSymGetReg,          dbgcSymSetReg,      (offsetof(CPUMCTX, edx) + 1)| SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },

    {".edi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    {".di",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },

    {".esi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    {".si",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },

    {".ebp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    {".bp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },

    {".esp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    {".sp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },

    {".eip",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    {".ip",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },

    {".efl",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    {".eflags", dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    {".fl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    {".flags",  dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },

    {".cs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cs)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    {".ds",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ds)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    {".es",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, es)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    {".fs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, fs)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    {".gs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gs)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    {".ss",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ss)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },

    {".cr0",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr0)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    {".cr2",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr2)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    {".cr3",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr3)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    {".cr4",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr4)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },

    {".tr",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, tr)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    {".ldtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ldtr)     | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },

    {".gdtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gdtr)     | SYMREG_SIZE_10 | SYMREG_FLAGS_HYPER },
    {".gdtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.cbGdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER },
    {".gdtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.pGdt)| SYMREG_SIZE_8 | SYMREG_FLAGS_HYPER },

    {".idtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, idtr)     | SYMREG_SIZE_10 | SYMREG_FLAGS_HYPER },
    {".idtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.cbIdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER },
    {".idtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.pIdt)| SYMREG_SIZE_8 | SYMREG_FLAGS_HYPER },

};



/**
 * Get builtin register symbol.
 *
 * The uUser is special for these symbol descriptors. See the SYMREG_* \#defines.
 *
 * @returns 0 on success.
 * @returns VBox evaluation / parsing error code on failure.
 *          The caller does the bitching.
 * @param   pSymDesc    Pointer to the symbol descriptor.
 * @param   pCmdHlp     Pointer to the command callback structure.
 * @param   enmType     The result type.
 * @param   pResult     Where to store the result.
 */
static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult)
{
    LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName));

    /*
     * pVM is required.
     */
    PDBGC       pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    Assert(pDbgc->pVM);

    /*
     * Get the right CPU context.
     */
    PVMCPU      pVCpu = VMMGetCpuById(pDbgc->pVM, pDbgc->idCpu);
    PCPUMCTX    pCtx;
    int         rc;
    if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER))
    {
        pCtx = CPUMQueryGuestCtxPtr(pVCpu);
        rc = VINF_SUCCESS;
    }
    else
        rc = CPUMQueryHyperCtxPtr(pVCpu, &pCtx);
    if (RT_FAILURE(rc))
        return rc;

    /*
     * Get the value.
     */
    void       *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser);
    uint64_t    u64;
    switch (SYMREG_SIZE(pSymDesc->uUser))
    {
        case 1: u64 = *(uint8_t *)pvValue; break;
        case 2: u64 = *(uint16_t *)pvValue; break;
        case 4: u64 = *(uint32_t *)pvValue; break;
        case 6: u64 = *(uint32_t *)pvValue | ((uint64_t)*(uint16_t *)((char *)pvValue + sizeof(uint32_t)) << 32); break;
        case 8: u64 = *(uint64_t *)pvValue; break;
        default:
            return VERR_PARSE_NOT_IMPLEMENTED;
    }

    /*
     * Construct the desired result.
     */
    if (enmType == DBGCVAR_TYPE_ANY)
        enmType = DBGCVAR_TYPE_NUMBER;
    pResult->pDesc          = NULL;
    pResult->pNext          = NULL;
    pResult->enmType        = enmType;
    pResult->enmRangeType   = DBGCVAR_RANGE_NONE;
    pResult->u64Range       = 0;

    switch (enmType)
    {
        case DBGCVAR_TYPE_GC_FLAT:
            pResult->u.GCFlat = (RTGCPTR)u64;
            break;

        case DBGCVAR_TYPE_GC_FAR:
            switch (SYMREG_SIZE(pSymDesc->uUser))
            {
                case 4:
                    if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
                    {
                        pResult->u.GCFar.off = (uint16_t)u64;
                        pResult->u.GCFar.sel = (uint16_t)(u64 >> 16);
                    }
                    else
                    {
                        pResult->u.GCFar.sel = (uint16_t)u64;
                        pResult->u.GCFar.off = (uint16_t)(u64 >> 16);
                    }
                    break;
                case 6:
                    if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
                    {
                        pResult->u.GCFar.off = (uint32_t)u64;
                        pResult->u.GCFar.sel = (uint16_t)(u64 >> 32);
                    }
                    else
                    {
                        pResult->u.GCFar.sel = (uint32_t)u64;
                        pResult->u.GCFar.off = (uint16_t)(u64 >> 32);
                    }
                    break;

                default:
                    return VERR_PARSE_BAD_RESULT_TYPE;
            }
            break;

        case DBGCVAR_TYPE_GC_PHYS:
            pResult->u.GCPhys = (RTGCPHYS)u64;
            break;

        case DBGCVAR_TYPE_HC_FLAT:
            pResult->u.pvHCFlat = (void *)(uintptr_t)u64;
            break;

        case DBGCVAR_TYPE_HC_FAR:
            switch (SYMREG_SIZE(pSymDesc->uUser))
            {
                case 4:
                    if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
                    {
                        pResult->u.HCFar.off = (uint16_t)u64;
                        pResult->u.HCFar.sel = (uint16_t)(u64 >> 16);
                    }
                    else
                    {
                        pResult->u.HCFar.sel = (uint16_t)u64;
                        pResult->u.HCFar.off = (uint16_t)(u64 >> 16);
                    }
                    break;
                case 6:
                    if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
                    {
                        pResult->u.HCFar.off = (uint32_t)u64;
                        pResult->u.HCFar.sel = (uint16_t)(u64 >> 32);
                    }
                    else
                    {
                        pResult->u.HCFar.sel = (uint32_t)u64;
                        pResult->u.HCFar.off = (uint16_t)(u64 >> 32);
                    }
                    break;

                default:
                    return VERR_PARSE_BAD_RESULT_TYPE;
            }
            break;

        case DBGCVAR_TYPE_HC_PHYS:
            pResult->u.GCPhys = (RTGCPHYS)u64;
            break;

        case DBGCVAR_TYPE_NUMBER:
            pResult->u.u64Number = u64;
            break;

        case DBGCVAR_TYPE_STRING:
        case DBGCVAR_TYPE_UNKNOWN:
        default:
            return VERR_PARSE_BAD_RESULT_TYPE;

    }

    return 0;
}


/**
 * Set builtin register symbol.
 *
 * The uUser is special for these symbol descriptors. See the SYMREG_* #defines.
 *
 * @returns 0 on success.
 * @returns VBox evaluation / parsing error code on failure.
 *          The caller does the bitching.
 * @param   pSymDesc    Pointer to the symbol descriptor.
 * @param   pCmdHlp     Pointer to the command callback structure.
 * @param   pValue      The value to assign the symbol.
 */
static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue)
{
    LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName));

    /*
     * pVM is required.
     */
    PDBGC       pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    Assert(pDbgc->pVM);

    /*
     * Get the right CPU context.
     */
    PVMCPU      pVCpu = VMMGetCpuById(pDbgc->pVM, pDbgc->idCpu);
    PCPUMCTX    pCtx;
    int         rc;
    if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER))
    {
        pCtx = CPUMQueryGuestCtxPtr(pVCpu);
        rc = VINF_SUCCESS;
    }
    else
        rc = CPUMQueryHyperCtxPtr(pVCpu, &pCtx);
    if (RT_FAILURE(rc))
        return rc;

    /*
     * Check the new value.
     */
    if (pValue->enmType != DBGCVAR_TYPE_NUMBER)
        return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;

    /*
     * Set the value.
     */
    void       *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser);
    switch (SYMREG_SIZE(pSymDesc->uUser))
    {
        case 1:
            *(uint8_t *)pvValue  = (uint8_t)pValue->u.u64Number;
            break;
        case 2:
            *(uint16_t *)pvValue = (uint16_t)pValue->u.u64Number;
            break;
        case 4:
            *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number;
            break;
        case 6:
            *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number;
            ((uint16_t *)pvValue)[3] = (uint16_t)(pValue->u.u64Number >> 32);
            break;
        case 8:
            *(uint64_t *)pvValue = pValue->u.u64Number;
            break;
        default:
            return VERR_PARSE_NOT_IMPLEMENTED;
    }

    return VINF_SUCCESS;
}


/**
 * Finds a builtin symbol.
 * @returns Pointer to symbol descriptor on success.
 * @returns NULL on failure.
 * @param   pDbgc       The debug console instance.
 * @param   pszSymbol   The symbol name.
 */
PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol)
{
    for (unsigned iSym = 0; iSym < RT_ELEMENTS(g_aSyms); iSym++)
        if (!strcmp(pszSymbol, g_aSyms[iSym].pszName))
            return &g_aSyms[iSym];

    /** @todo externally registered symbols. */
    NOREF(pDbgc);
    return NULL;
}

