Index: /trunk/src/VBox/Debugger/DBGCCmdWorkers.cpp
===================================================================
--- /trunk/src/VBox/Debugger/DBGCCmdWorkers.cpp	(revision 87787)
+++ /trunk/src/VBox/Debugger/DBGCCmdWorkers.cpp	(revision 87788)
@@ -228,2 +228,141 @@
 }
 
+
+
+
+//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
+//
+//
+//      F l o w T r a c e   M a n a g e m e n t
+//
+//
+//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
+
+
+
+/**
+ * Returns the trace flow module matching the given id or NULL if not found.
+ *
+ * @returns Pointer to the trace flow module or NULL if not found.
+ * @param   pDbgc         The DBGC instance.
+ * @param   iTraceFlowMod The trace flow module identifier.
+ */
+DECLHIDDEN(PDBGCTFLOW) dbgcFlowTraceModGet(PDBGC pDbgc, uint32_t iTraceFlowMod)
+{
+    PDBGCTFLOW pIt;
+    RTListForEach(&pDbgc->LstTraceFlowMods, pIt, DBGCTFLOW, NdTraceFlow)
+    {
+        if (pIt->iTraceFlowMod == iTraceFlowMod)
+            return pIt;
+    }
+
+    return NULL;
+}
+
+
+/**
+ * Inserts the given trace flow module into the list.
+ *
+ * @returns nothing.
+ * @param   pDbgc         The DBGC instance.
+ * @param   pTraceFlow    The trace flow module.
+ */
+static void dbgcFlowTraceModInsert(PDBGC pDbgc, PDBGCTFLOW pTraceFlow)
+{
+    PDBGCTFLOW pIt = RTListGetLast(&pDbgc->LstTraceFlowMods, DBGCTFLOW, NdTraceFlow);
+
+    if (   !pIt
+        || pIt->iTraceFlowMod < pTraceFlow->iTraceFlowMod)
+        RTListAppend(&pDbgc->LstTraceFlowMods, &pTraceFlow->NdTraceFlow);
+    else
+    {
+        RTListForEach(&pDbgc->LstTraceFlowMods, pIt, DBGCTFLOW, NdTraceFlow)
+        {
+            if (pIt->iTraceFlowMod < pTraceFlow->iTraceFlowMod)
+            {
+                RTListNodeInsertBefore(&pIt->NdTraceFlow, &pTraceFlow->NdTraceFlow);
+                break;
+            }
+        }
+    }
+}
+
+
+/**
+ * Returns the smallest free flow trace mod identifier.
+ *
+ * @returns Free flow trace mod identifier.
+ * @param   pDbgc         The DBGC instance.
+ */
+static uint32_t dbgcFlowTraceModIdFindFree(PDBGC pDbgc)
+{
+    uint32_t iId = 0;
+
+    PDBGCTFLOW pIt;
+    RTListForEach(&pDbgc->LstTraceFlowMods, pIt, DBGCTFLOW, NdTraceFlow)
+    {
+        PDBGCTFLOW pNext = RTListGetNext(&pDbgc->LstTraceFlowMods, pIt, DBGCTFLOW, NdTraceFlow);
+        if (   (   pNext
+                && pIt->iTraceFlowMod + 1 != pNext->iTraceFlowMod)
+            || !pNext)
+        {
+            iId = pIt->iTraceFlowMod + 1;
+            break;
+        }
+    }
+
+    return iId;
+}
+
+
+/**
+ * Adds a flow trace module to the debugger console.
+ *
+ * @returns VBox status code.
+ * @param   pDbgc         The DBGC instance.
+ * @param   hFlowTraceMod The flow trace module to add.
+ * @param   hFlow         The control flow graph to add.
+ * @param   piId          Where to store the ID of the module on success.
+ */
+DECLHIDDEN(int) dbgcFlowTraceModAdd(PDBGC pDbgc, DBGFFLOWTRACEMOD hFlowTraceMod, DBGFFLOW hFlow, uint32_t *piId)
+{
+    /*
+     * Add the module.
+     */
+    PDBGCTFLOW pTraceFlow = (PDBGCTFLOW)RTMemAlloc(sizeof(DBGCTFLOW));
+    if (!pTraceFlow)
+        return VERR_NO_MEMORY;
+
+    pTraceFlow->hTraceFlowMod = hFlowTraceMod;
+    pTraceFlow->hFlow         = hFlow;
+    pTraceFlow->iTraceFlowMod = dbgcFlowTraceModIdFindFree(pDbgc);
+    dbgcFlowTraceModInsert(pDbgc, pTraceFlow);
+
+    *piId = pTraceFlow->iTraceFlowMod;
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Deletes a breakpoint.
+ *
+ * @returns VBox status code.
+ * @param   pDbgc       The DBGC instance.
+ * @param   iTraceFlowMod The trace flow module identifier.
+ */
+DECLHIDDEN(int) dbgcFlowTraceModDelete(PDBGC pDbgc, uint32_t iFlowTraceMod)
+{
+    int rc = VINF_SUCCESS;
+    PDBGCTFLOW pTraceFlow = dbgcFlowTraceModGet(pDbgc, iFlowTraceMod);
+    if (pTraceFlow)
+    {
+        RTListNodeRemove(&pTraceFlow->NdTraceFlow);
+        RTMemFree(pTraceFlow);
+    }
+    else
+        rc = VERR_DBGC_BP_NOT_FOUND;
+
+    return rc;
+}
+
Index: /trunk/src/VBox/Debugger/DBGCEmulateCodeView.cpp
===================================================================
--- /trunk/src/VBox/Debugger/DBGCEmulateCodeView.cpp	(revision 87787)
+++ /trunk/src/VBox/Debugger/DBGCEmulateCodeView.cpp	(revision 87788)
@@ -23,4 +23,5 @@
 #include <VBox/dbg.h>
 #include <VBox/vmm/dbgf.h>
+#include <VBox/vmm/dbgfflowtrace.h>
 #include <VBox/vmm/pgm.h>
 #include <VBox/vmm/cpum.h>
@@ -86,4 +87,9 @@
 static FNDBGCCMD dbgcCmdUnassemble;
 static FNDBGCCMD dbgcCmdUnassembleCfg;
+static FNDBGCCMD dbgcCmdTraceFlowClear;
+static FNDBGCCMD dbgcCmdTraceFlowDisable;
+static FNDBGCCMD dbgcCmdTraceFlowEnable;
+static FNDBGCCMD dbgcCmdTraceFlowPrint;
+static FNDBGCCMD dbgcCmdTraceFlowReset;
 
 
@@ -371,4 +377,35 @@
 };
 
