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