summaryrefslogtreecommitdiffstats
path: root/src/VBox/Runtime/common/misc/assert.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Runtime/common/misc/assert.cpp')
-rw-r--r--src/VBox/Runtime/common/misc/assert.cpp353
1 files changed, 353 insertions, 0 deletions
diff --git a/src/VBox/Runtime/common/misc/assert.cpp b/src/VBox/Runtime/common/misc/assert.cpp
new file mode 100644
index 00000000..29dc3dd8
--- /dev/null
+++ b/src/VBox/Runtime/common/misc/assert.cpp
@@ -0,0 +1,353 @@
+/* $Id: assert.cpp $ */
+/** @file
+ * IPRT - Assertions, common code.
+ */
+
+/*
+ * Copyright (C) 2006-2019 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 <iprt/assert.h>
+#include "internal/iprt.h"
+
+#include <iprt/asm.h>
+#ifdef IPRT_WITH_ASSERT_STACK
+# ifndef IN_RING3
+# error "IPRT_WITH_ASSERT_STACK is only for ring-3 at present."
+# endif
+# include <iprt/dbg.h>
+#endif
+#include <iprt/errcore.h>
+#include <iprt/log.h>
+#include <iprt/string.h>
+#include <iprt/stdarg.h>
+#ifdef IN_RING3
+# include <iprt/env.h>
+# include <stdio.h>
+# ifdef RT_OS_WINDOWS
+# include <iprt/win/windows.h>
+# endif
+#endif
+#include "internal/assert.h"
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** The last assertion message, 1st part. */
+RTDATADECL(char) g_szRTAssertMsg1[1024];
+RT_EXPORT_SYMBOL(g_szRTAssertMsg1);
+/** The last assertion message, 2nd part. */
+RTDATADECL(char) g_szRTAssertMsg2[4096];
+RT_EXPORT_SYMBOL(g_szRTAssertMsg2);
+#ifdef IPRT_WITH_ASSERT_STACK
+/** The last assertion message, stack part. */
+RTDATADECL(char) g_szRTAssertStack[4096];
+RT_EXPORT_SYMBOL(g_szRTAssertStack);
+#endif
+/** The length of the g_szRTAssertMsg2 content.
+ * @remarks Race. */
+static uint32_t volatile g_cchRTAssertMsg2;
+/** The last assertion message, expression. */
+RTDATADECL(const char * volatile) g_pszRTAssertExpr;
+RT_EXPORT_SYMBOL(g_pszRTAssertExpr);
+/** The last assertion message, function name. */
+RTDATADECL(const char * volatile) g_pszRTAssertFunction;
+RT_EXPORT_SYMBOL(g_pszRTAssertFunction);
+/** The last assertion message, file name. */
+RTDATADECL(const char * volatile) g_pszRTAssertFile;
+RT_EXPORT_SYMBOL(g_pszRTAssertFile);
+/** The last assertion message, line number. */
+RTDATADECL(uint32_t volatile) g_u32RTAssertLine;
+RT_EXPORT_SYMBOL(g_u32RTAssertLine);
+
+
+/** Set if assertions are quiet. */
+static bool volatile g_fQuiet = false;
+/** Set if assertions may panic. */
+static bool volatile g_fMayPanic = true;
+
+
+RTDECL(bool) RTAssertSetQuiet(bool fQuiet)
+{
+ return ASMAtomicXchgBool(&g_fQuiet, fQuiet);
+}
+RT_EXPORT_SYMBOL(RTAssertSetQuiet);
+
+
+RTDECL(bool) RTAssertAreQuiet(void)
+{
+ return ASMAtomicUoReadBool(&g_fQuiet);
+}
+RT_EXPORT_SYMBOL(RTAssertAreQuiet);
+
+
+RTDECL(bool) RTAssertSetMayPanic(bool fMayPanic)
+{
+ return ASMAtomicXchgBool(&g_fMayPanic, fMayPanic);
+}
+RT_EXPORT_SYMBOL(RTAssertSetMayPanic);
+
+
+RTDECL(bool) RTAssertMayPanic(void)
+{
+ return ASMAtomicUoReadBool(&g_fMayPanic);
+}
+RT_EXPORT_SYMBOL(RTAssertMayPanic);
+
+
+RTDECL(void) RTAssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
+{
+ /*
+ * Fill in the globals.
+ */
+ ASMAtomicUoWritePtr(&g_pszRTAssertExpr, pszExpr);
+ ASMAtomicUoWritePtr(&g_pszRTAssertFile, pszFile);
+ ASMAtomicUoWritePtr(&g_pszRTAssertFunction, pszFunction);
+ ASMAtomicUoWriteU32(&g_u32RTAssertLine, uLine);
+ RTStrPrintf(g_szRTAssertMsg1, sizeof(g_szRTAssertMsg1),
+ "\n!!Assertion Failed!!\n"
+ "Expression: %s\n"
+ "Location : %s(%d) %s\n",
+ pszExpr, pszFile, uLine, pszFunction);
+
+ /*
+ * If not quiet, make noise.
+ */
+ if (!RTAssertAreQuiet())
+ {
+ RTERRVARS SavedErrVars;
+ RTErrVarsSave(&SavedErrVars);
+
+#ifdef IPRT_WITH_ASSERT_STACK
+ /* The stack dump. */
+ static volatile bool s_fDumpingStackAlready = false; /* for simple recursion prevention */
+ char szStack[sizeof(g_szRTAssertStack)];
+ size_t cchStack = 0;
+# if defined(IN_RING3) && defined(RT_OS_WINDOWS) /** @todo make this stack on/off thing more modular. */
+ bool fStack = !IsDebuggerPresent() && !RTEnvExist("IPRT_ASSERT_NO_STACK");
+# elif defined(IN_RING3)
+ bool fStack = !RTEnvExist("IPRT_ASSERT_NO_STACK");
+# else
+ bool fStack = true;
+# endif
+ szStack[0] = '\0';
+ if (fStack && !s_fDumpingStackAlready)
+ {
+ s_fDumpingStackAlready = true;
+ cchStack = RTDbgStackDumpSelf(szStack, sizeof(szStack), 0);
+ s_fDumpingStackAlready = false;
+ }
+ memcpy(g_szRTAssertStack, szStack, cchStack + 1);
+#endif
+
+#ifdef IN_RING0
+# ifdef IN_GUEST_R0
+ RTLogBackdoorPrintf("\n!!Assertion Failed!!\n"
+ "Expression: %s\n"
+ "Location : %s(%d) %s\n",
+ pszExpr, pszFile, uLine, pszFunction);
+# endif
+ /** @todo fully integrate this with the logger... play safe a bit for now. */
+ rtR0AssertNativeMsg1(pszExpr, uLine, pszFile, pszFunction);
+
+#else /* !IN_RING0 */
+# if !defined(IN_RING3) && !defined(LOG_NO_COM)
+# if 0 /* Enable this iff you have a COM port and really want this debug info. */
+ RTLogComPrintf("\n!!Assertion Failed!!\n"
+ "Expression: %s\n"
+ "Location : %s(%d) %s\n",
+ pszExpr, pszFile, uLine, pszFunction);
+# endif
+# endif
+
+ PRTLOGGER pLog = RTLogRelGetDefaultInstance();
+ if (pLog)
+ {
+ RTLogRelPrintf("\n!!Assertion Failed!!\n"
+ "Expression: %s\n"
+ "Location : %s(%d) %s\n",
+ pszExpr, pszFile, uLine, pszFunction);
+# ifdef IPRT_WITH_ASSERT_STACK
+ RTLogRelPrintf("Stack :\n%s\n", szStack);
+# endif
+# ifndef IN_RC /* flushing is done automatically in RC */
+ RTLogFlush(pLog);
+# endif
+ }
+
+# ifndef LOG_ENABLED
+ if (!pLog)
+# endif
+ {
+ pLog = RTLogDefaultInstance();
+ if (pLog)
+ {
+ RTLogPrintf("\n!!Assertion Failed!!\n"
+ "Expression: %s\n"
+ "Location : %s(%d) %s\n",
+ pszExpr, pszFile, uLine, pszFunction);
+# ifdef IPRT_WITH_ASSERT_STACK
+ RTLogPrintf("Stack :\n%s\n", szStack);
+# endif
+# ifndef IN_RC /* flushing is done automatically in RC */
+ RTLogFlush(pLog);
+# endif
+ }
+ }
+
+# ifdef IN_RING3
+ /* print to stderr, helps user and gdb debugging. */
+ fprintf(stderr,
+ "\n!!Assertion Failed!!\n"
+ "Expression: %s\n"
+ "Location : %s(%d) %s\n",
+ VALID_PTR(pszExpr) ? pszExpr : "<none>",
+ VALID_PTR(pszFile) ? pszFile : "<none>",
+ uLine,
+ VALID_PTR(pszFunction) ? pszFunction : "");
+# ifdef IPRT_WITH_ASSERT_STACK
+ fprintf(stderr, "Stack :\n%s\n", szStack);
+# endif
+ fflush(stderr);
+# endif
+#endif /* !IN_RING0 */
+
+ RTErrVarsRestore(&SavedErrVars);
+ }
+}
+RT_EXPORT_SYMBOL(RTAssertMsg1);
+
+
+/**
+ * Worker for RTAssertMsg2V and RTAssertMsg2AddV
+ *
+ * @param fInitial True if it's RTAssertMsg2V, otherwise false.
+ * @param pszFormat The message format string.
+ * @param va The format arguments.
+ */
+static void rtAssertMsg2Worker(bool fInitial, const char *pszFormat, va_list va)
+{
+ va_list vaCopy;
+ size_t cch;
+
+ /*
+ * The global first.
+ */
+ if (fInitial)
+ {
+ va_copy(vaCopy, va);
+ cch = RTStrPrintfV(g_szRTAssertMsg2, sizeof(g_szRTAssertMsg2), pszFormat, vaCopy);
+ ASMAtomicWriteU32(&g_cchRTAssertMsg2, (uint32_t)cch);
+ va_end(vaCopy);
+ }
+ else
+ {
+ cch = ASMAtomicReadU32(&g_cchRTAssertMsg2);
+ if (cch < sizeof(g_szRTAssertMsg2) - 4)
+ {
+ va_copy(vaCopy, va);
+ cch += RTStrPrintfV(&g_szRTAssertMsg2[cch], sizeof(g_szRTAssertMsg2) - cch, pszFormat, vaCopy);
+ ASMAtomicWriteU32(&g_cchRTAssertMsg2, (uint32_t)cch);
+ va_end(vaCopy);
+ }
+ }
+
+ /*
+ * If not quiet, make some noise.
+ */
+ if (!RTAssertAreQuiet())
+ {
+ RTERRVARS SavedErrVars;
+ RTErrVarsSave(&SavedErrVars);
+
+#ifdef IN_RING0
+# ifdef IN_GUEST_R0
+ va_copy(vaCopy, va);
+ RTLogBackdoorPrintfV(pszFormat, vaCopy);
+ va_end(vaCopy);
+# endif
+ /** @todo fully integrate this with the logger... play safe a bit for now. */
+ rtR0AssertNativeMsg2V(fInitial, pszFormat, va);
+
+#else /* !IN_RING0 */
+# if !defined(IN_RING3) && !defined(LOG_NO_COM)
+# if 0 /* Enable this iff you have a COM port and really want this debug info. */
+ va_copy(vaCopy, va);
+ RTLogComPrintfV(pszFormat, vaCopy);
+ va_end(vaCopy);
+# endif
+# endif
+
+ PRTLOGGER pLog = RTLogRelGetDefaultInstance();
+ if (pLog)
+ {
+ va_copy(vaCopy, va);
+ RTLogRelPrintfV(pszFormat, vaCopy);
+ va_end(vaCopy);
+# ifndef IN_RC /* flushing is done automatically in RC */
+ RTLogFlush(pLog);
+# endif
+ }
+
+ pLog = RTLogDefaultInstance();
+ if (pLog)
+ {
+ va_copy(vaCopy, va);
+ RTLogPrintfV(pszFormat, vaCopy);
+ va_end(vaCopy);
+# ifndef IN_RC /* flushing is done automatically in RC */
+ RTLogFlush(pLog);
+#endif
+ }
+
+# ifdef IN_RING3
+ /* print to stderr, helps user and gdb debugging. */
+ char szMsg[sizeof(g_szRTAssertMsg2)];
+ va_copy(vaCopy, va);
+ RTStrPrintfV(szMsg, sizeof(szMsg), pszFormat, vaCopy);
+ va_end(vaCopy);
+ fprintf(stderr, "%s", szMsg);
+ fflush(stderr);
+# endif
+#endif /* !IN_RING0 */
+
+ RTErrVarsRestore(&SavedErrVars);
+ }
+}
+
+
+RTDECL(void) RTAssertMsg2V(const char *pszFormat, va_list va)
+{
+ rtAssertMsg2Worker(true /*fInitial*/, pszFormat, va);
+}
+RT_EXPORT_SYMBOL(RTAssertMsg2V);
+
+
+RTDECL(void) RTAssertMsg2AddV(const char *pszFormat, va_list va)
+{
+ rtAssertMsg2Worker(false /*fInitial*/, pszFormat, va);
+}
+RT_EXPORT_SYMBOL(RTAssertMsg2AddV);
+