+/** 'tflowc' arguments. */
+static const DBGCVARDESC    g_aArgTraceFlowClear[] =
+{
+    /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
+    {  0,           ~0U,        DBGCVAR_CAT_NUMBER,     0,                              "#tf",          "Trace flow module number." },
+    {  0,           1,          DBGCVAR_CAT_STRING,     0,                              "all",          "All trace flow modules." },
+};
+
+/** 'tflowd' arguments. */
+static const DBGCVARDESC    g_aArgTraceFlowDisable[] =
+{
+    /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
+    {  0,           ~0U,        DBGCVAR_CAT_NUMBER,     0,                              "#tf",          "Trace flow module number." },
+    {  0,           1,          DBGCVAR_CAT_STRING,     0,                              "all",          "All trace flow modules." },
+};
+
+/** 'tflowe' arguments. */
+static const DBGCVARDESC    g_aArgTraceFlowEnable[] =
+{
+    /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
+    {  0,           1,          DBGCVAR_CAT_POINTER,       0,                           "address",      "Address where to start tracing." },
+    {  0,           1,          DBGCVAR_CAT_OPTION_NUMBER, 0,                           "<Hits>",       "Maximum number of hits before the module is disabled." }
+};
+
+/** 'tflowp', 'tflowr' arguments. */
+static const DBGCVARDESC    g_aArgTraceFlowPrintReset[] =
+{
+    /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
+    {  0,           ~0U,        DBGCVAR_CAT_NUMBER,     0,                              "#tf",          "Trace flow module number." },
+    {  0,           1,          DBGCVAR_CAT_STRING,     0,                              "all",          "All trace flow modules." },
+};
 
 /** Command descriptors for the CodeView / WinDbg emulation.
@@ -471,4 +508,9 @@
     { "sxr",        0,        0,        &g_aArgEventCtrlOpt[0], RT_ELEMENTS(g_aArgEventCtrlOpt), 0,  dbgcCmdEventCtrlReset, "",                    "Reset the settings to default for exceptions, exits and other events. All if no filter is specified." },
     { "t",          0,        2,        &g_aArgStepTrace[0], RT_ELEMENTS(g_aArgStepTrace),  0,       dbgcCmdStepTrace,   "[count] [cmds]",       "Trace ." },
+    { "tflowc",     1,       ~0U,       &g_aArgTraceFlowClear[0],   RT_ELEMENTS(g_aArgTraceFlowClear),   0, dbgcCmdTraceFlowClear,   "all | <tf#> [tf# []]", "Clears trace execution flow for the given method." },
+    { "tflowd",     0,        1,        &g_aArgTraceFlowDisable[0], RT_ELEMENTS(g_aArgTraceFlowDisable), 0, dbgcCmdTraceFlowDisable, "all | <tf#> [tf# []]", "Disables trace execution flow for the given method." },
+    { "tflowe",     0,        2,        &g_aArgTraceFlowEnable[0],  RT_ELEMENTS(g_aArgTraceFlowEnable),  0, dbgcCmdTraceFlowEnable,  "<addr> <hits>",        "Enable trace execution flow of the given method." },
+    { "tflowp",     0,        1,        &g_aArgTraceFlowPrintReset[0],   RT_ELEMENTS(g_aArgTraceFlowPrintReset),   0, dbgcCmdTraceFlowPrint,   "all | <tf#> [tf# []]", "Prints the collected trace data of the given method." },
+    { "tflowr",     0,        1,        &g_aArgTraceFlowPrintReset[0],   RT_ELEMENTS(g_aArgTraceFlowPrintReset),   0, dbgcCmdTraceFlowReset,   "all | <tf#> [tf# []]", "Resets the collected trace data of the given trace flow module." },
     { "tr",         0,        0,        NULL,               0,                              0,       dbgcCmdStepTraceToggle, "",                 "Toggle displaying registers for tracing & stepping (no code executed)." },
     { "ta",         1,        1,        &g_aArgStepTraceTo[0], RT_ELEMENTS(g_aArgStepTraceTo), 0,    dbgcCmdStepTraceTo, "<addr> [count] [cmds]","Trace to the given address." },
@@ -6251,4 +6293,480 @@
 
 
+/**
+ * @callback_method_impl{FNDBGCCMD, The 'tflowc' (clear trace flow) command.}
+ */
+static DECLCALLBACK(int) dbgcCmdTraceFlowClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
+{
+    DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
+
+    /*
+     * Enumerate the arguments.
+     */
+    PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
+    int     rc    = VINF_SUCCESS;
+    for (unsigned iArg = 0; iArg < cArgs && RT_SUCCESS(rc); iArg++)
+    {
+        if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
+        {
+            /* one */
+            uint32_t iFlowTraceMod = (uint32_t)paArgs[iArg].u.u64Number;
+            if (iFlowTraceMod == paArgs[iArg].u.u64Number)
+            {
+                PDBGCTFLOW pFlowTrace = dbgcFlowTraceModGet(pDbgc, iFlowTraceMod);
+                if (pFlowTrace)
+                {
+                    rc = DBGFR3FlowTraceModRelease(pFlowTrace->hTraceFlowMod);
+                    if (RT_FAILURE(rc))
+                        rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3FlowTraceModRelease failed for flow trace module %#x", iFlowTraceMod);
+                    rc = DBGFR3FlowRelease(pFlowTrace->hFlow);
+                    if (RT_FAILURE(rc))
+                        rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3FlowRelease failed for flow trace module %#x", iFlowTraceMod);
+                    dbgcFlowTraceModDelete(pDbgc, iFlowTraceMod);
+                }
+                else
+                    rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_NOT_FOUND, "Flow trace module %#x doesn't exist", iFlowTraceMod);
+            }
+            else
+                rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Flow trace mod id %RX64 is too large", paArgs[iArg].u.u64Number);
+        }
+        else if (!strcmp(paArgs[iArg].u.pszString, "all"))
+        {
+            /* all */
+            PDBGCTFLOW pIt, pItNext;
+            RTListForEachSafe(&pDbgc->LstTraceFlowMods, pIt, pItNext, DBGCTFLOW, NdTraceFlow)
+            {
+                int rc2 = DBGFR3FlowTraceModRelease(pIt->hTraceFlowMod);
+                if (RT_FAILURE(rc2))
+                    rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc2, "DBGFR3FlowTraceModDisable failed for flow trace module %#x", pIt->iTraceFlowMod);
+                dbgcFlowTraceModDelete(pDbgc, pIt->iTraceFlowMod);
+            }
+        }
+        else
+            rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid argument '%s'", paArgs[iArg].u.pszString);
+    }
+    return rc;
+}
+
+
+/**
+ * @callback_method_impl{FNDBGCCMD, The 'tflowd' (disable trace flow) command.}
+ */
+static DECLCALLBACK(int) dbgcCmdTraceFlowDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
+{
+    /*
+     * Enumerate the arguments.
+     */
+    RT_NOREF1(pUVM);
+    int rc = VINF_SUCCESS;
+    PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
+    for (unsigned iArg = 0; iArg < cArgs && RT_SUCCESS(rc); iArg++)
+    {
+        if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
+        {
+            /* one */
+            uint32_t iFlowTraceMod = (uint32_t)paArgs[iArg].u.u64Number;
+            if (iFlowTraceMod == paArgs[iArg].u.u64Number)
+            {
+                PDBGCTFLOW pFlowTrace = dbgcFlowTraceModGet(pDbgc, iFlowTraceMod);
+                if (pFlowTrace)
+                {
+                    rc = DBGFR3FlowTraceModDisable(pFlowTrace->hTraceFlowMod);
+                    if (RT_FAILURE(rc))
+                        rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3FlowTraceModDisable failed for flow trace module %#x", iFlowTraceMod);
+                }
+                else
+                    rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_NOT_FOUND, "Flow trace module %#x doesn't exist", iFlowTraceMod);
+            }
+            else
+                rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Breakpoint id %RX64 is too large", paArgs[iArg].u.u64Number);
+        }
+        else if (!strcmp(paArgs[iArg].u.pszString, "all"))
+        {
+            /* all */
+            PDBGCTFLOW pIt;
+            RTListForEach(&pDbgc->LstTraceFlowMods, pIt, DBGCTFLOW, NdTraceFlow)
+            {
+                int rc2 = DBGFR3FlowTraceModDisable(pIt->hTraceFlowMod);
+                if (RT_FAILURE(rc2))
+                    rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc2, "DBGFR3FlowTraceModDisable failed for flow trace module %#x",
+                                          pIt->iTraceFlowMod);
+            }
+        }
+        else
+            rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid argument '%s'", paArgs[iArg].u.pszString);
+    }
+    return rc;
+}
+
+
+/**
+ * @callback_method_impl{FNDBGCCMD, The 'tflowe' (enable trace flow) command.}
+ */
+static DECLCALLBACK(int) dbgcCmdTraceFlowEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
+{
+    PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
+
+    /*
+     * Validate input.
+     */
+    DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
+    DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, -1, cArgs <= 2);
+    DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs == 0 || DBGCVAR_ISPOINTER(paArgs[0].enmType));
+
+    if (!cArgs && !DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType))
+        return DBGCCmdHlpFail(pCmdHlp, pCmd, "Don't know where to start disassembling");
+
+    /*
+     * Check the desired mode.
+     */
+    unsigned fFlags =  DBGF_DISAS_FLAGS_UNPATCHED_BYTES | DBGF_DISAS_FLAGS_ANNOTATE_PATCHED | DBGF_DISAS_FLAGS_DEFAULT_MODE;
+
+    /** @todo should use DBGFADDRESS for everything */
+
+    /*
+     * Find address.
+     */
+    if (!cArgs)
+    {
+        if (!DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType))
+        {
+            /** @todo Batch query CS, RIP, CPU mode and flags. */
+            PVMCPU pVCpu = VMMR3GetCpuByIdU(pUVM, pDbgc->idCpu);
+            if (CPUMIsGuestIn64BitCode(pVCpu))
+            {
+                pDbgc->DisasmPos.enmType    = DBGCVAR_TYPE_GC_FLAT;
+                pDbgc->SourcePos.u.GCFlat   = CPUMGetGuestRIP(pVCpu);
+            }
+            else
+            {
+                pDbgc->DisasmPos.enmType     = DBGCVAR_TYPE_GC_FAR;
+                pDbgc->SourcePos.u.GCFar.off = CPUMGetGuestEIP(pVCpu);
+                pDbgc->SourcePos.u.GCFar.sel = CPUMGetGuestCS(pVCpu);
+                if (   (fFlags & DBGF_DISAS_FLAGS_MODE_MASK) == DBGF_DISAS_FLAGS_DEFAULT_MODE
+                    && (CPUMGetGuestEFlags(pVCpu) & X86_EFL_VM))
+                {
+                    fFlags &= ~DBGF_DISAS_FLAGS_MODE_MASK;
+                    fFlags |= DBGF_DISAS_FLAGS_16BIT_REAL_MODE;
+                }
+            }
+
+            fFlags |= DBGF_DISAS_FLAGS_CURRENT_GUEST;
+        }
+        else if ((fFlags & DBGF_DISAS_FLAGS_MODE_MASK) == DBGF_DISAS_FLAGS_DEFAULT_MODE && pDbgc->fDisasm)
+        {
+            fFlags &= ~DBGF_DISAS_FLAGS_MODE_MASK;
+            fFlags |= pDbgc->fDisasm & DBGF_DISAS_FLAGS_MODE_MASK;
+        }
+        pDbgc->DisasmPos.enmRangeType = DBGCVAR_RANGE_NONE;
+    }
+    else
+        pDbgc->DisasmPos = paArgs[0];
+    pDbgc->pLastPos = &pDbgc->DisasmPos;
+
+    /*
+     * Convert physical and host addresses to guest addresses.
+     */
+    RTDBGAS hDbgAs = pDbgc->hDbgAs;
+    int rc;
+    switch (pDbgc->DisasmPos.enmType)
+    {
+        case DBGCVAR_TYPE_GC_FLAT:
+        case DBGCVAR_TYPE_GC_FAR:
+            break;
+        case DBGCVAR_TYPE_GC_PHYS:
+            hDbgAs = DBGF_AS_PHYS;
+            /* fall thru */
+        case DBGCVAR_TYPE_HC_FLAT:
+        case DBGCVAR_TYPE_HC_PHYS:
+        {
+            DBGCVAR VarTmp;
+            rc = DBGCCmdHlpEval(pCmdHlp, &VarTmp, "%%(%Dv)", &pDbgc->DisasmPos);
+            if (RT_FAILURE(rc))
+                return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "failed to evaluate '%%(%Dv)'", &pDbgc->DisasmPos);
+            pDbgc->DisasmPos = VarTmp;
+            break;
+        }
+        default: AssertFailed(); break;
+    }
+
+    DBGFADDRESS CurAddr;
+    if (   (fFlags & DBGF_DISAS_FLAGS_MODE_MASK) == DBGF_DISAS_FLAGS_16BIT_REAL_MODE
+        && pDbgc->DisasmPos.enmType == DBGCVAR_TYPE_GC_FAR)
+        DBGFR3AddrFromFlat(pUVM, &CurAddr, ((uint32_t)pDbgc->DisasmPos.u.GCFar.sel << 4) + pDbgc->DisasmPos.u.GCFar.off);
+    else
+    {
+        rc = DBGCCmdHlpVarToDbgfAddr(pCmdHlp, &pDbgc->DisasmPos, &CurAddr);
+        if (RT_FAILURE(rc))
+            return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGCCmdHlpVarToDbgfAddr failed on '%Dv'", &pDbgc->DisasmPos);
+    }
+
+    DBGFFLOW hCfg;
+    rc = DBGFR3FlowCreate(pUVM, pDbgc->idCpu, &CurAddr, 0 /*cbDisasmMax*/,
+                          DBGF_FLOW_CREATE_F_TRY_RESOLVE_INDIRECT_BRANCHES, fFlags, &hCfg);
+    if (RT_SUCCESS(rc))
+    {
+        /* Create a probe. */
+        DBGFFLOWTRACEPROBE hFlowTraceProbe = NULL;
+        DBGFFLOWTRACEPROBE hFlowTraceProbeExit = NULL;
+        DBGFFLOWTRACEPROBEENTRY Entry;
+        DBGFFLOWTRACEMOD hFlowTraceMod = NULL;
+        uint32_t iTraceModId = 0;
+
+        RT_ZERO(Entry);
+        Entry.enmType = DBGFFLOWTRACEPROBEENTRYTYPE_DEBUGGER;
+
+        rc = DBGFR3FlowTraceProbeCreate(pUVM, NULL, &hFlowTraceProbe);
+        if (RT_SUCCESS(rc))
+            rc = DBGFR3FlowTraceProbeCreate(pUVM, NULL, &hFlowTraceProbeExit);
+        if (RT_SUCCESS(rc))
+            rc = DBGFR3FlowTraceProbeEntriesAdd(hFlowTraceProbeExit, &Entry, 1 /*cEntries*/);
+        if (RT_SUCCESS(rc))
+            rc = DBGFR3FlowTraceModCreateFromFlowGraph(pUVM, VMCPUID_ANY, hCfg, NULL,
+                                                       hFlowTraceProbe, hFlowTraceProbe,
+                                                       hFlowTraceProbeExit, &hFlowTraceMod);
+        if (RT_SUCCESS(rc))
+            rc = dbgcFlowTraceModAdd(pDbgc, hFlowTraceMod, hCfg, &iTraceModId);
+        if (RT_SUCCESS(rc))
+            rc = DBGFR3FlowTraceModEnable(hFlowTraceMod, 0, 0);
+        if (RT_SUCCESS(rc))
+            DBGCCmdHlpPrintf(pCmdHlp, "Enabled execution flow tracing %u at %RGv\n",
+                             iTraceModId, CurAddr.FlatPtr);
+
+        if (hFlowTraceProbe)
+            DBGFR3FlowTraceProbeRelease(hFlowTraceProbe);
+        if (hFlowTraceProbeExit)
+            DBGFR3FlowTraceProbeRelease(hFlowTraceProbeExit);
+    }
+    else
+        rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3FlowCreate failed on '%Dv'", &pDbgc->DisasmPos);
+
+    NOREF(pCmd);
+    return rc;
+}
+
+
+/**
+ * Enumerates and prints all records contained in the given flow tarce module.
+ *
+ * @returns VBox status code.
+ * @param   pCmd          The command.
+ * @param   pCmdHlp       The command helpers.
+ * @param   hFlowTraceMod The flow trace module to print.
+ * @param   hFlow         The control flow graph assoicated with the given module.
+ * @param   iFlowTraceMod The flow trace module identifier.
+ */
+static int dbgcCmdTraceFlowPrintOne(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, DBGFFLOWTRACEMOD hFlowTraceMod,
+                                    DBGFFLOW hFlow, uint32_t iFlowTraceMod)
+{
+    RT_NOREF(hFlow);
+
+    DBGFFLOWTRACEREPORT hFlowTraceReport;
+    int rc = DBGFR3FlowTraceModQueryReport(hFlowTraceMod, &hFlowTraceReport);
+    if (RT_SUCCESS(rc))
+    {
+        uint32_t cRecords = DBGFR3FlowTraceReportGetRecordCount(hFlowTraceReport);
+        DBGCCmdHlpPrintf(pCmdHlp, "Report for flow trace module %#x (%u records):\n",
+                         iFlowTraceMod, cRecords);
+
+        PDBGCFLOWBBDUMP paDumpBb = (PDBGCFLOWBBDUMP)RTMemTmpAllocZ(cRecords * sizeof(DBGCFLOWBBDUMP));
+        if (RT_LIKELY(paDumpBb))
+        {
+            /* Query the basic block referenced for each record and calculate the size. */
+            for (uint32_t i = 0; i < cRecords && RT_SUCCESS(rc); i++)
+            {
+                DBGFFLOWTRACERECORD hRec = NULL;
+                rc = DBGFR3FlowTraceReportQueryRecord(hFlowTraceReport, i, &hRec);
+                if (RT_SUCCESS(rc))
+                {
+                    DBGFADDRESS Addr;
+                    DBGFR3FlowTraceRecordGetAddr(hRec, &Addr);
+
+                    DBGFFLOWBB hFlowBb = NULL;
+                    rc = DBGFR3FlowQueryBbByAddress(hFlow, &Addr, &hFlowBb);
+                    if (RT_SUCCESS(rc))
+                        dbgcCmdUnassembleCfgDumpCalcBbSize(hFlowBb, &paDumpBb[i]);
+
+                    DBGFR3FlowTraceRecordRelease(hRec);
+                }
+            }
+
+            if (RT_SUCCESS(rc))
+            {
+                /* Calculate the ASCII screen dimensions and create one. */
+                uint32_t cchWidth = 0;
+                uint32_t cchHeight = 0;
+                for (unsigned i = 0; i < cRecords; i++)
+                {
+                    PDBGCFLOWBBDUMP pDumpBb = &paDumpBb[i];
+                    cchWidth = RT_MAX(cchWidth, pDumpBb->cchWidth);
+                    cchHeight += pDumpBb->cchHeight;
+
+                    /* Incomplete blocks don't have a successor. */
+                    if (DBGFR3FlowBbGetFlags(pDumpBb->hFlowBb) & DBGF_FLOW_BB_F_INCOMPLETE_ERR)
+                        continue;
+
+                    cchHeight += 2; /* For the arrow down to the next basic block. */
+                }
+
+
+                DBGCSCREEN hScreen = NULL;
+                rc = dbgcScreenAsciiCreate(&hScreen, cchWidth, cchHeight);
+                if (RT_SUCCESS(rc))
+                {
+                    uint32_t uY = 0;
+
+                    /* Dump the basic blocks and connections to the immediate successor. */
+                    for (unsigned i = 0; i < cRecords; i++)
+                    {
+                        paDumpBb[i].uStartX = (cchWidth - paDumpBb[i].cchWidth) / 2;
+                        paDumpBb[i].uStartY = uY;
+                        dbgcCmdUnassembleCfgDumpBb(&paDumpBb[i], hScreen);
+                        uY += paDumpBb[i].cchHeight;
+
+                        /* Incomplete blocks don't have a successor. */
+                        if (DBGFR3FlowBbGetFlags(paDumpBb[i].hFlowBb) & DBGF_FLOW_BB_F_INCOMPLETE_ERR)
+                            continue;
+
+                        if (DBGFR3FlowBbGetType(paDumpBb[i].hFlowBb) != DBGFFLOWBBENDTYPE_EXIT)
+                        {
+                            /* Draw the arrow down to the next block. */
+                            dbgcScreenAsciiDrawCharacter(hScreen, cchWidth / 2, uY,
+                                                         '|', DBGCSCREENCOLOR_BLUE_BRIGHT);
+                            uY++;
+                            dbgcScreenAsciiDrawCharacter(hScreen, cchWidth / 2, uY,
+                                                         'V', DBGCSCREENCOLOR_BLUE_BRIGHT);
+                            uY++;
+                        }
+                    }
+
+                    rc = dbgcScreenAsciiBlit(hScreen, dbgcCmdUnassembleCfgBlit, pCmdHlp, false /*fUseColor*/);
+                    dbgcScreenAsciiDestroy(hScreen);
+                }
+                else
+                    rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to create virtual screen for flow trace module %#x", iFlowTraceMod);
+            }
+            else
+                rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to query all records of flow trace module %#x", iFlowTraceMod);
+
+            for (unsigned i = 0; i < cRecords; i++)
+            {
+                if (paDumpBb[i].hFlowBb)
+                    DBGFR3FlowBbRelease(paDumpBb[i].hFlowBb);
+            }
+
+            RTMemTmpFree(paDumpBb);
+        }
+        else
+            rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to allocate memory for %u records", cRecords);
+
+        DBGFR3FlowTraceReportRelease(hFlowTraceReport);
+    }
+    else
+        rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to query report for flow trace module %#x", iFlowTraceMod);
+
+    return rc;
+}
+
+
+/**
+ * @callback_method_impl{FNDBGCCMD, The 'tflowp' (print trace flow) command.}
+ */
+static DECLCALLBACK(int) dbgcCmdTraceFlowPrint(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
+{
+    DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
+
+    /*
+     * Enumerate the arguments.
+     */
+    PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
+    int     rc    = VINF_SUCCESS;
+    for (unsigned iArg = 0; iArg < cArgs && RT_SUCCESS(rc); iArg++)
+    {
+        if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
+        {
+            /* one */
+            uint32_t iFlowTraceMod = (uint32_t)paArgs[iArg].u.u64Number;
+            if (iFlowTraceMod == paArgs[iArg].u.u64Number)
+            {
+                PDBGCTFLOW pFlowTrace = dbgcFlowTraceModGet(pDbgc, iFlowTraceMod);
+                if (pFlowTrace)
+                    rc = dbgcCmdTraceFlowPrintOne(pCmdHlp, pCmd, pFlowTrace->hTraceFlowMod,
+                                                  pFlowTrace->hFlow, pFlowTrace->iTraceFlowMod);
+                else
+                    rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_NOT_FOUND, "Flow trace module %#x doesn't exist", iFlowTraceMod);
+            }
+            else
+                rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Flow trace mod id %RX64 is too large", paArgs[iArg].u.u64Number);
+        }
+        else if (!strcmp(paArgs[iArg].u.pszString, "all"))
+        {
+            /* all */
+            PDBGCTFLOW pIt;
+            RTListForEach(&pDbgc->LstTraceFlowMods, pIt, DBGCTFLOW, NdTraceFlow)
+            {
+                rc = dbgcCmdTraceFlowPrintOne(pCmdHlp, pCmd, pIt->hTraceFlowMod,
+                                              pIt->hFlow, pIt->iTraceFlowMod);
+                if (RT_FAILURE(rc))
+                    break;
+            }
+        }
+        else
+            rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid argument '%s'", paArgs[iArg].u.pszString);
+    }
+    return rc;
+}
+
+
+/**
+ * @callback_method_impl{FNDBGCCMD, The 'tflowr' (reset trace flow) command.}
+ */
+static DECLCALLBACK(int) dbgcCmdTraceFlowReset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
+{
+    DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
+
+    /*
+     * Enumerate the arguments.
+     */
+    PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
+    int     rc    = VINF_SUCCESS;
+    for (unsigned iArg = 0; iArg < cArgs && RT_SUCCESS(rc); iArg++)
+    {
+        if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
+        {
+            /* one */
+            uint32_t iFlowTraceMod = (uint32_t)paArgs[iArg].u.u64Number;
+            if (iFlowTraceMod == paArgs[iArg].u.u64Number)
+            {
+                PDBGCTFLOW pFlowTrace = dbgcFlowTraceModGet(pDbgc, iFlowTraceMod);
+                if (pFlowTrace)
+                {
+                    rc = DBGFR3FlowTraceModClear(pFlowTrace->hTraceFlowMod);
+                    if (RT_FAILURE(rc))
+                        rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3FlowTraceModClear failed for flow trace module %#x", iFlowTraceMod);
+                }
+                else
+                    rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_NOT_FOUND, "Flow trace module %#x doesn't exist", iFlowTraceMod);
+            }
+            else
+                rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Flow trace mod id %RX64 is too large", paArgs[iArg].u.u64Number);
+        }
+        else if (!strcmp(paArgs[iArg].u.pszString, "all"))
+        {
+            /* all */
+            PDBGCTFLOW pIt;
+            RTListForEach(&pDbgc->LstTraceFlowMods, pIt, DBGCTFLOW, NdTraceFlow)
+            {
+                rc = DBGFR3FlowTraceModClear(pIt->hTraceFlowMod);
+                if (RT_FAILURE(rc))
+                    rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3FlowTraceModClear failed for flow trace module %#x", pIt->iTraceFlowMod);
+            }
+        }
+        else
+            rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid argument '%s'", paArgs[iArg].u.pszString);
+    }
+    return rc;
+}
+
+
 
 /**
Index: /trunk/src/VBox/Debugger/DBGCInternal.h
===================================================================
--- /trunk/src/VBox/Debugger/DBGCInternal.h	(revision 87787)
+++ /trunk/src/VBox/Debugger/DBGCInternal.h	(revision 87788)
@@ -28,5 +28,8 @@
 #include <VBox/dbg.h>
 #include <VBox/err.h>
-
+#include <VBox/vmm/dbgf.h>
+#include <VBox/vmm/dbgfflowtrace.h>
+
+#include <iprt/list.h>
 
 /*******************************************************************************
@@ -92,4 +95,22 @@
 /** Pointer to named variable. */
 typedef DBGCNAMEDVAR *PDBGCNAMEDVAR;
