dbgcfg.cpp revision 346bd62ee28c48783c944a36c285971d297f3f27
/* $Id$ */
/** @file
* IPRT - Debugging Configuration.
*/
/*
* 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;
* 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 *
*******************************************************************************/
#define LOG_GROUP RTLOGGROUP_DBG
#include <iprt/critsect.h>
#ifdef IPRT_WITH_HTTP
#endif
#include <iprt/semaphore.h>
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* String list entry.
*/
typedef struct RTDBGCFGSTR
{
/** List entry. */
/** Domain specific flags. */
/** The length of the string. */
/** The string. */
char sz[1];
} RTDBGCFGSTR;
/** Pointer to a string list entry. */
typedef RTDBGCFGSTR *PRTDBGCFGSTR;
/**
* Log callback.
*
* @param hDbgCfg The debug config instance.
* @param iLevel The message level.
* @param pszMsg The message.
* @param pvUser User argument.
*/
typedef DECLCALLBACK(int) FNRTDBGCFGLOG(RTDBGCFG hDbgCfg, uint32_t iLevel, const char *pszMsg, void *pvUser);
/** Pointer to a log callback. */
typedef FNRTDBGCFGLOG *PFNRTDBGCFGLOG;
/**
* Configuration instance.
*/
typedef struct RTDBGCFGINT
{
/** The magic value (RTDBGCFG_MAGIC). */
/** Reference counter. */
/** Flags, see RTDBGCFG_FLAGS_XXX. */
/** List of paths to search for debug files and executable images. */
/** List of debug file suffixes. */
/** List of paths to search for source files. */
#ifdef RT_OS_WINDOWS
/** The _NT_ALT_SYMBOL_PATH and _NT_SYMBOL_PATH combined. */
/** The _NT_EXECUTABLE_PATH. */
/** The _NT_SOURCE_PATH. */
#endif
/** Log callback function. */
/** User argument to pass to the log callback. */
void *pvLogUser;
/** Critical section protecting the instance data. */
} *PRTDBGCFGINT;
/**
* Mnemonics map entry for a 64-bit unsigned property value.
*/
typedef struct RTDBGCFGU64MNEMONIC
{
/** The flags to set or clear. */
/** The mnemonic. */
const char *pszMnemonic;
/** The length of the mnemonic. */
/** If @c true, the bits in fFlags will be set, if @c false they will be
* cleared. */
bool fSet;
/** Pointer to a read only mnemonic map entry for a uint64_t property. */
typedef RTDBGCFGU64MNEMONIC const *PCRTDBGCFGU64MNEMONIC;
/** @name Open flags.
* @{ */
/** The operative system mask. The values are RT_OPSYS_XXX. */
/** The files may be compressed MS styled. */
/** Whether to make a recursive search. */
/** We're looking for a separate debug file. */
/** We're looking for an executable image. */
/** The file search should be done in an case insensitive fashion. */
/** Use Windbg style symbol servers when encountered in the path. */
/** @} */
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** Validates a debug module handle and returns rc if not valid. */
do { \
} while (0)
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Mnemonics map for RTDBGCFGPROP_FLAGS. */
static const RTDBGCFGU64MNEMONIC g_aDbgCfgFlags[] =
{
{ 0, NULL, 0, false }
};
/**
* Runtime logging, level 1.
*
* @param pThis The debug config instance data.
* @param pszFormat The message format string.
* @param ... Arguments references in the format string.
*/
{
{
}
}
/**
* Runtime logging, level 2.
*
* @param pThis The debug config instance data.
* @param pszFormat The message format string.
* @param ... Arguments references in the format string.
*/
{
{
}
}
/**
* Checks if the file system at the given path is case insensitive or not.
*
* @returns true / false
* @param pszPath The path to query about.
*/
static int rtDbgCfgIsFsCaseInsensitive(const char *pszPath)
{
if (RT_FAILURE(rc))
return RT_OPSYS == RT_OPSYS_DARWIN
|| RT_OPSYS == RT_OPSYS_DOS
|| RT_OPSYS == RT_OPSYS_OS2
|| RT_OPSYS == RT_OPSYS_NT
|| RT_OPSYS == RT_OPSYS_WINDOWS;
return !Props.fCaseSensitive;
}
/**
*
* @returns true / false.
* @param pszPath The path buffer containing an existing directory.
* RTPATH_MAX in size. On success, this will contain
* the combined path with @a pszName case correct.
* @param offLastComp The offset of the last component (for chopping it
* off).
* @param pszName What we're looking for.
* @param enmType What kind of thing we're looking for.
*/
{
/** @todo IPRT should generalize this so we can use host specific tricks to
* speed it up. */
/* Return straight away if the name isn't case foldable. */
if (!RTStrIsCaseFoldable(pszName))
return false;
/*
* Try some simple case folding games.
*/
if (RTFileExists(pszPath))
return true;
if (RTFileExists(pszPath))
return true;
/*
* Open the directory and check each entry in it.
*/
if (RT_FAILURE(rc))
return false;
for (;;)
{
/* Read the next entry. */
union
{
} u;
if (RT_FAILURE(rc))
break;
{
&& RT_SUCCESS(rc))
|| RT_FAILURE(rc))
{
if (RT_FAILURE(rc))
{
return false;
}
return true;
}
}
}
return false;
}
/**
* Appends @a pszSubDir to @a pszPath and check whether it exists and is a
* directory.
*
* If @a fCaseInsensitive is set, we will do a case insensitive search for a
* matching sub directory.
*
* @returns true / false
* @param pszPath The path buffer containing an existing
* directory. RTPATH_MAX in size.
* @param pszSubDir The sub directory to append.
* @param fCaseInsensitive Whether case insensitive searching is required.
*/
{
/* Save the length of the input path so we can restore it in the case
insensitive branch further down. */
/*
* Append the sub directory and check if we got a hit.
*/
if (RT_FAILURE(rc))
return false;
if (RTDirExists(pszPath))
return true;
/*
* Do case insensitive lookup if requested.
*/
if (fCaseInsensitive)
return false;
}
/**
* Appends @a pszFilename to @a pszPath and check whether it exists and is a
* directory.
*
* If @a fCaseInsensitive is set, we will do a case insensitive search for a
* matching filename.
*
* @returns true / false
* @param pszPath The path buffer containing an existing
* directory. RTPATH_MAX in size.
* @param pszFilename The file name to append.
* @param fCaseInsensitive Whether case insensitive searching is required.
* @param fMsCompressed Whether to look for the MS compressed file name
* variant.
* @param pfProbablyCompressed This is set to true if a MS compressed
* filename variant is returned. Optional.
*/
bool fMsCompressed, bool *pfProbablyCompressed)
{
/* Save the length of the input path so we can restore it in the case
insensitive branch further down. */
if (pfProbablyCompressed)
*pfProbablyCompressed = false;
/*
* Append the filename and check if we got a hit.
*/
if (RT_FAILURE(rc))
return false;
if (RTFileExists(pszPath))
return true;
/*
* Do case insensitive file lookup if requested.
*/
if (fCaseInsensitive)
{
return true;
}
/*
* Look for MS compressed file if requested.
*/
if ( fMsCompressed
{
AssertRCReturn(rc, false);
if (pfProbablyCompressed)
*pfProbablyCompressed = true;
if (RTFileExists(pszPath))
return true;
if (fCaseInsensitive)
{
/* Note! Ugly hack here, the pszName parameter points into pszPath! */
return true;
}
if (pfProbablyCompressed)
*pfProbablyCompressed = false;
}
return false;
}
static int rtDbgCfgTryOpenDir(PRTDBGCFGINT pThis, char *pszPath, PRTPATHSPLIT pSplitFn, uint32_t fFlags,
{
int rcRet = VWRN_NOT_FOUND;
int rc2;
/* If the directory doesn't exist, just quit immediately.
Note! Our case insensitivity doesn't extend to the search dirs themselfs,
only to the bits under neath them. */
if (!RTDirExists(pszPath))
{
return rcRet;
}
/* Figure out whether we have to do a case sensitive search or not.
Note! As a simplification, we don't ask for case settings in each
directory under the user specified path, we assume the file
systems that mounted there have compatible settings. Faster
that way. */
/*
* Look for the file with less and less of the original path given.
*/
{
rc2 = VINF_SUCCESS;
if (RT_SUCCESS(rc2))
{
if (rtDbgCfgIsFileAndFixCase(pszPath, pSplitFn->apszComps[pSplitFn->cComps - 1], fCaseInsensitive, false, NULL))
{
{
if (rc2 == VINF_CALLBACK_RETURN)
else
return rc2;
}
}
}
}
/*
* Do a recursive search if requested.
*/
if ( (fFlags & RTDBGCFG_O_RECURSIVE)
{
/** @todo Recursive searching will be done later. */
}
return rcRet;
}
{
/*
* Duplicate the source file path, just for simplicity and restore the
* final character in the orignal. We cheerfully ignorining any
* possibility of multibyte UTF-8 sequences just like the caller did when
* setting it to '_'.
*/
if (!pszSrcArchive)
return VERR_NO_STR_MEMORY;
/*
* Figuring out the argument list for the platform specific unpack util.
*/
#ifdef RT_OS_WINDOWS
const char *papszArgs[] =
{
"expand.exe",
};
#else
char szExtractDir[RTPATH_MAX];
const char *papszArgs[] =
{
"cabextract",
"-L", /* Lower case extracted files. */
};
#endif
/*
* Do the unpacking.
*/
#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
#else
#endif
&hChild);
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
&& ProcStatus.iStatus == 0)
{
if (RTPathExists(pszPath))
{
rc = VINF_SUCCESS;
}
else
{
rtDbgCfgLog1(pThis, "Successfully ran unpacker on '%s', but '%s' is missing!\n", pszSrcArchive, pszPath);
rc = VERR_ZIP_ERROR;
}
}
else
{
}
}
else
}
else
return rc;
}
{
#ifdef IPRT_WITH_HTTP
return VWRN_NOT_FOUND;
/*
* Create the path.
*/
if (!RTDirExists(pszPath))
{
return rc;
}
if (RT_FAILURE(rc))
return rc;
if (!RTDirExists(pszPath))
{
if (RT_FAILURE(rc))
{
}
}
if (RT_FAILURE(rc))
return rc;
if (!RTDirExists(pszPath))
{
if (RT_FAILURE(rc))
{
}
}
/* Prepare the destination file name while we're here. */
if (RT_FAILURE(rc))
return rc;
/*
* Download the file.
*/
if (RT_FAILURE(rc))
return rc;
static const char * const s_apszHeaders[] =
{
"User-Agent: Microsoft-Symbol-Server/6.6.0999.9",
"Pragma: no-cache",
};
if (RT_SUCCESS(rc))
{
RTStrPrintf(szUrl, sizeof(szUrl), "%s/%s/%s/%s", pszServer, pszFilename, pszCacheSubDir, pszFilename);
/** @todo Use some temporary file name and rename it after the operation
* since not all systems support read-deny file sharing
* settings. */
if (RT_FAILURE(rc))
{
}
if (rc == VERR_HTTP_NOT_FOUND)
{
/* Try the compressed version of the file. */
if (RT_SUCCESS(rc))
else
{
}
}
}
/*
* If we succeeded, give it a try.
*/
if (RT_SUCCESS(rc))
{
if (rc == VINF_CALLBACK_RETURN)
else if (rc == VERR_CALLBACK_RETURN)
else
}
return rc;
#else /* !IPRT_WITH_HTTP */
return VWRN_NOT_FOUND;
#endif /* !IPRT_WITH_HTTP */
}
static int rtDbgCfgCopyFileToCache(PRTDBGCFGINT pThis, char const *pszSrc, const char *pchCache, size_t cchCache,
{
/** @todo copy to cache */
return VINF_SUCCESS;
}
static int rtDbgCfgTryOpenCache(PRTDBGCFGINT pThis, char *pszPath, const char *pszCacheSubDir, PRTPATHSPLIT pSplitFn,
{
/*
* If the cache doesn't exist, fail right away.
*/
if (!pszCacheSubDir || !*pszCacheSubDir)
return VWRN_NOT_FOUND;
if (!RTDirExists(pszPath))
{
return VWRN_NOT_FOUND;
}
/*
* Carefully construct the cache path with case insensitivity in mind.
*/
return VWRN_NOT_FOUND;
return VWRN_NOT_FOUND;
bool fProbablyCompressed = false;
return VWRN_NOT_FOUND;
if (fProbablyCompressed)
{
if (RT_FAILURE(rc))
return VWRN_NOT_FOUND;
}
if (rc2 == VINF_CALLBACK_RETURN)
else if (rc2 == VERR_CALLBACK_RETURN)
else
return rc2;
}
static int rtDbgCfgTryOpenList(PRTDBGCFGINT pThis, PRTLISTANCHOR pList, PRTPATHSPLIT pSplitFn, const char *pszCacheSubDir,
{
int rcRet = VWRN_NOT_FOUND;
int rc2;
int rcCache = VWRN_NOT_FOUND;
{
/* This is very simplistic, but we have a unreasonably large path
buffer, so it'll work just fine and simplify things greatly below. */
{
if (RT_SUCCESS_NP(rcRet))
continue;
}
/*
* Process the path according to it's type.
*/
{
/*
* Symbol server.
*/
bool fSearchCache = false;
if (!pszServer)
continue;
{
fSearchCache = true;
pszServer++;
}
/* We don't have any default cache directory, so skip if the cache is missing. */
if (cchCache == 0)
continue;
/* Search the cache first (if we haven't already done so). */
if (fSearchCache)
{
return rc2;
}
/* Try downloading the file. */
if (rcCache == VWRN_NOT_FOUND)
{
return rc2;
}
}
{
/*
* Cache directory.
*/
if (!cchDir)
continue;
return rc2;
}
else
{
/*
* Normal directory. Check for our own 'rec*' and 'norec*' prefix
* flags governing recursive searching.
*/
{
}
{
}
/* Copy the path into the buffer and do the searching. */
{
if ( rc2 == VINF_CALLBACK_RETURN
&& cchCache > 0)
return rc2;
}
}
/* Propagate errors. */
}
return rcRet;
}
/**
* Common worker routine for Image and debug info opening.
*
* This will not search using for suffixes.
*
* @returns IPRT status code.
* @param hDbgCfg The debugging configuration handle. NIL_RTDBGCFG is
* accepted, but the result is that no paths will be
* searched beyond the given and the current directory.
* @param pszFilename The filename to search for. This may or may not
* include a full or partial path.
* @param pszCacheSubDir The cache subdirectory to look in.
* @param fFlags Flags and hints.
* @param pfnCallback The open callback routine.
* @param pvUser1 User parameter 1.
* @param pvUser2 User parameter 2.
*/
static int rtDbgCfgOpenWithSubDir(RTDBGCFG hDbgCfg, const char *pszFilename, const char *pszCacheSubDir,
{
int rcRet = VINF_SUCCESS;
int rc2;
/*
* Do a little validating first.
*/
if (pThis != NIL_RTDBGCFG)
else
/*
* Do some guessing as to the way we should parse the filename and whether
* it's case exact or not.
*/
|| (fFlags & RTDBGCFG_O_CASE_INSENSITIVE);
if (fDosPath)
rtDbgCfgLog2(pThis, "Looking for '%s' w/ cache subdir '%s' and %#x flags...\n", pszFilename, pszCacheSubDir, fFlags);
rc2 = RTPathSplitA(pszFilename, &pSplitFn, fDosPath ? RTPATH_STR_F_STYLE_DOS : RTPATH_STR_F_STYLE_UNIX);
if (RT_FAILURE(rc2))
return rc2;
/*
* Try the stored file name first if it has a kind of absolute path.
*/
char szPath[RTPATH_MAX];
{
}
if ( rc2 != VINF_CALLBACK_RETURN
&& rc2 != VERR_CALLBACK_RETURN)
{
/*
* Try the current directory (will take cover relative paths
* skipped above).
*/
if (RT_FAILURE(rc2))
if ( rc2 != VINF_CALLBACK_RETURN
&& rc2 != VERR_CALLBACK_RETURN
&& pThis)
{
if (RT_SUCCESS(rc2))
{
/*
* Run the applicable lists.
*/
#ifdef RT_OS_WINDOWS
if ( rc2 != VINF_CALLBACK_RETURN
&& rc2 != VERR_CALLBACK_RETURN
{
rc2 = rtDbgCfgTryOpenList(pThis, &pThis->NtExecutablePathList, pSplitFn, pszCacheSubDir, fFlags, szPath,
}
if ( rc2 != VINF_CALLBACK_RETURN
&& rc2 != VERR_CALLBACK_RETURN
{
rc2 = rtDbgCfgTryOpenList(pThis, &pThis->NtSymbolPathList, pSplitFn, pszCacheSubDir, fFlags, szPath,
}
#endif
}
else if (RT_SUCCESS(rcRet))
}
}
if ( rc2 == VINF_CALLBACK_RETURN
|| rc2 == VERR_CALLBACK_RETURN)
else if (RT_SUCCESS(rcRet))
return rcRet;
}
RTDECL(int) RTDbgCfgOpenPeImage(RTDBGCFG hDbgCfg, const char *pszFilename, uint32_t cbImage, uint32_t uTimestamp,
{
char szSubDir[32];
}
RTDECL(int) RTDbgCfgOpenPdb70(RTDBGCFG hDbgCfg, const char *pszFilename, PCRTUUID pUuid, uint32_t uAge,
{
char szSubDir[64];
if (!pUuid)
szSubDir[0] = '\0';
else
{
/* Stringify the UUID and remove the dashes. */
char ch;
if (ch != '-')
}
}
RTDECL(int) RTDbgCfgOpenPdb20(RTDBGCFG hDbgCfg, const char *pszFilename, uint32_t cbImage, uint32_t uTimestamp, uint32_t uAge,
{
/** @todo test this! */
char szSubDir[32];
}
RTDECL(int) RTDbgCfgOpenDbg(RTDBGCFG hDbgCfg, const char *pszFilename, uint32_t cbImage, uint32_t uTimestamp,
{
char szSubDir[32];
}
{
char szSubDir[32];
}
/**
* Frees a string list.
*
* @param pList The list to free.
*/
{
{
}
}
/**
* Make changes to a string list, given a semicolon separated input string.
*
* @returns VINF_SUCCESS, VERR_FILENAME_TOO_LONG, VERR_NO_MEMORY
* @param pThis The config instance.
* @param enmOp The change operation.
* @param pszValue The input strings separated by semicolon.
* @param fPaths Indicates that this is a path list and that we
* should look for srv and cache prefixes.
* @param pList The string list anchor.
*/
static int rtDbgCfgChangeStringList(PRTDBGCFGINT pThis, RTDBGCFGOP enmOp, const char *pszValue, bool fPaths,
{
if (enmOp == RTDBGCFGOP_SET)
while (*pszValue)
{
/* Skip separators. */
while (*pszValue == ';')
pszValue++;
if (!*pszValue)
break;
/* Find the end of this path. */
char ch;
pszValue++;
if (cchPath >= UINT16_MAX)
return VERR_FILENAME_TOO_LONG;
if (enmOp == RTDBGCFGOP_REMOVE)
{
/*
* Remove all occurences.
*/
{
{
}
}
}
else
{
/*
* We're adding a new one.
*/
if (!pNew)
return VERR_NO_MEMORY;
if (enmOp == RTDBGCFGOP_PREPEND)
else
}
}
return VINF_SUCCESS;
}
/**
* Make changes to a 64-bit value
*
* @returns VINF_SUCCESS, VERR_DBG_CFG_INVALID_VALUE.
* @param pThis The config instance.
* @param enmOp The change operation.
* @param pszValue The input value.
* @param pszMnemonics The mnemonics map for this value.
* @param puValue The value to change.
*/
{
char ch;
{
/* skip whitespace and separators */
if (!ch)
break;
if (RT_C_IS_DIGIT(ch))
{
return VERR_DBG_CFG_INVALID_VALUE;
if (enmOp != RTDBGCFGOP_REMOVE)
else
}
else
{
/* A mnemonic, find the end of it. */
do
/* Look it up in the map and apply it. */
unsigned i = 0;
while (paMnemonics[i].pszMnemonic)
{
{
else
break;
}
i++;
}
if (!paMnemonics[i].pszMnemonic)
return VERR_DBG_CFG_INVALID_VALUE;
}
}
return VINF_SUCCESS;
}
RTDECL(int) RTDbgCfgChangeString(RTDBGCFG hDbgCfg, RTDBGCFGPROP enmProp, RTDBGCFGOP enmOp, const char *pszValue)
{
if (!pszValue)
pszValue = "";
else
if (RT_SUCCESS(rc))
{
switch (enmProp)
{
case RTDBGCFGPROP_FLAGS:
break;
case RTDBGCFGPROP_PATH:
break;
case RTDBGCFGPROP_SUFFIXES:
break;
case RTDBGCFGPROP_SRC_PATH:
break;
default:
AssertFailed();
}
}
return rc;
}
RTDECL(int) RTDbgCfgChangeUInt(RTDBGCFG hDbgCfg, RTDBGCFGPROP enmProp, RTDBGCFGOP enmOp, uint64_t uValue)
{
if (RT_SUCCESS(rc))
{
switch (enmProp)
{
case RTDBGCFGPROP_FLAGS:
break;
default:
}
if (RT_SUCCESS(rc))
{
switch (enmOp)
{
case RTDBGCFGOP_SET:
break;
case RTDBGCFGOP_APPEND:
case RTDBGCFGOP_PREPEND:
break;
case RTDBGCFGOP_REMOVE:
break;
default:
AssertFailed();
}
}
}
return rc;
}
/**
* Querys a string list as a single string (semicolon separators).
*
* @returns VINF_SUCCESS, VERR_BUFFER_OVERFLOW.
* @param pThis The config instance.
* @param pList The string list anchor.
* @param pszValue The output buffer.
* @param cbValue The size of the output buffer.
*/
{
/*
* Check the length first.
*/
return VERR_BUFFER_OVERFLOW;
/*
* Construct the string list in the buffer.
*/
{
*psz++ = ';';
}
*psz = '\0';
return VINF_SUCCESS;
}
/**
* Querys the string value of a 64-bit unsigned int.
*
* @returns VINF_SUCCESS, VERR_BUFFER_OVERFLOW.
* @param pThis The config instance.
* @param uValue The value to query.
* @param pszMnemonics The mnemonics map for this value.
* @param pszValue The output buffer.
* @param cbValue The size of the output buffer.
*/
static int rtDbgCfgQueryStringU64(RTDBGCFG hDbgCfg, uint64_t uValue, PCRTDBGCFGU64MNEMONIC paMnemonics,
{
/*
* If no mnemonics, just return the hex value.
*/
{
char szTmp[64];
return VERR_BUFFER_OVERFLOW;
return VINF_SUCCESS;
}
/*
* Check that there is sufficient buffer space first.
*/
for (unsigned i = 0; paMnemonics[i].pszMnemonic; i++)
if ( paMnemonics[i].fSet
return VERR_BUFFER_OVERFLOW;
/*
* Construct the string.
*/
for (unsigned i = 0; paMnemonics[i].pszMnemonic; i++)
if ( paMnemonics[i].fSet
{
*psz++ = ' ';
}
*psz = '\0';
return VINF_SUCCESS;
}
RTDECL(int) RTDbgCfgQueryString(RTDBGCFG hDbgCfg, RTDBGCFGPROP enmProp, char *pszValue, size_t cbValue)
{
if (RT_SUCCESS(rc))
{
switch (enmProp)
{
case RTDBGCFGPROP_FLAGS:
break;
case RTDBGCFGPROP_PATH:
break;
case RTDBGCFGPROP_SUFFIXES:
break;
case RTDBGCFGPROP_SRC_PATH:
break;
default:
AssertFailed();
}
}
return rc;
}
{
if (RT_SUCCESS(rc))
{
switch (enmProp)
{
case RTDBGCFGPROP_FLAGS:
break;
default:
}
}
return rc;
}
{
return cRefs;
}
{
if (hDbgCfg == NIL_RTDBGCFG)
return 0;
if (!cRefs)
{
/*
* Last reference - free all memory.
*/
#ifdef RT_OS_WINDOWS
#endif
}
else
return cRefs;
}
{
/*
* Validate input.
*/
if (pszEnvVarPrefix)
{
}
/*
* Allocate and initialize a new instance.
*/
if (!pThis)
return VERR_NO_MEMORY;
#ifdef RT_OS_WINDOWS
#endif
if (RT_FAILURE(rc))
{
return rc;
}
/*
* Read configurtion from the environment if requested to do so.
*/
if (pszEnvVarPrefix || fNativePaths)
{
if (pszEnvVar)
{
if (pszEnvVarPrefix)
{
static struct
{
const char *pszVar;
} const s_aProps[] =
{
{ RTDBGCFGPROP_FLAGS, "FLAGS" },
{ RTDBGCFGPROP_PATH, "PATH" },
{ RTDBGCFGPROP_SUFFIXES, "SUFFIXES" },
{ RTDBGCFGPROP_SRC_PATH, "SRC_PATH" },
};
for (unsigned i = 0; i < RT_ELEMENTS(s_aProps); i++)
{
{
break;
}
if (RT_SUCCESS(rc))
{
if (RT_FAILURE(rc))
break;
}
else if (rc != VERR_ENV_VAR_NOT_FOUND)
break;
else
rc = VINF_SUCCESS;
}
}
/*
* Pick up system specific search paths.
*/
{
struct
{
const char *pszVar;
char chSep;
} aNativePaths[] =
{
#ifdef RT_OS_WINDOWS
#endif
};
for (unsigned i = 0; aNativePaths[i].pList; i++)
{
if (RT_SUCCESS(rc))
{
if (RT_FAILURE(rc))
break;
}
else if (rc != VERR_ENV_VAR_NOT_FOUND)
break;
else
rc = VINF_SUCCESS;
}
}
}
else
if (RT_FAILURE(rc))
{
/*
* Error, bail out.
*/
return rc;
}
}
/*
* Returns successfully.
*/
return VINF_SUCCESS;
}