Home | History | Annotate | Download | only in debug
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/debug/debugger.h"
      6 #include "build/build_config.h"
      7 
      8 #include <errno.h>
      9 #include <execinfo.h>
     10 #include <fcntl.h>
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <sys/param.h>
     14 #include <sys/stat.h>
     15 #if !defined(OS_NACL)
     16 #include <sys/sysctl.h>
     17 #endif
     18 #include <sys/types.h>
     19 #include <unistd.h>
     20 
     21 #include <string>
     22 #include <vector>
     23 
     24 #if defined(__GLIBCXX__)
     25 #include <cxxabi.h>
     26 #endif
     27 
     28 #if defined(OS_MACOSX)
     29 #include <AvailabilityMacros.h>
     30 #endif
     31 
     32 #include <iostream>
     33 
     34 #include "base/basictypes.h"
     35 #include "base/eintr_wrapper.h"
     36 #include "base/logging.h"
     37 #include "base/memory/scoped_ptr.h"
     38 #include "base/safe_strerror_posix.h"
     39 #include "base/string_piece.h"
     40 #include "base/stringprintf.h"
     41 
     42 #if defined(USE_SYMBOLIZE)
     43 #include "base/third_party/symbolize/symbolize.h"
     44 #endif
     45 
     46 namespace base {
     47 namespace debug {
     48 
     49 bool SpawnDebuggerOnProcess(unsigned /* process_id */) {
     50   NOTIMPLEMENTED();
     51   return false;
     52 }
     53 
     54 #if defined(OS_MACOSX)
     55 
     56 // Based on Apple's recommended method as described in
     57 // http://developer.apple.com/qa/qa2004/qa1361.html
     58 bool BeingDebugged() {
     59   // If the process is sandboxed then we can't use the sysctl, so cache the
     60   // value.
     61   static bool is_set = false;
     62   static bool being_debugged = false;
     63 
     64   if (is_set) {
     65     return being_debugged;
     66   }
     67 
     68   // Initialize mib, which tells sysctl what info we want.  In this case,
     69   // we're looking for information about a specific process ID.
     70   int mib[] = {
     71     CTL_KERN,
     72     KERN_PROC,
     73     KERN_PROC_PID,
     74     getpid()
     75   };
     76 
     77   // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE.  The source and
     78   // binary interfaces may change.
     79   struct kinfo_proc info;
     80   size_t info_size = sizeof(info);
     81 
     82   int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, NULL, 0);
     83   DCHECK_EQ(sysctl_result, 0);
     84   if (sysctl_result != 0) {
     85     is_set = true;
     86     being_debugged = false;
     87     return being_debugged;
     88   }
     89 
     90   // This process is being debugged if the P_TRACED flag is set.
     91   is_set = true;
     92   being_debugged = (info.kp_proc.p_flag & P_TRACED) != 0;
     93   return being_debugged;
     94 }
     95 
     96 #elif defined(OS_LINUX)
     97 
     98 // We can look in /proc/self/status for TracerPid.  We are likely used in crash
     99 // handling, so we are careful not to use the heap or have side effects.
    100 // Another option that is common is to try to ptrace yourself, but then we
    101 // can't detach without forking(), and that's not so great.
    102 // static
    103 bool BeingDebugged() {
    104   int status_fd = open("/proc/self/status", O_RDONLY);
    105   if (status_fd == -1)
    106     return false;
    107 
    108   // We assume our line will be in the first 1024 characters and that we can
    109   // read this much all at once.  In practice this will generally be true.
    110   // This simplifies and speeds up things considerably.
    111   char buf[1024];
    112 
    113   ssize_t num_read = HANDLE_EINTR(read(status_fd, buf, sizeof(buf)));
    114   if (HANDLE_EINTR(close(status_fd)) < 0)
    115     return false;
    116 
    117   if (num_read <= 0)
    118     return false;
    119 
    120   StringPiece status(buf, num_read);
    121   StringPiece tracer("TracerPid:\t");
    122 
    123   StringPiece::size_type pid_index = status.find(tracer);
    124   if (pid_index == StringPiece::npos)
    125     return false;
    126 
    127   // Our pid is 0 without a debugger, assume this for any pid starting with 0.
    128   pid_index += tracer.size();
    129   return pid_index < status.size() && status[pid_index] != '0';
    130 }
    131 
    132 #elif defined(OS_NACL)
    133 
    134 bool BeingDebugged() {
    135   NOTIMPLEMENTED();
    136   return false;
    137 }
    138 
    139 #elif defined(OS_FREEBSD)
    140 
    141 bool BeingDebugged() {
    142   // TODO(benl): can we determine this under FreeBSD?
    143   NOTIMPLEMENTED();
    144   return false;
    145 }
    146 
    147 #endif  // defined(OS_FREEBSD)
    148 
    149 // We want to break into the debugger in Debug mode, and cause a crash dump in
    150 // Release mode. Breakpad behaves as follows:
    151 //
    152 // +-------+-----------------+-----------------+
    153 // | OS    | Dump on SIGTRAP | Dump on SIGABRT |
    154 // +-------+-----------------+-----------------+
    155 // | Linux |       N         |        Y        |
    156 // | Mac   |       Y         |        N        |
    157 // +-------+-----------------+-----------------+
    158 //
    159 // Thus we do the following:
    160 // Linux: Debug mode, send SIGTRAP; Release mode, send SIGABRT.
    161 // Mac: Always send SIGTRAP.
    162 
    163 #if defined(NDEBUG) && !defined(OS_MACOSX)
    164 #define DEBUG_BREAK() abort()
    165 #elif defined(OS_NACL)
    166 // The NaCl verifier doesn't let use use int3.  For now, we call abort().  We
    167 // should ask for advice from some NaCl experts about the optimum thing here.
    168 // http://code.google.com/p/nativeclient/issues/detail?id=645
    169 #define DEBUG_BREAK() abort()
    170 #elif defined(ARCH_CPU_ARM_FAMILY)
    171 #define DEBUG_BREAK() asm("bkpt 0")
    172 #elif defined(ARCH_CPU_MIPS_FAMILY)
    173 #define DEBUG_BREAK() asm("break 2")
    174 #else
    175 #define DEBUG_BREAK() asm("int3")
    176 #endif
    177 
    178 void BreakDebugger() {
    179   DEBUG_BREAK();
    180 #if defined(NDEBUG)
    181   _exit(1);
    182 #endif
    183 }
    184 
    185 }  // namespace debug
    186 }  // namespace base
    187