diff options
Diffstat (limited to 'libbacktrace/UnwindMap.cpp')
-rw-r--r-- | libbacktrace/UnwindMap.cpp | 122 |
1 files changed, 78 insertions, 44 deletions
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 @@ bool UnwindMap::Build() { 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; |