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-2011 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#else
156#  error Unknown platform
157#endif
158
159#define BACKTRACE_DEPTH    100         // nice and deep!
160
161/* Pull down the entire world */
162void VG_(exit)( Int status )
163{
164#if defined(VGO_linux)
165   (void)VG_(do_syscall1)(__NR_exit_group, status );
166#elif defined(VGO_darwin)
167   (void)VG_(do_syscall1)(__NR_exit, status );
168#else
169#  error Unknown OS
170#endif
171   /*NOTREACHED*/
172   // We really shouldn't reach here.  Just in case we do, use some very crude
173   // methods to force abort
174   __builtin_trap();
175   *(volatile Int*)0 = 'x';
176}
177
178// Print the scheduler status.
179void VG_(show_sched_status) ( void )
180{
181   Int i;
182   VG_(printf)("\nsched status:\n");
183   VG_(printf)("  running_tid=%d\n", VG_(get_running_tid)());
184   for (i = 1; i < VG_N_THREADS; i++) {
185      if (VG_(threads)[i].status == VgTs_Empty) continue;
186      VG_(printf)( "\nThread %d: status = %s\n", i,
187                   VG_(name_of_ThreadStatus)(VG_(threads)[i].status) );
188      VG_(get_and_pp_StackTrace)( i, BACKTRACE_DEPTH );
189   }
190   VG_(printf)("\n");
191}
192
193__attribute__ ((noreturn))
194static void report_and_quit ( const Char* report,
195                              UnwindStartRegs* startRegsIN )
196{
197   Addr stacktop;
198   Addr ips[BACKTRACE_DEPTH];
199   Int  n_ips;
200   ThreadState *tst
201      = VG_(get_ThreadState)( VG_(lwpid_to_vgtid)( VG_(gettid)() ) );
202
203   // If necessary, fake up an ExeContext which is of our actual real CPU
204   // state.  Could cause problems if we got the panic/exception within the
205   // execontext/stack dump/symtab code.  But it's better than nothing.
206   UnwindStartRegs startRegs;
207   VG_(memset)(&startRegs, 0, sizeof(startRegs));
208
209   if (startRegsIN == NULL) {
210      GET_STARTREGS(&startRegs);
211   } else {
212      startRegs = *startRegsIN;
213   }
214
215   stacktop = tst->os_state.valgrind_stack_init_SP;
216
217   n_ips =
218      VG_(get_StackTrace_wrk)(
219         0/*tid is unknown*/,
220         ips, BACKTRACE_DEPTH,
221         NULL/*array to dump SP values in*/,
222         NULL/*array to dump FP values in*/,
223         &startRegs, stacktop
224      );
225   VG_(clo_xml) = False;
226   VG_(pp_StackTrace) (ips, n_ips);
227
228   VG_(show_sched_status)();
229   VG_(printf)(
230      "\n"
231      "Note: see also the FAQ in the source distribution.\n"
232      "It contains workarounds to several common problems.\n"
233      "In particular, if Valgrind aborted or crashed after\n"
234      "identifying problems in your program, there's a good chance\n"
235      "that fixing those problems will prevent Valgrind aborting or\n"
236      "crashing, especially if it happened in m_mallocfree.c.\n"
237      "\n"
238      "If that doesn't help, please report this bug to: %s\n\n"
239      "In the bug report, send all the above text, the valgrind\n"
240      "version, and what OS and version you are using.  Thanks.\n\n",
241      report);
242   VG_(exit)(1);
243}
244
245void VG_(assert_fail) ( Bool isCore, const Char* expr, const Char* file,
246                        Int line, const Char* fn, const HChar* format, ... )
247{
248   va_list vargs;
249   Char buf[256];
250   Char* component;
251   Char* bugs_to;
252
253   static Bool entered = False;
254   if (entered)
255      VG_(exit)(2);
256   entered = True;
257
258   va_start(vargs, format);
259   VG_(vsprintf) ( buf, format, vargs );
260   va_end(vargs);
261
262   if (isCore) {
263      component = "valgrind";
264      bugs_to   = VG_BUGS_TO;
265   } else {
266      component = VG_(details).name;
267      bugs_to   = VG_(details).bug_reports_to;
268   }
269
270   if (VG_(clo_xml))
271      VG_(printf_xml)("</valgrindoutput>\n");
272
273   // Treat vg_assert2(0, "foo") specially, as a panicky abort
274   if (VG_STREQ(expr, "0")) {
275      VG_(printf)("\n%s: %s:%d (%s): the 'impossible' happened.\n",
276                  component, file, line, fn );
277   } else {
278      VG_(printf)("\n%s: %s:%d (%s): Assertion '%s' failed.\n",
279                  component, file, line, fn, expr );
280   }
281   if (!VG_STREQ(buf, ""))
282      VG_(printf)("%s: %s\n", component, buf );
283
284   report_and_quit(bugs_to, NULL);
285}
286
287__attribute__ ((noreturn))
288static void panic ( Char* name, Char* report, Char* str,
289                    UnwindStartRegs* startRegs )
290{
291   if (VG_(clo_xml))
292      VG_(printf_xml)("</valgrindoutput>\n");
293   VG_(printf)("\n%s: the 'impossible' happened:\n   %s\n", name, str);
294   report_and_quit(report, startRegs);
295}
296
297void VG_(core_panic_at) ( Char* str, UnwindStartRegs* startRegs )
298{
299   panic("valgrind", VG_BUGS_TO, str, startRegs);
300}
301
302void VG_(core_panic) ( Char* str )
303{
304   VG_(core_panic_at)(str, NULL);
305}
306
307void VG_(tool_panic) ( Char* str )
308{
309   panic(VG_(details).name, VG_(details).bug_reports_to, str, NULL);
310}
311
312/* Print some helpful-ish text about unimplemented things, and give up. */
313void VG_(unimplemented) ( Char* msg )
314{
315   if (VG_(clo_xml))
316      VG_(printf_xml)("</valgrindoutput>\n");
317   VG_(umsg)("\n");
318   VG_(umsg)("Valgrind detected that your program requires\n");
319   VG_(umsg)("the following unimplemented functionality:\n");
320   VG_(umsg)("   %s\n", msg);
321   VG_(umsg)("This may be because the functionality is hard to implement,\n");
322   VG_(umsg)("or because no reasonable program would behave this way,\n");
323   VG_(umsg)("or because nobody has yet needed it.  "
324             "In any case, let us know at\n");
325   VG_(umsg)("%s and/or try to work around the problem, if you can.\n",
326             VG_BUGS_TO);
327   VG_(umsg)("\n");
328   VG_(umsg)("Valgrind has to exit now.  Sorry.  Bye!\n");
329   VG_(umsg)("\n");
330   VG_(show_sched_status)();
331   VG_(exit)(1);
332}
333
334/*--------------------------------------------------------------------*/
335/*--- end                                                          ---*/
336/*--------------------------------------------------------------------*/
337
338