+
+
+/**
+ * Debugger console per trace flow data.
+ */
+typedef struct DBGCTFLOW
+{
+    /** Node for the trace flow module list. */
+    RTLISTNODE       NdTraceFlow;
+    /** Handle of the DGF trace flow module. */
+    DBGFFLOWTRACEMOD hTraceFlowMod;
+    /** The control flow graph for the module. */
+    DBGFFLOW         hFlow;
+    /** The trace flow module identifier. */
+    uint32_t         iTraceFlowMod;
+} DBGCTFLOW;
+/** Pointer to the per trace flow data. */
+typedef DBGCTFLOW *PDBGCTFLOW;
 
 
@@ -190,4 +211,6 @@
     /** The list of breakpoints. (singly linked) */
     PDBGCBP             pFirstBp;
+    /** The list of known trace flow modules. */
+    RTLISTANCHOR        LstTraceFlowMods;
 
     /** Software interrupt events. */
@@ -504,4 +527,8 @@
 PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp);
 int     dbgcBpExec(PDBGC pDbgc, RTUINT iBp);
+
+DECLHIDDEN(PDBGCTFLOW) dbgcFlowTraceModGet(PDBGC pDbgc, uint32_t iTraceFlowMod);
+DECLHIDDEN(int) dbgcFlowTraceModAdd(PDBGC pDbgc, DBGFFLOWTRACEMOD hFlowTraceMod, DBGFFLOW hFlow, uint32_t *piId);
+DECLHIDDEN(int) dbgcFlowTraceModDelete(PDBGC pDbgc, uint32_t iFlowTraceMod);
 
 void    dbgcEvalInit(void);
