trace_processor: use llvm frame demangling in standalone builds
This changes the Demangle() SQL function offered by trace processor to,
depending on build config, demangle function names using a small subset
of sources pulled from llvm-project (as a buildtools dependency). The
benefits are: demangling is no longer dependent on the platform that
trace processor runs on, and support for non-Itanium mangling schemes
(notably, Rust's _R v0 mangling). By default, this is enabled in
standalone GN builds, and can be turned off using
gn/perfetto.gni. The fallback implementation is the
current cpp runtime function (abi::__cxa_demangle).
One odd thing that this changes for standalone builds: in debug builds,
the llvm sources require c++14 (which is the project's natural standard
level, so the release logic might require it as well in the future). So
we build them using -std=c++14, and link the results into the rest of
the build that is using -std=c++11. This relies on the compiler being
ABI compatible across the two standards, and we assume that's the case
for the compilers we target in standalone builds. For example, I've read
that for GCC keeping such configurations sane is an explicit goal.
All wiring for standalone Bazel build is done and works if you make
tools/gen_bazel set enable_perfetto_llvm_demangle=true. Planning to make
that the default soon, but it's simpler for the google-internal
embedding if we do that separately.
The Bazel wiring introduces two indirections in PERFETTO_CONFIG, to
allow for the entire demangling target to be swapped out if necessary.
This will be used in google-internal builds, but all other embedders are
expected to stick to the default implementation.
Side-change: the nop fallback implementation (if on Windows and not
using llvm demangling) now returns nullptr to indicate that demangling
always fails, which is more consistent with the codepaths that attempt
demangling. Previously it returned the input string.
Bug: 204297290
Change-Id: Ic7844d02cce1418f11869a4ed32a4c59f866a766
diff --git a/Android.bp b/Android.bp
index 6a66249..0db1aae 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1586,6 +1586,11 @@
name: "perfetto_include_perfetto_ext_ipc_ipc",
}
+// GN: //include/perfetto/ext/trace_processor:demangle
+filegroup {
+ name: "perfetto_include_perfetto_ext_trace_processor_demangle",
+}
+
// GN: //include/perfetto/ext/trace_processor:export_json
filegroup {
name: "perfetto_include_perfetto_ext_trace_processor_export_json",
@@ -1855,6 +1860,7 @@
"libgmock",
"libgtest",
"libperfetto_client_experimental",
+ "perfetto_src_trace_processor_demangle",
],
whole_static_libs: [
"perfetto_gtest_logcat_printer",
@@ -8110,6 +8116,21 @@
],
}
+// GN: //src/trace_processor:demangle
+cc_library_static {
+ name: "perfetto_src_trace_processor_demangle",
+ srcs: [
+ ":perfetto_include_perfetto_base_base",
+ ":perfetto_include_perfetto_ext_base_base",
+ ":perfetto_include_perfetto_ext_trace_processor_demangle",
+ "src/trace_processor/demangle.cc",
+ ],
+ host_supported: true,
+ defaults: [
+ "perfetto_defaults",
+ ],
+}
+
// GN: //src/trace_processor:export_json
filegroup {
name: "perfetto_src_trace_processor_export_json",
@@ -9776,6 +9797,7 @@
static_libs: [
"libgmock",
"libgtest",
+ "perfetto_src_trace_processor_demangle",
],
whole_static_libs: [
"perfetto_gtest_logcat_printer",
@@ -10013,6 +10035,9 @@
"src/trace_processor/trace_processor_shell.cc",
"src/trace_processor/util/proto_to_json.cc",
],
+ static_libs: [
+ "perfetto_src_trace_processor_demangle",
+ ],
host_supported: true,
generated_headers: [
"perfetto_protos_perfetto_common_zero_gen_headers",
@@ -10172,6 +10197,7 @@
static_libs: [
"libsqlite",
"libz",
+ "perfetto_src_trace_processor_demangle",
],
generated_headers: [
"perfetto_protos_perfetto_common_zero_gen_headers",
diff --git a/BUILD b/BUILD
index 3260a6e..a285be5 100644
--- a/BUILD
+++ b/BUILD
@@ -423,6 +423,14 @@
],
)
+# GN target: //include/perfetto/ext/trace_processor:demangle
+perfetto_filegroup(
+ name = "include_perfetto_ext_trace_processor_demangle",
+ srcs = [
+ "include/perfetto/ext/trace_processor/demangle.h",
+ ],
+)
+
# GN target: //include/perfetto/ext/trace_processor:export_json
perfetto_filegroup(
name = "include_perfetto_ext_trace_processor_export_json",
@@ -1332,6 +1340,20 @@
],
)
+# GN target: //src/trace_processor:demangle
+perfetto_cc_library(
+ name = "src_trace_processor_demangle",
+ srcs = [
+ "src/trace_processor/demangle.cc",
+ ],
+ hdrs = [
+ ":include_perfetto_base_base",
+ ":include_perfetto_ext_base_base",
+ ":include_perfetto_ext_trace_processor_demangle",
+ ],
+ linkstatic = True,
+)
+
# GN target: //src/trace_processor:export_json
perfetto_filegroup(
name = "src_trace_processor_export_json",
@@ -3692,7 +3714,8 @@
PERFETTO_CONFIG.deps.sqlite_ext_percentile +
PERFETTO_CONFIG.deps.zlib + [
":cc_amalgamated_sql_metrics",
- ],
+ ] +
+ PERFETTO_CONFIG.deps.demangle_wrapper,
linkstatic = True,
)
@@ -3790,7 +3813,8 @@
PERFETTO_CONFIG.deps.sqlite_ext_percentile +
PERFETTO_CONFIG.deps.zlib + [
":cc_amalgamated_sql_metrics",
- ],
+ ] +
+ PERFETTO_CONFIG.deps.demangle_wrapper,
)
# GN target: //src/traced/probes:traced_probes
@@ -3974,7 +3998,8 @@
PERFETTO_CONFIG.deps.sqlite_ext_percentile +
PERFETTO_CONFIG.deps.zlib + [
":cc_amalgamated_sql_metrics",
- ],
+ ] +
+ PERFETTO_CONFIG.deps.demangle_wrapper,
)
# Content from BUILD.extras
diff --git a/CHANGELOG b/CHANGELOG
index 8f2d129..955527a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -8,7 +8,11 @@
message.
Trace Processor:
* Added prebuilts for mac-arm64.
- *
+ * Added an optional dependency from trace processor onto a subset of
+ sources from llvm-project for function name demangling. Bazel embedders
+ might need to update their PERFETTO_CONFIG in perfetto_cfg.bzl to opt in
+ or out of the new dependency. See
+ perfetto/bazel/standalone/perfetto_cfg.bzl for details.
UI:
* Added flow arrows between binder transaction pairs (request/reply
and async send/async recv).
diff --git a/bazel/deps.bzl b/bazel/deps.bzl
index 9d01d11..23fb787 100644
--- a/bazel/deps.bzl
+++ b/bazel/deps.bzl
@@ -74,6 +74,15 @@
shallow_since = "1557160162 -0700",
)
+ _add_repo_if_not_existing(
+ http_archive,
+ name = "perfetto_dep_llvm_demangle",
+ url = "https://storage.googleapis.com/perfetto/llvm-project-3b4c59c156919902c785ce3cbae0eee2ee53064d.tgz",
+ sha256 = "f4a52e7f36edd7cacc844d5ae0e5f60b6f57c5afc40683e99f295886c9ce8ff4",
+ strip_prefix = "llvm-project",
+ build_file = "//bazel:llvm_demangle.BUILD",
+ )
+
# Without this protobuf.bzl fails. This seems a bug in protobuf_deps().
_add_repo_if_not_existing(
http_archive,
diff --git a/bazel/llvm_demangle.BUILD b/bazel/llvm_demangle.BUILD
new file mode 100644
index 0000000..fe406fa
--- /dev/null
+++ b/bazel/llvm_demangle.BUILD
@@ -0,0 +1,39 @@
+# 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.
+
+load("@perfetto_cfg//:perfetto_cfg.bzl", "PERFETTO_CONFIG")
+
+cc_library(
+ name = "llvm_demangle",
+ srcs = [
+ "llvm/lib/Demangle/DLangDemangle.cpp",
+ "llvm/lib/Demangle/Demangle.cpp",
+ "llvm/lib/Demangle/ItaniumDemangle.cpp",
+ "llvm/lib/Demangle/MicrosoftDemangle.cpp",
+ "llvm/lib/Demangle/MicrosoftDemangleNodes.cpp",
+ "llvm/lib/Demangle/RustDemangle.cpp",
+ ],
+ hdrs = [
+ "llvm/include/llvm/Demangle/Demangle.h",
+ "llvm/include/llvm/Demangle/DemangleConfig.h",
+ "llvm/include/llvm/Demangle/ItaniumDemangle.h",
+ "llvm/include/llvm/Demangle/MicrosoftDemangle.h",
+ "llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h",
+ "llvm/include/llvm/Demangle/StringView.h",
+ "llvm/include/llvm/Demangle/Utility.h",
+ ],
+ copts = ["-std=c++14"] + PERFETTO_CONFIG.deps_copts.llvm_demangle,
+ includes = ["llvm/include"],
+ visibility = ["//visibility:public"],
+)
diff --git a/bazel/standalone/perfetto_cfg.bzl b/bazel/standalone/perfetto_cfg.bzl
index c9c89f1..a68bd34 100644
--- a/bazel/standalone/perfetto_cfg.bzl
+++ b/bazel/standalone/perfetto_cfg.bzl
@@ -56,6 +56,21 @@
protobuf_py = [],
pandas_py = [],
tp_vendor_py = [],
+
+ # There are multiple configurations for the function name demangling
+ # logic in trace processor:
+ # (1) The following defaults include a subset of demangling sources
+ # from llvm-project. This is the most complete implementation.
+ # (2) You can avoid the llvm dependency by setting "llvm_demangle = []"
+ # here and PERFETTO_LLVM_DEMANGLE to false in your
+ # perfetto_build_flags.h. Then the implementation will use a
+ # demangler from the c++ runtime, which will most likely handle
+ # only itanium mangling, and is unavailable on some platforms (e.g.
+ # Windows, where it becomes a nop).
+ # (3) You can override the whole demangle_wrapper below, and provide
+ # your own demangling implementation.
+ demangle_wrapper = [ "//:src_trace_processor_demangle" ],
+ llvm_demangle = ["@perfetto_dep_llvm_demangle//:llvm_demangle"],
),
# This struct allows embedders to customize the cc_opts for Perfetto
@@ -66,6 +81,7 @@
jsoncpp = [],
linenoise = [],
sqlite = [],
+ llvm_demangle = [],
),
# Allow Bazel embedders to change the visibility of "public" targets.
diff --git a/buildtools/.gitignore b/buildtools/.gitignore
index e29be60..869315f 100644
--- a/buildtools/.gitignore
+++ b/buildtools/.gitignore
@@ -27,6 +27,7 @@
linenoise/
linux/
linux64/
+llvm-project/
lzma/
mac/
ndk/
diff --git a/buildtools/BUILD.gn b/buildtools/BUILD.gn
index ee84087..a508a74 100644
--- a/buildtools/BUILD.gn
+++ b/buildtools/BUILD.gn
@@ -974,6 +974,12 @@
]
}
+# Here be dragons. Used only by standalone profiler builds, which are
+# considered best effort. Since the headers use c++17 features, this source_set
+# pushes -std=c++17 flags up the dependency tree, whereas the rest of the
+# project continues to build under c++11. So the profilers end up linking
+# together code built under different standards, and rely on that to be ABI
+# compatible.
source_set("libunwindstack") {
visibility = _buildtools_visibility
include_dirs = [
@@ -1033,9 +1039,7 @@
"android-unwinding/libunwindstack/MemoryMte.cpp",
]
} else {
- sources += [
- "android-unwinding/libunwindstack/LogAndroid.cpp",
- ]
+ sources += [ "android-unwinding/libunwindstack/LogAndroid.cpp" ]
}
if (current_cpu == "x86") {
sources += [ "android-unwinding/libunwindstack/AsmGetRegsX86.S" ]
@@ -1147,3 +1151,39 @@
deps = [ "//gn:default_deps" ]
}
}
+
+config("llvm_demangle_config") {
+ visibility = _buildtools_visibility
+ include_dirs = [ "llvm-project/llvm/include" ]
+}
+
+# NB: this is built under c++14 and linked into code that is c++11 by default.
+# We rely on the ABIs being compatible for this to be sane. At the time of
+# writing, the only c++14 specific code is behind an #ifndef NDEBUG, so we
+# could keep building as c++11 in non-debug builds, but we always use c++14 for
+# consistency.
+static_library("llvm_demangle") {
+ visibility = _buildtools_visibility
+ configs -= [
+ "//gn/standalone:extra_warnings",
+ "//gn/standalone:c++11",
+ ]
+ configs += [ "//gn/standalone:c++14" ]
+ public_configs = [ ":llvm_demangle_config" ]
+ sources = [
+ "llvm-project/llvm/include/llvm/Demangle/Demangle.h",
+ "llvm-project/llvm/include/llvm/Demangle/DemangleConfig.h",
+ "llvm-project/llvm/include/llvm/Demangle/ItaniumDemangle.h",
+ "llvm-project/llvm/include/llvm/Demangle/MicrosoftDemangle.h",
+ "llvm-project/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h",
+ "llvm-project/llvm/include/llvm/Demangle/StringView.h",
+ "llvm-project/llvm/include/llvm/Demangle/Utility.h",
+ "llvm-project/llvm/lib/Demangle/DLangDemangle.cpp",
+ "llvm-project/llvm/lib/Demangle/Demangle.cpp",
+ "llvm-project/llvm/lib/Demangle/ItaniumDemangle.cpp",
+ "llvm-project/llvm/lib/Demangle/MicrosoftDemangle.cpp",
+ "llvm-project/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp",
+ "llvm-project/llvm/lib/Demangle/RustDemangle.cpp",
+ ]
+ deps = [ "//gn:default_deps" ]
+}
diff --git a/gn/BUILD.gn b/gn/BUILD.gn
index f404832..b0e61b1 100644
--- a/gn/BUILD.gn
+++ b/gn/BUILD.gn
@@ -88,6 +88,7 @@
"PERFETTO_HEAPPROFD=$enable_perfetto_heapprofd",
"PERFETTO_STDERR_CRASH_DUMP=$enable_perfetto_stderr_crash_dump",
"PERFETTO_X64_CPU_OPT=$enable_perfetto_x64_cpu_opt",
+ "PERFETTO_LLVM_DEMANGLE=$enable_perfetto_llvm_demangle",
]
rel_out_path = rebase_path(gen_header_path, "$root_build_dir")
@@ -104,7 +105,8 @@
# All targets should depend on this target to inherit the right flags and
# include directories.
group("default_deps") {
- visibility = [ "../*" ] # Prevent chromium targets from depending on this (breaks component).
+ visibility = [ "../*" ] # Prevent chromium targets from depending on this
+ # (breaks component).
public_configs = [ ":default_config" ]
deps = [ ":gen_buildflags" ]
if (perfetto_build_standalone) {
@@ -124,7 +126,8 @@
# embedders that depend on perfetto (e.g. chrome). :public_config (see below) is
# used for that.
config("default_config") {
- visibility = [ "../*" ] # Prevent chromium targets from depending on this (breaks component).
+ visibility = [ "../*" ] # Prevent chromium targets from depending on this
+ # (breaks component).
configs = [ ":public_config" ]
defines = [ "PERFETTO_IMPLEMENTATION" ]
include_dirs = [
@@ -393,6 +396,12 @@
}
}
+if (enable_perfetto_llvm_demangle) {
+ group("llvm_demangle") {
+ public_deps = [ "//buildtools:llvm_demangle" ]
+ }
+}
+
# Used by fuzzers.
if (enable_perfetto_fuzzers && use_libfuzzer) {
group("libfuzzer") {
diff --git a/gn/perfetto.gni b/gn/perfetto.gni
index a755b8c..fe1fa11 100644
--- a/gn/perfetto.gni
+++ b/gn/perfetto.gni
@@ -100,7 +100,7 @@
# Only relevant for GN builds. Sets the path where perfetto lives. This is //
# for standalone builds and //third_party/perfetto/ in embedders. The embedder
-# can ovverride it in its GN files.
+# can override it in its GN files.
if (perfetto_build_standalone || is_perfetto_build_generator) {
perfetto_root_path = "//"
import("//gn/standalone/android.gni") # For android_api_level
@@ -291,6 +291,12 @@
enable_perfetto_zlib =
(enable_perfetto_trace_processor && !build_with_chromium) ||
enable_perfetto_platform_services
+
+ # Enables function name demangling using sources from llvm. Otherwise
+ # trace_processor falls back onto using the c++ runtime demangler, which
+ # typically handles only itanium mangling.
+ enable_perfetto_llvm_demangle =
+ enable_perfetto_trace_processor && perfetto_build_standalone
}
declare_args() {
diff --git a/gn/standalone/BUILD.gn b/gn/standalone/BUILD.gn
index bd33114..ab21e58 100644
--- a/gn/standalone/BUILD.gn
+++ b/gn/standalone/BUILD.gn
@@ -116,7 +116,16 @@
}
}
-# This is needed to compile libunwindstack.
+# Used in buildtools dependencies for standalone builds.
+config("c++14") {
+ if (is_win) {
+ cflags_cc = [ "/std:c++14" ]
+ } else {
+ cflags_cc = [ "-std=c++14" ]
+ }
+}
+
+# Used in buildtools dependencies for standalone builds.
config("c++17") {
if (is_win) {
cflags_cc = [ "/std:c++17" ]
diff --git a/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h b/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h
index a02f467..502e9bf 100644
--- a/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h
+++ b/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h
@@ -44,6 +44,7 @@
#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_HEAPPROFD() (1)
#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_STDERR_CRASH_DUMP() (0)
#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_X64_CPU_OPT() (0)
+#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_LLVM_DEMANGLE() (0)
// clang-format on
#endif // GEN_BUILD_CONFIG_PERFETTO_BUILD_FLAGS_H_
diff --git a/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h b/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
index 531445c..53c423e 100644
--- a/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
+++ b/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
@@ -44,6 +44,7 @@
#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_HEAPPROFD() (0)
#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_STDERR_CRASH_DUMP() (0)
#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_X64_CPU_OPT() (0)
+#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_LLVM_DEMANGLE() (0)
// clang-format on
#endif // GEN_BUILD_CONFIG_PERFETTO_BUILD_FLAGS_H_
diff --git a/include/perfetto/ext/trace_processor/BUILD.gn b/include/perfetto/ext/trace_processor/BUILD.gn
index a2fd7fa..6df0cca 100644
--- a/include/perfetto/ext/trace_processor/BUILD.gn
+++ b/include/perfetto/ext/trace_processor/BUILD.gn
@@ -21,3 +21,7 @@
sources += [ "export_json.h" ]
}
}
+
+source_set("demangle") {
+ sources = [ "demangle.h" ]
+}
diff --git a/include/perfetto/ext/trace_processor/demangle.h b/include/perfetto/ext/trace_processor/demangle.h
new file mode 100644
index 0000000..f3c337f
--- /dev/null
+++ b/include/perfetto/ext/trace_processor/demangle.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef INCLUDE_PERFETTO_EXT_TRACE_PROCESSOR_DEMANGLE_H_
+#define INCLUDE_PERFETTO_EXT_TRACE_PROCESSOR_DEMANGLE_H_
+
+#include "perfetto/ext/base/utils.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace demangle {
+
+// Returns a |malloc|-allocated C string with the demangled name.
+// Returns an empty pointer if demangling was unsuccessful.
+std::unique_ptr<char, base::FreeDeleter> Demangle(const char* mangled_name);
+
+} // namespace demangle
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_EXT_TRACE_PROCESSOR_DEMANGLE_H_
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 45e9774..0961c10 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -54,6 +54,19 @@
]
}
+static_library("demangle") {
+ sources = [ "demangle.cc" ]
+ deps = [
+ "../../gn:default_deps",
+ "../../include/perfetto/base",
+ "../../include/perfetto/ext/base",
+ ]
+ public_deps = [ "../../include/perfetto/ext/trace_processor:demangle" ]
+ if (enable_perfetto_llvm_demangle) {
+ deps += [ "../../gn:llvm_demangle" ]
+ }
+}
+
source_set("ftrace_descriptors") {
sources = [
"importers/ftrace/ftrace_descriptors.cc",
@@ -330,6 +343,7 @@
]
deps = [
+ ":demangle",
":export_json",
":metatrace",
":storage_full",
diff --git a/src/trace_processor/demangle.cc b/src/trace_processor/demangle.cc
new file mode 100644
index 0000000..c44f834
--- /dev/null
+++ b/src/trace_processor/demangle.cc
@@ -0,0 +1,69 @@
+/*
+ * 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 "perfetto/ext/trace_processor/demangle.h"
+
+#include <string.h>
+#include <string>
+
+#include "perfetto/base/build_config.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_LLVM_DEMANGLE)
+#include "llvm/Demangle/Demangle.h"
+#elif !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <cxxabi.h>
+#endif
+
+namespace perfetto {
+namespace trace_processor {
+namespace demangle {
+
+// Implementation depends on platform and build config. If llvm demangling
+// sources are available, use them. That is the most portable and handles more
+// than just Itanium mangling (e.g. Rust's _R scheme). Otherwise use the c++
+// standard library demangling if it implements the appropriate ABI. This
+// excludes Windows builds, where we therefore never demangle.
+// TODO(rsavitski): consider reimplementing llvm::demangle inline as it's
+// wrapping in std::strings a set of per-scheme demangling functions that
+// operate on C strings. Right now we're introducing yet another layer that
+// undoes that conversion.
+std::unique_ptr<char, base::FreeDeleter> Demangle(const char* mangled_name) {
+#if PERFETTO_BUILDFLAG(PERFETTO_LLVM_DEMANGLE)
+ std::string input(mangled_name);
+ std::string demangled = llvm::demangle(input);
+ if (demangled == input)
+ return nullptr; // demangling unsuccessful
+
+ std::unique_ptr<char, base::FreeDeleter> output(
+ static_cast<char*>(malloc(demangled.size() + 1)));
+ if (!output)
+ return nullptr;
+ memcpy(output.get(), demangled.c_str(), demangled.size() + 1);
+ return output;
+
+#elif !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ int ignored = 0;
+ return std::unique_ptr<char, base::FreeDeleter>(
+ abi::__cxa_demangle(mangled_name, nullptr, nullptr, &ignored));
+
+#else
+ return nullptr;
+#endif
+}
+
+} // namespace demangle
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/trace_database_integrationtest.cc b/src/trace_processor/trace_database_integrationtest.cc
index 6a59ca6..4df80b9 100644
--- a/src/trace_processor/trace_database_integrationtest.cc
+++ b/src/trace_processor/trace_database_integrationtest.cc
@@ -179,7 +179,8 @@
ASSERT_EQ(it.Get(0).long_value, static_cast<int64_t>(0xa9cb070fdc15f7a4));
}
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#if !PERFETTO_BUILDFLAG(PERFETTO_LLVM_DEMANGLE) && \
+ !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#define MAYBE_Demangle DISABLED_Demangle
#else
#define MAYBE_Demangle Demangle
@@ -187,15 +188,38 @@
TEST_F(TraceProcessorIntegrationTest, MAYBE_Demangle) {
auto it = Query("select DEMANGLE('_Znwm')");
ASSERT_TRUE(it.Next());
- ASSERT_STRCASEEQ(it.Get(0).string_value, "operator new(unsigned long)");
+ EXPECT_STRCASEEQ(it.Get(0).string_value, "operator new(unsigned long)");
it = Query("select DEMANGLE('_ZN3art6Thread14CreateCallbackEPv')");
ASSERT_TRUE(it.Next());
- ASSERT_STRCASEEQ(it.Get(0).string_value,
+ EXPECT_STRCASEEQ(it.Get(0).string_value,
"art::Thread::CreateCallback(void*)");
it = Query("select DEMANGLE('test')");
ASSERT_TRUE(it.Next());
+ EXPECT_TRUE(it.Get(0).is_null());
+}
+
+#if !PERFETTO_BUILDFLAG(PERFETTO_LLVM_DEMANGLE)
+#define MAYBE_DemangleRust DISABLED_DemangleRust
+#else
+#define MAYBE_DemangleRust DemangleRust
+#endif
+TEST_F(TraceProcessorIntegrationTest, MAYBE_DemangleRust) {
+ auto it = Query(
+ "select DEMANGLE("
+ "'_RNvNvMs0_NtNtNtCsg1Z12QU66Yk_3std3sys4unix6threadNtB7_"
+ "6Thread3new12thread_start')");
+ ASSERT_TRUE(it.Next());
+ EXPECT_STRCASEEQ(it.Get(0).string_value,
+ "<std::sys::unix::thread::Thread>::new::thread_start");
+
+ it = Query("select DEMANGLE('_RNvCsdV139EorvfX_14keystore2_main4main')");
+ ASSERT_TRUE(it.Next());
+ ASSERT_STRCASEEQ(it.Get(0).string_value, "keystore2_main::main");
+
+ it = Query("select DEMANGLE('_R')");
+ ASSERT_TRUE(it.Next());
ASSERT_TRUE(it.Get(0).is_null());
}
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 42d1d4e..9ace9ee 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -24,6 +24,7 @@
#include "perfetto/base/time.h"
#include "perfetto/ext/base/string_splitter.h"
#include "perfetto/ext/base/string_utils.h"
+#include "perfetto/ext/trace_processor/demangle.h"
#include "src/trace_processor/dynamic/ancestor_generator.h"
#include "src/trace_processor/dynamic/connected_flow_generator.h"
#include "src/trace_processor/dynamic/descendant_generator.h"
@@ -71,9 +72,6 @@
#include "src/trace_processor/metrics/metrics.h"
#include "src/trace_processor/metrics/sql/amalgamated_sql_metrics.h"
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <cxxabi.h>
-#endif
// In Android and Chromium tree builds, we don't have the percentile module.
// Just don't include it.
@@ -422,20 +420,16 @@
if (sqlite3_value_type(value) != SQLITE_TEXT)
return base::ErrStatus("Unsupported type of arg passed to DEMANGLE");
- const char* ptr = reinterpret_cast<const char*>(sqlite3_value_text(value));
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- int ignored = 0;
- // This memory was allocated by malloc and will be passed to SQLite to free.
- char* demangled_name = abi::__cxa_demangle(ptr, nullptr, nullptr, &ignored);
- if (!demangled_name)
+ const char* mangled =
+ reinterpret_cast<const char*>(sqlite3_value_text(value));
+
+ std::unique_ptr<char, base::FreeDeleter> demangled =
+ demangle::Demangle(mangled);
+ if (!demangled)
return base::OkStatus();
destructors.string_destructor = free;
- out = SqlValue::String(demangled_name);
-#else
- destructors.string_destructor = sqlite_utils::kSqliteTransient;
- out = SqlValue::String(ptr);
-#endif
+ out = SqlValue::String(demangled.release());
return base::OkStatus();
}
diff --git a/tools/gen_android_bp b/tools/gen_android_bp
index 0345604..a3e829f 100755
--- a/tools/gen_android_bp
+++ b/tools/gen_android_bp
@@ -96,6 +96,7 @@
'//:libperfetto',
'//:libperfetto_client_experimental',
'//protos/perfetto/trace:perfetto_trace_protos',
+ '//src/trace_processor:demangle',
'//src/trace_processor:trace_processor_shell',
]
diff --git a/tools/gen_bazel b/tools/gen_bazel
index 79bd4e8..c911be4 100755
--- a/tools/gen_bazel
+++ b/tools/gen_bazel
@@ -46,6 +46,7 @@
'enable_perfetto_heapprofd=false',
'enable_perfetto_traced_perf=false',
'perfetto_force_dcheck="off"',
+ 'enable_perfetto_llvm_demangle=false',
])
# Default targets to translate to the blueprint file.
@@ -113,6 +114,10 @@
'PERFETTO_CONFIG.deps.sqlite_ext_percentile'
],
'//gn:zlib': ['PERFETTO_CONFIG.deps.zlib'],
+ '//gn:llvm_demangle': ['PERFETTO_CONFIG.deps.llvm_demangle'],
+ '//src/trace_processor:demangle': [
+ 'PERFETTO_CONFIG.deps.demangle_wrapper'
+ ],
'//src/trace_processor/metrics/sql:gen_amalgamated_sql_metrics': [[
':cc_amalgamated_sql_metrics'
]],
diff --git a/tools/install-build-deps b/tools/install-build-deps
index bd9100c..96a2f65 100755
--- a/tools/install-build-deps
+++ b/tools/install-build-deps
@@ -211,6 +211,17 @@
'all',
'all'),
+ # Archive with only the demangling sources from llvm-project.
+ # See tools/repackage_llvm_demangler.sh on how to update this.
+ # File suffix is the git reference to the commit at which we rearchived the
+ # sources, as hosted on https://llvm.googlesource.com/llvm-project.
+ # If updating the version, also update bazel/deps.bzl.
+ Dependency(
+ 'buildtools/llvm-project.tgz',
+ 'https://storage.googleapis.com/perfetto/llvm-project-3b4c59c156919902c785ce3cbae0eee2ee53064d.tgz',
+ 'f4a52e7f36edd7cacc844d5ae0e5f60b6f57c5afc40683e99f295886c9ce8ff4',
+ 'all', 'all'),
+
# These dependencies are for libunwindstack, which is used by src/profiling.
Dependency('buildtools/android-core',
'https://android.googlesource.com/platform/system/core.git',