Home | History | Annotate | Download | only in coregrind
      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 (at) 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 */
    162 void 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.
    179 void 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))
    194 static 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 
    245 void 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))
    288 static 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 
    297 void VG_(core_panic_at) ( Char* str, UnwindStartRegs* startRegs )
    298 {
    299    panic("valgrind", VG_BUGS_TO, str, startRegs);
    300 }
    301 
    302 void VG_(core_panic) ( Char* str )
    303 {
    304    VG_(core_panic_at)(str, NULL);
    305 }
    306 
    307 void 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. */
    313 void 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