Create an UnwindMapLocal object.
The way libunwind handles local unwinds is different from remote unwinds,
so create a new map object to handle the differences.
Add new test to verify the map data is being generated correctly.
Add new tests to check for leaks.
Refactor the BACK_LOGW code into a single header file.
Change-Id: I01f3cbfc4b927646174ea1b614fa25d23b9b3427
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index 8268db6..1615518 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "libbacktrace"
-
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
@@ -24,6 +22,7 @@
#include <libunwind.h>
+#include "BacktraceLog.h"
#include "UnwindMap.h"
//-------------------------------------------------------------------------
@@ -32,57 +31,21 @@
// only update the local address space once, and keep a reference count
// of maps using the same map cursor.
//-------------------------------------------------------------------------
-static pthread_mutex_t g_map_mutex = PTHREAD_MUTEX_INITIALIZER;
-static unw_map_cursor_t g_map_cursor;
-static int g_map_references = 0;
-
UnwindMap::UnwindMap(pid_t pid) : BacktraceMap(pid) {
- map_cursor_.map_list = NULL;
}
UnwindMap::~UnwindMap() {
- if (pid_ == getpid()) {
- pthread_mutex_lock(&g_map_mutex);
- if (--g_map_references == 0) {
- // Clear the local address space map.
- unw_map_local_set(NULL);
- unw_map_cursor_destroy(&map_cursor_);
- }
- pthread_mutex_unlock(&g_map_mutex);
- } else {
- unw_map_cursor_destroy(&map_cursor_);
- }
+ unw_map_cursor_destroy(&map_cursor_);
+ unw_map_cursor_clear(&map_cursor_);
}
-bool UnwindMap::Build() {
- bool return_value = true;
- if (pid_ == getpid()) {
- pthread_mutex_lock(&g_map_mutex);
- if (g_map_references == 0) {
- return_value = (unw_map_cursor_create(&map_cursor_, pid_) == 0);
- if (return_value) {
- // Set the local address space map to our new map.
- unw_map_local_set(&map_cursor_);
- g_map_references = 1;
- g_map_cursor = map_cursor_;
- }
- } else {
- g_map_references++;
- map_cursor_ = g_map_cursor;
- }
- pthread_mutex_unlock(&g_map_mutex);
- } else {
- return_value = (unw_map_cursor_create(&map_cursor_, pid_) == 0);
- }
-
- if (!return_value)
- return false;
-
+bool UnwindMap::GenerateMap() {
// Use the map_cursor information to construct the BacktraceMap data
// rather than reparsing /proc/self/maps.
unw_map_cursor_reset(&map_cursor_);
+
unw_map_t unw_map;
- while (unw_map_cursor_get(&map_cursor_, &unw_map)) {
+ while (unw_map_cursor_get_next(&map_cursor_, &unw_map)) {
backtrace_map_t map;
map.start = unw_map.start;
@@ -97,11 +60,82 @@
return true;
}
+bool UnwindMap::Build() {
+ return (unw_map_cursor_create(&map_cursor_, pid_) == 0) && GenerateMap();
+}
+
+UnwindMapLocal::UnwindMapLocal() : UnwindMap(getpid()), map_created_(false) {
+}
+
+UnwindMapLocal::~UnwindMapLocal() {
+ if (map_created_) {
+ unw_map_local_destroy();
+ unw_map_cursor_clear(&map_cursor_);
+ }
+}
+
+bool UnwindMapLocal::GenerateMap() {
+ // It's possible for the map to be regenerated while this loop is occurring.
+ // If that happens, get the map again, but only try at most three times
+ // before giving up.
+ for (int i = 0; i < 3; i++) {
+ maps_.clear();
+
+ unw_map_local_cursor_get(&map_cursor_);
+
+ unw_map_t unw_map;
+ int ret;
+ while ((ret = unw_map_local_cursor_get_next(&map_cursor_, &unw_map)) > 0) {
+ backtrace_map_t map;
+
+ map.start = unw_map.start;
+ map.end = unw_map.end;
+ map.flags = unw_map.flags;
+ map.name = unw_map.path;
+
+ free(unw_map.path);
+
+ // The maps are in descending order, but we want them in ascending order.
+ maps_.push_front(map);
+ }
+ // Check to see if the map changed while getting the data.
+ if (ret != -UNW_EINVAL) {
+ return true;
+ }
+ }
+
+ BACK_LOGW("Unable to generate the map.");
+ return false;
+}
+
+bool UnwindMapLocal::Build() {
+ return (map_created_ = (unw_map_local_create() == 0)) && GenerateMap();;
+}
+
+const backtrace_map_t* UnwindMapLocal::Find(uintptr_t addr) {
+ const backtrace_map_t* map = BacktraceMap::Find(addr);
+ if (!map) {
+ // Check to see if the underlying map changed and regenerate the map
+ // if it did.
+ if (unw_map_local_cursor_valid(&map_cursor_) < 0) {
+ if (GenerateMap()) {
+ map = BacktraceMap::Find(addr);
+ }
+ }
+ }
+ return map;
+}
+
//-------------------------------------------------------------------------
// BacktraceMap create function.
//-------------------------------------------------------------------------
BacktraceMap* BacktraceMap::Create(pid_t pid) {
- BacktraceMap* map = new UnwindMap(pid);
+ BacktraceMap* map;
+ if (pid == getpid()) {
+ map = new UnwindMapLocal();
+ } else {
+ map = new UnwindMap(pid);
+ }
if (!map->Build()) {
delete map;
return NULL;