1 /* 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 #include <pthread.h> 18 #include <stdint.h> 19 #include <stdlib.h> 20 #include <sys/types.h> 21 #include <unistd.h> 22 23 #include <backtrace/BacktraceMap.h> 24 25 #include <libunwind.h> 26 27 #include "BacktraceLog.h" 28 #include "UnwindMap.h" 29 30 //------------------------------------------------------------------------- 31 // libunwind has a single shared address space for the current process 32 // aka local. If multiple maps are created for the current pid, then 33 // only update the local address space once, and keep a reference count 34 // of maps using the same map cursor. 35 //------------------------------------------------------------------------- 36 UnwindMap::UnwindMap(pid_t pid) : BacktraceMap(pid) { 37 unw_map_cursor_clear(&map_cursor_); 38 } 39 40 UnwindMapRemote::UnwindMapRemote(pid_t pid) : UnwindMap(pid) { 41 } 42 43 UnwindMapRemote::~UnwindMapRemote() { 44 unw_map_cursor_destroy(&map_cursor_); 45 unw_map_cursor_clear(&map_cursor_); 46 } 47 48 bool UnwindMapRemote::GenerateMap() { 49 // Use the map_cursor information to construct the BacktraceMap data 50 // rather than reparsing /proc/self/maps. 51 unw_map_cursor_reset(&map_cursor_); 52 53 unw_map_t unw_map; 54 while (unw_map_cursor_get_next(&map_cursor_, &unw_map)) { 55 backtrace_map_t map; 56 57 map.start = unw_map.start; 58 map.end = unw_map.end; 59 map.offset = unw_map.offset; 60 map.load_bias = unw_map.load_base; 61 map.flags = unw_map.flags; 62 map.name = unw_map.path; 63 64 // The maps are in descending order, but we want them in ascending order. 65 maps_.push_front(map); 66 } 67 68 return true; 69 } 70 71 bool UnwindMapRemote::Build() { 72 return (unw_map_cursor_create(&map_cursor_, pid_) == 0) && GenerateMap(); 73 } 74 75 UnwindMapLocal::UnwindMapLocal() : UnwindMap(getpid()), map_created_(false) { 76 pthread_rwlock_init(&map_lock_, nullptr); 77 } 78 79 UnwindMapLocal::~UnwindMapLocal() { 80 if (map_created_) { 81 unw_map_local_destroy(); 82 unw_map_cursor_clear(&map_cursor_); 83 } 84 } 85 86 bool UnwindMapLocal::GenerateMap() { 87 // Lock so that multiple threads cannot modify the maps data at the 88 // same time. 89 pthread_rwlock_wrlock(&map_lock_); 90 91 // It's possible for the map to be regenerated while this loop is occurring. 92 // If that happens, get the map again, but only try at most three times 93 // before giving up. 94 bool generated = false; 95 for (int i = 0; i < 3; i++) { 96 maps_.clear(); 97 98 // Save the map data retrieved so we can tell if it changes. 99 unw_map_local_cursor_get(&map_cursor_); 100 101 unw_map_t unw_map; 102 int ret; 103 while ((ret = unw_map_local_cursor_get_next(&map_cursor_, &unw_map)) > 0) { 104 backtrace_map_t map; 105 106 map.start = unw_map.start; 107 map.end = unw_map.end; 108 map.offset = unw_map.offset; 109 map.load_bias = unw_map.load_base; 110 map.flags = unw_map.flags; 111 map.name = unw_map.path; 112 113 free(unw_map.path); 114 115 // The maps are in descending order, but we want them in ascending order. 116 maps_.push_front(map); 117 } 118 // Check to see if the map changed while getting the data. 119 if (ret != -UNW_EINVAL) { 120 generated = true; 121 break; 122 } 123 } 124 125 pthread_rwlock_unlock(&map_lock_); 126 127 if (!generated) { 128 BACK_LOGW("Unable to generate the map."); 129 } 130 return generated; 131 } 132 133 bool UnwindMapLocal::Build() { 134 return (map_created_ = (unw_map_local_create() == 0)) && GenerateMap();; 135 } 136 137 void UnwindMapLocal::FillIn(uint64_t addr, backtrace_map_t* map) { 138 BacktraceMap::FillIn(addr, map); 139 if (!IsValid(*map)) { 140 // Check to see if the underlying map changed and regenerate the map 141 // if it did. 142 if (unw_map_local_cursor_valid(&map_cursor_) < 0) { 143 if (GenerateMap()) { 144 BacktraceMap::FillIn(addr, map); 145 } 146 } 147 } 148 } 149