1 /*
2 * Copyright (C) 2022 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 <optional>
18
19 #include "perfetto/ext/base/string_utils.h"
20 #include "perfetto/ext/base/string_view.h"
21 #include "src/trace_processor/importers/common/args_translation_table.h"
22
23 namespace perfetto {
24 namespace trace_processor {
25
26 namespace {
27
28 // The raw symbol name is namespace::Interface::Method_Sym::IPCStableHash.
29 // We want to return namespace::Interface::Method.
ExtractMojoMethod(const std::string & method_symbol)30 std::string ExtractMojoMethod(const std::string& method_symbol) {
31 // The symbol ends with "()" for some platforms, but not for all of them.
32 std::string without_sym_suffix = base::StripSuffix(method_symbol, "()");
33 // This suffix is platform-independent, it's coming from Chromium code.
34 // https://source.chromium.org/chromium/chromium/src/+/main:mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl;l=66;drc=9d9e6f5ce548ecf228aed711f55b11c7ea8bdb55
35 constexpr char kSymSuffix[] = "_Sym::IPCStableHash";
36 return base::StripSuffix(without_sym_suffix, kSymSuffix);
37 }
38
39 // The raw symbol name is namespace::Interface::Method_Sym::IPCStableHash.
40 // We want to return namespace.Interface (for historical compatibility).
ExtractMojoInterfaceTag(const std::string & method_symbol)41 std::string ExtractMojoInterfaceTag(const std::string& method_symbol) {
42 auto parts = base::SplitString(method_symbol, "::");
43 // If we have too few parts, return the original string as is to simplify
44 // debugging.
45 if (parts.size() <= 2) {
46 return method_symbol;
47 }
48 // Remove Method_Sym and IPCStableHash parts.
49 parts.erase(parts.end() - 2, parts.end());
50 return base::Join(parts, ".");
51 }
52
53 } // namespace
54
ArgsTranslationTable(TraceStorage * storage)55 ArgsTranslationTable::ArgsTranslationTable(TraceStorage* storage)
56 : storage_(storage),
57 interned_chrome_histogram_hash_key_(
58 storage->InternString(kChromeHistogramHashKey)),
59 interned_chrome_histogram_name_key_(
60 storage->InternString(kChromeHistogramNameKey)),
61 interned_chrome_user_event_hash_key_(
62 storage->InternString(kChromeUserEventHashKey)),
63 interned_chrome_user_event_action_key_(
64 storage->InternString(kChromeUserEventActionKey)),
65 interned_chrome_performance_mark_site_hash_key_(
66 storage->InternString(kChromePerformanceMarkSiteHashKey)),
67 interned_chrome_performance_mark_site_key_(
68 storage->InternString(kChromePerformanceMarkSiteKey)),
69 interned_chrome_performance_mark_mark_hash_key_(
70 storage->InternString(kChromePerformanceMarkMarkHashKey)),
71 interned_chrome_performance_mark_mark_key_(
72 storage->InternString(kChromePerformanceMarkMarkKey)),
73 interned_mojo_method_mapping_id_(
74 storage->InternString(kMojoMethodMappingIdKey)),
75 interned_mojo_method_rel_pc_(storage->InternString(kMojoMethodRelPcKey)),
76 interned_mojo_method_name_(storage->InternString(kMojoMethodNameKey)),
77 interned_mojo_interface_tag_(storage->InternString(kMojoIntefaceTagKey)),
78 interned_obfuscated_view_dump_class_name_flat_key_(
79 storage->InternString(kObfuscatedViewDumpClassNameFlatKey)) {}
80
NeedsTranslation(StringId flat_key_id,StringId key_id,Variadic::Type type) const81 bool ArgsTranslationTable::NeedsTranslation(StringId flat_key_id,
82 StringId key_id,
83 Variadic::Type type) const {
84 return KeyIdAndTypeToEnum(flat_key_id, key_id, type).has_value();
85 }
86
TranslateArgs(const ArgsTracker::CompactArgSet & arg_set,ArgsTracker::BoundInserter & inserter) const87 void ArgsTranslationTable::TranslateArgs(
88 const ArgsTracker::CompactArgSet& arg_set,
89 ArgsTracker::BoundInserter& inserter) const {
90 std::optional<uint64_t> mapping_id;
91 std::optional<uint64_t> rel_pc;
92
93 for (const auto& arg : arg_set) {
94 const auto key_type =
95 KeyIdAndTypeToEnum(arg.flat_key, arg.key, arg.value.type);
96 if (!key_type.has_value()) {
97 inserter.AddArg(arg.flat_key, arg.key, arg.value, arg.update_policy);
98 continue;
99 }
100
101 switch (*key_type) {
102 case KeyType::kChromeHistogramHash: {
103 inserter.AddArg(interned_chrome_histogram_hash_key_, arg.value);
104 const std::optional<base::StringView> translated_value =
105 TranslateChromeHistogramHash(arg.value.uint_value);
106 if (translated_value) {
107 inserter.AddArg(
108 interned_chrome_histogram_name_key_,
109 Variadic::String(storage_->InternString(*translated_value)));
110 }
111 break;
112 }
113 case KeyType::kChromeUserEventHash: {
114 inserter.AddArg(interned_chrome_user_event_hash_key_, arg.value);
115 const std::optional<base::StringView> translated_value =
116 TranslateChromeUserEventHash(arg.value.uint_value);
117 if (translated_value) {
118 inserter.AddArg(
119 interned_chrome_user_event_action_key_,
120 Variadic::String(storage_->InternString(*translated_value)));
121 }
122 break;
123 }
124 case KeyType::kChromePerformanceMarkMarkHash: {
125 inserter.AddArg(interned_chrome_performance_mark_mark_hash_key_,
126 arg.value);
127 const std::optional<base::StringView> translated_value =
128 TranslateChromePerformanceMarkMarkHash(arg.value.uint_value);
129 if (translated_value) {
130 inserter.AddArg(
131 interned_chrome_performance_mark_mark_key_,
132 Variadic::String(storage_->InternString(*translated_value)));
133 }
134 break;
135 }
136 case KeyType::kChromePerformanceMarkSiteHash: {
137 inserter.AddArg(interned_chrome_performance_mark_site_hash_key_,
138 arg.value);
139 const std::optional<base::StringView> translated_value =
140 TranslateChromePerformanceMarkSiteHash(arg.value.uint_value);
141 if (translated_value) {
142 inserter.AddArg(
143 interned_chrome_performance_mark_site_key_,
144 Variadic::String(storage_->InternString(*translated_value)));
145 }
146 break;
147 }
148 case KeyType::kClassName: {
149 const std::optional<StringId> translated_class_name =
150 TranslateClassName(arg.value.string_value);
151 if (translated_class_name) {
152 inserter.AddArg(arg.flat_key, arg.key,
153 Variadic::String(*translated_class_name));
154 } else {
155 inserter.AddArg(arg.flat_key, arg.key, arg.value);
156 }
157 break;
158 }
159 case KeyType::kMojoMethodMappingId: {
160 mapping_id = arg.value.uint_value;
161 break;
162 }
163 case KeyType::kMojoMethodRelPc: {
164 rel_pc = arg.value.uint_value;
165 break;
166 }
167 }
168 }
169 EmitMojoMethodLocation(mapping_id, rel_pc, inserter);
170 }
171
172 std::optional<ArgsTranslationTable::KeyType>
KeyIdAndTypeToEnum(StringId flat_key_id,StringId key_id,Variadic::Type type) const173 ArgsTranslationTable::KeyIdAndTypeToEnum(StringId flat_key_id,
174 StringId key_id,
175 Variadic::Type type) const {
176 if (type == Variadic::Type::kUint) {
177 if (key_id == interned_chrome_histogram_hash_key_) {
178 return KeyType::kChromeHistogramHash;
179 }
180 if (key_id == interned_chrome_user_event_hash_key_) {
181 return KeyType::kChromeUserEventHash;
182 }
183 if (key_id == interned_chrome_performance_mark_mark_hash_key_) {
184 return KeyType::kChromePerformanceMarkMarkHash;
185 }
186 if (key_id == interned_chrome_performance_mark_site_hash_key_) {
187 return KeyType::kChromePerformanceMarkSiteHash;
188 }
189 if (key_id == interned_mojo_method_mapping_id_) {
190 return KeyType::kMojoMethodMappingId;
191 }
192 if (key_id == interned_mojo_method_rel_pc_) {
193 return KeyType::kMojoMethodRelPc;
194 }
195 } else if (type == Variadic::Type::kString) {
196 if (flat_key_id == interned_obfuscated_view_dump_class_name_flat_key_) {
197 return KeyType::kClassName;
198 }
199 }
200 return std::nullopt;
201 }
202
203 std::optional<base::StringView>
TranslateChromeHistogramHash(uint64_t hash) const204 ArgsTranslationTable::TranslateChromeHistogramHash(uint64_t hash) const {
205 auto* value = chrome_histogram_hash_to_name_.Find(hash);
206 if (!value) {
207 return std::nullopt;
208 }
209 return base::StringView(*value);
210 }
211
212 std::optional<base::StringView>
TranslateChromeUserEventHash(uint64_t hash) const213 ArgsTranslationTable::TranslateChromeUserEventHash(uint64_t hash) const {
214 auto* value = chrome_user_event_hash_to_action_.Find(hash);
215 if (!value) {
216 return std::nullopt;
217 }
218 return base::StringView(*value);
219 }
220
221 std::optional<base::StringView>
TranslateChromePerformanceMarkSiteHash(uint64_t hash) const222 ArgsTranslationTable::TranslateChromePerformanceMarkSiteHash(
223 uint64_t hash) const {
224 auto* value = chrome_performance_mark_site_hash_to_name_.Find(hash);
225 if (!value) {
226 return std::nullopt;
227 }
228 return base::StringView(*value);
229 }
230
231 std::optional<base::StringView>
TranslateChromePerformanceMarkMarkHash(uint64_t hash) const232 ArgsTranslationTable::TranslateChromePerformanceMarkMarkHash(
233 uint64_t hash) const {
234 auto* value = chrome_performance_mark_mark_hash_to_name_.Find(hash);
235 if (!value) {
236 return std::nullopt;
237 }
238 return base::StringView(*value);
239 }
240
241 std::optional<ArgsTranslationTable::SourceLocation>
TranslateNativeSymbol(MappingId mapping_id,uint64_t rel_pc) const242 ArgsTranslationTable::TranslateNativeSymbol(MappingId mapping_id,
243 uint64_t rel_pc) const {
244 auto loc =
245 native_symbol_to_location_.Find(std::make_pair(mapping_id, rel_pc));
246 if (!loc) {
247 return std::nullopt;
248 }
249 return *loc;
250 }
251
TranslateClassName(StringId obfuscated_class_name_id) const252 std::optional<StringId> ArgsTranslationTable::TranslateClassName(
253 StringId obfuscated_class_name_id) const {
254 return deobfuscation_mapping_table_.TranslateClass(obfuscated_class_name_id);
255 }
256
EmitMojoMethodLocation(std::optional<uint64_t> mapping_id,std::optional<uint64_t> rel_pc,ArgsTracker::BoundInserter & inserter) const257 void ArgsTranslationTable::EmitMojoMethodLocation(
258 std::optional<uint64_t> mapping_id,
259 std::optional<uint64_t> rel_pc,
260 ArgsTracker::BoundInserter& inserter) const {
261 if (!mapping_id || !rel_pc) {
262 return;
263 }
264 const MappingId row_id(static_cast<uint32_t>(*mapping_id));
265 const auto loc = TranslateNativeSymbol(row_id, *rel_pc);
266 if (loc) {
267 inserter.AddArg(interned_mojo_method_name_,
268 Variadic::String(storage_->InternString(base::StringView(
269 ExtractMojoMethod((loc->function_name))))));
270 inserter.AddArg(interned_mojo_interface_tag_,
271 Variadic::String(storage_->InternString(base::StringView(
272 ExtractMojoInterfaceTag(loc->function_name)))),
273 // If the trace already has interface tag as a raw string
274 // (older Chromium versions, local traces, and so on), use
275 // the raw string.
276 GlobalArgsTracker::UpdatePolicy::kSkipIfExists);
277 } else {
278 // Could not find the corresponding source location. Let's emit raw arg
279 // values so that the data doesn't silently go missing.
280 inserter.AddArg(interned_mojo_method_mapping_id_,
281 Variadic::UnsignedInteger(*mapping_id));
282 inserter.AddArg(interned_mojo_method_rel_pc_,
283 Variadic::UnsignedInteger(*rel_pc));
284 }
285 }
286
287 } // namespace trace_processor
288 } // namespace perfetto
289