m_libcassert.c revision 738856f99eea33d86ce91dcb1d6cd5b151e307ca
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-2009 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_libcbase.h"
36#include "pub_core_libcassert.h"
37#include "pub_core_libcprint.h"
38#include "pub_core_libcproc.h"      // For VG_(gettid)()
39#include "pub_core_stacktrace.h"
40#include "pub_core_syscall.h"
41#include "pub_core_tooliface.h"     // For VG_(details).{name,bug_reports_to}
42#include "pub_core_options.h"       // For VG_(clo_xml)
43
44/* ---------------------------------------------------------------------
45   Assertery.
46   ------------------------------------------------------------------ */
47
48#if defined(VGP_x86_linux)  ||  defined(VGP_x86_darwin)
49#  define GET_REAL_PC_SP_AND_FP(pc, sp, fp)      \
50      asm("call 0f;" \
51          "0: popl %0;" \
52          "movl %%esp, %1;" \
53          "movl %%ebp, %2;" \
54          : "=r" (pc),\
55            "=r" (sp),\
56            "=r" (fp));
57#elif defined(VGP_amd64_linux)  ||  defined(VGP_amd64_darwin)
58#  define GET_REAL_PC_SP_AND_FP(pc, sp, fp)      \
59      asm("leaq 0(%%rip), %0;" \
60          "movq %%rsp, %1;" \
61          "movq %%rbp, %2;" \
62          : "=r" (pc),\
63            "=r" (sp),\
64            "=r" (fp));
65#elif defined(VGP_ppc32_linux) || defined(VGP_ppc32_aix5)
66#  define GET_REAL_PC_SP_AND_FP(pc, sp, fp)                   \
67      asm("mflr 0;"                   /* r0 = lr */           \
68          "bl m_libcassert_get_ip;"   /* lr = pc */           \
69          "m_libcassert_get_ip:\n"                            \
70          "mflr %0;"                \
71          "mtlr 0;"                   /* restore lr */        \
72          "mr %1,1;"                \
73          "mr %2,1;"                \
74          : "=r" (pc),              \
75            "=r" (sp),              \
76            "=r" (fp)               \
77          : /* reads none */        \
78          : "r0" /* trashed */ );
79#elif defined(VGP_ppc64_linux) || defined(VGP_ppc64_aix5)
80#  define GET_REAL_PC_SP_AND_FP(pc, sp, fp)                   \
81      asm("mflr 0;"                   /* r0 = lr */           \
82          "bl .m_libcassert_get_ip;"  /* lr = pc */           \
83          ".m_libcassert_get_ip:\n"                           \
84          "mflr %0;"                \
85          "mtlr 0;"                   /* restore lr */        \
86          "mr %1,1;"                \
87          "mr %2,1;"                \
88          : "=r" (pc),              \
89            "=r" (sp),              \
90            "=r" (fp)               \
91          : /* reads none */        \
92          : "r0" /* trashed */ );
93#else
94#  error Unknown platform
95#endif
96
97#define BACKTRACE_DEPTH    100         // nice and deep!
98
99/* Pull down the entire world */
100void VG_(exit)( Int status )
101{
102#if defined(VGO_linux)
103   (void)VG_(do_syscall1)(__NR_exit_group, status );
104#elif defined(VGO_aix5) || defined(VGO_darwin)
105   (void)VG_(do_syscall1)(__NR_exit, status );
106#else
107#  error Unknown OS
108#endif
109   /*NOTREACHED*/
110   // We really shouldn't reach here.  Just in case we do, use some very crude
111   // methods to force abort
112   __builtin_trap();
113   *(volatile Int*)0 = 'x';
114}
115
116// Print the scheduler status.
117void VG_(show_sched_status) ( void )
118{
119   Int i;
120   VG_(printf)("\nsched status:\n");
121   VG_(printf)("  running_tid=%d\n", VG_(get_running_tid)());
122   for (i = 1; i < VG_N_THREADS; i++) {
123      if (VG_(threads)[i].status == VgTs_Empty) continue;
124      VG_(printf)( "\nThread %d: status = %s\n", i,
125                   VG_(name_of_ThreadStatus)(VG_(threads)[i].status) );
126      VG_(get_and_pp_StackTrace)( i, BACKTRACE_DEPTH );
127   }
128   VG_(printf)("\n");
129}
130
131__attribute__ ((noreturn))
132static void report_and_quit ( const Char* report,
133                              Addr ip, Addr sp, Addr fp, Addr lr )
134{
135   Addr stacktop;
136   Addr ips[BACKTRACE_DEPTH];
137   Int  n_ips;
138   ThreadState *tst
139      = VG_(get_ThreadState)( VG_(lwpid_to_vgtid)( VG_(gettid)() ) );
140
141   // If necessary, fake up an ExeContext which is of our actual real CPU
142   // state.  Could cause problems if we got the panic/exception within the
143   // execontext/stack dump/symtab code.  But it's better than nothing.
144   if (0 == ip && 0 == sp && 0 == fp) {
145       GET_REAL_PC_SP_AND_FP(ip, sp, fp);
146   }
147
148   stacktop = tst->os_state.valgrind_stack_init_SP;
149
150   n_ips =
151      VG_(get_StackTrace_wrk)(
152         0/*tid is unknown*/,
153         ips, BACKTRACE_DEPTH,
154         NULL/*array to dump SP values in*/,
155         NULL/*array to dump FP values in*/,
156         ip, sp, fp, lr, sp, stacktop
157      );
158   VG_(clo_xml) = False;
159   VG_(pp_StackTrace) (ips, n_ips);
160
161   VG_(show_sched_status)();
162   VG_(printf)(
163      "\n"
164      "Note: see also the FAQ in the source distribution.\n"
165      "It contains workarounds to several common problems.\n"
166      "In particular, if Valgrind aborted or crashed after\n"
167      "identifying problems in your program, there's a good chance\n"
168      "that fixing those problems will prevent Valgrind aborting or\n"
169      "crashing, especially if it happened in m_mallocfree.c.\n"
170      "\n"
171      "If that doesn't help, please report this bug to: %s\n\n"
172      "In the bug report, send all the above text, the valgrind\n"
173      "version, and what OS and version you are using.  Thanks.\n\n",
174      report);
175   VG_(exit)(1);
176}
177
178void VG_(assert_fail) ( Bool isCore, const Char* expr, const Char* file,
179                        Int line, const Char* fn, const HChar* format, ... )
180{
181   va_list vargs;
182   Char buf[256];
183   Char* component;
184   Char* bugs_to;
185
186   static Bool entered = False;
187   if (entered)
188      VG_(exit)(2);
189   entered = True;
190
191   va_start(vargs, format);
192   VG_(vsprintf) ( buf, format, vargs );
193   va_end(vargs);
194
195   if (isCore) {
196      component = "valgrind";
197      bugs_to   = VG_BUGS_TO;
198   } else {
199      component = VG_(details).name;
200      bugs_to   = VG_(details).bug_reports_to;
201   }
202
203   if (VG_(clo_xml))
204      VG_(printf_xml)("</valgrindoutput>\n");
205
206   // Treat vg_assert2(0, "foo") specially, as a panicky abort
207   if (VG_STREQ(expr, "0")) {
208      VG_(printf)("\n%s: %s:%d (%s): the 'impossible' happened.\n",
209                  component, file, line, fn );
210   } else {
211      VG_(printf)("\n%s: %s:%d (%s): Assertion '%s' failed.\n",
212                  component, file, line, fn, expr );
213   }
214   if (!VG_STREQ(buf, ""))
215      VG_(printf)("%s: %s\n", component, buf );
216
217   report_and_quit(bugs_to, 0,0,0,0);
218}
219
220__attribute__ ((noreturn))
221static void panic ( Char* name, Char* report, Char* str,
222                    Addr ip, Addr sp, Addr fp, Addr lr )
223{
224   if (VG_(clo_xml))
225      VG_(printf_xml)("</valgrindoutput>\n");
226   VG_(printf)("\n%s: the 'impossible' happened:\n   %s\n", name, str);
227   report_and_quit(report, ip, sp, fp, lr);
228}
229
230void VG_(core_panic_at) ( Char* str, Addr ip, Addr sp, Addr fp, Addr lr )
231{
232   panic("valgrind", VG_BUGS_TO, str, ip, sp, fp, lr);
233}
234
235void VG_(core_panic) ( Char* str )
236{
237   VG_(core_panic_at)(str, 0,0,0,0);
238}
239
240void VG_(tool_panic) ( Char* str )
241{
242   panic(VG_(details).name, VG_(details).bug_reports_to, str, 0,0,0,0);
243}
244
245/* Print some helpful-ish text about unimplemented things, and give up. */
246void VG_(unimplemented) ( Char* msg )
247{
248   if (VG_(clo_xml))
249      VG_(printf_xml)("</valgrindoutput>\n");
250   VG_(umsg)("\n");
251   VG_(umsg)("Valgrind detected that your program requires\n");
252   VG_(umsg)("the following unimplemented functionality:\n");
253   VG_(umsg)("   %s\n", msg);
254   VG_(umsg)("This may be because the functionality is hard to implement,\n");
255   VG_(umsg)("or because no reasonable program would behave this way,\n");
256   VG_(umsg)("or because nobody has yet needed it.  "
257             "In any case, let us know at\n");
258   VG_(umsg)("%s and/or try to work around the problem, if you can.\n",
259             VG_BUGS_TO);
260   VG_(umsg)("\n");
261   VG_(umsg)("Valgrind has to exit now.  Sorry.  Bye!\n");
262   VG_(umsg)("\n");
263   VG_(show_sched_status)();
264   VG_(exit)(1);
265}
266
267/*--------------------------------------------------------------------*/
268/*--- end                                                          ---*/
269/*--------------------------------------------------------------------*/
270
271