• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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