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_chrome_trigger_hash_key_(
74 storage->InternString(kChromeTriggerHashKey)),
75 interned_chrome_trigger_name_key_(
76 storage->InternString(kChromeTriggerNameKey)),
77 interned_mojo_method_mapping_id_(
78 storage->InternString(kMojoMethodMappingIdKey)),
79 interned_mojo_method_rel_pc_(storage->InternString(kMojoMethodRelPcKey)),
80 interned_mojo_method_name_(storage->InternString(kMojoMethodNameKey)),
81 interned_mojo_interface_tag_(storage->InternString(kMojoIntefaceTagKey)),
82 interned_obfuscated_view_dump_class_name_flat_key_(
83 storage->InternString(kObfuscatedViewDumpClassNameFlatKey)) {}
84
NeedsTranslation(StringId flat_key_id,StringId key_id,Variadic::Type type) const85 bool ArgsTranslationTable::NeedsTranslation(StringId flat_key_id,
86 StringId key_id,
87 Variadic::Type type) const {
88 return KeyIdAndTypeToEnum(flat_key_id, key_id, type).has_value();
89 }
90
TranslateArgs(const ArgsTracker::CompactArgSet & arg_set,ArgsTracker::BoundInserter & inserter) const91 void ArgsTranslationTable::TranslateArgs(
92 const ArgsTracker::CompactArgSet& arg_set,
93 ArgsTracker::BoundInserter& inserter) const {
94 std::optional<uint64_t> mapping_id;
95 std::optional<uint64_t> rel_pc;
96
97 for (const auto& arg : arg_set) {
98 const auto key_type =
99 KeyIdAndTypeToEnum(arg.flat_key, arg.key, arg.value.type);
100 if (!key_type.has_value()) {
101 inserter.AddArg(arg.flat_key, arg.key, arg.value, arg.update_policy);
102 continue;
103 }
104
105 switch (*key_type) {
106 case KeyType::kChromeHistogramHash: {
107 inserter.AddArg(interned_chrome_histogram_hash_key_, arg.value);
108 const std::optional<base::StringView> translated_value =
109 TranslateChromeHistogramHash(arg.value.uint_value);
110 if (translated_value) {
111 inserter.AddArg(
112 interned_chrome_histogram_name_key_,
113 Variadic::String(storage_->InternString(*translated_value)));
114 }
115 break;
116 }
117 case KeyType::kChromeUserEventHash: {
118 inserter.AddArg(interned_chrome_user_event_hash_key_, arg.value);
119 const std::optional<base::StringView> translated_value =
120 TranslateChromeUserEventHash(arg.value.uint_value);
121 if (translated_value) {
122 inserter.AddArg(
123 interned_chrome_user_event_action_key_,
124 Variadic::String(storage_->InternString(*translated_value)));
125 }
126 break;
127 }
128 case KeyType::kChromePerformanceMarkMarkHash: {
129 inserter.AddArg(interned_chrome_performance_mark_mark_hash_key_,
130 arg.value);
131 const std::optional<base::StringView> translated_value =
132 TranslateChromePerformanceMarkMarkHash(arg.value.uint_value);
133 if (translated_value) {
134 inserter.AddArg(
135 interned_chrome_performance_mark_mark_key_,
136 Variadic::String(storage_->InternString(*translated_value)));
137 }
138 break;
139 }
140 case KeyType::kChromePerformanceMarkSiteHash: {
141 inserter.AddArg(interned_chrome_performance_mark_site_hash_key_,
142 arg.value);
143 const std::optional<base::StringView> translated_value =
144 TranslateChromePerformanceMarkSiteHash(arg.value.uint_value);
145 if (translated_value) {
146 inserter.AddArg(
147 interned_chrome_performance_mark_site_key_,
148 Variadic::String(storage_->InternString(*translated_value)));
149 }
150 break;
151 }
152 case KeyType::kClassName: {
153 const std::optional<StringId> translated_class_name =
154 TranslateClassName(arg.value.string_value);
155 if (translated_class_name) {
156 inserter.AddArg(arg.flat_key, arg.key,
157 Variadic::String(*translated_class_name));
158 } else {
159 inserter.AddArg(arg.flat_key, arg.key, arg.value);
160 }
161 break;
162 }
163 case KeyType::kChromeTriggerHash: {
164 inserter.AddArg(interned_chrome_trigger_hash_key_, arg.value);
165 const std::optional<base::StringView> translated_value =
166 TranslateChromeStudyHash(arg.value.uint_value);
167 if (translated_value) {
168 inserter.AddArg(
169 interned_chrome_trigger_name_key_,
170 Variadic::String(storage_->InternString(*translated_value)));
171 }
172 break;
173 }
174 case KeyType::kMojoMethodMappingId: {
175 mapping_id = arg.value.uint_value;
176 break;
177 }
178 case KeyType::kMojoMethodRelPc: {
179 rel_pc = arg.value.uint_value;
180 break;
181 }
182 }
183 }
184 EmitMojoMethodLocation(mapping_id, rel_pc, inserter);
185 }
186
187 std::optional<ArgsTranslationTable::KeyType>
KeyIdAndTypeToEnum(StringId flat_key_id,StringId key_id,Variadic::Type type) const188 ArgsTranslationTable::KeyIdAndTypeToEnum(StringId flat_key_id,
189 StringId key_id,
190 Variadic::Type type) const {
191 if (type == Variadic::Type::kUint) {
192 if (key_id == interned_chrome_histogram_hash_key_) {
193 return KeyType::kChromeHistogramHash;
194 }
195 if (key_id == interned_chrome_user_event_hash_key_) {
196 return KeyType::kChromeUserEventHash;
197 }
198 if (key_id == interned_chrome_performance_mark_mark_hash_key_) {
199 return KeyType::kChromePerformanceMarkMarkHash;
200 }
201 if (key_id == interned_chrome_performance_mark_site_hash_key_) {
202 return KeyType::kChromePerformanceMarkSiteHash;
203 }
204 if (key_id == interned_mojo_method_mapping_id_) {
205 return KeyType::kMojoMethodMappingId;
206 }
207 if (key_id == interned_mojo_method_rel_pc_) {
208 return KeyType::kMojoMethodRelPc;
209 }
210 if (key_id == interned_chrome_trigger_hash_key_) {
211 return KeyType::kChromeTriggerHash;
212 }
213 } else if (type == Variadic::Type::kString) {
214 if (flat_key_id == interned_obfuscated_view_dump_class_name_flat_key_) {
215 return KeyType::kClassName;
216 }
217 }
218 return std::nullopt;
219 }
220
221 std::optional<base::StringView>
TranslateChromeHistogramHash(uint64_t hash) const222 ArgsTranslationTable::TranslateChromeHistogramHash(uint64_t hash) const {
223 auto* value = chrome_histogram_hash_to_name_.Find(hash);
224 if (!value) {
225 return std::nullopt;
226 }
227 return base::StringView(*value);
228 }
229
230 std::optional<base::StringView>
TranslateChromeUserEventHash(uint64_t hash) const231 ArgsTranslationTable::TranslateChromeUserEventHash(uint64_t hash) const {
232 auto* value = chrome_user_event_hash_to_action_.Find(hash);
233 if (!value) {
234 return std::nullopt;
235 }
236 return base::StringView(*value);
237 }
238
239 std::optional<base::StringView>
TranslateChromePerformanceMarkSiteHash(uint64_t hash) const240 ArgsTranslationTable::TranslateChromePerformanceMarkSiteHash(
241 uint64_t hash) const {
242 auto* value = chrome_performance_mark_site_hash_to_name_.Find(hash);
243 if (!value) {
244 return std::nullopt;
245 }
246 return base::StringView(*value);
247 }
248
249 std::optional<base::StringView>
TranslateChromePerformanceMarkMarkHash(uint64_t hash) const250 ArgsTranslationTable::TranslateChromePerformanceMarkMarkHash(
251 uint64_t hash) const {
252 auto* value = chrome_performance_mark_mark_hash_to_name_.Find(hash);
253 if (!value) {
254 return std::nullopt;
255 }
256 return base::StringView(*value);
257 }
258
TranslateChromeStudyHash(uint64_t hash) const259 std::optional<base::StringView> ArgsTranslationTable::TranslateChromeStudyHash(
260 uint64_t hash) const {
261 auto* value = chrome_study_hash_to_name_.Find(hash);
262 if (!value) {
263 return std::nullopt;
264 }
265 return base::StringView(*value);
266 }
267
268 std::optional<ArgsTranslationTable::SourceLocation>
TranslateNativeSymbol(MappingId mapping_id,uint64_t rel_pc) const269 ArgsTranslationTable::TranslateNativeSymbol(MappingId mapping_id,
270 uint64_t rel_pc) const {
271 auto loc =
272 native_symbol_to_location_.Find(std::make_pair(mapping_id, rel_pc));
273 if (!loc) {
274 return std::nullopt;
275 }
276 return *loc;
277 }
278
TranslateClassName(StringId obfuscated_class_name_id) const279 std::optional<StringId> ArgsTranslationTable::TranslateClassName(
280 StringId obfuscated_class_name_id) const {
281 return deobfuscation_mapping_table_.TranslateClass(obfuscated_class_name_id);
282 }
283
EmitMojoMethodLocation(std::optional<uint64_t> mapping_id,std::optional<uint64_t> rel_pc,ArgsTracker::BoundInserter & inserter) const284 void ArgsTranslationTable::EmitMojoMethodLocation(
285 std::optional<uint64_t> mapping_id,
286 std::optional<uint64_t> rel_pc,
287 ArgsTracker::BoundInserter& inserter) const {
288 if (!mapping_id || !rel_pc) {
289 return;
290 }
291 const MappingId row_id(static_cast<uint32_t>(*mapping_id));
292 const auto loc = TranslateNativeSymbol(row_id, *rel_pc);
293 if (loc) {
294 inserter.AddArg(interned_mojo_method_name_,
295 Variadic::String(storage_->InternString(base::StringView(
296 ExtractMojoMethod((loc->function_name))))));
297 inserter.AddArg(interned_mojo_interface_tag_,
298 Variadic::String(storage_->InternString(base::StringView(
299 ExtractMojoInterfaceTag(loc->function_name)))),
300 // If the trace already has interface tag as a raw string
301 // (older Chromium versions, local traces, and so on), use
302 // the raw string.
303 GlobalArgsTracker::UpdatePolicy::kSkipIfExists);
304 } else {
305 // Could not find the corresponding source location. Let's emit raw arg
306 // values so that the data doesn't silently go missing.
307 inserter.AddArg(interned_mojo_method_mapping_id_,
308 Variadic::UnsignedInteger(*mapping_id));
309 inserter.AddArg(interned_mojo_method_rel_pc_,
310 Variadic::UnsignedInteger(*rel_pc));
311 }
312 }
313
314 } // namespace trace_processor
315 } // namespace perfetto
316