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