summaryrefslogtreecommitdiff
path: root/perfprofd/symbolizer.cc
blob: bde680f582c8d961f28adb6ef6919cc5ed756bde (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*
 *
 * Copyright 2018, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "symbolizer.h"

#include <map>
#include <memory>
#include <unordered_map>

#include <android-base/logging.h>

#include "build_id.h"
#include "read_elf.h"

namespace perfprofd {

namespace {

struct SimpleperfSymbolizer : public Symbolizer {
  // For simplicity, we assume non-overlapping symbols.
  struct Symbol {
    std::string name;
    uint64_t length;
  };
  using SymbolMap = std::map<uint64_t, Symbol>;

  std::string Decode(const std::string& dso, uint64_t address) override {
    auto it = dsos.find(dso);
    if (it == dsos.end()) {
      LoadDso(dso);
      it = dsos.find(dso);
      DCHECK(it != dsos.end());
    }

    const SymbolMap& map = it->second;
    if (map.empty()) {
      return "";
    }
    auto upper_bound = map.upper_bound(address);
    if (upper_bound == map.begin()) {
      // Nope, not in the map.
      return "";
    }

    upper_bound--;
    if (upper_bound->first + upper_bound->second.length > address) {
      // This element covers the given address, return its name.
      return upper_bound->second.name;
    }

    return "";
  }

  void LoadDso(const std::string& dso) {
    SymbolMap data;
    auto callback = [&data](const ElfFileSymbol& sym) {
      if (sym.is_func) {
        Symbol symbol;
        symbol.name = sym.name;
        symbol.length = sym.len;
        if (sym.len == 0) {
          LOG(ERROR) << "Symbol size is zero for " << sym.name;
        }
        data.emplace(sym.vaddr, std::move(symbol));
      }
    };
    ElfStatus status = ParseSymbolsFromElfFile(dso, BuildId(), callback);
    if (status != ElfStatus::NO_ERROR) {
      LOG(WARNING) << "Could not parse dso " << dso << ": " << status;
    }
    dsos.emplace(dso, std::move(data));
  }

  bool GetMinExecutableVAddr(const std::string& dso, uint64_t* addr) override {
    ElfStatus status = ReadMinExecutableVirtualAddressFromElfFile(dso, BuildId(), addr);
    return status == ElfStatus::NO_ERROR;
  }

  std::unordered_map<std::string, SymbolMap> dsos;
};

}  // namespace

std::unique_ptr<Symbolizer> CreateELFSymbolizer() {
  return std::unique_ptr<Symbolizer>(new SimpleperfSymbolizer());
}

}  // namespace perfprofd