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 */
187void 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.
204void 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))
219static 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
270void 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))
313static 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
322void VG_(core_panic_at) ( Char* str, UnwindStartRegs* startRegs )
323{
324   panic("valgrind", VG_BUGS_TO, str, startRegs);
325}
326
327void VG_(core_panic) ( Char* str )
328{
329   VG_(core_panic_at)(str, NULL);
330}
331
332void 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. */
338void 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