1
2 /*--------------------------------------------------------------------*/
3 /*--- Assertions and panics. m_libcassert.c ---*/
4 /*--------------------------------------------------------------------*/
5
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
10 Copyright (C) 2000-2012 Julian Seward
11 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29 */
30
31 #include "pub_core_basics.h"
32 #include "pub_core_vki.h"
33 #include "pub_core_vkiscnums.h"
34 #include "pub_core_libcsetjmp.h" // to keep threadstate.h happy
35 #include "pub_core_threadstate.h"
36 #include "pub_core_libcbase.h"
37 #include "pub_core_libcassert.h"
38 #include "pub_core_libcprint.h"
39 #include "pub_core_libcproc.h" // For VG_(gettid)()
40 #include "pub_core_stacktrace.h"
41 #include "pub_core_syscall.h"
42 #include "pub_core_tooliface.h" // For VG_(details).{name,bug_reports_to}
43 #include "pub_core_options.h" // For VG_(clo_xml)
44
45 /* ---------------------------------------------------------------------
46 Assertery.
47 ------------------------------------------------------------------ */
48
49 #if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
50 # define GET_STARTREGS(srP) \
51 { UInt eip, esp, ebp; \
52 __asm__ __volatile__( \
53 "call 0f;" \
54 "0: popl %0;" \
55 "movl %%esp, %1;" \
56 "movl %%ebp, %2;" \
57 : "=r" (eip), "=r" (esp), "=r" (ebp) \
58 : /* reads none */ \
59 : "memory" \
60 ); \
61 (srP)->r_pc = (ULong)eip; \
62 (srP)->r_sp = (ULong)esp; \
63 (srP)->misc.X86.r_ebp = ebp; \
64 }
65 #elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin)
66 # define GET_STARTREGS(srP) \
67 { ULong rip, rsp, rbp; \
68 __asm__ __volatile__( \
69 "leaq 0(%%rip), %0;" \
70 "movq %%rsp, %1;" \
71 "movq %%rbp, %2;" \
72 : "=r" (rip), "=r" (rsp), "=r" (rbp) \
73 : /* reads none */ \
74 : "memory" \
75 ); \
76 (srP)->r_pc = rip; \
77 (srP)->r_sp = rsp; \
78 (srP)->misc.AMD64.r_rbp = rbp; \
79 }
80 #elif defined(VGP_ppc32_linux)
81 # define GET_STARTREGS(srP) \
82 { UInt cia, r1, lr; \
83 __asm__ __volatile__( \
84 "mflr 0;" /* r0 = lr */ \
85 "bl m_libcassert_get_ip;" /* lr = pc */ \
86 "m_libcassert_get_ip:\n" \
87 "mflr %0;" /* %0 = pc */ \
88 "mtlr 0;" /* restore lr */ \
89 "mr %1,1;" /* %1 = r1 */ \
90 "mr %2,0;" /* %2 = lr */ \
91 : "=r" (cia), "=r" (r1), "=r" (lr) \
92 : /* reads none */ \
93 : "r0" /* trashed */ \
94 ); \
95 (srP)->r_pc = (ULong)cia; \
96 (srP)->r_sp = (ULong)r1; \
97 (srP)->misc.PPC32.r_lr = lr; \
98 }
99 #elif defined(VGP_ppc64_linux)
100 # define GET_STARTREGS(srP) \
101 { ULong cia, r1, lr; \
102 __asm__ __volatile__( \
103 "mflr 0;" /* r0 = lr */ \
104 "bl .m_libcassert_get_ip;" /* lr = pc */ \
105 ".m_libcassert_get_ip:\n" \
106 "mflr %0;" /* %0 = pc */ \
107 "mtlr 0;" /* restore lr */ \
108 "mr %1,1;" /* %1 = r1 */ \
109 "mr %2,0;" /* %2 = lr */ \
110 : "=r" (cia), "=r" (r1), "=r" (lr) \
111 : /* reads none */ \
112 : "r0" /* trashed */ \
113 ); \
114 (srP)->r_pc = cia; \
115 (srP)->r_sp = r1; \
116 (srP)->misc.PPC64.r_lr = lr; \
117 }
118 #elif defined(VGP_arm_linux)
119 # define GET_STARTREGS(srP) \
120 { UInt block[6]; \
121 __asm__ __volatile__( \
122 "str r15, [%0, #+0];" \
123 "str r14, [%0, #+4];" \
124 "str r13, [%0, #+8];" \
125 "str r12, [%0, #+12];" \
126 "str r11, [%0, #+16];" \
127 "str r7, [%0, #+20];" \
128 : /* out */ \
129 : /* in */ "r"(&block[0]) \
130 : /* trash */ "memory" \
131 ); \
132 (srP)->r_pc = block[0] - 8; \
133 (srP)->r_sp = block[1]; \
134 (srP)->misc.ARM.r14 = block[2]; \
135 (srP)->misc.ARM.r12 = block[3]; \
136 (srP)->misc.ARM.r11 = block[4]; \
137 (srP)->misc.ARM.r7 = block[5]; \
138 }
139 #elif defined(VGP_s390x_linux)
140 # define GET_STARTREGS(srP) \
141 { ULong ia, sp, fp, lr; \
142 __asm__ __volatile__( \
143 "bras %0,0f;" \
144 "0: lgr %1,15;" \
145 "lgr %2,11;" \
146 "lgr %3,14;" \
147 : "=r" (ia), "=r" (sp),"=r" (fp),"=r" (lr) \
148 /* no read & clobber */ \
149 ); \
150 (srP)->r_pc = ia; \
151 (srP)->r_sp = sp; \
152 (srP)->misc.S390X.r_fp = fp; \
153 (srP)->misc.S390X.r_lr = lr; \
154 }
155 #elif defined(VGP_mips32_linux)
156 # define GET_STARTREGS(srP) \
157 { UInt pc, sp, fp, ra, gp; \
158 asm("move $8, $31;" /* t0 = ra */ \
159 "bal m_libcassert_get_ip;" /* ra = pc */ \
160 "m_libcassert_get_ip:\n" \
161 "move %0, $31;" \
162 "move $31, $8;" /* restore lr */ \
163 "move %1, $29;" \
164 "move %2, $30;" \
165 "move %3, $31;" \
166 "move %4, $28;" \
167 : "=r" (pc), \
168 "=r" (sp), \
169 "=r" (fp), \
170 "=r" (ra), \
171 "=r" (gp) \
172 : /* reads none */ \
173 : "$8" /* trashed */ ); \
174 (srP)->r_pc = (ULong)pc - 8; \
175 (srP)->r_sp = (ULong)sp; \
176 (srP)->misc.MIPS32.r30 = (ULong)fp; \
177 (srP)->misc.MIPS32.r31 = (ULong)ra; \
178 (srP)->misc.MIPS32.r28 = (ULong)gp; \
179 }
180 #else
181 # error Unknown platform
182 #endif
183
184 #define BACKTRACE_DEPTH 100 // nice and deep!
185
186 /* Pull down the entire world */
VG_(exit)187 void VG_(exit)( Int status )
188 {
189 #if defined(VGO_linux)
190 (void)VG_(do_syscall1)(__NR_exit_group, status );
191 #elif defined(VGO_darwin)
192 (void)VG_(do_syscall1)(__NR_exit, status );
193 #else
194 # error Unknown OS
195 #endif
196 /*NOTREACHED*/
197 // We really shouldn't reach here. Just in case we do, use some very crude
198 // methods to force abort
199 __builtin_trap();
200 *(volatile Int*)0 = 'x';
201 }
202
203 // Print the scheduler status.
VG_(show_sched_status)204 void VG_(show_sched_status) ( void )
205 {
206 Int i;
207 VG_(printf)("\nsched status:\n");
208 VG_(printf)(" running_tid=%d\n", VG_(get_running_tid)());
209 for (i = 1; i < VG_N_THREADS; i++) {
210 if (VG_(threads)[i].status == VgTs_Empty) continue;
211 VG_(printf)( "\nThread %d: status = %s\n", i,
212 VG_(name_of_ThreadStatus)(VG_(threads)[i].status) );
213 VG_(get_and_pp_StackTrace)( i, BACKTRACE_DEPTH );
214 }
215 VG_(printf)("\n");
216 }
217
218 __attribute__ ((noreturn))
report_and_quit(const Char * report,UnwindStartRegs * startRegsIN)219 static void report_and_quit ( const Char* report,
220 UnwindStartRegs* startRegsIN )
221 {
222 Addr stacktop;
223 Addr ips[BACKTRACE_DEPTH];
224 Int n_ips;
225 ThreadState *tst
226 = VG_(get_ThreadState)( VG_(lwpid_to_vgtid)( VG_(gettid)() ) );
227
228 // If necessary, fake up an ExeContext which is of our actual real CPU
229 // state. Could cause problems if we got the panic/exception within the
230 // execontext/stack dump/symtab code. But it's better than nothing.
231 UnwindStartRegs startRegs;
232 VG_(memset)(&startRegs, 0, sizeof(startRegs));
233
234 if (startRegsIN == NULL) {
235 GET_STARTREGS(&startRegs);
236 } else {
237 startRegs = *startRegsIN;
238 }
239
240 stacktop = tst->os_state.valgrind_stack_init_SP;
241
242 n_ips =
243 VG_(get_StackTrace_wrk)(
244 0/*tid is unknown*/,
245 ips, BACKTRACE_DEPTH,
246 NULL/*array to dump SP values in*/,
247 NULL/*array to dump FP values in*/,
248 &startRegs, stacktop
249 );
250 VG_(clo_xml) = False;
251 VG_(pp_StackTrace) (ips, n_ips);
252
253 VG_(show_sched_status)();
254 VG_(printf)(
255 "\n"
256 "Note: see also the FAQ in the source distribution.\n"
257 "It contains workarounds to several common problems.\n"
258 "In particular, if Valgrind aborted or crashed after\n"
259 "identifying problems in your program, there's a good chance\n"
260 "that fixing those problems will prevent Valgrind aborting or\n"
261 "crashing, especially if it happened in m_mallocfree.c.\n"
262 "\n"
263 "If that doesn't help, please report this bug to: %s\n\n"
264 "In the bug report, send all the above text, the valgrind\n"
265 "version, and what OS and version you are using. Thanks.\n\n",
266 report);
267 VG_(exit)(1);
268 }
269
VG_(assert_fail)270 void VG_(assert_fail) ( Bool isCore, const Char* expr, const Char* file,
271 Int line, const Char* fn, const HChar* format, ... )
272 {
273 va_list vargs;
274 Char buf[256];
275 Char* component;
276 Char* bugs_to;
277
278 static Bool entered = False;
279 if (entered)
280 VG_(exit)(2);
281 entered = True;
282
283 va_start(vargs, format);
284 VG_(vsprintf) ( buf, format, vargs );
285 va_end(vargs);
286
287 if (isCore) {
288 component = "valgrind";
289 bugs_to = VG_BUGS_TO;
290 } else {
291 component = VG_(details).name;
292 bugs_to = VG_(details).bug_reports_to;
293 }
294
295 if (VG_(clo_xml))
296 VG_(printf_xml)("</valgrindoutput>\n");
297
298 // Treat vg_assert2(0, "foo") specially, as a panicky abort
299 if (VG_STREQ(expr, "0")) {
300 VG_(printf)("\n%s: %s:%d (%s): the 'impossible' happened.\n",
301 component, file, line, fn );
302 } else {
303 VG_(printf)("\n%s: %s:%d (%s): Assertion '%s' failed.\n",
304 component, file, line, fn, expr );
305 }
306 if (!VG_STREQ(buf, ""))
307 VG_(printf)("%s: %s\n", component, buf );
308
309 report_and_quit(bugs_to, NULL);
310 }
311
312 __attribute__ ((noreturn))
panic(Char * name,Char * report,Char * str,UnwindStartRegs * startRegs)313 static void panic ( Char* name, Char* report, Char* str,
314 UnwindStartRegs* startRegs )
315 {
316 if (VG_(clo_xml))
317 VG_(printf_xml)("</valgrindoutput>\n");
318 VG_(printf)("\n%s: the 'impossible' happened:\n %s\n", name, str);
319 report_and_quit(report, startRegs);
320 }
321
VG_(core_panic_at)322 void VG_(core_panic_at) ( Char* str, UnwindStartRegs* startRegs )
323 {
324 panic("valgrind", VG_BUGS_TO, str, startRegs);
325 }
326
VG_(core_panic)327 void VG_(core_panic) ( Char* str )
328 {
329 VG_(core_panic_at)(str, NULL);
330 }
331
VG_(tool_panic)332 void VG_(tool_panic) ( Char* str )
333 {
334 panic(VG_(details).name, VG_(details).bug_reports_to, str, NULL);
335 }
336
337 /* Print some helpful-ish text about unimplemented things, and give up. */
VG_(unimplemented)338 void VG_(unimplemented) ( Char* msg )
339 {
340 if (VG_(clo_xml))
341 VG_(printf_xml)("</valgrindoutput>\n");
342 VG_(umsg)("\n");
343 VG_(umsg)("Valgrind detected that your program requires\n");
344 VG_(umsg)("the following unimplemented functionality:\n");
345 VG_(umsg)(" %s\n", msg);
346 VG_(umsg)("This may be because the functionality is hard to implement,\n");
347 VG_(umsg)("or because no reasonable program would behave this way,\n");
348 VG_(umsg)("or because nobody has yet needed it. "
349 "In any case, let us know at\n");
350 VG_(umsg)("%s and/or try to work around the problem, if you can.\n",
351 VG_BUGS_TO);
352 VG_(umsg)("\n");
353 VG_(umsg)("Valgrind has to exit now. Sorry. Bye!\n");
354 VG_(umsg)("\n");
355 VG_(show_sched_status)();
356 VG_(exit)(1);
357 }
358
359 /*--------------------------------------------------------------------*/
360 /*--- end ---*/
361 /*--------------------------------------------------------------------*/
362
363