Index: /trunk/src/VBox/Debugger/DBGConsole.cpp
===================================================================
--- /trunk/src/VBox/Debugger/DBGConsole.cpp	(revision 87787)
+++ /trunk/src/VBox/Debugger/DBGConsole.cpp	(revision 87788)
@@ -1165,4 +1165,5 @@
     //pDbgc->pPlugInHead      = NULL;
     //pDbgc->pFirstBp         = NULL;
+    RTListInit(&pDbgc->LstTraceFlowMods);
     //pDbgc->abSearch         = {0};
     //pDbgc->cbSearch         = 0;
Index: /trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp
===================================================================
--- /trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp	(revision 87787)
+++ /trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp	(revision 87788)
@@ -23,4 +23,5 @@
 
 #include <VBox/vmm/dbgf.h>
+#include <VBox/vmm/dbgfflowtrace.h>
 VMMR3DECL(PDBGFADDRESS) DBGFR3AddrFromFlat(PUVM pUVM, PDBGFADDRESS pAddress, RTGCUINTPTR FlatPtr)
 {
@@ -560,4 +561,129 @@
     return VERR_INTERNAL_ERROR;
 }
+VMMR3DECL(int) DBGFR3FlowTraceModCreateFromFlowGraph(PUVM pUVM, VMCPUID idCpu, DBGFFLOW hFlow,
+                                                     DBGFFLOWTRACEPROBE hFlowTraceProbeCommon,
+                                                     DBGFFLOWTRACEPROBE hFlowTraceProbeEntry,
+                                                     DBGFFLOWTRACEPROBE hFlowTraceProbeRegular,
+                                                     DBGFFLOWTRACEPROBE hFlowTraceProbeExit,
+                                                     PDBGFFLOWTRACEMOD phFlowTraceMod)
+{
+    return VERR_INTERNAL_ERROR;
+}
+VMMR3DECL(uint32_t) DBGFR3FlowTraceModRetain(DBGFFLOWTRACEMOD hFlowTraceMod)
+{
+    return 0;
+}
+VMMR3DECL(uint32_t) DBGFR3FlowTraceModRelease(DBGFFLOWTRACEMOD hFlowTraceMod)
+{
+    return 0;
+}
+VMMR3DECL(int) DBGFR3FlowTraceModEnable(DBGFFLOWTRACEMOD hFlowTraceMod, uint32_t cHits, uint32_t cRecordsMax)
+{
+    return VERR_INTERNAL_ERROR;
+}
+VMMR3DECL(int) DBGFR3FlowTraceModDisable(DBGFFLOWTRACEMOD hFlowTraceMod)
+{
+    return VERR_INTERNAL_ERROR;
+}
+VMMR3DECL(int) DBGFR3FlowTraceModQueryReport(DBGFFLOWTRACEMOD hFlowTraceMod,
+                                             PDBGFFLOWTRACEREPORT phFlowTraceReport)
+{
+    return VERR_INTERNAL_ERROR;
+}
+VMMR3DECL(int) DBGFR3FlowTraceModClear(DBGFFLOWTRACEMOD hFlowTraceMod)
+{
+    return VERR_INTERNAL_ERROR;
+}
+VMMR3DECL(int) DBGFR3FlowTraceModAddProbe(DBGFFLOWTRACEMOD hFlowTraceMod, PCDBGFADDRESS pAddrProbe,
+                                          DBGFFLOWTRACEPROBE hFlowTraceProbe, uint32_t fFlags)
+{
+    return VERR_INTERNAL_ERROR;
+}
+VMMR3DECL(int) DBGFR3FlowTraceProbeCreate(PUVM pUVM, const char *pszDescr, PDBGFFLOWTRACEPROBE phFlowTraceProbe)
+{
+    return VERR_INTERNAL_ERROR;
+}
+VMMR3DECL(uint32_t) DBGFR3FlowTraceProbeRetain(DBGFFLOWTRACEPROBE hFlowTraceProbe)
+{
+    return 0;
+}
+VMMR3DECL(uint32_t) DBGFR3FlowTraceProbeRelease(DBGFFLOWTRACEPROBE hFlowTraceProbe)
+{
+    return 0;
+}
+VMMR3DECL(int) DBGFR3FlowTraceProbeEntriesAdd(DBGFFLOWTRACEPROBE hFlowTraceProbe,
+                                              PCDBGFFLOWTRACEPROBEENTRY paEntries, uint32_t cEntries)
+{
+    return VERR_INTERNAL_ERROR;
+}
+VMMR3DECL(uint32_t) DBGFR3FlowTraceReportRetain(DBGFFLOWTRACEREPORT hFlowTraceReport)
+{
+    return 0;
+}
+VMMR3DECL(uint32_t) DBGFR3FlowTraceReportRelease(DBGFFLOWTRACEREPORT hFlowTraceReport)
+{
+    return 0;
+}
+VMMR3DECL(uint32_t) DBGFR3FlowTraceReportGetRecordCount(DBGFFLOWTRACEREPORT hFlowTraceReport)
+{
+    return 0;
+}
+VMMR3DECL(int) DBGFR3FlowTraceReportQueryRecord(DBGFFLOWTRACEREPORT hFlowTraceReport, uint32_t idxRec, PDBGFFLOWTRACERECORD phFlowTraceRec)
+{
+    return VERR_INTERNAL_ERROR;
+}
+VMMR3DECL(int) DBGFR3FlowTraceReportQueryFiltered(DBGFFLOWTRACEREPORT hFlowTraceReport, uint32_t fFlags,
+                                                  PDBGFFLOWTRACEREPORTFILTER paFilters, uint32_t cFilters,
+                                                  DBGFFLOWTRACEREPORTFILTEROP enmOp,
+                                                  PDBGFFLOWTRACEREPORT phFlowTraceReportFiltered)
+{
+    return VERR_INTERNAL_ERROR;
+}
+VMMR3DECL(int) DBGFR3FlowTraceReportEnumRecords(DBGFFLOWTRACEREPORT hFlowTraceReport,
+                                                PFNDBGFFLOWTRACEREPORTENUMCLBK pfnEnum,
+                                                void *pvUser)
+{
+    return VERR_INTERNAL_ERROR;
+}
+VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordRetain(DBGFFLOWTRACERECORD hFlowTraceRecord)
+{
+    return 0;
+}
+VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordRelease(DBGFFLOWTRACERECORD hFlowTraceRecord)
+{
+    return 0;
+}
+VMMR3DECL(uint64_t) DBGFR3FlowTraceRecordGetSeqNo(DBGFFLOWTRACERECORD hFlowTraceRecord)
+{
+    return 0;
+}
+VMMR3DECL(uint64_t) DBGFR3FlowTraceRecordGetTimestamp(DBGFFLOWTRACERECORD hFlowTraceRecord)
+{
+    return 0;
+}
+VMMR3DECL(PDBGFADDRESS) DBGFR3FlowTraceRecordGetAddr(DBGFFLOWTRACERECORD hFlowTraceRecord, PDBGFADDRESS pAddr)
+{
+    return NULL;
+}
+VMMR3DECL(DBGFFLOWTRACEPROBE) DBGFR3FlowTraceRecordGetProbe(DBGFFLOWTRACERECORD hFlowTraceRecord)
+{
+    return NULL;
+}
+VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordGetValCount(DBGFFLOWTRACERECORD hFlowTraceRecord)
+{
+    return 0;
+}
+VMMR3DECL(PCDBGFFLOWTRACEPROBEVAL) DBGFR3FlowTraceRecordGetVals(DBGFFLOWTRACERECORD hFlowTraceRecord)
+{
+    return NULL;
+}
+VMMR3DECL(PCDBGFFLOWTRACEPROBEVAL) DBGFR3FlowTraceRecordGetValsCommon(DBGFFLOWTRACERECORD hFlowTraceRecord)
+{
+    return NULL;
+}
+VMMR3DECL(VMCPUID) DBGFR3FlowTraceRecordGetCpuId(DBGFFLOWTRACERECORD hFlowTraceRecord)
+{
+    return 0;
+}
 
 VMMR3DECL(int) DBGFR3FormatBugCheck(PUVM pUVM, char *pszDetails, size_t cbDetails,
