backtrace.cpp revision 20303f856f1f1cdb5af58af0b116b8c598f0ea5c
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stddef.h> 18#include <stdlib.h> 19#include <string.h> 20#include <stdio.h> 21#include <time.h> 22#include <errno.h> 23#include <limits.h> 24#include <dirent.h> 25#include <unistd.h> 26#include <sys/types.h> 27#include <sys/ptrace.h> 28 29#include <backtrace/Backtrace.h> 30#include <UniquePtr.h> 31 32#include "backtrace.h" 33#include "utility.h" 34 35static void dump_process_header(log_t* log, pid_t pid) { 36 char path[PATH_MAX]; 37 char procnamebuf[1024]; 38 char* procname = NULL; 39 FILE* fp; 40 41 snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); 42 if ((fp = fopen(path, "r"))) { 43 procname = fgets(procnamebuf, sizeof(procnamebuf), fp); 44 fclose(fp); 45 } 46 47 time_t t = time(NULL); 48 struct tm tm; 49 localtime_r(&t, &tm); 50 char timestr[64]; 51 strftime(timestr, sizeof(timestr), "%F %T", &tm); 52 _LOG(log, SCOPE_AT_FAULT, "\n\n----- pid %d at %s -----\n", pid, timestr); 53 54 if (procname) { 55 _LOG(log, SCOPE_AT_FAULT, "Cmd line: %s\n", procname); 56 } 57} 58 59static void dump_process_footer(log_t* log, pid_t pid) { 60 _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid); 61} 62 63static void dump_thread( 64 log_t* log, pid_t tid, bool attached, bool* detach_failed, int* total_sleep_time_usec) { 65 char path[PATH_MAX]; 66 char threadnamebuf[1024]; 67 char* threadname = NULL; 68 FILE* fp; 69 70 snprintf(path, sizeof(path), "/proc/%d/comm", tid); 71 if ((fp = fopen(path, "r"))) { 72 threadname = fgets(threadnamebuf, sizeof(threadnamebuf), fp); 73 fclose(fp); 74 if (threadname) { 75 size_t len = strlen(threadname); 76 if (len && threadname[len - 1] == '\n') { 77 threadname[len - 1] = '\0'; 78 } 79 } 80 } 81 82 _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid); 83 84 if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) { 85 _LOG(log, SCOPE_AT_FAULT, "Could not attach to thread: %s\n", strerror(errno)); 86 return; 87 } 88 89 wait_for_stop(tid, total_sleep_time_usec); 90 91 UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD)); 92 if (backtrace->Unwind(0)) { 93 dump_backtrace_to_log(backtrace.get(), log, SCOPE_AT_FAULT, " "); 94 } 95 96 if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) { 97 LOG("ptrace detach from %d failed: %s\n", tid, strerror(errno)); 98 *detach_failed = true; 99 } 100} 101 102void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, 103 int* total_sleep_time_usec) { 104 log_t log; 105 log.tfd = fd; 106 log.amfd = amfd; 107 log.quiet = true; 108 109 dump_process_header(&log, pid); 110 dump_thread(&log, tid, true, detach_failed, total_sleep_time_usec); 111 112 char task_path[64]; 113 snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid); 114 DIR* d = opendir(task_path); 115 if (d != NULL) { 116 struct dirent* de = NULL; 117 while ((de = readdir(d)) != NULL) { 118 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { 119 continue; 120 } 121 122 char* end; 123 pid_t new_tid = strtoul(de->d_name, &end, 10); 124 if (*end || new_tid == tid) { 125 continue; 126 } 127 128 dump_thread(&log, new_tid, false, detach_failed, total_sleep_time_usec); 129 } 130 closedir(d); 131 } 132 133 dump_process_footer(&log, pid); 134} 135 136void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, 137 int scope_flags, const char* prefix) { 138 for (size_t i = 0; i < backtrace->NumFrames(); i++) { 139 _LOG(log, scope_flags, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str()); 140 } 141} 142