blob: c75537c849de206f38dd423ac29954309e29738f [file] [log] [blame]
Yabin Cuiec12ed92015-06-08 10:38:10 -07001/*
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 "dso.h"
18
Yabin Cuib3783552015-06-11 11:15:42 -070019#include <stdlib.h>
20#include <base/logging.h>
Yabin Cuiec12ed92015-06-08 10:38:10 -070021#include "environment.h"
22#include "read_elf.h"
Yabin Cuib3783552015-06-11 11:15:42 -070023#include "utils.h"
Yabin Cuiec12ed92015-06-08 10:38:10 -070024
25bool SymbolComparator::operator()(const std::unique_ptr<SymbolEntry>& symbol1,
26 const std::unique_ptr<SymbolEntry>& symbol2) {
27 return symbol1->addr < symbol2->addr;
28}
29
30const SymbolEntry* DsoEntry::FindSymbol(uint64_t offset_in_dso) {
31 std::unique_ptr<SymbolEntry> symbol(new SymbolEntry{
Yabin Cui9fd3cc12015-06-25 17:42:23 -070032 "", // name
33 offset_in_dso, // addr
34 0, // len
Yabin Cuiec12ed92015-06-08 10:38:10 -070035 });
36
37 auto it = symbols.upper_bound(symbol);
38 if (it != symbols.begin()) {
39 --it;
40 if ((*it)->addr <= offset_in_dso && (*it)->addr + (*it)->len > offset_in_dso) {
41 return (*it).get();
42 }
43 }
44 return nullptr;
45}
46
Yabin Cuib3783552015-06-11 11:15:42 -070047bool DsoFactory::demangle = true;
48
49void DsoFactory::SetDemangle(bool demangle) {
50 DsoFactory::demangle = demangle;
51}
52
53std::string DsoFactory::symfs_dir;
54
55bool DsoFactory::SetSymFsDir(const std::string& symfs_dir) {
56 std::string dirname = symfs_dir;
Yabin Cui638c5582015-07-01 16:16:57 -070057 if (!dirname.empty()) {
58 if (dirname.back() != '/') {
59 dirname.push_back('/');
60 }
61 std::vector<std::string> files;
62 std::vector<std::string> subdirs;
63 GetEntriesInDir(symfs_dir, &files, &subdirs);
64 if (files.empty() && subdirs.empty()) {
65 LOG(ERROR) << "Invalid symfs_dir '" << symfs_dir << "'";
66 return false;
67 }
Yabin Cuib3783552015-06-11 11:15:42 -070068 }
69 DsoFactory::symfs_dir = dirname;
70 return true;
71}
72
Yabin Cui638c5582015-07-01 16:16:57 -070073std::unordered_map<std::string, BuildId> DsoFactory::build_id_map;
74
75void DsoFactory::SetBuildIds(const std::vector<std::pair<std::string, BuildId>>& build_ids) {
76 std::unordered_map<std::string, BuildId> map;
77 for (auto& pair : build_ids) {
78 LOG(DEBUG) << "build_id_map: " << pair.first << ", " << pair.second.ToString();
79 map.insert(pair);
80 }
81 build_id_map = std::move(map);
82}
83
Yabin Cuiec12ed92015-06-08 10:38:10 -070084static bool IsKernelFunctionSymbol(const KernelSymbol& symbol) {
85 return (symbol.type == 'T' || symbol.type == 't' || symbol.type == 'W' || symbol.type == 'w');
86}
87
88static bool KernelSymbolCallback(const KernelSymbol& kernel_symbol, DsoEntry* dso) {
89 if (IsKernelFunctionSymbol(kernel_symbol)) {
90 SymbolEntry* symbol = new SymbolEntry{
Yabin Cui9fd3cc12015-06-25 17:42:23 -070091 kernel_symbol.name, // name
92 kernel_symbol.addr, // addr
93 0, // len
Yabin Cuiec12ed92015-06-08 10:38:10 -070094 };
95 dso->symbols.insert(std::unique_ptr<SymbolEntry>(symbol));
96 }
97 return false;
98}
99
Yabin Cuib3783552015-06-11 11:15:42 -0700100static void FixupSymbolLength(DsoEntry* dso) {
101 SymbolEntry* prev_symbol = nullptr;
102 for (auto& symbol : dso->symbols) {
103 if (prev_symbol != nullptr && prev_symbol->len == 0) {
104 prev_symbol->len = symbol->addr - prev_symbol->addr;
105 }
106 prev_symbol = symbol.get();
107 }
108 if (prev_symbol != nullptr && prev_symbol->len == 0) {
109 prev_symbol->len = ULLONG_MAX - prev_symbol->addr;
110 }
111}
112
Yabin Cui9fd3cc12015-06-25 17:42:23 -0700113// TODO: Fix the way to get kernel symbols. See b/22179177.
Yabin Cuiec12ed92015-06-08 10:38:10 -0700114std::unique_ptr<DsoEntry> DsoFactory::LoadKernel() {
115 std::unique_ptr<DsoEntry> dso(new DsoEntry);
116 dso->path = "[kernel.kallsyms]";
Yabin Cui638c5582015-07-01 16:16:57 -0700117 BuildId build_id = GetExpectedBuildId(DEFAULT_KERNEL_FILENAME_FOR_BUILD_ID);
118 BuildId real_build_id;
119 GetKernelBuildId(&real_build_id);
120 bool match = (build_id == real_build_id);
121 LOG(DEBUG) << "check kernel build id (" << (match ? "match" : "mismatch") << "): expected "
122 << build_id.ToString() << ", real " << real_build_id.ToString();
123 if (match) {
124 ProcessKernelSymbols("/proc/kallsyms",
125 std::bind(&KernelSymbolCallback, std::placeholders::_1, dso.get()));
126 }
Yabin Cuib3783552015-06-11 11:15:42 -0700127 FixupSymbolLength(dso.get());
Yabin Cuiec12ed92015-06-08 10:38:10 -0700128 return dso;
129}
130
131static void ParseSymbolCallback(const ElfFileSymbol& elf_symbol, DsoEntry* dso,
132 bool (*filter)(const ElfFileSymbol&)) {
133 if (filter(elf_symbol)) {
134 SymbolEntry* symbol = new SymbolEntry{
Yabin Cui9fd3cc12015-06-25 17:42:23 -0700135 elf_symbol.name, // name
136 elf_symbol.start_in_file, // addr
137 elf_symbol.len, // len
Yabin Cuiec12ed92015-06-08 10:38:10 -0700138 };
139 dso->symbols.insert(std::unique_ptr<SymbolEntry>(symbol));
140 }
141}
142
143static bool SymbolFilterForKernelModule(const ElfFileSymbol& elf_symbol) {
144 // TODO: Parse symbol outside of .text section.
145 return (elf_symbol.is_func && elf_symbol.is_in_text_section);
146}
147
148std::unique_ptr<DsoEntry> DsoFactory::LoadKernelModule(const std::string& dso_path) {
149 std::unique_ptr<DsoEntry> dso(new DsoEntry);
150 dso->path = dso_path;
Yabin Cui638c5582015-07-01 16:16:57 -0700151 BuildId build_id = GetExpectedBuildId(dso_path);
152 ParseSymbolsFromElfFile(symfs_dir + dso_path, build_id,
153 std::bind(ParseSymbolCallback, std::placeholders::_1, dso.get(),
154 SymbolFilterForKernelModule));
Yabin Cuib3783552015-06-11 11:15:42 -0700155 FixupSymbolLength(dso.get());
Yabin Cuiec12ed92015-06-08 10:38:10 -0700156 return dso;
157}
158
159static bool SymbolFilterForDso(const ElfFileSymbol& elf_symbol) {
Yabin Cuib3783552015-06-11 11:15:42 -0700160 return elf_symbol.is_func || (elf_symbol.is_label && elf_symbol.is_in_text_section);
161}
162
163extern "C" char* __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status);
164
165static void DemangleInPlace(std::string* name) {
166 int status;
Yabin Cui2c17e0d2015-06-11 14:57:21 -0700167 bool is_linker_symbol = (name->find(linker_prefix) == 0);
168 const char* mangled_str = name->c_str();
169 if (is_linker_symbol) {
170 mangled_str += linker_prefix.size();
171 }
172 char* demangled_name = __cxa_demangle(mangled_str, nullptr, nullptr, &status);
Yabin Cuib3783552015-06-11 11:15:42 -0700173 if (status == 0) {
Yabin Cui2c17e0d2015-06-11 14:57:21 -0700174 if (is_linker_symbol) {
175 *name = std::string("[linker]") + demangled_name;
176 } else {
177 *name = demangled_name;
178 }
Yabin Cuib3783552015-06-11 11:15:42 -0700179 free(demangled_name);
Yabin Cui2c17e0d2015-06-11 14:57:21 -0700180 } else if (is_linker_symbol) {
181 std::string temp = std::string("[linker]") + mangled_str;
182 *name = std::move(temp);
Yabin Cuib3783552015-06-11 11:15:42 -0700183 }
Yabin Cuiec12ed92015-06-08 10:38:10 -0700184}
185
186std::unique_ptr<DsoEntry> DsoFactory::LoadDso(const std::string& dso_path) {
187 std::unique_ptr<DsoEntry> dso(new DsoEntry);
188 dso->path = dso_path;
Yabin Cui638c5582015-07-01 16:16:57 -0700189 BuildId build_id = GetExpectedBuildId(dso_path);
190 ParseSymbolsFromElfFile(
191 symfs_dir + dso_path, build_id,
192 std::bind(ParseSymbolCallback, std::placeholders::_1, dso.get(), SymbolFilterForDso));
Yabin Cuib3783552015-06-11 11:15:42 -0700193 if (demangle) {
194 for (auto& symbol : dso->symbols) {
195 DemangleInPlace(&symbol->name);
196 }
197 }
198 FixupSymbolLength(dso.get());
Yabin Cuiec12ed92015-06-08 10:38:10 -0700199 return dso;
200}
Yabin Cui638c5582015-07-01 16:16:57 -0700201
202BuildId DsoFactory::GetExpectedBuildId(const std::string& filename) {
203 auto it = build_id_map.find(filename);
204 if (it != build_id_map.end()) {
205 return it->second;
206 }
207 return BuildId();
208}