Loading debuggerd/backtrace.c +7 −7 Original line number Diff line number Diff line Loading @@ -89,12 +89,12 @@ static void dump_thread(log_t* log, pid_t tid, bool attached, wait_for_stop(tid, total_sleep_time_usec); backtrace_t backtrace; if (!backtrace_get_data(&backtrace, tid)) { backtrace_context_t context; if (!backtrace_create_context(&context, tid, -1, 0)) { _LOG(log, SCOPE_AT_FAULT, "Could not create backtrace context.\n"); } else { dump_backtrace_to_log(&backtrace, log, SCOPE_AT_FAULT, " "); backtrace_free_data(&backtrace); dump_backtrace_to_log(&context, log, SCOPE_AT_FAULT, " "); backtrace_destroy_context(&context); } if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) { Loading Loading @@ -137,11 +137,11 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, dump_process_footer(&log, pid); } void dump_backtrace_to_log(const backtrace_t* backtrace, log_t* log, void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log, int scope_flags, const char* prefix) { char buf[512]; for (size_t i = 0; i < backtrace->num_frames; i++) { backtrace_format_frame_data(&backtrace->frames[i], i, buf, sizeof(buf)); for (size_t i = 0; i < context->backtrace->num_frames; i++) { backtrace_format_frame_data(context, i, buf, sizeof(buf)); _LOG(log, scope_flags, "%s%s\n", prefix, buf); } } debuggerd/backtrace.h +1 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, int* total_sleep_time_usec); /* Dumps the backtrace in the backtrace data structure to the log. */ void dump_backtrace_to_log(const backtrace_t* backtrace, log_t* log, void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log, int scope_flags, const char* prefix); #endif // _DEBUGGERD_BACKTRACE_H debuggerd/tombstone.c +35 −33 Original line number Diff line number Diff line Loading @@ -228,39 +228,39 @@ static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags) } } static void dump_stack_segment(const backtrace_t* backtrace, log_t* log, static void dump_stack_segment(const backtrace_context_t* context, log_t* log, int scope_flags, uintptr_t *sp, size_t words, int label) { for (size_t i = 0; i < words; i++) { uint32_t stack_content; if (!backtrace_read_word(backtrace, *sp, &stack_content)) { if (!backtrace_read_word(context, *sp, &stack_content)) { break; } const char* map_name = backtrace_get_map_info(backtrace, stack_content, NULL); const char* map_name = backtrace_get_map_name(context, stack_content, NULL); if (!map_name) { map_name = ""; } uintptr_t offset = 0; char* proc_name = backtrace_get_proc_name(backtrace, stack_content, &offset); if (proc_name) { char* func_name = backtrace_get_func_name(context, stack_content, &offset); if (func_name) { if (!i && label >= 0) { if (offset) { _LOG(log, scope_flags, " #%02d %08x %08x %s (%s+%u)\n", label, *sp, stack_content, map_name, proc_name, offset); label, *sp, stack_content, map_name, func_name, offset); } else { _LOG(log, scope_flags, " #%02d %08x %08x %s (%s)\n", label, *sp, stack_content, map_name, proc_name); label, *sp, stack_content, map_name, func_name); } } else { if (offset) { _LOG(log, scope_flags, " %08x %08x %s (%s+%u)\n", *sp, stack_content, map_name, proc_name, offset); *sp, stack_content, map_name, func_name, offset); } else { _LOG(log, scope_flags, " %08x %08x %s (%s)\n", *sp, stack_content, map_name, proc_name); *sp, stack_content, map_name, func_name); } } free(proc_name); free(func_name); } else { if (!i && label >= 0) { _LOG(log, scope_flags, " #%02d %08x %08x %s\n", Loading @@ -275,7 +275,8 @@ static void dump_stack_segment(const backtrace_t* backtrace, log_t* log, } } static void dump_stack(const backtrace_t* backtrace, log_t* log, int scope_flags) { static void dump_stack(const backtrace_context_t* context, log_t* log, int scope_flags) { const backtrace_t* backtrace = context->backtrace; size_t first = 0, last; for (size_t i = 0; i < backtrace->num_frames; i++) { if (backtrace->frames[i].sp) { Loading @@ -294,7 +295,7 @@ static void dump_stack(const backtrace_t* backtrace, log_t* log, int scope_flags // Dump a few words before the first frame. uintptr_t sp = backtrace->frames[first].sp - STACK_WORDS * sizeof(uint32_t); dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, -1); dump_stack_segment(context, log, scope_flags, &sp, STACK_WORDS, -1); // Dump a few words from all successive frames. // Only log the first 3 frames, put the rest in the tombstone. Loading @@ -308,7 +309,7 @@ static void dump_stack(const backtrace_t* backtrace, log_t* log, int scope_flags scope_flags &= (~SCOPE_AT_FAULT); } if (i == last) { dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, i); dump_stack_segment(context, log, scope_flags, &sp, STACK_WORDS, i); if (sp < frame->sp + frame->stack_size) { _LOG(log, scope_flags, " ........ ........\n"); } Loading @@ -319,19 +320,19 @@ static void dump_stack(const backtrace_t* backtrace, log_t* log, int scope_flags } else if (words > STACK_WORDS) { words = STACK_WORDS; } dump_stack_segment(backtrace, log, scope_flags, &sp, words, i); dump_stack_segment(context, log, scope_flags, &sp, words, i); } } } static void dump_backtrace_and_stack(const backtrace_t* backtrace, log_t* log, int scope_flags) { if (backtrace->num_frames) { static void dump_backtrace_and_stack(const backtrace_context_t* context, log_t* log, int scope_flags) { if (context->backtrace->num_frames) { _LOG(log, scope_flags, "\nbacktrace:\n"); dump_backtrace_to_log(backtrace, log, scope_flags, " "); dump_backtrace_to_log(context, log, scope_flags, " "); _LOG(log, scope_flags, "\nstack:\n"); dump_stack(backtrace, log, scope_flags); dump_stack(context, log, scope_flags); } } Loading Loading @@ -399,12 +400,13 @@ static void dump_nearby_maps(const backtrace_map_info_t* map_info_list, log_t* l dump_map(log, prev, "map above", scope_flags); } static void dump_thread(const backtrace_t* backtrace, log_t* log, int scope_flags, int* total_sleep_time_usec) { static void dump_thread(const backtrace_context_t* context, log_t* log, int scope_flags, int* total_sleep_time_usec) { const backtrace_t* backtrace = context->backtrace; wait_for_stop(backtrace->tid, total_sleep_time_usec); dump_registers(log, backtrace->tid, scope_flags); dump_backtrace_and_stack(backtrace, log, scope_flags); dump_backtrace_and_stack(context, log, scope_flags); if (IS_AT_FAULT(scope_flags)) { dump_memory_and_code(log, backtrace->tid, scope_flags); dump_nearby_maps(backtrace->map_info_list, log, backtrace->tid, scope_flags); Loading Loading @@ -446,11 +448,11 @@ static bool dump_sibling_thread_report( _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n"); dump_thread_info(log, pid, new_tid, 0); backtrace_t new_backtrace; if (backtrace_get_data(&new_backtrace, new_tid)) { dump_thread(&new_backtrace, log, 0, total_sleep_time_usec); backtrace_context_t new_context; if (backtrace_create_context(&new_context, pid, new_tid, 0)) { dump_thread(&new_context, log, 0, total_sleep_time_usec); backtrace_destroy_context(&new_context); } backtrace_free_data(&new_backtrace); if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) { LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno)); Loading Loading @@ -606,7 +608,7 @@ static void dump_logs(log_t* log, pid_t pid, bool tailOnly) dump_log_file(log, pid, "/dev/log/main", tailOnly); } static void dump_abort_message(const backtrace_t* backtrace, log_t* log, uintptr_t address) { static void dump_abort_message(const backtrace_context_t* context, log_t* log, uintptr_t address) { if (address == 0) { return; } Loading @@ -618,7 +620,7 @@ static void dump_abort_message(const backtrace_t* backtrace, log_t* log, uintptr char* p = &msg[0]; while (p < &msg[sizeof(msg)]) { uint32_t data; if (!backtrace_read_word(backtrace, address, &data)) { if (!backtrace_read_word(context, address, &data)) { break; } address += sizeof(uint32_t); Loading Loading @@ -673,11 +675,11 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a dump_fault_addr(log, tid, signal); } backtrace_t backtrace; if (backtrace_get_data(&backtrace, tid)) { dump_abort_message(&backtrace, log, abort_msg_address); dump_thread(&backtrace, log, SCOPE_AT_FAULT, total_sleep_time_usec); backtrace_free_data(&backtrace); backtrace_context_t context; if (backtrace_create_context(&context, pid, tid, 0)) { dump_abort_message(&context, log, abort_msg_address); dump_thread(&context, log, SCOPE_AT_FAULT, total_sleep_time_usec); backtrace_destroy_context(&context); } if (want_logs) { Loading include/backtrace/Backtrace.h 0 → 100644 +85 −0 Original line number Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _BACKTRACE_BACKTRACE_H #define _BACKTRACE_BACKTRACE_H #include <backtrace/backtrace.h> #include <string> class BacktraceImpl; class Backtrace { public: Backtrace(BacktraceImpl* impl); virtual ~Backtrace(); // Get the current stack trace and store in the backtrace_ structure. virtual bool Unwind(size_t num_ignore_frames); // Get the function name and offset into the function given the pc. // If the string is empty, then no valid function name was found. virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset); // Get the name of the map associated with the given pc. If NULL is returned, // then map_start is not set. Otherwise, map_start is the beginning of this // map. virtual const char* GetMapName(uintptr_t pc, uintptr_t* map_start); // Finds the memory map associated with the given ptr. virtual const backtrace_map_info_t* FindMapInfo(uintptr_t ptr); // Read the data at a specific address. virtual bool ReadWord(uintptr_t ptr, uint32_t* out_value) = 0; // Create a string representing the formatted line of backtrace information // for a single frame. virtual std::string FormatFrameData(size_t frame_num); pid_t Pid() { return backtrace_.pid; } pid_t Tid() { return backtrace_.tid; } size_t NumFrames() { return backtrace_.num_frames; } const backtrace_t* GetBacktrace() { return &backtrace_; } const backtrace_frame_data_t* GetFrame(size_t frame_num) { return &backtrace_.frames[frame_num]; } // Create the correct Backtrace object based on what is to be unwound. // If pid < 0 or equals the current pid, then the Backtrace object // corresponds to the current process. // If pid < 0 or equals the current pid and tid >= 0, then the Backtrace // object corresponds to a thread in the current process. // If pid >= 0 and tid < 0, then the Backtrace object corresponds to a // different process. // Tracing a thread in a different process is not supported. static Backtrace* Create(pid_t pid, pid_t tid); protected: virtual bool VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value); BacktraceImpl* impl_; backtrace_map_info_t* map_info_; backtrace_t backtrace_; friend class BacktraceImpl; }; #endif // _BACKTRACE_BACKTRACE_H include/backtrace/backtrace.h +35 −25 Original line number Diff line number Diff line Loading @@ -21,9 +21,7 @@ #include <stdbool.h> #include <inttypes.h> #ifdef __cplusplus extern "C" { #endif __BEGIN_DECLS #define MAX_BACKTRACE_FRAMES 64 Loading @@ -43,48 +41,58 @@ typedef struct { size_t stack_size; /* The size of the stack, zero indicate an unknown stack size. */ const char* map_name; /* The name of the map to which this pc belongs, NULL indicates the pc doesn't belong to a known map. */ uintptr_t map_offset; /* pc relative to the start of the map, only valid if map_name is not NULL. */ char* proc_name; /* The function name associated with this pc, NULL if not found. */ uintptr_t proc_offset; /* pc relative to the start of the procedure, only valid if proc_name is not NULL. */ char* func_name; /* The function name associated with this pc, NULL if not found. */ uintptr_t func_offset; /* pc relative to the start of the function, only valid if func_name is not NULL. */ } backtrace_frame_data_t; typedef struct { backtrace_frame_data_t frames[MAX_BACKTRACE_FRAMES]; size_t num_frames; pid_t pid; pid_t tid; backtrace_map_info_t* map_info_list; void* private_data; } backtrace_t; /* Gather the backtrace data for tid and fill in the backtrace structure. * If tid < 0, then gather the backtrace for the current thread. typedef struct { void* data; const backtrace_t* backtrace; } backtrace_context_t; /* Create a context for the backtrace data and gather the backtrace. * If pid < 0, then gather the backtrace for the current process. */ bool backtrace_get_data(backtrace_t* backtrace, pid_t tid); bool backtrace_create_context( backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames); /* Free any memory associated with the backtrace structure. */ void backtrace_free_data(backtrace_t* backtrace); /* Gather the backtrace data for a pthread instead of a process. */ bool backtrace_create_thread_context( backtrace_context_t* context, pid_t tid, size_t num_ignore_frames); /* Free any memory allocated during the context create. */ void backtrace_destroy_context(backtrace_context_t* context); /* Read data at a specific address for a process. */ bool backtrace_read_word( const backtrace_t* backtrace, uintptr_t ptr, uint32_t* value); const backtrace_context_t* context, uintptr_t ptr, uint32_t* value); /* Get information about the map associated with a pc. If NULL is /* Get information about the map name associated with a pc. If NULL is * returned, then map_start is not set. */ const char* backtrace_get_map_info( const backtrace_t* backtrace, uintptr_t pc, uintptr_t* map_start); const char* backtrace_get_map_name( const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start); /* Get the procedure name and offest given the pc. If NULL is returned, * then proc_offset is not set. The returned string is allocated using /* Get the function name and offset given the pc. If NULL is returned, * then func_offset is not set. The returned string is allocated using * malloc and must be freed by the caller. */ char* backtrace_get_proc_name( const backtrace_t* backtrace, uintptr_t pc, uintptr_t* proc_offset); char* backtrace_get_func_name( const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset); /* Loads memory map from /proc/<tid>/maps. If tid < 0, then load the memory /* Loads memory map from /proc/<pid>/maps. If pid < 0, then load the memory * map for the current process. */ backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid); backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid); /* Frees memory associated with the map list. */ void backtrace_destroy_map_info_list(backtrace_map_info_t* map_info_list); Loading @@ -95,10 +103,12 @@ const backtrace_map_info_t* backtrace_find_map_info( /* Create a formatted line of backtrace information for a single frame. */ void backtrace_format_frame_data( const backtrace_frame_data_t* frame, size_t frame_num, char *buf, size_t buf_size); const backtrace_context_t* context, size_t frame_num, char* buf, size_t buf_size); /* Get the backtrace data structure associated with the context. */ const backtrace_t* backtrace_get_data(backtrace_context_t* context); #ifdef __cplusplus } #endif __END_DECLS #endif /* _BACKTRACE_H */ Loading
debuggerd/backtrace.c +7 −7 Original line number Diff line number Diff line Loading @@ -89,12 +89,12 @@ static void dump_thread(log_t* log, pid_t tid, bool attached, wait_for_stop(tid, total_sleep_time_usec); backtrace_t backtrace; if (!backtrace_get_data(&backtrace, tid)) { backtrace_context_t context; if (!backtrace_create_context(&context, tid, -1, 0)) { _LOG(log, SCOPE_AT_FAULT, "Could not create backtrace context.\n"); } else { dump_backtrace_to_log(&backtrace, log, SCOPE_AT_FAULT, " "); backtrace_free_data(&backtrace); dump_backtrace_to_log(&context, log, SCOPE_AT_FAULT, " "); backtrace_destroy_context(&context); } if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) { Loading Loading @@ -137,11 +137,11 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, dump_process_footer(&log, pid); } void dump_backtrace_to_log(const backtrace_t* backtrace, log_t* log, void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log, int scope_flags, const char* prefix) { char buf[512]; for (size_t i = 0; i < backtrace->num_frames; i++) { backtrace_format_frame_data(&backtrace->frames[i], i, buf, sizeof(buf)); for (size_t i = 0; i < context->backtrace->num_frames; i++) { backtrace_format_frame_data(context, i, buf, sizeof(buf)); _LOG(log, scope_flags, "%s%s\n", prefix, buf); } }
debuggerd/backtrace.h +1 −1 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, int* total_sleep_time_usec); /* Dumps the backtrace in the backtrace data structure to the log. */ void dump_backtrace_to_log(const backtrace_t* backtrace, log_t* log, void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log, int scope_flags, const char* prefix); #endif // _DEBUGGERD_BACKTRACE_H
debuggerd/tombstone.c +35 −33 Original line number Diff line number Diff line Loading @@ -228,39 +228,39 @@ static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags) } } static void dump_stack_segment(const backtrace_t* backtrace, log_t* log, static void dump_stack_segment(const backtrace_context_t* context, log_t* log, int scope_flags, uintptr_t *sp, size_t words, int label) { for (size_t i = 0; i < words; i++) { uint32_t stack_content; if (!backtrace_read_word(backtrace, *sp, &stack_content)) { if (!backtrace_read_word(context, *sp, &stack_content)) { break; } const char* map_name = backtrace_get_map_info(backtrace, stack_content, NULL); const char* map_name = backtrace_get_map_name(context, stack_content, NULL); if (!map_name) { map_name = ""; } uintptr_t offset = 0; char* proc_name = backtrace_get_proc_name(backtrace, stack_content, &offset); if (proc_name) { char* func_name = backtrace_get_func_name(context, stack_content, &offset); if (func_name) { if (!i && label >= 0) { if (offset) { _LOG(log, scope_flags, " #%02d %08x %08x %s (%s+%u)\n", label, *sp, stack_content, map_name, proc_name, offset); label, *sp, stack_content, map_name, func_name, offset); } else { _LOG(log, scope_flags, " #%02d %08x %08x %s (%s)\n", label, *sp, stack_content, map_name, proc_name); label, *sp, stack_content, map_name, func_name); } } else { if (offset) { _LOG(log, scope_flags, " %08x %08x %s (%s+%u)\n", *sp, stack_content, map_name, proc_name, offset); *sp, stack_content, map_name, func_name, offset); } else { _LOG(log, scope_flags, " %08x %08x %s (%s)\n", *sp, stack_content, map_name, proc_name); *sp, stack_content, map_name, func_name); } } free(proc_name); free(func_name); } else { if (!i && label >= 0) { _LOG(log, scope_flags, " #%02d %08x %08x %s\n", Loading @@ -275,7 +275,8 @@ static void dump_stack_segment(const backtrace_t* backtrace, log_t* log, } } static void dump_stack(const backtrace_t* backtrace, log_t* log, int scope_flags) { static void dump_stack(const backtrace_context_t* context, log_t* log, int scope_flags) { const backtrace_t* backtrace = context->backtrace; size_t first = 0, last; for (size_t i = 0; i < backtrace->num_frames; i++) { if (backtrace->frames[i].sp) { Loading @@ -294,7 +295,7 @@ static void dump_stack(const backtrace_t* backtrace, log_t* log, int scope_flags // Dump a few words before the first frame. uintptr_t sp = backtrace->frames[first].sp - STACK_WORDS * sizeof(uint32_t); dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, -1); dump_stack_segment(context, log, scope_flags, &sp, STACK_WORDS, -1); // Dump a few words from all successive frames. // Only log the first 3 frames, put the rest in the tombstone. Loading @@ -308,7 +309,7 @@ static void dump_stack(const backtrace_t* backtrace, log_t* log, int scope_flags scope_flags &= (~SCOPE_AT_FAULT); } if (i == last) { dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, i); dump_stack_segment(context, log, scope_flags, &sp, STACK_WORDS, i); if (sp < frame->sp + frame->stack_size) { _LOG(log, scope_flags, " ........ ........\n"); } Loading @@ -319,19 +320,19 @@ static void dump_stack(const backtrace_t* backtrace, log_t* log, int scope_flags } else if (words > STACK_WORDS) { words = STACK_WORDS; } dump_stack_segment(backtrace, log, scope_flags, &sp, words, i); dump_stack_segment(context, log, scope_flags, &sp, words, i); } } } static void dump_backtrace_and_stack(const backtrace_t* backtrace, log_t* log, int scope_flags) { if (backtrace->num_frames) { static void dump_backtrace_and_stack(const backtrace_context_t* context, log_t* log, int scope_flags) { if (context->backtrace->num_frames) { _LOG(log, scope_flags, "\nbacktrace:\n"); dump_backtrace_to_log(backtrace, log, scope_flags, " "); dump_backtrace_to_log(context, log, scope_flags, " "); _LOG(log, scope_flags, "\nstack:\n"); dump_stack(backtrace, log, scope_flags); dump_stack(context, log, scope_flags); } } Loading Loading @@ -399,12 +400,13 @@ static void dump_nearby_maps(const backtrace_map_info_t* map_info_list, log_t* l dump_map(log, prev, "map above", scope_flags); } static void dump_thread(const backtrace_t* backtrace, log_t* log, int scope_flags, int* total_sleep_time_usec) { static void dump_thread(const backtrace_context_t* context, log_t* log, int scope_flags, int* total_sleep_time_usec) { const backtrace_t* backtrace = context->backtrace; wait_for_stop(backtrace->tid, total_sleep_time_usec); dump_registers(log, backtrace->tid, scope_flags); dump_backtrace_and_stack(backtrace, log, scope_flags); dump_backtrace_and_stack(context, log, scope_flags); if (IS_AT_FAULT(scope_flags)) { dump_memory_and_code(log, backtrace->tid, scope_flags); dump_nearby_maps(backtrace->map_info_list, log, backtrace->tid, scope_flags); Loading Loading @@ -446,11 +448,11 @@ static bool dump_sibling_thread_report( _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n"); dump_thread_info(log, pid, new_tid, 0); backtrace_t new_backtrace; if (backtrace_get_data(&new_backtrace, new_tid)) { dump_thread(&new_backtrace, log, 0, total_sleep_time_usec); backtrace_context_t new_context; if (backtrace_create_context(&new_context, pid, new_tid, 0)) { dump_thread(&new_context, log, 0, total_sleep_time_usec); backtrace_destroy_context(&new_context); } backtrace_free_data(&new_backtrace); if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) { LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno)); Loading Loading @@ -606,7 +608,7 @@ static void dump_logs(log_t* log, pid_t pid, bool tailOnly) dump_log_file(log, pid, "/dev/log/main", tailOnly); } static void dump_abort_message(const backtrace_t* backtrace, log_t* log, uintptr_t address) { static void dump_abort_message(const backtrace_context_t* context, log_t* log, uintptr_t address) { if (address == 0) { return; } Loading @@ -618,7 +620,7 @@ static void dump_abort_message(const backtrace_t* backtrace, log_t* log, uintptr char* p = &msg[0]; while (p < &msg[sizeof(msg)]) { uint32_t data; if (!backtrace_read_word(backtrace, address, &data)) { if (!backtrace_read_word(context, address, &data)) { break; } address += sizeof(uint32_t); Loading Loading @@ -673,11 +675,11 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a dump_fault_addr(log, tid, signal); } backtrace_t backtrace; if (backtrace_get_data(&backtrace, tid)) { dump_abort_message(&backtrace, log, abort_msg_address); dump_thread(&backtrace, log, SCOPE_AT_FAULT, total_sleep_time_usec); backtrace_free_data(&backtrace); backtrace_context_t context; if (backtrace_create_context(&context, pid, tid, 0)) { dump_abort_message(&context, log, abort_msg_address); dump_thread(&context, log, SCOPE_AT_FAULT, total_sleep_time_usec); backtrace_destroy_context(&context); } if (want_logs) { Loading
include/backtrace/Backtrace.h 0 → 100644 +85 −0 Original line number Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _BACKTRACE_BACKTRACE_H #define _BACKTRACE_BACKTRACE_H #include <backtrace/backtrace.h> #include <string> class BacktraceImpl; class Backtrace { public: Backtrace(BacktraceImpl* impl); virtual ~Backtrace(); // Get the current stack trace and store in the backtrace_ structure. virtual bool Unwind(size_t num_ignore_frames); // Get the function name and offset into the function given the pc. // If the string is empty, then no valid function name was found. virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset); // Get the name of the map associated with the given pc. If NULL is returned, // then map_start is not set. Otherwise, map_start is the beginning of this // map. virtual const char* GetMapName(uintptr_t pc, uintptr_t* map_start); // Finds the memory map associated with the given ptr. virtual const backtrace_map_info_t* FindMapInfo(uintptr_t ptr); // Read the data at a specific address. virtual bool ReadWord(uintptr_t ptr, uint32_t* out_value) = 0; // Create a string representing the formatted line of backtrace information // for a single frame. virtual std::string FormatFrameData(size_t frame_num); pid_t Pid() { return backtrace_.pid; } pid_t Tid() { return backtrace_.tid; } size_t NumFrames() { return backtrace_.num_frames; } const backtrace_t* GetBacktrace() { return &backtrace_; } const backtrace_frame_data_t* GetFrame(size_t frame_num) { return &backtrace_.frames[frame_num]; } // Create the correct Backtrace object based on what is to be unwound. // If pid < 0 or equals the current pid, then the Backtrace object // corresponds to the current process. // If pid < 0 or equals the current pid and tid >= 0, then the Backtrace // object corresponds to a thread in the current process. // If pid >= 0 and tid < 0, then the Backtrace object corresponds to a // different process. // Tracing a thread in a different process is not supported. static Backtrace* Create(pid_t pid, pid_t tid); protected: virtual bool VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value); BacktraceImpl* impl_; backtrace_map_info_t* map_info_; backtrace_t backtrace_; friend class BacktraceImpl; }; #endif // _BACKTRACE_BACKTRACE_H
include/backtrace/backtrace.h +35 −25 Original line number Diff line number Diff line Loading @@ -21,9 +21,7 @@ #include <stdbool.h> #include <inttypes.h> #ifdef __cplusplus extern "C" { #endif __BEGIN_DECLS #define MAX_BACKTRACE_FRAMES 64 Loading @@ -43,48 +41,58 @@ typedef struct { size_t stack_size; /* The size of the stack, zero indicate an unknown stack size. */ const char* map_name; /* The name of the map to which this pc belongs, NULL indicates the pc doesn't belong to a known map. */ uintptr_t map_offset; /* pc relative to the start of the map, only valid if map_name is not NULL. */ char* proc_name; /* The function name associated with this pc, NULL if not found. */ uintptr_t proc_offset; /* pc relative to the start of the procedure, only valid if proc_name is not NULL. */ char* func_name; /* The function name associated with this pc, NULL if not found. */ uintptr_t func_offset; /* pc relative to the start of the function, only valid if func_name is not NULL. */ } backtrace_frame_data_t; typedef struct { backtrace_frame_data_t frames[MAX_BACKTRACE_FRAMES]; size_t num_frames; pid_t pid; pid_t tid; backtrace_map_info_t* map_info_list; void* private_data; } backtrace_t; /* Gather the backtrace data for tid and fill in the backtrace structure. * If tid < 0, then gather the backtrace for the current thread. typedef struct { void* data; const backtrace_t* backtrace; } backtrace_context_t; /* Create a context for the backtrace data and gather the backtrace. * If pid < 0, then gather the backtrace for the current process. */ bool backtrace_get_data(backtrace_t* backtrace, pid_t tid); bool backtrace_create_context( backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames); /* Free any memory associated with the backtrace structure. */ void backtrace_free_data(backtrace_t* backtrace); /* Gather the backtrace data for a pthread instead of a process. */ bool backtrace_create_thread_context( backtrace_context_t* context, pid_t tid, size_t num_ignore_frames); /* Free any memory allocated during the context create. */ void backtrace_destroy_context(backtrace_context_t* context); /* Read data at a specific address for a process. */ bool backtrace_read_word( const backtrace_t* backtrace, uintptr_t ptr, uint32_t* value); const backtrace_context_t* context, uintptr_t ptr, uint32_t* value); /* Get information about the map associated with a pc. If NULL is /* Get information about the map name associated with a pc. If NULL is * returned, then map_start is not set. */ const char* backtrace_get_map_info( const backtrace_t* backtrace, uintptr_t pc, uintptr_t* map_start); const char* backtrace_get_map_name( const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start); /* Get the procedure name and offest given the pc. If NULL is returned, * then proc_offset is not set. The returned string is allocated using /* Get the function name and offset given the pc. If NULL is returned, * then func_offset is not set. The returned string is allocated using * malloc and must be freed by the caller. */ char* backtrace_get_proc_name( const backtrace_t* backtrace, uintptr_t pc, uintptr_t* proc_offset); char* backtrace_get_func_name( const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset); /* Loads memory map from /proc/<tid>/maps. If tid < 0, then load the memory /* Loads memory map from /proc/<pid>/maps. If pid < 0, then load the memory * map for the current process. */ backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid); backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid); /* Frees memory associated with the map list. */ void backtrace_destroy_map_info_list(backtrace_map_info_t* map_info_list); Loading @@ -95,10 +103,12 @@ const backtrace_map_info_t* backtrace_find_map_info( /* Create a formatted line of backtrace information for a single frame. */ void backtrace_format_frame_data( const backtrace_frame_data_t* frame, size_t frame_num, char *buf, size_t buf_size); const backtrace_context_t* context, size_t frame_num, char* buf, size_t buf_size); /* Get the backtrace data structure associated with the context. */ const backtrace_t* backtrace_get_data(backtrace_context_t* context); #ifdef __cplusplus } #endif __END_DECLS #endif /* _BACKTRACE_H */