• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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