summaryrefslogtreecommitdiffstats
path: root/libbacktrace
diff options
context:
space:
mode:
authorChristopher Ferris <cferris@google.com>2014-01-14 20:16:30 -0800
committerChristopher Ferris <cferris@google.com>2014-01-16 16:12:29 -0800
commit46756821c4fe238f12a6e5ea18c356398f8d8795 (patch)
treef0a17c7afec73b58608ffe0230fad7d5c8f6371b /libbacktrace
parente847f429f43ae56aaa406697ca603c8469e2100b (diff)
downloadsystem_core-46756821c4fe238f12a6e5ea18c356398f8d8795.zip
system_core-46756821c4fe238f12a6e5ea18c356398f8d8795.tar.gz
system_core-46756821c4fe238f12a6e5ea18c356398f8d8795.tar.bz2
Rewrite libbacktrace to be all C++.
This includes removing the map_info.c source and replacing it with the BacktraceMap class to handle all map related code. Change all callers of libbacktrace map functionality. Also modify the corkscrew thread code so that it doesn't need to build the map twice (once in the corkscrew format and once in the libbacktrace format). Change-Id: I32865a39f83a3dd6f958fc03c2759ba47d12382e
Diffstat (limited to 'libbacktrace')
-rw-r--r--libbacktrace/Android.mk4
-rw-r--r--libbacktrace/Backtrace.cpp208
-rw-r--r--libbacktrace/Backtrace.h18
-rw-r--r--libbacktrace/BacktraceMap.cpp130
-rw-r--r--libbacktrace/BacktraceThread.cpp26
-rw-r--r--libbacktrace/BacktraceThread.h6
-rw-r--r--libbacktrace/Corkscrew.cpp150
-rw-r--r--libbacktrace/Corkscrew.h20
-rw-r--r--libbacktrace/UnwindCurrent.cpp49
-rw-r--r--libbacktrace/UnwindCurrent.h2
-rw-r--r--libbacktrace/UnwindPtrace.cpp40
-rw-r--r--libbacktrace/UnwindPtrace.h2
-rw-r--r--libbacktrace/backtrace_test.cpp95
-rw-r--r--libbacktrace/map_info.c173
14 files changed, 412 insertions, 511 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;
+ 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;
+ 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));
}
diff --git a/libbacktrace/map_info.c b/libbacktrace/map_info.c
deleted file mode 100644
index 9cc6e01..0000000
--- a/libbacktrace/map_info.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * 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.
- */
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <cutils/log.h>
-#include <sys/time.h>
-
-#include <backtrace/backtrace.h>
-
-#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
-static backtrace_map_info_t* parse_vmmap_line(const char* line) {
- unsigned long int start;
- unsigned long int end;
- char permissions[4];
- int name_pos;
- if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c %n",
- &start, &end, permissions, &name_pos) != 3) {
- return NULL;
- }
-
- const char* name = line + name_pos;
- size_t name_len = strlen(name);
-
- backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len);
- if (mi != NULL) {
- mi->start = start;
- mi->end = end;
- mi->is_readable = permissions[0] == 'r';
- mi->is_writable = permissions[1] == 'w';
- mi->is_executable = permissions[2] == 'x';
- memcpy(mi->name, name, name_len);
- mi->name[name_len - 1] = '\0';
- ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
- "is_readable=%d, is_writable=%d is_executable=%d, name=%s",
- mi->start, mi->end,
- mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
- }
- return mi;
-}
-
-backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid) {
- char cmd[1024];
- if (pid < 0) {
- pid = getpid();
- }
- snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid);
- FILE* fp = popen(cmd, "r");
- if (fp == NULL) {
- return NULL;
- }
-
- char line[1024];
- backtrace_map_info_t* milist = NULL;
- while (fgets(line, sizeof(line), fp) != NULL) {
- backtrace_map_info_t* mi = parse_vmmap_line(line);
- if (mi != NULL) {
- mi->next = milist;
- milist = mi;
- }
- }
- pclose(fp);
- return milist;
-}
-
-#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
-static backtrace_map_info_t* parse_maps_line(const char* line)
-{
- unsigned long int start;
- unsigned long int end;
- char permissions[5];
- int name_pos;
- if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d%n", &start, &end,
- permissions, &name_pos) != 3) {
- return NULL;
- }
-
- while (isspace(line[name_pos])) {
- name_pos += 1;
- }
- const char* name = line + name_pos;
- size_t name_len = strlen(name);
- if (name_len && name[name_len - 1] == '\n') {
- name_len -= 1;
- }
-
- backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len + 1);
- if (mi) {
- mi->start = start;
- mi->end = end;
- mi->is_readable = strlen(permissions) == 4 && permissions[0] == 'r';
- mi->is_writable = strlen(permissions) == 4 && permissions[1] == 'w';
- mi->is_executable = strlen(permissions) == 4 && permissions[2] == 'x';
- memcpy(mi->name, name, name_len);
- mi->name[name_len] = '\0';
- ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
- "is_readable=%d, is_writable=%d, is_executable=%d, name=%s",
- mi->start, mi->end,
- mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
- }
- return mi;
-}
-
-backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid) {
- char path[PATH_MAX];
- char line[1024];
- FILE* fp;
- backtrace_map_info_t* milist = NULL;
-
- if (tid < 0) {
- tid = getpid();
- }
- snprintf(path, PATH_MAX, "/proc/%d/maps", tid);
- fp = fopen(path, "r");
- if (fp) {
- while(fgets(line, sizeof(line), fp)) {
- backtrace_map_info_t* mi = parse_maps_line(line);
- if (mi) {
- mi->next = milist;
- milist = mi;
- }
- }
- fclose(fp);
- }
- return milist;
-}
-
-#endif
-
-void backtrace_destroy_map_info_list(backtrace_map_info_t* milist) {
- while (milist) {
- backtrace_map_info_t* next = milist->next;
- free(milist);
- milist = next;
- }
-}
-
-const backtrace_map_info_t* backtrace_find_map_info(
- const backtrace_map_info_t* milist, uintptr_t addr) {
- const backtrace_map_info_t* mi = milist;
- while (mi && !(addr >= mi->start && addr < mi->end)) {
- mi = mi->next;
- }
- return mi;
-}