diff options
author | Christopher Ferris <cferris@google.com> | 2014-01-17 11:56:04 -0800 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2014-01-17 11:56:04 -0800 |
commit | 6c625f67174cf12ecec1c2c86e9541a7a08e0607 (patch) | |
tree | 1afc698454281262d6e8e06a2e6394846450d7a4 /libbacktrace | |
parent | c176e14ce3fd28432e2eaca7bc7a60046dd8be40 (diff) | |
parent | 47fa90641e5321f853d50de1e129b6233fa183e1 (diff) | |
download | system_core-6c625f67174cf12ecec1c2c86e9541a7a08e0607.zip system_core-6c625f67174cf12ecec1c2c86e9541a7a08e0607.tar.gz system_core-6c625f67174cf12ecec1c2c86e9541a7a08e0607.tar.bz2 |
resolved conflicts for merge of 47fa9064 to master
Change-Id: I53fb8ff2dfbefe6246385e624c5c3525cc6f4253
Diffstat (limited to 'libbacktrace')
-rw-r--r-- | libbacktrace/Android.mk | 4 | ||||
-rw-r--r-- | libbacktrace/Backtrace.cpp | 208 | ||||
-rw-r--r-- | libbacktrace/Backtrace.h | 18 | ||||
-rw-r--r-- | libbacktrace/BacktraceMap.cpp | 130 | ||||
-rw-r--r-- | libbacktrace/BacktraceThread.cpp | 26 | ||||
-rw-r--r-- | libbacktrace/BacktraceThread.h | 6 | ||||
-rw-r--r-- | libbacktrace/Corkscrew.cpp | 150 | ||||
-rw-r--r-- | libbacktrace/Corkscrew.h | 20 | ||||
-rw-r--r-- | libbacktrace/UnwindCurrent.cpp | 49 | ||||
-rw-r--r-- | libbacktrace/UnwindCurrent.h | 2 | ||||
-rw-r--r-- | libbacktrace/UnwindPtrace.cpp | 40 | ||||
-rw-r--r-- | libbacktrace/UnwindPtrace.h | 2 | ||||
-rw-r--r-- | libbacktrace/backtrace_test.cpp | 95 |
13 files changed, 412 insertions, 338 deletions
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk index d2fd79e..d729c1c 100644 --- a/libbacktrace/Android.mk +++ b/libbacktrace/Android.mk @@ -2,8 +2,8 @@ LOCAL_PATH:= $(call my-dir) common_src := \ Backtrace.cpp \ + BacktraceMap.cpp \ BacktraceThread.cpp \ - map_info.c \ thread_utils.c \ common_cflags := \ @@ -222,7 +222,7 @@ LOCAL_LDLIBS += \ else LOCAL_SRC_FILES += \ - map_info.c \ + BacktraceMap.cpp \ endif diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp index 20667e0..d7b40ab 100644 --- a/libbacktrace/Backtrace.cpp +++ b/libbacktrace/Backtrace.cpp @@ -27,46 +27,28 @@ #include <string> #include <backtrace/Backtrace.h> -#include <cutils/log.h> +#include <backtrace/BacktraceMap.h> #include "Backtrace.h" #include "thread_utils.h" //------------------------------------------------------------------------- -// BacktraceImpl functions. -//------------------------------------------------------------------------- -backtrace_t* BacktraceImpl::GetBacktraceData() { - return &backtrace_obj_->backtrace_; -} - -//------------------------------------------------------------------------- // Backtrace functions. //------------------------------------------------------------------------- -Backtrace::Backtrace(BacktraceImpl* impl, pid_t pid, backtrace_map_info_t* map_info) - : impl_(impl), map_info_(map_info), map_info_requires_delete_(false) { +Backtrace::Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map) + : pid_(pid), tid_(-1), map_(map), map_shared_(true), impl_(impl) { impl_->SetParent(this); - backtrace_.num_frames = 0; - backtrace_.pid = pid; - backtrace_.tid = -1; - if (map_info_ == NULL) { - // Create the map and manage it internally. - map_info_ = backtrace_create_map_info_list(pid); - map_info_requires_delete_ = true; + if (map_ == NULL) { + // The map will be created when needed. + map_shared_ = false; } } Backtrace::~Backtrace() { - for (size_t i = 0; i < NumFrames(); i++) { - if (backtrace_.frames[i].func_name) { - free(backtrace_.frames[i].func_name); - backtrace_.frames[i].func_name = NULL; - } - } - - if (map_info_ && map_info_requires_delete_) { - backtrace_destroy_map_info_list(map_info_); - map_info_ = NULL; + if (map_ && !map_shared_) { + delete map_; + map_ = NULL; } if (impl_) { @@ -109,47 +91,36 @@ bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value) { return true; } -const char* Backtrace::GetMapName(uintptr_t pc, uintptr_t* map_start) { - const backtrace_map_info_t* map_info = FindMapInfo(pc); - if (map_info) { - if (map_start) { - *map_start = map_info->start; - } - return map_info->name; - } - return NULL; -} - -const backtrace_map_info_t* Backtrace::FindMapInfo(uintptr_t ptr) { - return backtrace_find_map_info(map_info_, ptr); -} - std::string Backtrace::FormatFrameData(size_t frame_num) { - return FormatFrameData(&backtrace_.frames[frame_num]); + if (frame_num >= frames_.size()) { + return ""; + } + return FormatFrameData(&frames_[frame_num]); } std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) { const char* map_name; - if (frame->map_name) { - map_name = frame->map_name; + if (frame->map && !frame->map->name.empty()) { + map_name = frame->map->name.c_str(); } else { map_name = "<unknown>"; } + uintptr_t relative_pc; - if (frame->map_offset) { - relative_pc = frame->map_offset; + if (frame->map) { + relative_pc = frame->pc - frame->map->start; } else { relative_pc = frame->pc; } char buf[512]; - if (frame->func_name && frame->func_offset) { + if (!frame->func_name.empty() && frame->func_offset) { snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s+%" PRIuPTR ")", frame->num, (int)sizeof(uintptr_t)*2, relative_pc, map_name, - frame->func_name, frame->func_offset); - } else if (frame->func_name) { + frame->func_name.c_str(), frame->func_offset); + } else if (!frame->func_name.empty()) { snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s)", frame->num, - (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name); + (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name.c_str()); } else { snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s", frame->num, (int)sizeof(uintptr_t)*2, relative_pc, map_name); @@ -158,13 +129,35 @@ std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) { return buf; } +bool Backtrace::BuildMap() { + map_ = impl_->CreateBacktraceMap(pid_); + if (!map_->Build()) { + BACK_LOGW("Failed to build map for process %d", pid_); + return false; + } + return true; +} + +const backtrace_map_t* Backtrace::FindMap(uintptr_t pc) { + if (map_ == NULL) { + // Lazy eval, time to build the map. + if (!BuildMap()) { + return NULL; + } + } + return map_->Find(pc); +} + +BacktraceMap* Backtrace::TakeMapOwnership() { + map_shared_ = true; + return map_; +} + //------------------------------------------------------------------------- // BacktraceCurrent functions. //------------------------------------------------------------------------- BacktraceCurrent::BacktraceCurrent( - BacktraceImpl* impl, backtrace_map_info_t *map_info) : Backtrace(impl, getpid(), map_info) { - - backtrace_.pid = getpid(); + BacktraceImpl* impl, BacktraceMap* map) : Backtrace(impl, getpid(), map) { } BacktraceCurrent::~BacktraceCurrent() { @@ -175,8 +168,8 @@ bool BacktraceCurrent::ReadWord(uintptr_t ptr, uint32_t* out_value) { return false; } - const backtrace_map_info_t* map_info = FindMapInfo(ptr); - if (map_info && map_info->is_readable) { + const backtrace_map_t* map = FindMap(ptr); + if (map && map->flags & PROT_READ) { *out_value = *reinterpret_cast<uint32_t*>(ptr); return true; } else { @@ -190,9 +183,9 @@ bool BacktraceCurrent::ReadWord(uintptr_t ptr, uint32_t* out_value) { // BacktracePtrace functions. //------------------------------------------------------------------------- BacktracePtrace::BacktracePtrace( - BacktraceImpl* impl, pid_t pid, pid_t tid, backtrace_map_info_t* map_info) - : Backtrace(impl, pid, map_info) { - backtrace_.tid = tid; + BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map) + : Backtrace(impl, pid, map) { + tid_ = tid; } BacktracePtrace::~BacktracePtrace() { @@ -220,103 +213,16 @@ bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) { #endif } -Backtrace* Backtrace::Create(pid_t pid, pid_t tid, backtrace_map_info_t* map_info) { +Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) { if (pid == BACKTRACE_CURRENT_PROCESS || pid == getpid()) { if (tid == BACKTRACE_CURRENT_THREAD || tid == gettid()) { - return CreateCurrentObj(map_info); + return CreateCurrentObj(map); } else { - return CreateThreadObj(tid, map_info); + return CreateThreadObj(tid, map); } } else if (tid == BACKTRACE_CURRENT_THREAD) { - return CreatePtraceObj(pid, pid, map_info); + return CreatePtraceObj(pid, pid, map); } else { - return CreatePtraceObj(pid, tid, map_info); - } -} - -//------------------------------------------------------------------------- -// Common interface functions. -//------------------------------------------------------------------------- -bool backtrace_create_context_with_map( - backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames, - backtrace_map_info_t* map_info) { - Backtrace* backtrace = Backtrace::Create(pid, tid, map_info); - if (!backtrace) { - return false; - } - if (!backtrace->Unwind(num_ignore_frames)) { - delete backtrace; - return false; - } - - context->data = backtrace; - context->backtrace = backtrace->GetBacktrace(); - return true; -} - -bool backtrace_create_context( - backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames) { - return backtrace_create_context_with_map(context, pid, tid, num_ignore_frames, NULL); -} - - -void backtrace_destroy_context(backtrace_context_t* context) { - if (context->data) { - Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data); - delete backtrace; - context->data = NULL; - } - context->backtrace = NULL; -} - -const backtrace_t* backtrace_get_data(backtrace_context_t* context) { - if (context && context->data) { - Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data); - return backtrace->GetBacktrace(); - } - return NULL; -} - -bool backtrace_read_word(const backtrace_context_t* context, uintptr_t ptr, uint32_t* value) { - if (context->data) { - Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data); - return backtrace->ReadWord(ptr, value); - } - return true; -} - -const char* backtrace_get_map_name(const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start) { - if (context->data) { - Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data); - return backtrace->GetMapName(pc, map_start); - } - return NULL; -} - -char* backtrace_get_func_name(const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset) { - if (context->data) { - Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data); - std::string func_name = backtrace->GetFunctionName(pc, func_offset); - if (!func_name.empty()) { - return strdup(func_name.c_str()); - } - } - return NULL; -} - -void backtrace_format_frame_data( - const backtrace_context_t* context, size_t frame_num, char* buf, - size_t buf_size) { - if (buf_size == 0 || buf == NULL) { - BACK_LOGW("bad call buf %p buf_size %zu", buf, buf_size); - } else if (context->data) { - Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data); - std::string line = backtrace->FormatFrameData(frame_num); - if (line.size() > buf_size) { - memcpy(buf, line.c_str(), buf_size-1); - buf[buf_size] = '\0'; - } else { - memcpy(buf, line.c_str(), line.size()+1); - } + return CreatePtraceObj(pid, tid, map); } } diff --git a/libbacktrace/Backtrace.h b/libbacktrace/Backtrace.h index d741ef1..31fcaf2 100644 --- a/libbacktrace/Backtrace.h +++ b/libbacktrace/Backtrace.h @@ -18,8 +18,10 @@ #define _LIBBACKTRACE_BACKTRACE_H #include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> #include <sys/types.h> +#include <log/log.h> // Macro to log the function name along with the warning message. #define BACK_LOGW(format, ...) \ @@ -37,15 +39,19 @@ public: void SetParent(Backtrace* backtrace) { backtrace_obj_ = backtrace; } + virtual BacktraceMap* CreateBacktraceMap(pid_t pid) = 0; + protected: - backtrace_t* GetBacktraceData(); + inline std::vector<backtrace_frame_data_t>* GetFrames() { return &backtrace_obj_->frames_; } + + inline bool BuildMap() { return backtrace_obj_->BuildMap(); } Backtrace* backtrace_obj_; }; class BacktraceCurrent : public Backtrace { public: - BacktraceCurrent(BacktraceImpl* impl, backtrace_map_info_t* map_info); + BacktraceCurrent(BacktraceImpl* impl, BacktraceMap* map); virtual ~BacktraceCurrent(); bool ReadWord(uintptr_t ptr, uint32_t* out_value); @@ -53,14 +59,14 @@ public: class BacktracePtrace : public Backtrace { public: - BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid, backtrace_map_info_t* map_info); + BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map); virtual ~BacktracePtrace(); bool ReadWord(uintptr_t ptr, uint32_t* out_value); }; -Backtrace* CreateCurrentObj(backtrace_map_info_t* map_info); -Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, backtrace_map_info_t* map_info); -Backtrace* CreateThreadObj(pid_t tid, backtrace_map_info_t* map_info); +Backtrace* CreateCurrentObj(BacktraceMap* map); +Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map); +Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map); #endif // _LIBBACKTRACE_BACKTRACE_H diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp new file mode 100644 index 0000000..b3b4300 --- /dev/null +++ b/libbacktrace/BacktraceMap.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2014 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. + */ + +#include <ctype.h> +#include <sys/types.h> +#include <unistd.h> + +#include <string> +#include <vector> + +#include <backtrace/BacktraceMap.h> +#include <log/log.h> + +BacktraceMap::BacktraceMap(pid_t pid) : pid_(pid) { + if (pid_ < 0) { + pid_ = getpid(); + } +} + +BacktraceMap::~BacktraceMap() { +} + +const backtrace_map_t* BacktraceMap::Find(uintptr_t addr) { + for (BacktraceMap::const_iterator it = begin(); + it != end(); ++it) { + if (addr >= it->start && addr < it->end) { + return &*it; + } + } + return NULL; +} + +bool BacktraceMap::ParseLine(const char* line, backtrace_map_t* map) { + unsigned long int start; + unsigned long int end; + char permissions[5]; + int name_pos; + +#if defined(__APPLE__) +// Mac OS vmmap(1) output: +// __TEXT 0009f000-000a1000 [ 8K 8K] r-x/rwx SM=COW /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n +// 012345678901234567890123456789012345678901234567890123456789 +// 0 1 2 3 4 5 + if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c %n", + &start, &end, permissions, &name_pos) != 3) { +#else +// Linux /proc/<pid>/maps lines: +// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so\n +// 012345678901234567890123456789012345678901234567890123456789 +// 0 1 2 3 4 5 + if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d%n", + &start, &end, permissions, &name_pos) != 3) { +#endif + return false; + } + + map->start = start; + map->end = end; + map->flags = PROT_NONE; + if (permissions[0] == 'r') { + map->flags |= PROT_READ; + } + if (permissions[1] == 'w') { + map->flags |= PROT_WRITE; + } + if (permissions[2] == 'x') { + map->flags |= PROT_EXEC; + } + + while (isspace(line[name_pos])) { + name_pos += 1; + } + map->name = line+name_pos; + if (!map->name.empty() && map->name[map->name.length()-1] == '\n') { + map->name.erase(map->name.length()-1); + } + + ALOGV("Parsed map: start=%p, end=%p, flags=%x, name=%s", + map->start, map->end, map->flags, map->name.c_str()); + return true; +} + +bool BacktraceMap::Build() { +#if defined(__APPLE__) + char cmd[sizeof(pid_t)*3 + sizeof("vmmap -w -resident -submap -allSplitLibs -interleaved ") + 1]; +#else + char path[sizeof(pid_t)*3 + sizeof("/proc//maps") + 1]; +#endif + char line[1024]; + +#if defined(__APPLE__) + // cmd is guaranteed to always be big enough to hold this string. + sprintf(cmd, "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid); + FILE* fp = popen(cmd, "r"); +#else + // path is guaranteed to always be big enough to hold this string. + sprintf(path, "/proc/%d/maps", pid_); + FILE* fp = fopen(path, "r"); +#endif + if (fp == NULL) { + return false; + } + + while(fgets(line, sizeof(line), fp)) { + backtrace_map_t map; + if (ParseLine(line, &map)) { + maps_.push_back(map); + } + } +#if defined(__APPLE__) + pclose(fp); +#else + fclose(fp); +#endif + + return true; +} diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp index 70616b0..9953dc1 100644 --- a/libbacktrace/BacktraceThread.cpp +++ b/libbacktrace/BacktraceThread.cpp @@ -22,7 +22,6 @@ #include <sys/types.h> #include <cutils/atomic.h> -#include <cutils/log.h> #include "BacktraceThread.h" #include "thread_utils.h" @@ -115,30 +114,21 @@ static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo, BacktraceThread::BacktraceThread( BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid, - backtrace_map_info_t* map_info) - : BacktraceCurrent(impl, map_info), thread_intf_(thread_intf) { - backtrace_.tid = tid; + BacktraceMap* map) + : BacktraceCurrent(impl, map), thread_intf_(thread_intf) { + tid_ = tid; } BacktraceThread::~BacktraceThread() { } void BacktraceThread::FinishUnwind() { - for (size_t i = 0; i < NumFrames(); i++) { - backtrace_frame_data_t* frame = &backtrace_.frames[i]; - - frame->map_offset = 0; - uintptr_t map_start; - frame->map_name = GetMapName(frame->pc, &map_start); - if (frame->map_name) { - frame->map_offset = frame->pc - map_start; - } + for (std::vector<backtrace_frame_data_t>::iterator it = frames_.begin(); + it != frames_.end(); ++it) { + it->map = FindMap(it->pc); - frame->func_offset = 0; - std::string func_name = GetFunctionName(frame->pc, &frame->func_offset); - if (!func_name.empty()) { - frame->func_name = strdup(func_name.c_str()); - } + it->func_offset = 0; + it->func_name = GetFunctionName(it->pc, &it->func_offset); } } diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h index a4b6ecb..cae496a 100644 --- a/libbacktrace/BacktraceThread.h +++ b/libbacktrace/BacktraceThread.h @@ -22,12 +22,12 @@ #include "Backtrace.h" -typedef enum { +enum state_e { STATE_WAITING = 0, STATE_DUMPING, STATE_DONE, STATE_CANCEL, -} state_e; +}; class BacktraceThreadInterface; @@ -71,7 +71,7 @@ public: // subclass both. BacktraceThread( BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid, - backtrace_map_info_t* map_info); + BacktraceMap* map); virtual ~BacktraceThread(); virtual bool Unwind(size_t num_ignore_frames); diff --git a/libbacktrace/Corkscrew.cpp b/libbacktrace/Corkscrew.cpp index 63b8c7c..fd31a26 100644 --- a/libbacktrace/Corkscrew.cpp +++ b/libbacktrace/Corkscrew.cpp @@ -16,12 +16,11 @@ #define LOG_TAG "libbacktrace" -#include <backtrace/backtrace.h> +#include <backtrace/Backtrace.h> #include <string.h> #include <backtrace-arch.h> -#include <cutils/log.h> #include <corkscrew/backtrace.h> #ifndef __USE_GNU @@ -32,6 +31,48 @@ #include "Corkscrew.h" //------------------------------------------------------------------------- +// CorkscrewMap functions. +//------------------------------------------------------------------------- +CorkscrewMap::CorkscrewMap(pid_t pid) : BacktraceMap(pid), map_info_(NULL) { +} + +CorkscrewMap::~CorkscrewMap() { + if (map_info_) { + free_map_info_list(map_info_); + map_info_ = NULL; + } +} + +bool CorkscrewMap::Build() { + map_info_ = load_map_info_list(pid_); + + // Use the information in map_info_ to construct the BacktraceMap data + // rather than reparsing /proc/self/maps. + map_info_t* cur_map = map_info_; + while (cur_map) { + backtrace_map_t map; + map.start = cur_map->start; + map.end = cur_map->end; + map.flags = 0; + if (cur_map->is_readable) { + map.flags |= PROT_READ; + } + if (cur_map->is_writable) { + map.flags |= PROT_WRITE; + } + if (cur_map->is_executable) { + map.flags |= PROT_EXEC; + } + map.name = cur_map->name; + + maps_.push_back(map); + + cur_map = cur_map->next; + } + return map_info_ != NULL; +} + +//------------------------------------------------------------------------- // CorkscrewCommon functions. //------------------------------------------------------------------------- bool CorkscrewCommon::GenerateFrameData( @@ -41,29 +82,19 @@ bool CorkscrewCommon::GenerateFrameData( return false; } - backtrace_t* data = GetBacktraceData(); - data->num_frames = num_frames; - for (size_t i = 0; i < data->num_frames; i++) { - backtrace_frame_data_t* frame = &data->frames[i]; - frame->num = i; - frame->pc = cork_frames[i].absolute_pc; - frame->sp = cork_frames[i].stack_top; - frame->stack_size = cork_frames[i].stack_size; - frame->map_name = NULL; - frame->map_offset = 0; - frame->func_name = NULL; - frame->func_offset = 0; - - uintptr_t map_start; - frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start); - if (frame->map_name) { - frame->map_offset = frame->pc - map_start; - } - - std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset); - if (!func_name.empty()) { - frame->func_name = strdup(func_name.c_str()); - } + std::vector<backtrace_frame_data_t>* frames = GetFrames(); + frames->resize(num_frames); + size_t i = 0; + for (std::vector<backtrace_frame_data_t>::iterator it = frames->begin(); + it != frames->end(); ++it, ++i) { + it->num = i; + it->pc = cork_frames[i].absolute_pc; + it->sp = cork_frames[i].stack_top; + it->stack_size = cork_frames[i].stack_size; + it->func_offset = 0; + + it->map = backtrace_obj_->FindMap(it->pc); + it->func_name = backtrace_obj_->GetFunctionName(it->pc, &it->func_offset); } return true; } @@ -88,23 +119,23 @@ std::string CorkscrewCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset *offset = 0; Dl_info info; - const backtrace_map_info_t* map_info = backtrace_obj_->FindMapInfo(pc); - if (map_info) { + const backtrace_map_t* map = backtrace_obj_->FindMap(pc); + if (map) { if (dladdr((const void*)pc, &info)) { if (info.dli_sname) { - *offset = pc - map_info->start - (uintptr_t)info.dli_saddr + (uintptr_t)info.dli_fbase; + *offset = pc - map->start - (uintptr_t)info.dli_saddr + (uintptr_t)info.dli_fbase; return info.dli_sname; } } else { // dladdr(3) didn't find a symbol; maybe it's static? Look in the ELF file... - symbol_table_t* symbol_table = load_symbol_table(map_info->name); + symbol_table_t* symbol_table = load_symbol_table(map->name.c_str()); if (symbol_table) { // First check if we can find the symbol using a relative pc. std::string name; - const symbol_t* elf_symbol = find_symbol(symbol_table, pc - map_info->start); + const symbol_t* elf_symbol = find_symbol(symbol_table, pc - map->start); if (elf_symbol) { name = elf_symbol->name; - *offset = pc - map_info->start - elf_symbol->start; + *offset = pc - map->start - elf_symbol->start; } else if ((elf_symbol = find_symbol(symbol_table, pc)) != NULL) { // Found the symbol using the absolute pc. name = elf_symbol->name; @@ -125,39 +156,36 @@ CorkscrewThread::CorkscrewThread() { } CorkscrewThread::~CorkscrewThread() { - if (corkscrew_map_info_) { - free_map_info_list(corkscrew_map_info_); - corkscrew_map_info_ = NULL; - } } bool CorkscrewThread::Init() { - corkscrew_map_info_ = load_map_info_list(backtrace_obj_->Pid()); - return corkscrew_map_info_ != NULL; + if (backtrace_obj_->GetMap() == NULL) { + // Trigger the map object creation, which will create the corkscrew + // map information. + return BuildMap(); + } + return true; } void CorkscrewThread::ThreadUnwind( siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) { - backtrace_frame_t frames[MAX_BACKTRACE_FRAMES]; + backtrace_frame_t cork_frames[MAX_BACKTRACE_FRAMES]; + CorkscrewMap* map = static_cast<CorkscrewMap*>(backtrace_obj_->GetMap()); ssize_t num_frames = unwind_backtrace_signal_arch( - siginfo, sigcontext, corkscrew_map_info_, frames, num_ignore_frames, - MAX_BACKTRACE_FRAMES); + siginfo, sigcontext, map->GetMapInfo(), cork_frames, + num_ignore_frames, MAX_BACKTRACE_FRAMES); if (num_frames > 0) { - backtrace_t* data = GetBacktraceData(); - data->num_frames = num_frames; - for (size_t i = 0; i < data->num_frames; i++) { - backtrace_frame_data_t* frame = &data->frames[i]; - frame->num = i; - frame->pc = frames[i].absolute_pc; - frame->sp = frames[i].stack_top; - frame->stack_size = frames[i].stack_size; - - frame->map_offset = 0; - frame->map_name = NULL; - frame->map_offset = 0; - - frame->func_offset = 0; - frame->func_name = NULL; + std::vector<backtrace_frame_data_t>* frames = GetFrames(); + frames->resize(num_frames); + size_t i = 0; + for (std::vector<backtrace_frame_data_t>::iterator it = frames->begin(); + it != frames->end(); ++it, ++i) { + it->num = i; + it->pc = cork_frames[i].absolute_pc; + it->sp = cork_frames[i].stack_top; + it->stack_size = cork_frames[i].stack_size; + it->map = NULL; + it->func_offset = 0; } } } @@ -206,15 +234,15 @@ std::string CorkscrewPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) //------------------------------------------------------------------------- // C++ object creation functions. //------------------------------------------------------------------------- -Backtrace* CreateCurrentObj(backtrace_map_info_t* map_info) { - return new BacktraceCurrent(new CorkscrewCurrent(), map_info); +Backtrace* CreateCurrentObj(BacktraceMap* map) { + return new BacktraceCurrent(new CorkscrewCurrent(), map); } -Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, backtrace_map_info_t* map_info) { - return new BacktracePtrace(new CorkscrewPtrace(), pid, tid, map_info); +Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map) { + return new BacktracePtrace(new CorkscrewPtrace(), pid, tid, map); } -Backtrace* CreateThreadObj(pid_t tid, backtrace_map_info_t* map_info) { +Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) { CorkscrewThread* thread_obj = new CorkscrewThread(); - return new BacktraceThread(thread_obj, thread_obj, tid, map_info); + return new BacktraceThread(thread_obj, thread_obj, tid, map); } diff --git a/libbacktrace/Corkscrew.h b/libbacktrace/Corkscrew.h index 7cb125c..229bb01 100644 --- a/libbacktrace/Corkscrew.h +++ b/libbacktrace/Corkscrew.h @@ -21,8 +21,8 @@ #include <string> -#include <backtrace/backtrace.h> #include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> #include <corkscrew/backtrace.h> @@ -32,6 +32,8 @@ class CorkscrewCommon : public BacktraceImpl { public: bool GenerateFrameData(backtrace_frame_t* cork_frames, ssize_t num_frames); + + virtual BacktraceMap* CreateBacktraceMap(pid_t pid) { return new BacktraceMap(pid); } }; class CorkscrewCurrent : public CorkscrewCommon { @@ -44,6 +46,19 @@ public: virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset); }; +class CorkscrewMap : public BacktraceMap { +public: + CorkscrewMap(pid_t pid); + virtual ~CorkscrewMap(); + + virtual bool Build(); + + map_info_t* GetMapInfo() { return map_info_; } + +private: + map_info_t* map_info_; +}; + class CorkscrewThread : public CorkscrewCurrent, public BacktraceThreadInterface { public: CorkscrewThread(); @@ -54,8 +69,7 @@ public: virtual void ThreadUnwind( siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames); -private: - map_info_t* corkscrew_map_info_; + virtual BacktraceMap* CreateBacktraceMap(pid_t pid) { return new CorkscrewMap(pid); } }; class CorkscrewPtrace : public CorkscrewCommon { diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp index 6cdbc42..747eb21 100644 --- a/libbacktrace/UnwindCurrent.cpp +++ b/libbacktrace/UnwindCurrent.cpp @@ -18,9 +18,8 @@ #include <sys/types.h> -#include <cutils/log.h> - -#include <backtrace/backtrace.h> +#include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> #define UNW_LOCAL_ONLY #include <libunwind.h> @@ -79,9 +78,6 @@ std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { } bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) { - backtrace_t* backtrace = GetBacktraceData(); - backtrace->num_frames = 0; - // The cursor structure is pretty large, do not put it on the stack. unw_cursor_t* cursor = new unw_cursor_t; int ret = unw_init_local(cursor, &context_); @@ -91,6 +87,9 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) { return false; } + std::vector<backtrace_frame_data_t>* frames = GetFrames(); + frames->reserve(MAX_BACKTRACE_FRAMES); + size_t num_frames = 0; do { unw_word_t pc; ret = unw_get_reg(cursor, UNW_REG_IP, &pc); @@ -106,42 +105,32 @@ bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) { } if (num_ignore_frames == 0) { - size_t num_frames = backtrace->num_frames; - backtrace_frame_data_t* frame = &backtrace->frames[num_frames]; + frames->resize(num_frames+1); + backtrace_frame_data_t* frame = &frames->at(num_frames); frame->num = num_frames; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; - frame->map_name = NULL; - frame->map_offset = 0; - frame->func_name = NULL; - frame->func_offset = 0; if (num_frames > 0) { // Set the stack size for the previous frame. - backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1]; + backtrace_frame_data_t* prev = &frames->at(num_frames-1); prev->stack_size = frame->sp - prev->sp; } if (resolve) { - std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset); - if (!func_name.empty()) { - frame->func_name = strdup(func_name.c_str()); - } - - uintptr_t map_start; - frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start); - if (frame->map_name) { - frame->map_offset = frame->pc - map_start; - } + frame->func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset); + frame->map = backtrace_obj_->FindMap(frame->pc); + } else { + frame->map = NULL; + frame->func_offset = 0; } - - backtrace->num_frames++; + num_frames++; } else { num_ignore_frames--; } ret = unw_step (cursor); - } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES); + } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); delete cursor; return true; @@ -195,11 +184,11 @@ void UnwindThread::ThreadUnwind( //------------------------------------------------------------------------- // C++ object creation function. //------------------------------------------------------------------------- -Backtrace* CreateCurrentObj(backtrace_map_info_t* map_info) { - return new BacktraceCurrent(new UnwindCurrent(), map_info); +Backtrace* CreateCurrentObj(BacktraceMap* map) { + return new BacktraceCurrent(new UnwindCurrent(), map); } -Backtrace* CreateThreadObj(pid_t tid, backtrace_map_info_t* map_info) { +Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) { UnwindThread* thread_obj = new UnwindThread(); - return new BacktraceThread(thread_obj, thread_obj, tid, map_info); + return new BacktraceThread(thread_obj, thread_obj, tid, map); } diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h index 7dc977d..8302c0b 100644 --- a/libbacktrace/UnwindCurrent.h +++ b/libbacktrace/UnwindCurrent.h @@ -38,6 +38,8 @@ public: void ExtractContext(void* sigcontext); + virtual BacktraceMap* CreateBacktraceMap(pid_t pid) { return new BacktraceMap(pid); } + protected: unw_context_t context_; }; diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp index 6fecb76..e45c5f8 100644 --- a/libbacktrace/UnwindPtrace.cpp +++ b/libbacktrace/UnwindPtrace.cpp @@ -16,13 +16,12 @@ #define LOG_TAG "libbacktrace" -#include <backtrace/backtrace.h> +#include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> #include <sys/types.h> #include <string.h> -#include <cutils/log.h> - #include <libunwind.h> #include <libunwind-ptrace.h> @@ -55,9 +54,6 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames) { return false; } - backtrace_t* backtrace = GetBacktraceData(); - backtrace->num_frames = 0; - unw_cursor_t cursor; int ret = unw_init_remote(&cursor, addr_space_, upt_info_); if (ret < 0) { @@ -65,6 +61,9 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames) { return false; } + std::vector<backtrace_frame_data_t>* frames = GetFrames(); + frames->reserve(MAX_BACKTRACE_FRAMES); + size_t num_frames = 0; do { unw_word_t pc; ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); @@ -80,39 +79,28 @@ bool UnwindPtrace::Unwind(size_t num_ignore_frames) { } if (num_ignore_frames == 0) { - size_t num_frames = backtrace->num_frames; - backtrace_frame_data_t* frame = &backtrace->frames[num_frames]; + frames->resize(num_frames+1); + backtrace_frame_data_t* frame = &frames->at(num_frames); frame->num = num_frames; frame->pc = static_cast<uintptr_t>(pc); frame->sp = static_cast<uintptr_t>(sp); frame->stack_size = 0; - frame->map_name = NULL; - frame->map_offset = 0; - frame->func_name = NULL; - frame->func_offset = 0; if (num_frames > 0) { - backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1]; + backtrace_frame_data_t* prev = &frames->at(num_frames-1); prev->stack_size = frame->sp - prev->sp; } - std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset); - if (!func_name.empty()) { - frame->func_name = strdup(func_name.c_str()); - } + frame->func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset); - uintptr_t map_start; - frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start); - if (frame->map_name) { - frame->map_offset = frame->pc - map_start; - } + frame->map = backtrace_obj_->FindMap(frame->pc); - backtrace->num_frames++; + num_frames++; } else { num_ignore_frames--; } ret = unw_step (&cursor); - } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES); + } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); return true; } @@ -132,6 +120,6 @@ std::string UnwindPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { //------------------------------------------------------------------------- // C++ object creation function. //------------------------------------------------------------------------- -Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, backtrace_map_info_t* map_info) { - return new BacktracePtrace(new UnwindPtrace(), pid, tid, map_info); +Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map) { + return new BacktracePtrace(new UnwindPtrace(), pid, tid, map); } diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h index 781405b..05375dd 100644 --- a/libbacktrace/UnwindPtrace.h +++ b/libbacktrace/UnwindPtrace.h @@ -32,6 +32,8 @@ public: virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset); + virtual BacktraceMap* CreateBacktraceMap(pid_t pid) { return new BacktraceMap(pid); } + private: unw_addr_space_t addr_space_; struct UPT_info* upt_info_; diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp index 2fed993..0ff7897 100644 --- a/libbacktrace/backtrace_test.cpp +++ b/libbacktrace/backtrace_test.cpp @@ -29,6 +29,7 @@ #include <unistd.h> #include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> #include <UniquePtr.h> #include <cutils/atomic.h> @@ -50,18 +51,18 @@ // Number of simultaneous threads running in our forked process. #define NUM_PTRACE_THREADS 5 -typedef struct { +struct thread_t { pid_t tid; int32_t state; pthread_t threadId; -} thread_t; +}; -typedef struct { +struct dump_thread_t { thread_t thread; Backtrace* backtrace; int32_t* now; int32_t done; -} dump_thread_t; +}; extern "C" { // Prototypes for functions in the test library. @@ -103,9 +104,8 @@ void WaitForStop(pid_t pid) { bool ReadyLevelBacktrace(Backtrace* backtrace) { // See if test_level_four is in the backtrace. bool found = false; - for (size_t i = 0; i < backtrace->NumFrames(); i++) { - const backtrace_frame_data_t* frame = backtrace->GetFrame(i); - if (frame->func_name != NULL && strcmp(frame->func_name, "test_level_four") == 0) { + for (Backtrace::const_iterator it = backtrace->begin(); it != backtrace->end(); ++it) { + if (it->func_name == "test_level_four") { found = true; break; } @@ -122,8 +122,7 @@ void VerifyLevelDump(Backtrace* backtrace) { // frame we want. size_t frame_num = 0; for (size_t i = backtrace->NumFrames()-1; i > 2; i--) { - if (backtrace->GetFrame(i)->func_name != NULL && - strcmp(backtrace->GetFrame(i)->func_name, "test_level_one") == 0) { + if (backtrace->GetFrame(i)->func_name == "test_level_one") { frame_num = i; break; } @@ -131,14 +130,10 @@ void VerifyLevelDump(Backtrace* backtrace) { ASSERT_LT(static_cast<size_t>(0), frame_num); ASSERT_LE(static_cast<size_t>(3), frame_num); - ASSERT_TRUE(NULL != backtrace->GetFrame(frame_num)->func_name); - ASSERT_STREQ(backtrace->GetFrame(frame_num)->func_name, "test_level_one"); - ASSERT_TRUE(NULL != backtrace->GetFrame(frame_num-1)->func_name); - ASSERT_STREQ(backtrace->GetFrame(frame_num-1)->func_name, "test_level_two"); - ASSERT_TRUE(NULL != backtrace->GetFrame(frame_num-2)->func_name); - ASSERT_STREQ(backtrace->GetFrame(frame_num-2)->func_name, "test_level_three"); - ASSERT_TRUE(NULL != backtrace->GetFrame(frame_num-3)->func_name); - ASSERT_STREQ(backtrace->GetFrame(frame_num-3)->func_name, "test_level_four"); + ASSERT_EQ(backtrace->GetFrame(frame_num)->func_name, "test_level_one"); + ASSERT_EQ(backtrace->GetFrame(frame_num-1)->func_name, "test_level_two"); + ASSERT_EQ(backtrace->GetFrame(frame_num-2)->func_name, "test_level_three"); + ASSERT_EQ(backtrace->GetFrame(frame_num-3)->func_name, "test_level_four"); } void VerifyLevelBacktrace(void*) { @@ -157,9 +152,8 @@ bool ReadyMaxBacktrace(Backtrace* backtrace) { void VerifyMaxDump(Backtrace* backtrace) { ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES)); // Verify that the last frame is our recursive call. - ASSERT_TRUE(NULL != backtrace->GetFrame(MAX_BACKTRACE_FRAMES-1)->func_name); - ASSERT_STREQ(backtrace->GetFrame(MAX_BACKTRACE_FRAMES-1)->func_name, - "test_recursive_call"); + ASSERT_EQ(backtrace->GetFrame(MAX_BACKTRACE_FRAMES-1)->func_name, + "test_recursive_call"); } void VerifyMaxBacktrace(void*) { @@ -220,8 +214,7 @@ void VerifyIgnoreFrames( EXPECT_EQ(bt_ign2->GetFrame(i)->sp, bt_all->GetFrame(i+2)->sp); EXPECT_EQ(bt_ign2->GetFrame(i)->stack_size, bt_all->GetFrame(i+2)->stack_size); } - if (!check && bt_ign2->GetFrame(i)->func_name && - strcmp(bt_ign2->GetFrame(i)->func_name, cur_proc) == 0) { + if (!check && bt_ign2->GetFrame(i)->func_name == cur_proc) { check = true; } } @@ -598,38 +591,64 @@ TEST(libbacktrace, format_test) { ASSERT_TRUE(backtrace.get() != NULL); backtrace_frame_data_t frame; - memset(&frame, 0, sizeof(backtrace_frame_data_t)); + frame.num = 1; + frame.pc = 2; + frame.sp = 0; + frame.stack_size = 0; + frame.map = NULL; + frame.func_offset = 0; + backtrace_map_t map; + map.start = 0; + map.end = 0; + + // Check no map set. frame.num = 1; #if defined(__LP64__) - EXPECT_STREQ("#01 pc 0000000000000000 <unknown>", + EXPECT_EQ("#01 pc 0000000000000002 <unknown>", +#else + EXPECT_EQ("#01 pc 00000002 <unknown>", +#endif + backtrace->FormatFrameData(&frame)); + + // Check map name empty, but exists. + frame.map = ↦ + map.start = 1; +#if defined(__LP64__) + EXPECT_EQ("#01 pc 0000000000000001 <unknown>", #else - EXPECT_STREQ("#01 pc 00000000 <unknown>", + EXPECT_EQ("#01 pc 00000001 <unknown>", #endif - backtrace->FormatFrameData(&frame).c_str()); + backtrace->FormatFrameData(&frame)); + - frame.pc = 0x12345678; - frame.map_name = "MapFake"; + // Check relative pc is set and map name is set. + frame.pc = 0x12345679; + frame.map = ↦ + map.name = "MapFake"; + map.start = 1; #if defined(__LP64__) - EXPECT_STREQ("#01 pc 0000000012345678 MapFake", + EXPECT_EQ("#01 pc 0000000012345678 MapFake", #else - EXPECT_STREQ("#01 pc 12345678 MapFake", + EXPECT_EQ("#01 pc 12345678 MapFake", #endif - backtrace->FormatFrameData(&frame).c_str()); + backtrace->FormatFrameData(&frame)); - frame.func_name = const_cast<char*>("ProcFake"); + // Check func_name is set, but no func offset. + frame.func_name = "ProcFake"; #if defined(__LP64__) - EXPECT_STREQ("#01 pc 0000000012345678 MapFake (ProcFake)", + EXPECT_EQ("#01 pc 0000000012345678 MapFake (ProcFake)", #else - EXPECT_STREQ("#01 pc 12345678 MapFake (ProcFake)", + EXPECT_EQ("#01 pc 12345678 MapFake (ProcFake)", #endif - backtrace->FormatFrameData(&frame).c_str()); + backtrace->FormatFrameData(&frame)); + // Check func_name is set, and func offset is non-zero. frame.func_offset = 645; #if defined(__LP64__) - EXPECT_STREQ("#01 pc 0000000012345678 MapFake (ProcFake+645)", + EXPECT_EQ("#01 pc 0000000012345678 MapFake (ProcFake+645)", #else - EXPECT_STREQ("#01 pc 12345678 MapFake (ProcFake+645)", + EXPECT_EQ("#01 pc 12345678 MapFake (ProcFake+645)", #endif - backtrace->FormatFrameData(&frame).c_str()); + backtrace->FormatFrameData(&frame)); } |