1df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris/* 2df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris * Copyright (C) 2014 The Android Open Source Project 3df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris * 4df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris * Licensed under the Apache License, Version 2.0 (the "License"); 5df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris * you may not use this file except in compliance with the License. 6df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris * You may obtain a copy of the License at 7df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris * 8df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris * http://www.apache.org/licenses/LICENSE-2.0 9df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris * 10df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris * Unless required by applicable law or agreed to in writing, software 11df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris * distributed under the License is distributed on an "AS IS" BASIS, 12df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris * See the License for the specific language governing permissions and 14df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris * limitations under the License. 15df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris */ 16df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris 17df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris#include <pthread.h> 18ac2fe7eb81789274ab98573d0c4b0866bed1f254Dan Albert#include <stdlib.h> 19df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris#include <sys/types.h> 20df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris#include <unistd.h> 21df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris 22df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris#include <backtrace/BacktraceMap.h> 23df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris 24df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris#include <libunwind.h> 25df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris 26e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris#include "BacktraceLog.h" 27df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris#include "UnwindMap.h" 28df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris 29df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris//------------------------------------------------------------------------- 30df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris// libunwind has a single shared address space for the current process 31df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris// aka local. If multiple maps are created for the current pid, then 32df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris// only update the local address space once, and keep a reference count 33df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris// of maps using the same map cursor. 34df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris//------------------------------------------------------------------------- 35df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher FerrisUnwindMap::UnwindMap(pid_t pid) : BacktraceMap(pid) { 36df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris} 37df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris 38df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher FerrisUnwindMap::~UnwindMap() { 39e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris unw_map_cursor_destroy(&map_cursor_); 40e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris unw_map_cursor_clear(&map_cursor_); 41df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris} 42df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris 43e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferrisbool UnwindMap::GenerateMap() { 44df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris // Use the map_cursor information to construct the BacktraceMap data 45df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris // rather than reparsing /proc/self/maps. 46df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris unw_map_cursor_reset(&map_cursor_); 47e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris 48df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris unw_map_t unw_map; 49e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris while (unw_map_cursor_get_next(&map_cursor_, &unw_map)) { 50df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris backtrace_map_t map; 51df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris 52df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris map.start = unw_map.start; 53df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris map.end = unw_map.end; 54df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris map.flags = unw_map.flags; 55df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris map.name = unw_map.path; 56df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris 57df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris // The maps are in descending order, but we want them in ascending order. 58df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris maps_.push_front(map); 59df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris } 60df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris 61df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris return true; 62df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris} 63df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris 64e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferrisbool UnwindMap::Build() { 65e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris return (unw_map_cursor_create(&map_cursor_, pid_) == 0) && GenerateMap(); 66e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris} 67e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris 68e29609106033a48a6128664668d22bf4fb42a7eeChristopher FerrisUnwindMapLocal::UnwindMapLocal() : UnwindMap(getpid()), map_created_(false) { 69e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris} 70e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris 71e29609106033a48a6128664668d22bf4fb42a7eeChristopher FerrisUnwindMapLocal::~UnwindMapLocal() { 72e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris if (map_created_) { 73e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris unw_map_local_destroy(); 74e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris unw_map_cursor_clear(&map_cursor_); 75e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris } 76e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris} 77e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris 78e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferrisbool UnwindMapLocal::GenerateMap() { 79e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris // It's possible for the map to be regenerated while this loop is occurring. 80e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris // If that happens, get the map again, but only try at most three times 81e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris // before giving up. 82e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris for (int i = 0; i < 3; i++) { 83e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris maps_.clear(); 84e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris 85e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris unw_map_local_cursor_get(&map_cursor_); 86e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris 87e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris unw_map_t unw_map; 88e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris int ret; 89e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris while ((ret = unw_map_local_cursor_get_next(&map_cursor_, &unw_map)) > 0) { 90e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris backtrace_map_t map; 91e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris 92e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris map.start = unw_map.start; 93e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris map.end = unw_map.end; 94e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris map.flags = unw_map.flags; 95e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris map.name = unw_map.path; 96e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris 97e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris free(unw_map.path); 98e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris 99e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris // The maps are in descending order, but we want them in ascending order. 100e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris maps_.push_front(map); 101e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris } 102e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris // Check to see if the map changed while getting the data. 103e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris if (ret != -UNW_EINVAL) { 104e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris return true; 105e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris } 106e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris } 107e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris 108e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris BACK_LOGW("Unable to generate the map."); 109e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris return false; 110e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris} 111e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris 112e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferrisbool UnwindMapLocal::Build() { 113e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris return (map_created_ = (unw_map_local_create() == 0)) && GenerateMap();; 114e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris} 115e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris 116e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferrisconst backtrace_map_t* UnwindMapLocal::Find(uintptr_t addr) { 117e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris const backtrace_map_t* map = BacktraceMap::Find(addr); 118e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris if (!map) { 119e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris // Check to see if the underlying map changed and regenerate the map 120e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris // if it did. 121e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris if (unw_map_local_cursor_valid(&map_cursor_) < 0) { 122e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris if (GenerateMap()) { 123e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris map = BacktraceMap::Find(addr); 124e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris } 125e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris } 126e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris } 127e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris return map; 128e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris} 129e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris 130df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris//------------------------------------------------------------------------- 131df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris// BacktraceMap create function. 132df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris//------------------------------------------------------------------------- 133f02593b0e61f8108449770094caa7bb39a646ec1Christopher FerrisBacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) { 134e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris BacktraceMap* map; 135f02593b0e61f8108449770094caa7bb39a646ec1Christopher Ferris 136f02593b0e61f8108449770094caa7bb39a646ec1Christopher Ferris if (uncached) { 137f02593b0e61f8108449770094caa7bb39a646ec1Christopher Ferris // Force use of the base class to parse the maps when this call is made. 138f02593b0e61f8108449770094caa7bb39a646ec1Christopher Ferris map = new BacktraceMap(pid); 139f02593b0e61f8108449770094caa7bb39a646ec1Christopher Ferris } else if (pid == getpid()) { 140e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris map = new UnwindMapLocal(); 141e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris } else { 142e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris map = new UnwindMap(pid); 143e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris } 144df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris if (!map->Build()) { 145df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris delete map; 146df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris return NULL; 147df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris } 148df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris return map; 149df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris} 150