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