Index: /trunk/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp	(revision 38643)
+++ /trunk/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp	(revision 38644)
@@ -1162,5 +1162,5 @@
     {
         rc = VDDbgIoLogCreate(&pThis->hIoLogger, pszIoLogFilename, VDDBG_IOLOG_LOG_DATA);
-        RTStrFree(pszIoLogFilename);
+        MMR3HeapFree(pszIoLogFilename);
     }
 
Index: /trunk/src/VBox/Storage/Debug/VDDbgIoLog.cpp
===================================================================
--- /trunk/src/VBox/Storage/Debug/VDDbgIoLog.cpp	(revision 38643)
+++ /trunk/src/VBox/Storage/Debug/VDDbgIoLog.cpp	(revision 38644)
@@ -98,5 +98,5 @@
 {
     /** Event type. */
-    uint8_t     u32Type;
+    uint32_t    u32Type;
     /** Id of the matching start entry. */
     uint64_t    u64Id;
@@ -328,4 +328,5 @@
                 pIoLogger->offReadNext  = sizeof(Hdr);
                 pIoLogger->idNext       = RT_LE2H_U64(Hdr.u64Id);
+                *phIoLogger = pIoLogger;
             }
             else if (RT_SUCCESS(rc))
@@ -468,7 +469,8 @@
         pIoLogEntry->idStart = pIoLogger->idNext++;
 
-        Entry.u32Type          = VDIOLOG_EVENT_START;
+        Entry.u32Type         = VDIOLOG_EVENT_START;
         Entry.u8AsyncIo       = fAsync ? 1 : 0;
         Entry.u32ReqType      = VDDBGIOLOGREQ_DISCARD;
+        Entry.u64Id           = RT_H2LE_U64(pIoLogEntry->idStart);
         Entry.Discard.cRanges = RT_H2LE_U32(cRanges);
 
@@ -588,5 +590,5 @@
         if (RT_SUCCESS(rc))
         {
-            pIoLogger->u32EventTypeNext = (VDIOLOGEVENT)abBuf[0];
+            pIoLogger->u32EventTypeNext = abBuf[0];
             pIoLogger->enmReqTypeNext   = (VDDBGIOLOGREQ)abBuf[1];
         }
@@ -687,4 +689,7 @@
         rc = VERR_INVALID_STATE;
 
+    if (RT_SUCCESS(rc))
+        pIoLogger->u32EventTypeNext = 0;
+
     RTSemFastMutexRelease(pIoLogger->hMtx);
     return rc;
@@ -748,4 +753,7 @@
         rc = VERR_INVALID_STATE;
 
+    if (RT_SUCCESS(rc))
+        pIoLogger->u32EventTypeNext = 0;
+
     RTSemFastMutexRelease(pIoLogger->hMtx);
     return rc;
@@ -796,4 +804,7 @@
         rc = VERR_INVALID_STATE;
 
+    if (RT_SUCCESS(rc))
+        pIoLogger->u32EventTypeNext = 0;
+
     RTSemFastMutexRelease(pIoLogger->hMtx);
     return rc;
Index: /trunk/src/VBox/Storage/testcase/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Storage/testcase/Makefile.kmk	(revision 38643)
+++ /trunk/src/VBox/Storage/testcase/Makefile.kmk	(revision 38644)
@@ -53,5 +53,7 @@
 	VDMemDisk.cpp \
 	VDIoRnd.cpp
- tstVDIo_LIBS = $(LIB_DDU)
+ tstVDIo_LIBS = \
+ 	$(LIB_DDU) \
+ 	$(PATH_STAGE_LIB)/StorageDbgLib$(VBOX_SUFF_LIB)
 
  tstVDSetUuid_TEMPLATE = VBOXR3TSTEXE
Index: /trunk/src/VBox/Storage/testcase/tstVDIo.cpp
===================================================================
--- /trunk/src/VBox/Storage/testcase/tstVDIo.cpp	(revision 38643)
+++ /trunk/src/VBox/Storage/testcase/tstVDIo.cpp	(revision 38644)
@@ -18,4 +18,5 @@
 #define LOGGROUP LOGGROUP_DEFAULT
 #include <VBox/vd.h>
+#include <VBox/vddbg.h>
 #include <VBox/err.h>
 #include <VBox/log.h>
@@ -300,4 +301,5 @@
 static DECLCALLBACK(int) vdScriptHandlerClose(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs);
 static DECLCALLBACK(int) vdScriptHandlerPrintFileSize(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs);
