blob: 8aa9a0d825822cac096f78beb4b80df0ffe8cf0b [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <optional>
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/string_view.h"
#include "src/trace_processor/importers/common/args_translation_table.h"
namespace perfetto {
namespace trace_processor {
namespace {
// The raw symbol name is namespace::Interface::Method_Sym::IPCStableHash.
// We want to return namespace::Interface::Method.
std::string ExtractMojoMethod(const std::string& method_symbol) {
// The symbol ends with "()" for some platforms, but not for all of them.
std::string without_sym_suffix = base::StripSuffix(method_symbol, "()");
// This suffix is platform-independent, it's coming from Chromium code.
// https://source.chromium.org/chromium/chromium/src/+/main:mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl;l=66;drc=9d9e6f5ce548ecf228aed711f55b11c7ea8bdb55
constexpr char kSymSuffix[] = "_Sym::IPCStableHash";
return base::StripSuffix(without_sym_suffix, kSymSuffix);
}
// The raw symbol name is namespace::Interface::Method_Sym::IPCStableHash.
// We want to return namespace.Interface (for historical compatibility).
std::string ExtractMojoInterfaceTag(const std::string& method_symbol) {
auto parts = base::SplitString(method_symbol, "::");
// If we have too few parts, return the original string as is to simplify
// debugging.
if (parts.size() <= 2) {
return method_symbol;
}
// Remove Method_Sym and IPCStableHash parts.
parts.erase(parts.end() - 2, parts.end());
return base::Join(parts, ".");
}
} // namespace
ArgsTranslationTable::ArgsTranslationTable(TraceStorage* storage)
: storage_(storage),
interned_chrome_histogram_hash_key_(
storage->InternString(kChromeHistogramHashKey)),
interned_chrome_histogram_name_key_(
storage->InternString(kChromeHistogramNameKey)),
interned_chrome_user_event_hash_key_(
storage->InternString(kChromeUserEventHashKey)),
interned_chrome_user_event_action_key_(
storage->InternString(kChromeUserEventActionKey)),
interned_chrome_performance_mark_site_hash_key_(
storage->InternString(kChromePerformanceMarkSiteHashKey)),
interned_chrome_performance_mark_site_key_(
storage->InternString(kChromePerformanceMarkSiteKey)),
interned_chrome_performance_mark_mark_hash_key_(
storage->InternString(kChromePerformanceMarkMarkHashKey)),
interned_chrome_performance_mark_mark_key_(
storage->InternString(kChromePerformanceMarkMarkKey)),
interned_mojo_method_mapping_id_(
storage->InternString(kMojoMethodMappingIdKey)),
interned_mojo_method_rel_pc_(storage->InternString(kMojoMethodRelPcKey)),
interned_mojo_method_name_(storage->InternString(kMojoMethodNameKey)),
interned_mojo_interface_tag_(storage->InternString(kMojoIntefaceTagKey)),
interned_obfuscated_view_dump_class_name_flat_key_(
storage->InternString(kObfuscatedViewDumpClassNameFlatKey)) {}
bool ArgsTranslationTable::NeedsTranslation(StringId flat_key_id,
StringId key_id,
Variadic::Type type) const {
return KeyIdAndTypeToEnum(flat_key_id, key_id, type).has_value();
}
void ArgsTranslationTable::TranslateArgs(
const ArgsTracker::CompactArgSet& arg_set,
ArgsTracker::BoundInserter& inserter) const {
std::optional<uint64_t> mapping_id;
std::optional<uint64_t> rel_pc;
for (const auto& arg : arg_set) {
const auto key_type =
KeyIdAndTypeToEnum(arg.flat_key, arg.key, arg.value.type);
if (!key_type.has_value()) {
inserter.AddArg(arg.flat_key, arg.key, arg.value, arg.update_policy);
continue;
}
switch (*key_type) {
case KeyType::kChromeHistogramHash: {
inserter.AddArg(interned_chrome_histogram_hash_key_, arg.value);
const std::optional<base::StringView> translated_value =
TranslateChromeHistogramHash(arg.value.uint_value);
if (translated_value) {
inserter.AddArg(
interned_chrome_histogram_name_key_,
Variadic::String(storage_->InternString(*translated_value)));
}
break;
}
case KeyType::kChromeUserEventHash: {
inserter.AddArg(interned_chrome_user_event_hash_key_, arg.value);
const std::optional<base::StringView> translated_value =
TranslateChromeUserEventHash(arg.value.uint_value);
if (translated_value) {
inserter.AddArg(
interned_chrome_user_event_action_key_,
Variadic::String(storage_->InternString(*translated_value)));
}
break;
}
case KeyType::kChromePerformanceMarkMarkHash: {
inserter.AddArg(interned_chrome_performance_mark_mark_hash_key_,
arg.value);
const std::optional<base::StringView> translated_value =
TranslateChromePerformanceMarkMarkHash(arg.value.uint_value);
if (translated_value) {
inserter.AddArg(
interned_chrome_performance_mark_mark_key_,
Variadic::String(storage_->InternString(*translated_value)));
}
break;
}
case KeyType::kChromePerformanceMarkSiteHash: {
inserter.AddArg(interned_chrome_performance_mark_site_hash_key_,
arg.value);
const std::optional<base::StringView> translated_value =
TranslateChromePerformanceMarkSiteHash(arg.value.uint_value);
if (translated_value) {
inserter.AddArg(
interned_chrome_performance_mark_site_key_,
Variadic::String(storage_->InternString(*translated_value)));
}
break;
}
case KeyType::kClassName: {
const std::optional<StringId> translated_class_name =
TranslateClassName(arg.value.string_value);
if (translated_class_name) {
inserter.AddArg(arg.flat_key, arg.key,
Variadic::String(*translated_class_name));
} else {
inserter.AddArg(arg.flat_key, arg.key, arg.value);
}
break;
}
case KeyType::kMojoMethodMappingId: {
mapping_id = arg.value.uint_value;
break;
}
case KeyType::kMojoMethodRelPc: {
rel_pc = arg.value.uint_value;
break;
}
}
}
EmitMojoMethodLocation(mapping_id, rel_pc, inserter);
}
std::optional<ArgsTranslationTable::KeyType>
ArgsTranslationTable::KeyIdAndTypeToEnum(StringId flat_key_id,
StringId key_id,
Variadic::Type type) const {
if (type == Variadic::Type::kUint) {
if (key_id == interned_chrome_histogram_hash_key_) {
return KeyType::kChromeHistogramHash;
}
if (key_id == interned_chrome_user_event_hash_key_) {
return KeyType::kChromeUserEventHash;
}
if (key_id == interned_chrome_performance_mark_mark_hash_key_) {
return KeyType::kChromePerformanceMarkMarkHash;
}
if (key_id == interned_chrome_performance_mark_site_hash_key_) {
return KeyType::kChromePerformanceMarkSiteHash;
}
if (key_id == interned_mojo_method_mapping_id_) {
return KeyType::kMojoMethodMappingId;
}
if (key_id == interned_mojo_method_rel_pc_) {
return KeyType::kMojoMethodRelPc;
}
} else if (type == Variadic::Type::kString) {
if (flat_key_id == interned_obfuscated_view_dump_class_name_flat_key_) {
return KeyType::kClassName;
}
}
return std::nullopt;
}
std::optional<base::StringView>
ArgsTranslationTable::TranslateChromeHistogramHash(uint64_t hash) const {
auto* value = chrome_histogram_hash_to_name_.Find(hash);
if (!value) {
return std::nullopt;
}
return base::StringView(*value);
}
std::optional<base::StringView>
ArgsTranslationTable::TranslateChromeUserEventHash(uint64_t hash) const {
auto* value = chrome_user_event_hash_to_action_.Find(hash);
if (!value) {
return std::nullopt;
}
return base::StringView(*value);
}
std::optional<base::StringView>
ArgsTranslationTable::TranslateChromePerformanceMarkSiteHash(
uint64_t hash) const {
auto* value = chrome_performance_mark_site_hash_to_name_.Find(hash);
if (!value) {
return std::nullopt;
}
return base::StringView(*value);
}
std::optional<base::StringView>
ArgsTranslationTable::TranslateChromePerformanceMarkMarkHash(
uint64_t hash) const {
auto* value = chrome_performance_mark_mark_hash_to_name_.Find(hash);
if (!value) {
return std::nullopt;
}
return base::StringView(*value);
}
std::optional<ArgsTranslationTable::SourceLocation>
ArgsTranslationTable::TranslateNativeSymbol(MappingId mapping_id,
uint64_t rel_pc) const {
auto loc =
native_symbol_to_location_.Find(std::make_pair(mapping_id, rel_pc));
if (!loc) {
return std::nullopt;
}
return *loc;
}
std::optional<StringId> ArgsTranslationTable::TranslateClassName(
StringId obfuscated_class_name_id) const {
return deobfuscation_mapping_table_.TranslateClass(obfuscated_class_name_id);
}
void ArgsTranslationTable::EmitMojoMethodLocation(
std::optional<uint64_t> mapping_id,
std::optional<uint64_t> rel_pc,
ArgsTracker::BoundInserter& inserter) const {
if (!mapping_id || !rel_pc) {
return;
}
const MappingId row_id(static_cast<uint32_t>(*mapping_id));
const auto loc = TranslateNativeSymbol(row_id, *rel_pc);
if (loc) {
inserter.AddArg(interned_mojo_method_name_,
Variadic::String(storage_->InternString(base::StringView(
ExtractMojoMethod((loc->function_name))))));
inserter.AddArg(interned_mojo_interface_tag_,
Variadic::String(storage_->InternString(base::StringView(
ExtractMojoInterfaceTag(loc->function_name)))),
// If the trace already has interface tag as a raw string
// (older Chromium versions, local traces, and so on), use
// the raw string.
GlobalArgsTracker::UpdatePolicy::kSkipIfExists);
} else {
// Could not find the corresponding source location. Let's emit raw arg
// values so that the data doesn't silently go missing.
inserter.AddArg(interned_mojo_method_mapping_id_,
Variadic::UnsignedInteger(*mapping_id));
inserter.AddArg(interned_mojo_method_rel_pc_,
Variadic::UnsignedInteger(*rel_pc));
}
}
} // namespace trace_processor
} // namespace perfetto