michael@0: // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #include "build/build_config.h" michael@0: #include "base/debug_util.h" michael@0: michael@0: #define MOZ_HAVE_EXECINFO_H (defined(OS_LINUX) && !defined(ANDROID)) michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #if MOZ_HAVE_EXECINFO_H michael@0: #include michael@0: #endif michael@0: michael@0: #if defined(OS_MACOSX) || defined(OS_BSD) michael@0: #if defined(OS_OPENBSD) michael@0: #include michael@0: #endif michael@0: #include michael@0: #endif michael@0: michael@0: #if defined(OS_DRAGONFLY) || defined(OS_FREEBSD) michael@0: #include michael@0: #endif michael@0: michael@0: #include "base/basictypes.h" michael@0: #include "base/eintr_wrapper.h" michael@0: #include "base/logging.h" michael@0: #include "base/scoped_ptr.h" michael@0: #include "base/string_piece.h" michael@0: michael@0: #if defined(OS_NETBSD) michael@0: #undef KERN_PROC michael@0: #define KERN_PROC KERN_PROC2 michael@0: #define KINFO_PROC struct kinfo_proc2 michael@0: #else michael@0: #define KINFO_PROC struct kinfo_proc michael@0: #endif michael@0: michael@0: #if defined(OS_MACOSX) michael@0: #define KP_FLAGS kp_proc.p_flag michael@0: #elif defined(OS_DRAGONFLY) michael@0: #define KP_FLAGS kp_flags michael@0: #elif defined(OS_FREEBSD) michael@0: #define KP_FLAGS ki_flag michael@0: #elif defined(OS_OPENBSD) && !defined(_P_TRACED) michael@0: #define KP_FLAGS p_psflags michael@0: #define P_TRACED PS_TRACED michael@0: #else michael@0: #define KP_FLAGS p_flag michael@0: #endif michael@0: michael@0: // static michael@0: bool DebugUtil::SpawnDebuggerOnProcess(unsigned /* process_id */) { michael@0: NOTIMPLEMENTED(); michael@0: return false; michael@0: } michael@0: michael@0: #if defined(OS_MACOSX) || defined(OS_BSD) michael@0: michael@0: // Based on Apple's recommended method as described in michael@0: // http://developer.apple.com/qa/qa2004/qa1361.html michael@0: // static michael@0: bool DebugUtil::BeingDebugged() { michael@0: // If the process is sandboxed then we can't use the sysctl, so cache the michael@0: // value. michael@0: static bool is_set = false; michael@0: static bool being_debugged = false; michael@0: michael@0: if (is_set) { michael@0: return being_debugged; michael@0: } michael@0: michael@0: // Initialize mib, which tells sysctl what info we want. In this case, michael@0: // we're looking for information about a specific process ID. michael@0: int mib[] = { michael@0: CTL_KERN, michael@0: KERN_PROC, michael@0: KERN_PROC_PID, michael@0: getpid(), michael@0: #if defined(OS_NETBSD) || defined(OS_OPENBSD) michael@0: sizeof(KINFO_PROC), michael@0: 1, michael@0: #endif michael@0: }; michael@0: michael@0: // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE. The source and michael@0: // binary interfaces may change. michael@0: KINFO_PROC info; michael@0: size_t info_size = sizeof(info); michael@0: michael@0: int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, NULL, 0); michael@0: DCHECK(sysctl_result == 0); michael@0: if (sysctl_result != 0) { michael@0: is_set = true; michael@0: being_debugged = false; michael@0: return being_debugged; michael@0: } michael@0: michael@0: // This process is being debugged if the P_TRACED flag is set. michael@0: is_set = true; michael@0: being_debugged = (info.KP_FLAGS & P_TRACED) != 0; michael@0: return being_debugged; michael@0: } michael@0: michael@0: #elif defined(OS_LINUX) michael@0: michael@0: // We can look in /proc/self/status for TracerPid. We are likely used in crash michael@0: // handling, so we are careful not to use the heap or have side effects. michael@0: // Another option that is common is to try to ptrace yourself, but then we michael@0: // can't detach without forking(), and that's not so great. michael@0: // static michael@0: bool DebugUtil::BeingDebugged() { michael@0: int status_fd = open("/proc/self/status", O_RDONLY); michael@0: if (status_fd == -1) michael@0: return false; michael@0: michael@0: // We assume our line will be in the first 1024 characters and that we can michael@0: // read this much all at once. In practice this will generally be true. michael@0: // This simplifies and speeds up things considerably. michael@0: char buf[1024]; michael@0: michael@0: ssize_t num_read = HANDLE_EINTR(read(status_fd, buf, sizeof(buf))); michael@0: HANDLE_EINTR(close(status_fd)); michael@0: michael@0: if (num_read <= 0) michael@0: return false; michael@0: michael@0: StringPiece status(buf, num_read); michael@0: StringPiece tracer("TracerPid:\t"); michael@0: michael@0: StringPiece::size_type pid_index = status.find(tracer); michael@0: if (pid_index == StringPiece::npos) michael@0: return false; michael@0: michael@0: // Our pid is 0 without a debugger, assume this for any pid starting with 0. michael@0: pid_index += tracer.size(); michael@0: return pid_index < status.size() && status[pid_index] != '0'; michael@0: } michael@0: michael@0: #endif // OS_LINUX michael@0: michael@0: // static michael@0: void DebugUtil::BreakDebugger() { michael@0: #if defined(ARCH_CPU_X86_FAMILY) michael@0: asm ("int3"); michael@0: #endif michael@0: } michael@0: michael@0: StackTrace::StackTrace() { michael@0: const int kMaxCallers = 256; michael@0: michael@0: void* callers[kMaxCallers]; michael@0: #if MOZ_HAVE_EXECINFO_H michael@0: int count = backtrace(callers, kMaxCallers); michael@0: #else michael@0: int count = 0; michael@0: #endif michael@0: michael@0: // Though the backtrace API man page does not list any possible negative michael@0: // return values, we still still exclude them because they would break the michael@0: // memcpy code below. michael@0: if (count > 0) { michael@0: trace_.resize(count); michael@0: memcpy(&trace_[0], callers, sizeof(callers[0]) * count); michael@0: } else { michael@0: trace_.resize(0); michael@0: } michael@0: } michael@0: michael@0: void StackTrace::PrintBacktrace() { michael@0: fflush(stderr); michael@0: #if MOZ_HAVE_EXECINFO_H michael@0: backtrace_symbols_fd(&trace_[0], trace_.size(), STDERR_FILENO); michael@0: #endif michael@0: } michael@0: michael@0: void StackTrace::OutputToStream(std::ostream* os) { michael@0: return; michael@0: }