blob: 9c8193bed7878a4a7a1a93509a86e157f7c5cd28 [file] [log] [blame]
Christopher Ferrisdf290612014-01-22 19:21:07 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "libbacktrace"
18
19#include <pthread.h>
20#include <sys/types.h>
21#include <unistd.h>
22
23#include <backtrace/BacktraceMap.h>
24
25#include <libunwind.h>
26
27#include "UnwindMap.h"
28
29//-------------------------------------------------------------------------
30// libunwind has a single shared address space for the current process
31// aka local. If multiple maps are created for the current pid, then
32// only update the local address space once, and keep a reference count
33// of maps using the same map cursor.
34//-------------------------------------------------------------------------
35static pthread_mutex_t g_map_mutex = PTHREAD_MUTEX_INITIALIZER;
36static unw_map_cursor_t* g_map_cursor = NULL;
37static int g_map_references = 0;
38
39UnwindMap::UnwindMap(pid_t pid) : BacktraceMap(pid) {
40 map_cursor_.map_list = NULL;
41}
42
43UnwindMap::~UnwindMap() {
44 if (pid_ == getpid()) {
45 pthread_mutex_lock(&g_map_mutex);
46 if (--g_map_references == 0) {
47 // Clear the local address space map.
48 unw_map_set(unw_local_addr_space, NULL);
49 unw_map_cursor_destroy(&map_cursor_);
50 }
51 pthread_mutex_unlock(&g_map_mutex);
52 } else {
53 unw_map_cursor_destroy(&map_cursor_);
54 }
55}
56
57bool UnwindMap::Build() {
58 bool return_value = true;
59 if (pid_ == getpid()) {
60 pthread_mutex_lock(&g_map_mutex);
61 if (g_map_references == 0) {
62 return_value = (unw_map_cursor_create(&map_cursor_, pid_) == 0);
63 if (return_value) {
64 // Set the local address space to this cursor map.
65 unw_map_set(unw_local_addr_space, &map_cursor_);
66 g_map_references = 1;
67 g_map_cursor = &map_cursor_;
68 }
69 } else {
70 g_map_references++;
71 map_cursor_ = *g_map_cursor;
72 }
73 pthread_mutex_unlock(&g_map_mutex);
74 } else {
75 return_value = (unw_map_cursor_create(&map_cursor_, pid_) == 0);
76 }
77
78 if (!return_value)
79 return false;
80
81 // Use the map_cursor information to construct the BacktraceMap data
82 // rather than reparsing /proc/self/maps.
83 unw_map_cursor_reset(&map_cursor_);
84 unw_map_t unw_map;
85 while (unw_map_cursor_get(&map_cursor_, &unw_map)) {
86 backtrace_map_t map;
87
88 map.start = unw_map.start;
89 map.end = unw_map.end;
90 map.flags = unw_map.flags;
91 map.name = unw_map.path;
92
93 // The maps are in descending order, but we want them in ascending order.
94 maps_.push_front(map);
95 }
96
97 return true;
98}
99
100//-------------------------------------------------------------------------
101// BacktraceMap create function.
102//-------------------------------------------------------------------------
103BacktraceMap* BacktraceMap::Create(pid_t pid) {
104 BacktraceMap* map = new UnwindMap(pid);
105 if (!map->Build()) {
106 delete map;
107 return NULL;
108 }
109 return map;
110}