+static DECLCALLBACK(int) vdScriptHandlerIoLogReplay(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs);
 static DECLCALLBACK(int) vdScriptHandlerIoRngCreate(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs);
 static DECLCALLBACK(int) vdScriptHandlerIoRngDestroy(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs);
@@ -419,4 +421,12 @@
 };
 
+/* print file size action */
+const VDSCRIPTARGDESC g_aArgIoLogReplay[] =
+{
+    /* pcszName    chId enmType                          fFlags */
+    {"disk",       'd', VDSCRIPTARGTYPE_STRING,          VDSCRIPTARGDESC_FLAG_MANDATORY},
+    {"iolog",      'i', VDSCRIPTARGTYPE_STRING, VDSCRIPTARGDESC_FLAG_MANDATORY}
+};
+
 /* I/O RNG create action */
 const VDSCRIPTARGDESC g_aArgIoRngCreate[] =
@@ -513,4 +523,5 @@
     {"close",                      g_aArgClose,                       RT_ELEMENTS(g_aArgClose),                      vdScriptHandlerClose},
     {"printfilesize",              g_aArgPrintFileSize,               RT_ELEMENTS(g_aArgPrintFileSize),              vdScriptHandlerPrintFileSize},
+    {"ioreplay",                   g_aArgIoLogReplay,                 RT_ELEMENTS(g_aArgIoLogReplay),                vdScriptHandlerIoLogReplay},
     {"merge",                      g_aArgMerge,                       RT_ELEMENTS(g_aArgMerge),                      vdScriptHandlerMerge},
     {"compact",                    g_aArgCompact,                     RT_ELEMENTS(g_aArgCompact),                    vdScriptHandlerCompact},
@@ -1512,4 +1523,171 @@
     if (pDisk)
         RTPrintf("%s: size of image %u is %llu\n", pcszDisk, nImage, VDGetFileSize(pDisk->pVD, nImage));
