log.cpp revision 75fd5371312e98d90a04367c9f100849ce559bda
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Runtime VBox - Logger.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Copyright (C) 2006-2007 Sun Microsystems, Inc.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * This file is part of VirtualBox Open Source Edition (OSE), as
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * available from http://www.virtualbox.org. This file is free software;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * you can redistribute it and/or modify it under the terms of the GNU
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * General Public License (GPL) as published by the Free Software
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Foundation, in version 2 as it comes in the "COPYING" file of the
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * The contents of this file may alternatively be used under the terms
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * of the Common Development and Distribution License Version 1.0
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * VirtualBox OSE distribution, in which case the provisions of the
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * CDDL are applicable instead of those of the GPL.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * You may elect to license modified versions of this file under the
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * terms and conditions of either the GPL or the CDDL or both.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Clara, CA 95054 USA or visit http://www.sun.com if you need
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * additional information or have any questions.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/*******************************************************************************
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster* Header Files *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster*******************************************************************************/
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/*******************************************************************************
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster* Structures and Typedefs *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster*******************************************************************************/
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Arguments passed to the output function.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /** The logger instance. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /** The flags. (used for prefixing.) */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /** The group. (used for prefixing.) */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster} RTLOGOUTPUTPREFIXEDARGS, *PRTLOGOUTPUTPREFIXEDARGS;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/*******************************************************************************
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster* Internal Functions *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster*******************************************************************************/
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterstatic unsigned rtlogGroupFlags(const char *psz);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterstatic void rtR0LogLoggerExFallback(uint32_t fDestFlags, const char *pszFormat, va_list va);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterstatic DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterstatic DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars, size_t cbChars);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/*******************************************************************************
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster* Global Variables *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster*******************************************************************************/
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/** Default logger instance. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#else /* !IN_RC */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/** Default logger instance. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#endif /* !IN_RC */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/** The RTThreadGetWriteLockCount() change caused by the logger mutex semaphore. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/** Number of per-thread loggers. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/** Per-thread loggers.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * This is just a quick TLS hack suitable for debug logging only.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * If we run out of entries, just unload and reload the driver. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /** The thread. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /** The (process / session) key. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /** The logger instance.*/
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#endif /* IN_RING0 */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Locks the logger instance.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @returns See RTSemFastMutexRequest().
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param pLogger The logger instance.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster# if defined(IN_RING0) \
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster && (defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX))
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Unlocks the logger instance.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param pLogger The logger instance.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Create a logger instance, comprehensive version.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @returns iprt status code.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param ppLogger Where to store the logger instance.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param fFlags Logger instance flags, a combination of the RTLOGFLAGS_* values.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param pszGroupSettings The initial group settings.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param pszEnvVarBase Base name for the environment variables for this instance.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param cGroups Number of groups in the array.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param papszGroups Pointer to array of groups. This must stick around for the life of the
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * logger instance.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param fDestFlags The destination flags. RTLOGDEST_FILE is ORed if pszFilenameFmt specified.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param pszErrorMsg A buffer which is filled with an error message if something fails. May be NULL.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param cchErrorMsg The size of the error message buffer.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param pszFilenameFmt Log filename format string. Standard RTStrFormat().
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * @param ... Format arguments.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan FosterRTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, RTUINT fFlags, const char *pszGroupSettings,
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster RTUINT fDestFlags, char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, va_list args)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Validate input.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster RTStrPrintf(pszErrorMsg, cchErrorMsg, "unknown error");
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Allocate a logger instance.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster cb = RT_OFFSETOF(RTLOGGER, afGroups[cGroups + 1]) + RTPATH_MAX;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster pLogger->pszFilename = (char *)&pLogger->afGroups[cGroups + 1];
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Emit wrapper code.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /* this wrapper will not be used on AMD64, we will be requiring C99 compilers there. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster pu8Code += sizeof(void *);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster *(uint32_t *)pu8Code = (uintptr_t)RTLogLogger - ((uintptr_t)pu8Code + sizeof(uint32_t));
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster AssertMsg((uintptr_t)pu8Code - (uintptr_t)pLogger->pfnLogger <= 64,
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ("Wrapper assembly is too big! %d bytes\n", (uintptr_t)pu8Code - (uintptr_t)pLogger->pfnLogger));
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#ifdef IN_RING3 /* files and env.vars. are only accessible when in R3 at the present time. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Format the filename.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster RTStrPrintfV(pLogger->pszFilename, RTPATH_MAX, pszFilenameFmt, args);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Parse the environment variables.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /* make temp copy of environment variable base. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster char *pszEnvVar = (char *)alloca(cchEnvVarBase + 16);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster memcpy(pszEnvVar, pszEnvVarBase, cchEnvVarBase);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Destination.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /* skip blanks. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /* parse instruction. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster static struct
bool fNo = false;
fNo = true;
if (!fNo)
pszVar++;
pszVar++;
if (!pszEnd)
if (pszFile)
AssertMsgFailed(("Invalid %s_DEST! %s%s doesn't take a value!\n", pszEnvVarBase, fNo ? "no" : "", aDest[i].pszInstr));
pszVar++;
pszVar++;
if (pszVar)
if (pszVar)
#ifdef IN_RING3
return VINF_SUCCESS;
if (pszErrorMsg)
#ifdef IN_RING3
#ifdef RT_OS_LINUX
if (pszErrorMsg)
return rc;
int rc;
rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, NULL, 0, pszFilenameFmt, args);
return rc;
* @param pszErrorMsg A buffer which is filled with an error message if something fails. May be NULL.
int rc;
rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, pszErrorMsg, cchErrorMsg, pszFilenameFmt, args);
return rc;
int rc;
if (!pLogger)
return VINF_SUCCESS;
while (iGroup-- > 0)
#ifdef IN_RING3
int rc2;
return rc;
if ( !pLoggerRC
|| !pfnFlushRCPtr
|| !pfnLoggerRCPtr)
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
if (!pLogger)
if (!pLogger)
return VINF_SUCCESS;
AssertMsgFailed(("%d req=%d cGroups=%d\n", cbLoggerRC, RT_OFFSETOF(RTLOGGERRC, afGroups[pLogger->cGroups]), pLogger->cGroups));
return VERR_INVALID_PARAMETER;
memcpy(&pLoggerRC->afGroups[0], &pLogger->afGroups[0], pLogger->cGroups * sizeof(pLoggerRC->afGroups[0]));
return VINF_SUCCESS;
if (!pLogger)
if (!pLogger)
#ifdef IN_RING3
RTDECL(int) RTLogCreateForR0(PRTLOGGER pLogger, size_t cbLogger, PFNRTLOGGER pfnLogger, PFNRTLOGFLUSH pfnFlush, RTUINT fFlags, RTUINT fDestFlags)
pLogger->cMaxGroups = (RTUINT)((cbLogger - RT_OFFSETOF(RTLOGGER, afGroups[0])) / sizeof(pLogger->afGroups[0]));
return VINF_SUCCESS;
RTDECL(int) RTLogCopyGroupsAndFlags(PRTLOGGER pDstLogger, PCRTLOGGER pSrcLogger, unsigned fFlagsOr, unsigned fFlagsAnd)
int rc;
unsigned cGroups;
if (!pSrcLogger)
if (!pSrcLogger)
return VINF_SUCCESS;
memcpy(&pDstLogger->afGroups[0], &pSrcLogger->afGroups[0], cGroups * sizeof(pDstLogger->afGroups[0]));
return rc;
if (!pDstLogger)
if (!pDstLogger)
RTDECL(int) RTLogSetCustomPrefixCallback(PRTLOGGER pLogger, PFNRTLOGPREFIX pfnCallback, void *pvUser)
if (!pLogger)
if (!pLogger)
return VINF_SUCCESS;
return VINF_SUCCESS;
const char *pachMask;
const char *pszTmp;
do pachMask++;
if ( !cchMask
if (!pszTmp)
if (!pszTmp)
if (!*++pszGrp)
pachMask++;
cchMask--;
if ( !cchMask
if (!--cchMask)
pachMask++;
if (!pLogger)
if (!pLogger)
return VINF_SUCCESS;
while (*pszVar)
bool fEnabled = true;
char ch;
const char *pszStart;
pszVar++;
if (!*pszVar)
pszVar++;
if (fEnabled)
if (fEnabled)
return VINF_SUCCESS;
unsigned fFlags = 0;
unsigned fFlag;
} aFlags[] =
bool fFound = false;
psz++;
psz1++;
psz2++;
if (!*psz1)
fFound = true;
psz++;
return fFlags;
if (!pLogger)
if (!pLogger)
return VINF_SUCCESS;
while (*pszVar)
const char *pszInstr;
unsigned fFlag;
bool fInverted;
} const aDest[] =
bool fNo = false;
char ch;
pszVar++;
if (!*pszVar)
return rc;
pszVar++;
fNo = true;
pszVar++;
pszVar++;
pszVar++;
return rc;
if (!pLogger)
#ifdef IN_RC
if (!pLogger)
#ifndef IN_RC
#ifndef IN_RC
#ifdef IN_RC
return &g_Logger;
# ifdef IN_RING0
if (g_cPerThreadLoggers)
if (!g_pLogger)
return g_pLogger;
#ifdef IN_RC
return &g_Logger;
# ifdef IN_RING0
if (g_cPerThreadLoggers)
return g_pLogger;
#ifndef IN_RC
#ifdef IN_RING0
int rc;
if (pLogger)
int32_t i;
return VINF_SUCCESS;
&& ASMAtomicCmpXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].NativeThread, (void *)Self, (void *)NIL_RTNATIVETHREAD))
return VINF_SUCCESS;
ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].NativeThread, (void *)NIL_RTNATIVETHREAD);
return rc;
RTDECL(void) RTLogLoggerExV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
int rc;
if (!pLogger)
if (!pLogger)
iGroup = 0;
#ifndef IN_RC
if ( iGroup != ~0U
&& (pLogger->afGroups[iGroup] & (fFlags | RTLOGGRPFLAGS_ENABLED)) != (fFlags | RTLOGGRPFLAGS_ENABLED))
#ifdef IN_RING0
#ifdef IN_RING0
typedef struct RTR0LOGLOGGERFALLBACK
#ifndef LOG_NO_COM
static DECLCALLBACK(size_t) rtR0LogLoggerExFallbackOutput(void *pv, const char *pachChars, size_t cbChars)
if (cbChars)
uint32_t cb = sizeof(pThis->achScratch) - pThis->offScratch - 1; /* minus 1 - for the string terminator. */
if (cbChars <= 0)
return cbRet;
#ifndef IN_RC
# ifdef IN_RING3
if (cbChars)
if (cbChars <= 0)
return cbRet;
if (cbChars)
char *psz;
const char *pszNewLine;
fFlags = 0;
fFlags = 0;
#ifdef IN_RING3
#ifdef IN_RING3
#ifndef IN_RC
#ifndef IN_RC
#ifdef IN_RING3
if (pszName)
#ifndef IN_RC
#ifdef IN_RING3
if (pszGroup)
const char *pszGroup;
if (pszGroup)
else if (cb <= 0)
if (pszNewLine)
if ( pszNewLine
cbRet++;
cbChars--;
cb++;
if (cbChars <= 0)
return cbRet;