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;