+    else
+        rc = VERR_NOT_FOUND;
+
+    return rc;
+}
+
+
+static DECLCALLBACK(int) vdScriptHandlerIoLogReplay(PVDTESTGLOB pGlob, PVDSCRIPTARG paScriptArgs, unsigned cScriptArgs)
+{
+    int rc = VINF_SUCCESS;
+    const char *pcszDisk = NULL;
+    PVDDISK pDisk = NULL;
+    const char *pcszIoLog = NULL;
+
+    for (unsigned i = 0; i < cScriptArgs; i++)
+    {
+        switch (paScriptArgs[i].chId)
+        {
+            case 'd':
+            {
+                pcszDisk = paScriptArgs[i].u.pcszString;
+                break;
+            }
+            case 'i':
+            {
+                pcszIoLog = paScriptArgs[i].u.pcszString;
+                break;
+            }
+            default:
+                AssertMsgFailed(("Invalid argument given!\n"));
+        }
+    }
+
+    pDisk = tstVDIoGetDiskByName(pGlob, pcszDisk);
+    if (pDisk)
+    {
+        VDIOLOGGER hIoLogger;
+
+        rc = VDDbgIoLogOpen(&hIoLogger, pcszIoLog);
+        if (RT_SUCCESS(rc))
+        {
+            uint32_t fIoLogFlags;
+            VDIOLOGEVENT enmEvent;
+            void *pvBuf = NULL;
+            size_t cbBuf = 0;
+
+            fIoLogFlags = VDDbgIoLogGetFlags(hIoLogger);
+
+            /* Loop through events. */
+            rc = VDDbgIoLogEventTypeGetNext(hIoLogger, &enmEvent);
+            while (   RT_SUCCESS(rc)
+                   && enmEvent != VDIOLOGEVENT_END)
+            {
+                VDDBGIOLOGREQ enmReq = VDDBGIOLOGREQ_INVALID;
+                uint64_t idEvent = 0;
+                bool fAsync = false;
+                uint64_t off = 0;
+                size_t cbIo = 0;
+                Assert(enmEvent == VDIOLOGEVENT_START);
+
+                rc = VDDbgIoLogReqTypeGetNext(hIoLogger, &enmReq);
+                if (RT_FAILURE(rc))
+                    break;
+
+                switch (enmReq)
+                {
+                    case VDDBGIOLOGREQ_READ:
+                    {
+                        rc = VDDbgIoLogEventGetStart(hIoLogger, &idEvent, &fAsync,
+                                                     &off, &cbIo, 0, NULL);
+                        if (   RT_SUCCESS(rc)
+                            && cbIo > cbBuf)
+                        {
+                            pvBuf = RTMemRealloc(pvBuf, cbIo);
+                            if (pvBuf)
+                                cbBuf = cbIo;
+                            else
+                                rc = VERR_NO_MEMORY;
+                        }
+
+                        if (   RT_SUCCESS(rc)
+                            && !fAsync)
+                            rc = VDRead(pDisk->pVD, off, pvBuf, cbIo);
+                        else if (RT_SUCCESS(rc))
+                            rc = VERR_NOT_SUPPORTED;
+                        break;
+                    }
+                    case VDDBGIOLOGREQ_WRITE:
+                    {
+                        rc = VDDbgIoLogEventGetStart(hIoLogger, &idEvent, &fAsync,
+                                                     &off, &cbIo, cbBuf, pvBuf);
+                        if (rc == VERR_BUFFER_OVERFLOW)
+                        {
+                            pvBuf = RTMemRealloc(pvBuf, cbIo);
+                            if (pvBuf)
+                            {
+                                cbBuf = cbIo;
+                                rc = VDDbgIoLogEventGetStart(hIoLogger, &idEvent, &fAsync,
+                                                             &off, &cbIo, cbBuf, pvBuf);
+                            }
+                            else
+                                rc = VERR_NO_MEMORY;
+                        }
+
+                        if (   RT_SUCCESS(rc)
+                            && !fAsync)
+                            rc = VDWrite(pDisk->pVD, off, pvBuf, cbIo);
+                        else if (RT_SUCCESS(rc))
+                            rc = VERR_NOT_SUPPORTED;
+                        break;
+                    }
+                    case VDDBGIOLOGREQ_FLUSH:
+                    {
+                        rc = VDDbgIoLogEventGetStart(hIoLogger, &idEvent, &fAsync,
+                                                     &off, &cbIo, 0, NULL);
+                        if (   RT_SUCCESS(rc)
+                            && !fAsync)
+                            rc = VDFlush(pDisk->pVD);
+                        else if (RT_SUCCESS(rc))
+                            rc = VERR_NOT_SUPPORTED;
+                        break;
+                    }
+                    case VDDBGIOLOGREQ_DISCARD:
+                    {
+                        PVDRANGE paRanges = NULL;
+                        unsigned cRanges = 0;
+
+                        rc = VDDbgIoLogEventGetStartDiscard(hIoLogger, &idEvent, &fAsync,
+                                                            &paRanges, &cRanges);
+                        if (   RT_SUCCESS(rc)
+                            && !fAsync)
+                        {
+                            rc = VDDiscardRanges(pDisk->pVD, paRanges, cRanges);
+                            RTMemFree(paRanges);
+                        }
+                        else if (RT_SUCCESS(rc))
+                            rc = VERR_NOT_SUPPORTED;
+                        break;
+                    }
+                    default:
+                        AssertMsgFailed(("Invalid request type %d\n", enmReq));
+                }
+
+                if (RT_SUCCESS(rc))
+                {
+                    /* Get matching complete event. */
+                    rc = VDDbgIoLogEventTypeGetNext(hIoLogger, &enmEvent);
+                    if (RT_SUCCESS(rc))
+                    {
+                        uint64_t idEvtComplete;
+                        int rcReq;
+                        uint64_t msDuration;
+
+                        Assert(enmEvent == VDIOLOGEVENT_COMPLETE);
+                        rc = VDDbgIoLogEventGetComplete(hIoLogger, &idEvtComplete, &rcReq,
+                                                        &msDuration, &cbIo, cbBuf, pvBuf);
+                        Assert(RT_FAILURE(rc) || idEvtComplete == idEvent);
+                    }
+                }
+
+                if (RT_SUCCESS(rc))
+                    rc = VDDbgIoLogEventTypeGetNext(hIoLogger, &enmEvent);
+            }
+
+            VDDbgIoLogDestroy(hIoLogger);
+        }
+    }
     else
         rc = VERR_NOT_FOUND;
@@ -3185,12 +3363,10 @@
 {
     RTPrintf("Usage:\n"
-             "--script <filename>    Script to execute\n"
-             "--replay <filename>    Log to replay (not implemented yet)\n");
+             "--script <filename>    Script to execute\n");
 }
 
 static const RTGETOPTDEF g_aOptions[] =
 {
-    { "--script",   's', RTGETOPT_REQ_STRING },
-    { "--replay",   'r', RTGETOPT_REQ_STRING },
+    { "--script",   's', RTGETOPT_REQ_STRING }
 };
 
@@ -3224,7 +3400,4 @@
                 tstVDIoScriptRun(ValueUnion.psz);
                 break;
-            case 'r':
-                RTPrintf("Replaying I/O logs is not implemented yet\n");
-                break;
             default:
                 printUsage();
