local-symbolizer: Parse Windows paths.
They contained colons in the filename, which broke the parsing logic.
Bug: 161203839
Change-Id: Id4edf76b896a86fb808680883156c8aca0190a2d
diff --git a/Android.bp b/Android.bp
index 12507ee..be1e483 100644
--- a/Android.bp
+++ b/Android.bp
@@ -6415,6 +6415,14 @@
],
}
+// GN: //src/profiling/symbolizer:unittests
+filegroup {
+ name: "perfetto_src_profiling_symbolizer_unittests",
+ srcs: [
+ "src/profiling/symbolizer/local_symbolizer_unittest.cc",
+ ],
+}
+
// GN: //src/profiling:unittests
filegroup {
name: "perfetto_src_profiling_unittests",
@@ -7845,6 +7853,8 @@
":perfetto_src_profiling_perf_producer_unittests",
":perfetto_src_profiling_perf_regs_parsing",
":perfetto_src_profiling_perf_unwinding",
+ ":perfetto_src_profiling_symbolizer_symbolizer",
+ ":perfetto_src_profiling_symbolizer_unittests",
":perfetto_src_profiling_unittests",
":perfetto_src_protozero_protozero",
":perfetto_src_protozero_testing_messages_cpp_gen",
diff --git a/gn/perfetto_unittests.gni b/gn/perfetto_unittests.gni
index aae3085..41fcd00 100644
--- a/gn/perfetto_unittests.gni
+++ b/gn/perfetto_unittests.gni
@@ -21,6 +21,7 @@
"src/protozero:unittests",
"src/tracing/core:unittests",
"src/profiling:unittests",
+ "src/profiling/symbolizer:unittests",
]
if (enable_perfetto_ipc) {
diff --git a/src/profiling/symbolizer/BUILD.gn b/src/profiling/symbolizer/BUILD.gn
index 69c9446..79c770e 100644
--- a/src/profiling/symbolizer/BUILD.gn
+++ b/src/profiling/symbolizer/BUILD.gn
@@ -13,6 +13,7 @@
# limitations under the License.
import("../../../gn/perfetto.gni")
+import("../../../gn/test.gni")
source_set("symbolizer") {
public_deps = [ "../../../include/perfetto/ext/base" ]
@@ -42,3 +43,13 @@
"symbolize_database.h",
]
}
+
+perfetto_unittest_source_set("unittests") {
+ testonly = true
+ deps = [
+ ":symbolizer",
+ "../../../gn:default_deps",
+ "../../../gn:gtest_and_gmock",
+ ]
+ sources = [ "local_symbolizer_unittest.cc" ]
+}
diff --git a/src/profiling/symbolizer/local_symbolizer.cc b/src/profiling/symbolizer/local_symbolizer.cc
index 814b5a1..fce57fe 100644
--- a/src/profiling/symbolizer/local_symbolizer.cc
+++ b/src/profiling/symbolizer/local_symbolizer.cc
@@ -247,20 +247,6 @@
void* ptr_;
};
-bool ParseLine(std::string line, std::string* file_name, uint32_t* line_no) {
- base::StringSplitter sp(std::move(line), ':');
- if (!sp.Next())
- return false;
- *file_name = sp.cur_token();
- if (!sp.Next())
- return false;
- char* endptr;
- auto parsed_line_no = strtoll(sp.cur_token(), &endptr, 10);
- if (parsed_line_no >= 0)
- *line_no = static_cast<uint32_t>(parsed_line_no);
- return *endptr == '\0' && parsed_line_no >= 0;
-}
-
std::string SplitBuildID(const std::string& hex_build_id) {
if (hex_build_id.size() < 3) {
PERFETTO_DFATAL_OR_ELOG("Invalid build-id (< 3 char) %s",
@@ -273,6 +259,25 @@
} // namespace
+bool ParseLlvmSymbolizerLine(const std::string& line,
+ std::string* file_name,
+ uint32_t* line_no) {
+ size_t col_pos = line.rfind(':');
+ if (col_pos == std::string::npos || col_pos == 0)
+ return false;
+ size_t row_pos = line.rfind(':', col_pos - 1);
+ if (row_pos == std::string::npos || row_pos == 0)
+ return false;
+ *file_name = line.substr(0, row_pos);
+ auto line_no_str = line.substr(row_pos + 1, col_pos - row_pos - 1);
+
+ base::Optional<int32_t> opt_parsed_line_no = base::StringToInt32(line_no_str);
+ if (!opt_parsed_line_no || *opt_parsed_line_no < 0)
+ return false;
+ *line_no = static_cast<uint32_t>(*opt_parsed_line_no);
+ return true;
+}
+
base::Optional<std::string> LocalBinaryFinder::FindBinary(
const std::string& abspath,
const std::string& build_id) {
@@ -459,7 +464,7 @@
if (i % 2 == 0) {
cur.function_name = lines[i];
} else {
- if (!ParseLine(lines[i], &cur.file_name, &cur.line)) {
+ if (!ParseLlvmSymbolizerLine(lines[i], &cur.file_name, &cur.line)) {
PERFETTO_ELOG("Failed to parse llvm-symbolizer line: %s",
lines[i].c_str());
cur.file_name = "";
diff --git a/src/profiling/symbolizer/local_symbolizer.h b/src/profiling/symbolizer/local_symbolizer.h
index eb3a717..fd33576 100644
--- a/src/profiling/symbolizer/local_symbolizer.h
+++ b/src/profiling/symbolizer/local_symbolizer.h
@@ -28,9 +28,13 @@
namespace perfetto {
namespace profiling {
+bool ParseLlvmSymbolizerLine(const std::string& line,
+ std::string* file_name,
+ uint32_t* line_no);
+
class LocalBinaryFinder {
public:
- LocalBinaryFinder(std::vector<std::string> roots)
+ explicit LocalBinaryFinder(std::vector<std::string> roots)
: roots_(std::move(roots)) {}
base::Optional<std::string> FindBinary(const std::string& abspath,
@@ -79,7 +83,8 @@
class LocalSymbolizer : public Symbolizer {
public:
- LocalSymbolizer(std::vector<std::string> roots) : finder_(std::move(roots)) {}
+ explicit LocalSymbolizer(std::vector<std::string> roots)
+ : finder_(std::move(roots)) {}
std::vector<std::vector<SymbolizedFrame>> Symbolize(
const std::string& mapping_name,
diff --git a/src/profiling/symbolizer/local_symbolizer_unittest.cc b/src/profiling/symbolizer/local_symbolizer_unittest.cc
new file mode 100644
index 0000000..b515866
--- /dev/null
+++ b/src/profiling/symbolizer/local_symbolizer_unittest.cc
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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/base/build_config.h"
+#include "test/gtest_and_gmock.h"
+
+// This translation unit is built only on Linux and MacOS. See //gn/BUILD.gn.
+#if PERFETTO_BUILDFLAG(PERFETTO_LOCAL_SYMBOLIZER)
+
+#include "src/profiling/symbolizer/local_symbolizer.h"
+
+namespace perfetto {
+namespace profiling {
+namespace {
+
+TEST(LocalSymbolizerTest, ParseLineWindows) {
+ std::string file_name;
+ uint32_t lineno;
+ ASSERT_TRUE(
+ ParseLlvmSymbolizerLine("C:\\Foo\\Bar.cc:123:1", &file_name, &lineno));
+ EXPECT_EQ(file_name, "C:\\Foo\\Bar.cc");
+ EXPECT_EQ(lineno, 123u);
+}
+
+} // namespace
+} // namespace profiling
+} // namespace perfetto
+
+#endif