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-2013 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_threadstate.h"
35 #include "pub_core_gdbserver.h"
36 #include "pub_core_aspacemgr.h"
37 #include "pub_core_libcbase.h"
38 #include "pub_core_libcassert.h"
39 #include "pub_core_libcprint.h"
40 #include "pub_core_libcproc.h" // For VG_(gettid)()
41 #include "pub_core_machine.h"
42 #include "pub_core_stacks.h"
43 #include "pub_core_stacktrace.h"
44 #include "pub_core_syscall.h"
45 #include "pub_core_tooliface.h" // For VG_(details).{name,bug_reports_to}
46 #include "pub_core_options.h" // For VG_(clo_xml)
47
48 /* ---------------------------------------------------------------------
49 Assertery.
50 ------------------------------------------------------------------ */
51
52 #if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
53 # define GET_STARTREGS(srP) \
54 { UInt eip, esp, ebp; \
55 __asm__ __volatile__( \
56 "call 0f;" \
57 "0: popl %0;" \
58 "movl %%esp, %1;" \
59 "movl %%ebp, %2;" \
60 : "=r" (eip), "=r" (esp), "=r" (ebp) \
61 : /* reads none */ \
62 : "memory" \
63 ); \
64 (srP)->r_pc = (ULong)eip; \
65 (srP)->r_sp = (ULong)esp; \
66 (srP)->misc.X86.r_ebp = ebp; \
67 }
68 #elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin)
69 # define GET_STARTREGS(srP) \
70 { ULong rip, rsp, rbp; \
71 __asm__ __volatile__( \
72 "leaq 0(%%rip), %0;" \
73 "movq %%rsp, %1;" \
74 "movq %%rbp, %2;" \
75 : "=r" (rip), "=r" (rsp), "=r" (rbp) \
76 : /* reads none */ \
77 : "memory" \
78 ); \
79 (srP)->r_pc = rip; \
80 (srP)->r_sp = rsp; \
81 (srP)->misc.AMD64.r_rbp = rbp; \
82 }
83 #elif defined(VGP_ppc32_linux)
84 # define GET_STARTREGS(srP) \
85 { UInt cia, r1, lr; \
86 __asm__ __volatile__( \
87 "mflr 0;" /* r0 = lr */ \
88 "bl m_libcassert_get_ip;" /* lr = pc */ \
89 "m_libcassert_get_ip:\n" \
90 "mflr %0;" /* %0 = pc */ \
91 "mtlr 0;" /* restore lr */ \
92 "mr %1,1;" /* %1 = r1 */ \
93 "mr %2,0;" /* %2 = lr */ \
94 : "=r" (cia), "=r" (r1), "=r" (lr) \
95 : /* reads none */ \
96 : "r0" /* trashed */ \
97 ); \
98 (srP)->r_pc = (ULong)cia; \
99 (srP)->r_sp = (ULong)r1; \
100 (srP)->misc.PPC32.r_lr = lr; \
101 }
102 #elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
103 # define GET_STARTREGS(srP) \
104 { ULong cia, r1, lr; \
105 __asm__ __volatile__( \
106 "mflr 0;" /* r0 = lr */ \
107 "bl .m_libcassert_get_ip;" /* lr = pc */ \
108 ".m_libcassert_get_ip:\n" \
109 "mflr %0;" /* %0 = pc */ \
110 "mtlr 0;" /* restore lr */ \
111 "mr %1,1;" /* %1 = r1 */ \
112 "mr %2,0;" /* %2 = lr */ \
113 : "=r" (cia), "=r" (r1), "=r" (lr) \
114 : /* reads none */ \
115 : "r0" /* trashed */ \
116 ); \
117 (srP)->r_pc = cia; \
118 (srP)->r_sp = r1; \
119 (srP)->misc.PPC64.r_lr = lr; \
120 }
121 #elif defined(VGP_arm_linux)
122 # define GET_STARTREGS(srP) \
123 { UInt block[6]; \
124 __asm__ __volatile__( \
125 "str r15, [%0, #+0];" \
126 "str r14, [%0, #+4];" \
127 "str r13, [%0, #+8];" \
128 "str r12, [%0, #+12];" \
129 "str r11, [%0, #+16];" \
130 "str r7, [%0, #+20];" \
131 : /* out */ \
132 : /* in */ "r"(&block[0]) \
133 : /* trash */ "memory" \
134 ); \
135 (srP)->r_pc = block[0] - 8; \
136 (srP)->misc.ARM.r14 = block[1]; \
137 (srP)->r_sp = block[2]; \
138 (srP)->misc.ARM.r12 = block[3]; \
139 (srP)->misc.ARM.r11 = block[4]; \
140 (srP)->misc.ARM.r7 = block[5]; \
141 }
142 #elif defined(VGP_arm64_linux)
143 # define GET_STARTREGS(srP) \
144 { ULong block[4]; \
145 __asm__ __volatile__( \
146 "adr x19, 0;" \
147 "str x19, [%0, #+0];" /* pc */ \
148 "mov x19, sp;" \
149 "str x19, [%0, #+8];" /* sp */ \
150 "str x29, [%0, #+16];" /* fp */ \
151 "str x30, [%0, #+24];" /* lr */ \
152 : /* out */ \
153 : /* in */ "r"(&block[0]) \
154 : /* trash */ "memory","x19" \
155 ); \
156 (srP)->r_pc = block[0]; \
157 (srP)->r_sp = block[1]; \
158 (srP)->misc.ARM64.x29 = block[2]; \
159 (srP)->misc.ARM64.x30 = block[3]; \
160 }
161 #elif defined(VGP_s390x_linux)
162 # define GET_STARTREGS(srP) \
163 { ULong ia, sp, fp, lr; \
164 __asm__ __volatile__( \
165 "bras %0,0f;" \
166 "0: lgr %1,15;" \
167 "lgr %2,11;" \
168 "lgr %3,14;" \
169 : "=r" (ia), "=r" (sp),"=r" (fp),"=r" (lr) \
170 /* no read & clobber */ \
171 ); \
172 (srP)->r_pc = ia; \
173 (srP)->r_sp = sp; \
174 (srP)->misc.S390X.r_fp = fp; \
175 (srP)->misc.S390X.r_lr = lr; \
176 }
177 #elif defined(VGP_mips32_linux)
178 # define GET_STARTREGS(srP) \
179 { UInt pc, sp, fp, ra, gp; \
180 asm("move $8, $31;" /* t0 = ra */ \
181 "bal m_libcassert_get_ip;" /* ra = pc */ \
182 "m_libcassert_get_ip:\n" \
183 "move %0, $31;" \
184 "move $31, $8;" /* restore lr */ \
185 "move %1, $29;" \
186 "move %2, $30;" \
187 "move %3, $31;" \
188 "move %4, $28;" \
189 : "=r" (pc), \
190 "=r" (sp), \
191 "=r" (fp), \
192 "=r" (ra), \
193 "=r" (gp) \
194 : /* reads none */ \
195 : "$8" /* trashed */ ); \
196 (srP)->r_pc = (ULong)pc - 8; \
197 (srP)->r_sp = (ULong)sp; \
198 (srP)->misc.MIPS32.r30 = (ULong)fp; \
199 (srP)->misc.MIPS32.r31 = (ULong)ra; \
200 (srP)->misc.MIPS32.r28 = (ULong)gp; \
201 }
202 #elif defined(VGP_mips64_linux)
203 # define GET_STARTREGS(srP) \
204 { ULong pc, sp, fp, ra, gp; \
205 asm("move $8, $31;" /* t0 = ra */ \
206 "bal m_libcassert_get_ip;" /* ra = pc */ \
207 "m_libcassert_get_ip:\n" \
208 "move %0, $31;" \
209 "move $31, $8;" /* restore lr */ \
210 "move %1, $29;" \
211 "move %2, $30;" \
212 "move %3, $31;" \
213 "move %4, $28;" \
214 : "=r" (pc), \
215 "=r" (sp), \
216 "=r" (fp), \
217 "=r" (ra), \
218 "=r" (gp) \
219 : /* reads none */ \
220 : "$8" /* trashed */ ); \
221 (srP)->r_pc = (ULong)pc - 8; \
222 (srP)->r_sp = (ULong)sp; \
223 (srP)->misc.MIPS64.r30 = (ULong)fp; \
224 (srP)->misc.MIPS64.r31 = (ULong)ra; \
225 (srP)->misc.MIPS64.r28 = (ULong)gp; \
226 }
227 #elif defined(VGP_tilegx_linux)
228 # define GET_STARTREGS(srP) \
229 { ULong pc, sp, fp, ra; \
230 __asm__ __volatile__( \
231 "move r8, lr \n" \
232 "jal 0f \n" \
233 "0:\n" \
234 "move %0, lr \n" \
235 "move lr, r8 \n" /* put old lr back*/ \
236 "move %1, sp \n" \
237 "move %2, r52 \n" \
238 "move %3, lr \n" \
239 : "=r" (pc), \
240 "=r" (sp), \
241 "=r" (fp), \
242 "=r" (ra) \
243 : /* reads none */ \
244 : "%r8" /* trashed */ ); \
245 (srP)->r_pc = (ULong)pc - 8; \
246 (srP)->r_sp = (ULong)sp; \
247 (srP)->misc.TILEGX.r52 = (ULong)fp; \
248 (srP)->misc.TILEGX.r55 = (ULong)ra; \
249 }
250 #else
251 # error Unknown platform
252 #endif
253
254 #define BACKTRACE_DEPTH 100 // nice and deep!
255
256 __attribute__ ((__noreturn__))
exit_wrk(Int status,Bool gdbserver_call_allowed)257 static void exit_wrk( Int status, Bool gdbserver_call_allowed)
258 {
259 static Bool exit_called = False;
260 // avoid recursive exit during gdbserver call.
261
262 if (gdbserver_call_allowed && !exit_called) {
263 const ThreadId atid = 1; // Arbitrary tid used to call/terminate gdbsrv.
264 exit_called = True;
265 if (status != 0 && VG_(gdbserver_stop_at) (VgdbStopAt_ValgrindAbExit)) {
266 if (VG_(gdbserver_init_done)()) {
267 VG_(umsg)("(action at valgrind abnormal exit) vgdb me ... \n");
268 VG_(gdbserver) (atid);
269 } else {
270 VG_(umsg)("(action at valgrind abnormal exit) "
271 "Early valgrind exit : vgdb not yet usable\n");
272 }
273 }
274 if (VG_(gdbserver_init_done)()) {
275 // Always terminate the gdbserver when Valgrind exits, so as
276 // to e.g. cleanup the FIFOs.
277 VG_(gdbserver_exit) (atid,
278 status == 0 ? VgSrc_ExitProcess : VgSrc_FatalSig);
279 }
280 }
281 exit_called = True;
282
283 VG_(exit_now) (status);
284 }
285
286 /* Call the appropriate system call and nothing else. This function should
287 be called in places where the dependencies of VG_(exit) need to be
288 avoided. */
289 __attribute__ ((__noreturn__))
VG_(exit_now)290 void VG_(exit_now)( Int status )
291 {
292 #if defined(VGO_linux)
293 (void)VG_(do_syscall1)(__NR_exit_group, status );
294 #elif defined(VGO_darwin)
295 (void)VG_(do_syscall1)(__NR_exit, status );
296 #else
297 # error Unknown OS
298 #endif
299 /*NOTREACHED*/
300 // We really shouldn't reach here. Just in case we do, use some very crude
301 // methods to force abort
302 __builtin_trap();
303 *(volatile Int*)0 = 'x';
304 }
305
306 /* Pull down the entire world */
VG_(exit)307 void VG_(exit)( Int status )
308 {
309 exit_wrk (status, True);
310 }
311
312 /* Pull down the entire world */
VG_(client_exit)313 void VG_(client_exit)( Int status )
314 {
315 exit_wrk (status, False);
316 }
317
318
319 // Print the scheduler status.
show_sched_status_wrk(Bool host_stacktrace,Bool stack_usage,Bool exited_threads,const UnwindStartRegs * startRegsIN)320 static void show_sched_status_wrk ( Bool host_stacktrace,
321 Bool stack_usage,
322 Bool exited_threads,
323 const UnwindStartRegs* startRegsIN)
324 {
325 Int i;
326 if (host_stacktrace) {
327 const Bool save_clo_xml = VG_(clo_xml);
328 Addr stacktop;
329 Addr ips[BACKTRACE_DEPTH];
330 Int n_ips;
331 ThreadState *tst
332 = VG_(get_ThreadState)( VG_(lwpid_to_vgtid)( VG_(gettid)() ) );
333
334 // If necessary, fake up an ExeContext which is of our actual real CPU
335 // state. Could cause problems if we got the panic/exception within the
336 // execontext/stack dump/symtab code. But it's better than nothing.
337 UnwindStartRegs startRegs;
338 VG_(memset)(&startRegs, 0, sizeof(startRegs));
339
340 if (startRegsIN == NULL) {
341 GET_STARTREGS(&startRegs);
342 } else {
343 startRegs = *startRegsIN;
344 }
345
346 stacktop = tst->os_state.valgrind_stack_init_SP;
347
348 n_ips =
349 VG_(get_StackTrace_wrk)(
350 0/*tid is unknown*/,
351 ips, BACKTRACE_DEPTH,
352 NULL/*array to dump SP values in*/,
353 NULL/*array to dump FP values in*/,
354 &startRegs, stacktop
355 );
356 VG_(printf)("\nhost stacktrace:\n");
357 VG_(clo_xml) = False;
358 VG_(pp_StackTrace) (ips, n_ips);
359 VG_(clo_xml) = save_clo_xml;
360 }
361
362 VG_(printf)("\nsched status:\n");
363 VG_(printf)(" running_tid=%d\n", VG_(get_running_tid)());
364 for (i = 1; i < VG_N_THREADS; i++) {
365 VgStack* stack
366 = (VgStack*)VG_(threads)[i].os_state.valgrind_stack_base;
367 /* If a thread slot was never used (yet), valgrind_stack_base is 0.
368 If a thread slot is used by a thread or was used by a thread which
369 has exited, then valgrind_stack_base points to the stack base. */
370 if (VG_(threads)[i].status == VgTs_Empty
371 && (!exited_threads || stack == 0)) continue;
372 VG_(printf)("\nThread %d: status = %s (lwpid %d)\n", i,
373 VG_(name_of_ThreadStatus)(VG_(threads)[i].status),
374 VG_(threads)[i].os_state.lwpid);
375 if (VG_(threads)[i].status != VgTs_Empty)
376 VG_(get_and_pp_StackTrace)( i, BACKTRACE_DEPTH );
377 if (stack_usage && VG_(threads)[i].client_stack_highest_byte != 0 ) {
378 Addr start, end;
379
380 start = end = 0;
381 VG_(stack_limits)(VG_(threads)[i].client_stack_highest_byte,
382 &start, &end);
383 if (start != end)
384 VG_(printf)("client stack range: [%p %p] client SP: %p\n",
385 (void*)start, (void*)end, (void*)VG_(get_SP)(i));
386 else
387 VG_(printf)("client stack range: ???????\n");
388 }
389 if (stack_usage && stack != 0)
390 VG_(printf)("valgrind stack top usage: %ld of %ld\n",
391 VG_(clo_valgrind_stacksize)
392 - VG_(am_get_VgStack_unused_szB)
393 (stack, VG_(clo_valgrind_stacksize)),
394 (SizeT) VG_(clo_valgrind_stacksize));
395 }
396 VG_(printf)("\n");
397 }
398
VG_(show_sched_status)399 void VG_(show_sched_status) ( Bool host_stacktrace,
400 Bool stack_usage,
401 Bool exited_threads)
402 {
403 show_sched_status_wrk (host_stacktrace,
404 stack_usage,
405 exited_threads,
406 NULL);
407 }
408
409 __attribute__ ((noreturn))
report_and_quit(const HChar * report,const UnwindStartRegs * startRegsIN)410 static void report_and_quit ( const HChar* report,
411 const UnwindStartRegs* startRegsIN )
412 {
413 show_sched_status_wrk (True, // host_stacktrace
414 False, // stack_usage
415 False, // exited_threads
416 startRegsIN);
417 VG_(printf)(
418 "\n"
419 "Note: see also the FAQ in the source distribution.\n"
420 "It contains workarounds to several common problems.\n"
421 "In particular, if Valgrind aborted or crashed after\n"
422 "identifying problems in your program, there's a good chance\n"
423 "that fixing those problems will prevent Valgrind aborting or\n"
424 "crashing, especially if it happened in m_mallocfree.c.\n"
425 "\n"
426 "If that doesn't help, please report this bug to: %s\n\n"
427 "In the bug report, send all the above text, the valgrind\n"
428 "version, and what OS and version you are using. Thanks.\n\n",
429 report);
430 VG_(exit)(1);
431 }
432
VG_(assert_fail)433 void VG_(assert_fail) ( Bool isCore, const HChar* expr, const HChar* file,
434 Int line, const HChar* fn, const HChar* format, ... )
435 {
436 va_list vargs, vargs_copy;
437 const HChar* component;
438 const HChar* bugs_to;
439 UInt written;
440
441 static Bool entered = False;
442 if (entered)
443 VG_(exit)(2);
444 entered = True;
445
446 if (isCore) {
447 component = "valgrind";
448 bugs_to = VG_BUGS_TO;
449 } else {
450 component = VG_(details).name;
451 bugs_to = VG_(details).bug_reports_to;
452 }
453
454 if (VG_(clo_xml))
455 VG_(printf_xml)("</valgrindoutput>\n");
456
457 // Treat vg_assert2(0, "foo") specially, as a panicky abort
458 if (VG_STREQ(expr, "0")) {
459 VG_(printf)("\n%s: %s:%d (%s): the 'impossible' happened.\n",
460 component, file, line, fn );
461 } else {
462 VG_(printf)("\n%s: %s:%d (%s): Assertion '%s' failed.\n",
463 component, file, line, fn, expr );
464 }
465
466 /* Check whether anything will be written */
467 HChar buf[5];
468 va_start(vargs, format);
469 va_copy(vargs_copy, vargs);
470 written = VG_(vsnprintf) ( buf, sizeof(buf), format, vargs );
471 va_end(vargs);
472
473 if (written > 0) {
474 VG_(printf)("%s: ", component);
475 VG_(vprintf)(format, vargs_copy);
476 VG_(printf)("\n");
477 }
478
479 report_and_quit(bugs_to, NULL);
480 }
481
482 __attribute__ ((noreturn))
panic(const HChar * name,const HChar * report,const HChar * str,const UnwindStartRegs * startRegs)483 static void panic ( const HChar* name, const HChar* report, const HChar* str,
484 const UnwindStartRegs* startRegs )
485 {
486 if (VG_(clo_xml))
487 VG_(printf_xml)("</valgrindoutput>\n");
488 VG_(printf)("\n%s: the 'impossible' happened:\n %s\n", name, str);
489 report_and_quit(report, startRegs);
490 }
491
VG_(core_panic_at)492 void VG_(core_panic_at) ( const HChar* str, const UnwindStartRegs* startRegs )
493 {
494 panic("valgrind", VG_BUGS_TO, str, startRegs);
495 }
496
VG_(core_panic)497 void VG_(core_panic) ( const HChar* str )
498 {
499 VG_(core_panic_at)(str, NULL);
500 }
501
VG_(tool_panic)502 void VG_(tool_panic) ( const HChar* str )
503 {
504 panic(VG_(details).name, VG_(details).bug_reports_to, str, NULL);
505 }
506
507 /* Print some helpful-ish text about unimplemented things, and give up. */
VG_(unimplemented)508 void VG_(unimplemented) ( const HChar* msg )
509 {
510 if (VG_(clo_xml))
511 VG_(printf_xml)("</valgrindoutput>\n");
512 VG_(umsg)("\n");
513 VG_(umsg)("Valgrind detected that your program requires\n");
514 VG_(umsg)("the following unimplemented functionality:\n");
515 VG_(umsg)(" %s\n", msg);
516 VG_(umsg)("This may be because the functionality is hard to implement,\n");
517 VG_(umsg)("or because no reasonable program would behave this way,\n");
518 VG_(umsg)("or because nobody has yet needed it. "
519 "In any case, let us know at\n");
520 VG_(umsg)("%s and/or try to work around the problem, if you can.\n",
521 VG_BUGS_TO);
522 VG_(umsg)("\n");
523 VG_(umsg)("Valgrind has to exit now. Sorry. Bye!\n");
524 VG_(umsg)("\n");
525 VG_(show_sched_status)(False, // host_stacktrace
526 False, // stack_usage
527 False); // exited_threads
528 VG_(exit)(1);
529 }
530
531 /*--------------------------------------------------------------------*/
532 /*--- end ---*/
533 /*--------------------------------------------------------------------*/
534