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