• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 "src/profiling/symbolizer/symbolize_database.h"
18 
19 #include <map>
20 #include <utility>
21 #include <vector>
22 
23 #include "perfetto/base/logging.h"
24 #include "perfetto/ext/base/string_utils.h"
25 #include "perfetto/protozero/scattered_heap_buffer.h"
26 #include "perfetto/trace_processor/trace_processor.h"
27 
28 #include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
29 #include "protos/perfetto/trace/trace.pbzero.h"
30 #include "protos/perfetto/trace/trace_packet.pbzero.h"
31 
32 namespace perfetto {
33 namespace profiling {
34 
35 namespace {
36 using trace_processor::Iterator;
37 
38 constexpr const char* kQueryUnsymbolized =
39     "select spm.name, spm.build_id, spf.rel_pc, spm.load_bias "
40     "from stack_profile_frame spf "
41     "join stack_profile_mapping spm "
42     "on spf.mapping = spm.id "
43     "where spm.build_id != '' and spf.symbol_set_id IS NULL";
44 
45 using NameAndBuildIdPair = std::pair<std::string, std::string>;
46 
47 struct UnsymbolizedMapping {
48   std::string name;
49   std::string build_id;
50   uint64_t load_bias;
operator <perfetto::profiling::__anon5f452aea0111::UnsymbolizedMapping51   bool operator<(const UnsymbolizedMapping& o) const {
52     return std::tie(name, build_id, load_bias) <
53            std::tie(o.name, o.build_id, o.load_bias);
54   }
55 };
56 
FromHex(const char * str,size_t size)57 std::string FromHex(const char* str, size_t size) {
58   if (size % 2) {
59     PERFETTO_DFATAL_OR_ELOG("Failed to parse hex %s", str);
60     return "";
61   }
62   std::string result(size / 2, '\0');
63   for (size_t i = 0; i < size; i += 2) {
64     char hex_byte[3];
65     hex_byte[0] = str[i];
66     hex_byte[1] = str[i + 1];
67     hex_byte[2] = '\0';
68     char* end;
69     long int byte = strtol(hex_byte, &end, 16);
70     if (*end != '\0') {
71       PERFETTO_DFATAL_OR_ELOG("Failed to parse hex %s", str);
72       return "";
73     }
74     result[i / 2] = static_cast<char>(byte);
75   }
76   return result;
77 }
78 
FromHex(const std::string & str)79 std::string FromHex(const std::string& str) {
80   return FromHex(str.c_str(), str.size());
81 }
82 
GetUnsymbolizedFrames(trace_processor::TraceProcessor * tp,bool convert_build_id_to_bytes)83 std::map<UnsymbolizedMapping, std::vector<uint64_t>> GetUnsymbolizedFrames(
84     trace_processor::TraceProcessor* tp,
85     bool convert_build_id_to_bytes) {
86   std::map<UnsymbolizedMapping, std::vector<uint64_t>> res;
87   Iterator it = tp->ExecuteQuery(kQueryUnsymbolized);
88   while (it.Next()) {
89     int64_t load_bias = it.Get(3).AsLong();
90     PERFETTO_CHECK(load_bias >= 0);
91     std::string build_id;
92     if (convert_build_id_to_bytes) {
93       build_id = FromHex(it.Get(1).AsString());
94     } else {
95       build_id = it.Get(1).AsString();
96     }
97     UnsymbolizedMapping unsymbolized_mapping{it.Get(0).AsString(), build_id,
98                                              static_cast<uint64_t>(load_bias)};
99     int64_t rel_pc = it.Get(2).AsLong();
100     res[unsymbolized_mapping].emplace_back(rel_pc);
101   }
102   if (!it.Status().ok()) {
103     PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
104                             it.Status().message().c_str());
105     return {};
106   }
107   return res;
108 }
109 }  // namespace
110 
SymbolizeDatabase(trace_processor::TraceProcessor * tp,Symbolizer * symbolizer,std::function<void (const std::string &)> callback)111 void SymbolizeDatabase(trace_processor::TraceProcessor* tp,
112                        Symbolizer* symbolizer,
113                        std::function<void(const std::string&)> callback) {
114   PERFETTO_CHECK(symbolizer);
115   auto unsymbolized =
116       GetUnsymbolizedFrames(tp, symbolizer->BuildIdNeedsHexConversion());
117   for (auto it = unsymbolized.cbegin(); it != unsymbolized.cend(); ++it) {
118     const auto& unsymbolized_mapping = it->first;
119     const std::vector<uint64_t>& rel_pcs = it->second;
120     auto res = symbolizer->Symbolize(unsymbolized_mapping.name,
121                                      unsymbolized_mapping.build_id,
122                                      unsymbolized_mapping.load_bias, rel_pcs);
123     if (res.empty())
124       continue;
125 
126     protozero::HeapBuffered<perfetto::protos::pbzero::Trace> trace;
127     auto* packet = trace->add_packet();
128     auto* module_symbols = packet->set_module_symbols();
129     module_symbols->set_path(unsymbolized_mapping.name);
130     module_symbols->set_build_id(unsymbolized_mapping.build_id);
131     PERFETTO_DCHECK(res.size() == rel_pcs.size());
132     for (size_t i = 0; i < res.size(); ++i) {
133       auto* address_symbols = module_symbols->add_address_symbols();
134       address_symbols->set_address(rel_pcs[i]);
135       for (const SymbolizedFrame& frame : res[i]) {
136         auto* line = address_symbols->add_lines();
137         line->set_function_name(frame.function_name);
138         line->set_source_file_name(frame.file_name);
139         line->set_line_number(frame.line);
140       }
141     }
142     callback(trace.SerializeAsString());
143   }
144 }
145 
GetPerfettoBinaryPath()146 std::vector<std::string> GetPerfettoBinaryPath() {
147   const char* root = getenv("PERFETTO_BINARY_PATH");
148   if (root != nullptr)
149     return base::SplitString(root, ":");
150   return {};
151 }
152 
153 }  // namespace profiling
154 }  // namespace perfetto
155