thread_tree.cpp revision 60a0ea96c0fb9e807c899759256df5e20bd904bd
1/* 2 * Copyright (C) 2015 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 "thread_tree.h" 18 19#include <base/logging.h> 20#include "environment.h" 21 22bool MapComparator::operator()(const MapEntry* map1, const MapEntry* map2) const { 23 if (map1->start_addr != map2->start_addr) { 24 return map1->start_addr < map2->start_addr; 25 } 26 if (map1->len != map2->len) { 27 return map1->len < map2->len; 28 } 29 if (map1->time != map2->time) { 30 return map1->time < map2->time; 31 } 32 return false; 33} 34 35void ThreadTree::AddThread(int pid, int tid, const std::string& comm) { 36 auto it = thread_tree_.find(tid); 37 if (it == thread_tree_.end()) { 38 ThreadEntry* thread = new ThreadEntry{ 39 pid, tid, 40 "unknown", // comm 41 std::set<MapEntry*, MapComparator>(), // maps 42 }; 43 auto pair = thread_tree_.insert(std::make_pair(tid, std::unique_ptr<ThreadEntry>(thread))); 44 CHECK(pair.second); 45 it = pair.first; 46 } 47 thread_comm_storage_.push_back(std::unique_ptr<std::string>(new std::string(comm))); 48 it->second->comm = thread_comm_storage_.back()->c_str(); 49} 50 51void ThreadTree::ForkThread(int pid, int tid, int ppid, int ptid) { 52 ThreadEntry* parent = FindThreadOrNew(ppid, ptid); 53 ThreadEntry* child = FindThreadOrNew(pid, tid); 54 child->comm = parent->comm; 55 child->maps = parent->maps; 56} 57 58ThreadEntry* ThreadTree::FindThreadOrNew(int pid, int tid) { 59 auto it = thread_tree_.find(tid); 60 if (it == thread_tree_.end()) { 61 AddThread(pid, tid, "unknown"); 62 it = thread_tree_.find(tid); 63 } else { 64 CHECK_EQ(pid, it->second.get()->pid) << "tid = " << tid; 65 } 66 return it->second.get(); 67} 68 69static void RemoveOverlappedMap(std::set<MapEntry*, MapComparator>* map_set, const MapEntry* map) { 70 for (auto it = map_set->begin(); it != map_set->end();) { 71 if ((*it)->start_addr >= map->start_addr + map->len) { 72 break; 73 } 74 if ((*it)->start_addr + (*it)->len <= map->start_addr) { 75 ++it; 76 } else { 77 it = map_set->erase(it); 78 } 79 } 80} 81 82void ThreadTree::AddKernelMap(uint64_t start_addr, uint64_t len, uint64_t pgoff, uint64_t time, 83 const std::string& filename) { 84 // kernel map len can be 0 when record command is not run in supervisor mode. 85 if (len == 0) { 86 return; 87 } 88 DsoEntry* dso = FindKernelDsoOrNew(filename); 89 MapEntry* map = new MapEntry{ 90 start_addr, len, pgoff, time, dso, 91 }; 92 map_storage_.push_back(std::unique_ptr<MapEntry>(map)); 93 RemoveOverlappedMap(&kernel_map_tree_, map); 94 auto pair = kernel_map_tree_.insert(map); 95 CHECK(pair.second); 96} 97 98DsoEntry* ThreadTree::FindKernelDsoOrNew(const std::string& filename) { 99 if (filename == DEFAULT_KERNEL_MMAP_NAME) { 100 if (kernel_dso_ == nullptr) { 101 kernel_dso_ = DsoFactory::GetInstance()->CreateDso(DSO_KERNEL); 102 } 103 return kernel_dso_.get(); 104 } 105 auto it = module_dso_tree_.find(filename); 106 if (it == module_dso_tree_.end()) { 107 module_dso_tree_[filename] = DsoFactory::GetInstance()->CreateDso(DSO_KERNEL_MODULE, filename); 108 it = module_dso_tree_.find(filename); 109 } 110 return it->second.get(); 111} 112 113void ThreadTree::AddThreadMap(int pid, int tid, uint64_t start_addr, uint64_t len, uint64_t pgoff, 114 uint64_t time, const std::string& filename) { 115 ThreadEntry* thread = FindThreadOrNew(pid, tid); 116 DsoEntry* dso = FindUserDsoOrNew(filename); 117 MapEntry* map = new MapEntry{ 118 start_addr, len, pgoff, time, dso, 119 }; 120 map_storage_.push_back(std::unique_ptr<MapEntry>(map)); 121 RemoveOverlappedMap(&thread->maps, map); 122 auto pair = thread->maps.insert(map); 123 CHECK(pair.second); 124} 125 126DsoEntry* ThreadTree::FindUserDsoOrNew(const std::string& filename) { 127 auto it = user_dso_tree_.find(filename); 128 if (it == user_dso_tree_.end()) { 129 user_dso_tree_[filename] = DsoFactory::GetInstance()->CreateDso(DSO_ELF_FILE, filename); 130 it = user_dso_tree_.find(filename); 131 } 132 return it->second.get(); 133} 134 135static bool IsAddrInMap(uint64_t addr, const MapEntry* map) { 136 return (addr >= map->start_addr && addr < map->start_addr + map->len); 137} 138 139static MapEntry* FindMapByAddr(const std::set<MapEntry*, MapComparator>& maps, uint64_t addr) { 140 // Construct a map_entry which is strictly after the searched map_entry, based on MapComparator. 141 MapEntry find_map = { 142 addr, // start_addr 143 ULLONG_MAX, // len 144 0, // pgoff 145 ULLONG_MAX, // time 146 nullptr, // dso 147 }; 148 auto it = maps.upper_bound(&find_map); 149 if (it != maps.begin() && IsAddrInMap(addr, *--it)) { 150 return *it; 151 } 152 return nullptr; 153} 154 155const MapEntry* ThreadTree::FindMap(const ThreadEntry* thread, uint64_t ip, bool in_kernel) { 156 MapEntry* result = nullptr; 157 if (!in_kernel) { 158 result = FindMapByAddr(thread->maps, ip); 159 } else { 160 result = FindMapByAddr(kernel_map_tree_, ip); 161 } 162 return result != nullptr ? result : &unknown_map_; 163} 164 165const SymbolEntry* ThreadTree::FindSymbol(const MapEntry* map, uint64_t ip) { 166 uint64_t offset_in_file; 167 if (map->dso == kernel_dso_.get()) { 168 offset_in_file = ip; 169 } else { 170 offset_in_file = ip - map->start_addr + map->pgoff; 171 } 172 const SymbolEntry* symbol = map->dso->FindSymbol(offset_in_file); 173 if (symbol == nullptr) { 174 symbol = &unknown_symbol_; 175 } 176 return symbol; 177} 178