VirtualBox

source: vbox/trunk/src/VBox/Runtime/VBox/RTAssertShouldPanic-vbox.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 6.8 KB
Line 
1/* $Id: RTAssertShouldPanic-vbox.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Assertions, generic RTAssertShouldPanic.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/assert.h>
42#include <iprt/env.h>
43#include <iprt/errcore.h>
44#include <iprt/string.h>
45
46/** @def VBOX_RTASSERT_WITH_GDB
47 * Enables the 'gdb' VBOX_ASSERT option.
48 */
49#if defined(DOXYGEN_RUNNING) \
50 || ( !defined(VBOX_RTASSERT_WITH_GDB) \
51 && !defined(IN_GUEST) \
52 && !defined(IN_RT_STATIC) /* valkit too big, sorry */ \
53 && !defined(RT_OS_OS2) \
54 && !defined(RT_OS_WINDOWS))
55# define VBOX_RTASSERT_WITH_GDB
56#endif
57
58/** @def VBOX_RTASSERT_WITH_WAIT
59 * Enables the 'wait' VBOX_ASSERT option.
60 */
61#if defined(DOXYGEN_RUNNING) \
62 || ( !defined(VBOX_RTASSERT_WITH_WAIT) \
63 && defined(IN_RING3) \
64 && !defined(RT_OS_OS2) \
65 && !defined(RT_OS_WINDOWS))
66# define VBOX_RTASSERT_WITH_WAIT
67#endif
68
69#ifdef VBOX_RTASSERT_WITH_GDB
70# include <iprt/process.h>
71# include <iprt/path.h>
72# include <iprt/thread.h>
73# include <iprt/asm.h>
74#endif
75
76#ifdef VBOX_RTASSERT_WITH_WAIT
77# include <signal.h>
78# include <unistd.h>
79#endif
80
81/**
82 * Worker that we can wrap with error variable saving and restoring.
83 */
84static bool rtAssertShouldPanicWorker(void)
85{
86 /*
87 * Check for the VBOX_ASSERT variable.
88 */
89 const char *psz = RTEnvGet("VBOX_ASSERT");
90
91 /* not defined => default behaviour. */
92 if (!psz)
93 return true;
94
95 /* 'breakpoint' or 'panic' means default behaviour. */
96 if (!strcmp(psz, "breakpoint") || !strcmp(psz, "panic"))
97 return true;
98
99 /* 'disabled' does not trigger a breakpoint. */
100 if (!strcmp(psz, "disabled"))
101 return false;
102
103#ifdef VBOX_RTASSERT_WITH_WAIT
104 /* 'wait' - execute a sigwait(3) while a debugger is attached. */
105 if (!strcmp(psz, "wait"))
106 {
107 sigset_t signalMask, oldMask;
108 int iSignal;
109 static pid_t lastPid = -1;
110
111 /* Only wait on the first assertion we hit per process fork, assuming
112 * the user will attach the debugger at once if they want to do so.
113 * For a clever solution to detect an attached debugger, see:
114 * http://stackoverflow.com/a/8135517
115 * For now I preferred to keep things simple and hopefully reliable. */
116 if (lastPid == getpid())
117 return true;
118 lastPid = getpid();
119 /* Register signal that we are waiting for */
120 sigemptyset(&signalMask);
121 sigaddset(&signalMask, SIGUSR2);
122 RTAssertMsg2("Attach debugger (pid: %ld) and resume with SIGUSR2.\n", (long)lastPid);
123 pthread_sigmask(SIG_BLOCK, &signalMask, &oldMask);
124 /* Ignoring return status */
125 sigwait(&signalMask, &iSignal);
126 pthread_sigmask(SIG_SETMASK, &oldMask, NULL);
127 /* Breakpoint no longer needed. */
128 return false;
129 }
130#endif
131
132#ifdef VBOX_RTASSERT_WITH_GDB
133 /* 'gdb' - means try launch a gdb session in xterm. */
134 if (!strcmp(psz, "gdb"))
135 {
136 /* Did we already fire up gdb? If so, just hit the breakpoint. */
137 static bool volatile s_fAlreadyLaunchedGdb = false;
138 if (ASMAtomicUoReadBool(&s_fAlreadyLaunchedGdb))
139 return true;
140
141 /* Try find a suitable terminal program. */
142 const char *pszTerm = RTEnvGet("VBOX_ASSERT_TERM");
143 if ( !pszTerm
144 || !RTPathExists(pszTerm))
145 {
146 pszTerm = "/usr/bin/gnome-terminal";
147 if (!RTPathExists(pszTerm))
148 {
149 pszTerm = "/usr/X11R6/bin/xterm";
150 if (!RTPathExists(pszTerm))
151 {
152 pszTerm ="/usr/bin/xterm";
153 if (!RTPathExists(pszTerm))
154 return true;
155 }
156 }
157 }
158
159 /* And find gdb. */
160 const char *pszGdb = RTEnvGet("VBOX_ASSERT_GDB");
161 if ( !pszGdb
162 || !RTPathExists(pszGdb))
163 {
164 pszGdb = "/usr/bin/gdb";
165 if (!RTPathExists(pszGdb))
166 pszGdb = "gdb";
167 }
168
169 /* Try spawn the process. */
170 char szCmd[512];
171 size_t cch = RTStrPrintf(szCmd, sizeof(szCmd), "%s -p %d ", pszGdb, RTProcSelf());
172 if (cch < sizeof(szCmd))
173 {
174 char *pszExecName = &szCmd[cch];
175 if (!RTProcGetExecutablePath(pszExecName, sizeof(szCmd) - cch))
176 *pszExecName = '\0';
177 }
178 const char *apszArgs[] =
179 {
180 pszTerm,
181 "-e",
182 szCmd,
183 NULL
184 };
185 RTPROCESS Process;
186 int rc = RTProcCreate(apszArgs[0], &apszArgs[0], RTENV_DEFAULT, 0, &Process);
187 if (RT_FAILURE(rc))
188 return false;
189
190 ASMAtomicWriteBool(&s_fAlreadyLaunchedGdb, true);
191
192 /* Wait for gdb to attach. */
193 RTThreadSleep(15000);
194 return true;
195 }
196#endif
197
198 /* '*' - don't hit the breakpoint. */
199 return false;
200}
201
202
203RTDECL(bool) RTAssertShouldPanic(void)
204{
205 /*
206 * Check if panicing is excluded by the RTAssert settings first.
207 */
208 if (!RTAssertMayPanic())
209 return false;
210
211 /*
212 * Preserve error state variables.
213 */
214 RTERRVARS SavedErrVars;
215 RTErrVarsSave(&SavedErrVars);
216
217 bool fRc = rtAssertShouldPanicWorker();
218
219 RTErrVarsRestore(&SavedErrVars);
220 return fRc;
221}
222
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use