Index: trunk/src/VBox/Runtime/tools/Makefile.kmk
===================================================================
--- trunk/src/VBox/Runtime/tools/Makefile.kmk	(revision 45927)
+++ trunk/src/VBox/Runtime/tools/Makefile.kmk	(revision 45929)
@@ -66,4 +66,9 @@
  RTTar_SOURCES = RTTar.cpp
 
+ # RTNtDbgHelp - our tar clone (for testing the tar/gzip/gunzip streaming code)
+ PROGRAMS.win += RTNtDbgHelp
+ RTNtDbgHelp_TEMPLATE = VBOXR3TSTEXE
+ RTNtDbgHelp_SOURCES = RTNtDbgHelp.cpp
+
 endif # !VBOX_ONLY_EXTPACKS_USE_IMPLIBS
 
Index: trunk/src/VBox/Runtime/tools/RTNtDbgHelp.cpp
===================================================================
--- trunk/src/VBox/Runtime/tools/RTNtDbgHelp.cpp	(revision 45929)
+++ trunk/src/VBox/Runtime/tools/RTNtDbgHelp.cpp	(revision 45929)
@@ -0,0 +1,367 @@
+﻿/* $Id$ */
+/** @file
+ * IPRT - RTNtDbgHelp -  Tool for working/exploring DbgHelp.dll.
+ */
+
+/*
+ * Copyright (C) 2013 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.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <Windows.h>
+#include <Dbghelp.h>
+
+#include <iprt/alloca.h>
+#include <iprt/dir.h>
+#include <iprt/file.h>
+#include <iprt/getopt.h>
+#include <iprt/env.h>
+#include <iprt/initterm.h>
+#include <iprt/list.h>
+#include <iprt/mem.h>
+#include <iprt/message.h>
+#include <iprt/path.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/err.h>
+
+#include <iprt/win/lazy-dbghelp.h>
+
+#include <iprt/ldrlazy.h>
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Debug module record.
+ *
+ * Used for dumping the whole context.
+ */
+typedef struct RTNTDBGHELPMOD
+{
+    /** The list bits. */
+    RTLISTNODE      ListEntry;
+    /** The module address. */
+    uint64_t        uModAddr;
+    /** Pointer to the name part of szFullName. */
+    char           *pszName;
+    /** The module name. */
+    char            szFullName[1];
+} RTNTDBGHELPMOD;
+/** Pointer to a debug module. */
+typedef RTNTDBGHELPMOD *PRTNTDBGHELPMOD;
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** Verbosity level. */
+static int          g_iOptVerbose = 1;
+
+/** Fake process handle. */
+static HANDLE       g_hFake = (HANDLE)0x1234567;
+/** Number of modules in the list. */
+static uint32_t     g_cModules = 0;
+/** Module list. */
+static RTLISTANCHOR g_ModuleList;
+/** Set when initialized, clear until then. Lazy init on first operation. */
+static bool         g_fInitialized = false;
+
+/** The current address register. */
+static uint64_t     g_uCurAddress = 0;
+
+
+
+/**
+ * For debug/verbose output.
+ *
+ * @param   iMin                The minimum verbosity level for this message.
+ * @param   pszFormat           The format string.
+ * @param   ...                 The arguments referenced in the format string.
+ */
+static void infoPrintf(int iMin, const char *pszFormat, ...)
+{
+    if (g_iOptVerbose >= iMin)
+    {
+        va_list va;
+        va_start(va, pszFormat);
+        RTPrintf("info: ");
+        RTPrintfV(pszFormat, va);
+        va_end(va);
+    }
+}
+
+static BOOL CALLBACK symDebugCallback64(HANDLE hProcess, ULONG uAction, ULONG64 ullData, ULONG64 ullUserCtx)
+{
+    NOREF(hProcess); NOREF(ullUserCtx);
+    switch (uAction)
+    {
+        case CBA_DEBUG_INFO:
+        {
+            const char *pszMsg = (const char *)(uintptr_t)ullData;
+            size_t      cchMsg = strlen(pszMsg);
+            if (cchMsg > 0 && pszMsg[cchMsg - 1] == '\n')
+                RTPrintf("cba_debug_info: %s", pszMsg);
+            else
+                RTPrintf("cba_debug_info: %s\n", pszMsg);
+            return TRUE;
+        }
+
+        case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
+            return FALSE;
+
+        case CBA_EVENT:
+            return FALSE;
+
+        default:
+            RTPrintf("cba_???: uAction=%#x ullData=%#llx\n", uAction, ullData);
+            break;
+    }
+
+    return FALSE;
+}
+
+/**
+ * Lazy initialization.
+ * @returns Exit code with any relevant complaints printed.
+ */
+static RTEXITCODE ensureInitialized(void)
+{
+    if (!g_fInitialized)
+    {
+        if (!SymInitialize(g_hFake, NULL, FALSE))
+            return RTMsgErrorExit(RTEXITCODE_FAILURE, "SymInitialied failed: %u\n", GetLastError());
+        if (!SymRegisterCallback64(g_hFake, symDebugCallback64, 0))
+            return RTMsgErrorExit(RTEXITCODE_FAILURE, "SymRegisterCallback64 failed: %u\n", GetLastError());
+        g_fInitialized = true;
+        infoPrintf(2, "SymInitialized(,,)\n");
+    }
+    return RTEXITCODE_SUCCESS;
+}
+
+
+/**
+ * Loads the given module, the address is either automatic or a previously given
+ * one.
+ *
+ * @returns Exit code with any relevant complaints printed.
+ * @param   pszFile             The file to load.
+ */
+static RTEXITCODE loadModule(const char *pszFile)
+{
+    RTEXITCODE rcExit = ensureInitialized();
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
+
+    uint64_t uModAddrReq = g_uCurAddress == 0 ? UINT64_C(0x1000000) * g_cModules : g_uCurAddress;
+    uint64_t uModAddrGot = SymLoadModuleEx(g_hFake, NULL /*hFile*/, pszFile, NULL /*pszModuleName*/,
+                                           uModAddrReq, 0, NULL /*pData*/, 0 /*fFlags*/);
+    if (uModAddrGot == 0)
+        return RTMsgErrorExit(RTEXITCODE_FAILURE, "SymLoadModuleEx failed: %u\n", GetLastError());
+
+    size_t cbFullName = strlen(pszFile) + 1;
+    PRTNTDBGHELPMOD pMod = (PRTNTDBGHELPMOD)RTMemAlloc(RT_OFFSETOF(RTNTDBGHELPMOD, szFullName[cbFullName + 1]));
+    memcpy(pMod->szFullName, pszFile, cbFullName);
+    pMod->pszName  = RTPathFilename(pMod->szFullName);
+    pMod->uModAddr = uModAddrGot;
+    RTListAppend(&g_ModuleList, &pMod->ListEntry);
+    infoPrintf(1, "%#018x %s\n", pMod->uModAddr, pMod->pszName);
+
+    return RTEXITCODE_SUCCESS;
+}
+
+
+/**
+ * Translates SYM_TYPE to string.
+ *
+ * @returns String.
+ * @param   enmType             The symbol type value.
+ */
+static const char *symTypeName(SYM_TYPE enmType)
+{
+    switch (enmType)
+    {
+        case SymCoff:       return "SymCoff";
+        case SymCv:         return "SymCv";
+        case SymPdb:        return "SymPdb";
+        case SymExport:     return "SymExport";
+        case SymDeferred:   return "SymDeferred";
+        case SymSym:        return "SymSym";
+        case SymDia:        return "SymDia";
+        case SymVirtual:    return "SymVirtual";
+    }
+    static char s_szBuf[32];
+    RTStrPrintf(s_szBuf, sizeof(s_szBuf), "Unknown-%#x", enmType);
+    return s_szBuf;
+}
+
+
+/**
+ * Symbol enumeration callback.
+ *
+ * @returns TRUE (continue enum).
+ * @param   pSymInfo            The symbol info.
+ * @param   cbSymbol            The symbol length (calculated).
+ * @param   pvUser              NULL.
+ */
+static BOOL CALLBACK dumpSymbolCallback(PSYMBOL_INFO pSymInfo, ULONG cbSymbol, PVOID pvUser)
+{
+    NOREF(pvUser);
+    RTPrintf("  %#018x LB %#07x  %s\n", pSymInfo->Address, cbSymbol, pSymInfo->Name);
+    return TRUE;
+}
+
+/**
+ * Dumps all info.
+ * @returns Exit code with any relevant complaints printed.
+ */
+static RTEXITCODE dumpAll(void)
+{
+    RTEXITCODE      rcExit = RTEXITCODE_SUCCESS;
+    PRTNTDBGHELPMOD pMod;
+    RTListForEach(&g_ModuleList, pMod, RTNTDBGHELPMOD, ListEntry)
+    {
+        RTPrintf("*** %#018x - %s ***\n", pMod->uModAddr, pMod->szFullName);
+
+        IMAGEHLP_MODULE64 ModInfo;
+        RT_ZERO(ModInfo);
+        ModInfo.SizeOfStruct = sizeof(ModInfo);
+        if (SymGetModuleInfo64(g_hFake, pMod->uModAddr, &ModInfo))
+        {
+            RTPrintf("    BaseOfImage     = %#018llx\n", ModInfo.BaseOfImage);
+            RTPrintf("    ImageSize       = %#010x\n", ModInfo.ImageSize);
+            RTPrintf("    TimeDateStamp   = %#010x\n", ModInfo.TimeDateStamp);
+            RTPrintf("    CheckSum        = %#010x\n", ModInfo.CheckSum);
+            RTPrintf("    NumSyms         = %#010x (%u)\n", ModInfo.NumSyms, ModInfo.NumSyms);
+            RTPrintf("    SymType         = %s\n", symTypeName(ModInfo.SymType));
+            RTPrintf("    ModuleName      = %.32s\n", ModInfo.ModuleName);
+            RTPrintf("    ImageName       = %.256s\n", ModInfo.ImageName);
+            RTPrintf("    LoadedImageName = %.256s\n", ModInfo.LoadedImageName);
+            RTPrintf("    LoadedPdbName   = %.256s\n", ModInfo.LoadedPdbName);
+            RTPrintf("    CVSig           = %#010x\n", ModInfo.CVSig);
+            /** @todo CVData. */
+            RTPrintf("    PdbSig          = %#010x\n", ModInfo.PdbSig);
+            RTPrintf("    PdbSig70        = %RTuuid\n", &ModInfo.PdbSig70);
+            RTPrintf("    PdbSig          = %#010x\n", ModInfo.PdbAge);
+            RTPrintf("    PdbUnmatched    = %RTbool\n", ModInfo.PdbUnmatched);
+            RTPrintf("    DbgUnmatched    = %RTbool\n", ModInfo.DbgUnmatched);
+            RTPrintf("    LineNumbers     = %RTbool\n", ModInfo.LineNumbers);
+            RTPrintf("    GlobalSymbols   = %RTbool\n", ModInfo.GlobalSymbols);
+            RTPrintf("    TypeInfo        = %RTbool\n", ModInfo.TypeInfo);
+            RTPrintf("    SourceIndexed   = %RTbool\n", ModInfo.SourceIndexed);
+            RTPrintf("    Publics         = %RTbool\n", ModInfo.Publics);
+        }
+        else
+            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "SymGetModuleInfo64 failed: %u\n", GetLastError());
+
+        if (!SymEnumSymbols(g_hFake, pMod->uModAddr, NULL, dumpSymbolCallback, NULL))
+            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "SymEnumSymbols failed: %u\n", GetLastError());
+
+    }
+    return rcExit;
+}
+
+
+int main(int argc, char **argv)
+{
+    int rc = RTR3InitExe(argc, &argv, 0 /*fFlags*/);
+    if (RT_FAILURE(rc))
+        return RTMsgInitFailure(rc);
+
+    RTListInit(&g_ModuleList);
+
+    /*
+     * Parse options.
+     */
+    static const RTGETOPTDEF s_aOptions[] =
+    {
+        { "--dump-all",         'd', RTGETOPT_REQ_NOTHING },
+        { "--load",             'l', RTGETOPT_REQ_STRING  },
+        { "--set-address",      'a', RTGETOPT_REQ_UINT64  },
+#define OPT_SET_DEBUG_INFO  0x1000
+        { "--set-debug-info",   OPT_SET_DEBUG_INFO, RTGETOPT_REQ_NOTHING  },
+        { "--verbose",          'v', RTGETOPT_REQ_NOTHING },
+        { "--quiet",            'q', RTGETOPT_REQ_NOTHING },
+    };
+
+    RTEXITCODE  rcExit      = RTEXITCODE_SUCCESS;
+    const char *pszOutput   = "-";
+
+    int ch;
+    RTGETOPTUNION ValueUnion;
+    RTGETOPTSTATE GetState;
+    RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
+                 RTGETOPTINIT_FLAGS_OPTS_FIRST);
+    while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
+    {
+        switch (ch)
+        {
+            case 'v':
+                g_iOptVerbose++;
+                break;
+
+            case 'q':
+                g_iOptVerbose++;
+                break;
+
+            case 'l':
+                rcExit = loadModule(ValueUnion.psz);
+                break;
+
+            case 'a':
+                g_uCurAddress = ValueUnion.u64;
+                break;
+
+            case 'd':
+                rcExit = dumpAll();
+                break;
+
+            case OPT_SET_DEBUG_INFO:
+                rcExit = ensureInitialized();
+                if (rcExit == RTEXITCODE_SUCCESS && !SymSetOptions(SymGetOptions() | SYMOPT_DEBUG))
+                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "SymSetOptions failed: %u\n", GetLastError());
+                break;
+
+
+            case 'V':
+                RTPrintf("$Revision$");
+                break;
+
+            case 'h':
+                RTPrintf("usage: %s [-v|--verbose] [-q|--quiet] [-f|--force] [-o|--output <file.h>] <dir1|pdb1> [...]\n"
+                         "   or: %s [-V|--version]\n"
+                         "   or: %s [-h|--help]\n",
+                         argv[0], argv[0], argv[0]);
+                return RTEXITCODE_SUCCESS;
+
+            case VINF_GETOPT_NOT_OPTION:
+            default:
+                return RTGetOptPrintError(ch, &ValueUnion);
+        }
+        if (rcExit != RTEXITCODE_SUCCESS)
+            break;
+    }
+    return rcExit;
+}
+
