1 /*
2 * Copyright (C) 2021 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 "src/profiling/symbolizer/breakpad_symbolizer.h"
18
19 #include "perfetto/base/build_config.h"
20 #include "perfetto/ext/base/file_utils.h"
21 #include "perfetto/ext/base/optional.h"
22 #include "perfetto/ext/base/string_view.h"
23 #include "perfetto/ext/base/string_writer.h"
24 #include "src/profiling/symbolizer/breakpad_parser.h"
25
26 namespace perfetto {
27 namespace profiling {
28
29 namespace {
30
31 // Returns the file path for a breakpad symbol file with the given |build_id|.
MakeFilePath(const std::string & build_id,const std::string & symbol_dir_path)32 std::string MakeFilePath(const std::string& build_id,
33 const std::string& symbol_dir_path) {
34 // The directory of the symbol file is stored in an environment variable.
35 constexpr char kBreakpadSuffix[] = ".breakpad";
36 std::string file_path;
37 // Append file name to symbol directory path using |build_id| and
38 // |kBreakpadSuffix|.
39 file_path.append(symbol_dir_path);
40 // TODO: Add a path utility for perfetto to use here.
41 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
42 file_path.append("\\");
43 #else
44 file_path.append("/");
45 #endif
46 file_path.append(build_id);
47 file_path.append(kBreakpadSuffix);
48
49 return file_path;
50 }
51
52 } // namespace
53
BreakpadSymbolizer(const std::string & symbol_dir_path)54 BreakpadSymbolizer::BreakpadSymbolizer(const std::string& symbol_dir_path)
55 : symbol_dir_path_(symbol_dir_path) {}
56
Symbolize(const std::string &,const std::string & build_id,uint64_t,const std::vector<uint64_t> & address)57 std::vector<std::vector<SymbolizedFrame>> BreakpadSymbolizer::Symbolize(
58 const std::string&,
59 const std::string& build_id,
60 uint64_t,
61 const std::vector<uint64_t>& address) {
62 std::vector<std::vector<SymbolizedFrame>> result;
63 size_t num_symbolized_frames = 0;
64 result.reserve(address.size());
65 std::string file_path;
66
67 // Check to see if the |file_path_for_testing_| member is populated. If it is,
68 // this file must be used.
69 if (file_path_for_testing_.empty()) {
70 file_path = MakeFilePath(build_id, symbol_dir_path_).c_str();
71 } else {
72 file_path = file_path_for_testing_;
73 }
74
75 BreakpadParser parser(file_path);
76 if (!parser.ParseFile()) {
77 PERFETTO_ELOG("Failed to parse file %s.", file_path.c_str());
78 PERFETTO_PLOG("Symbolized %zu of %zu frames.", num_symbolized_frames,
79 address.size());
80 return result;
81 }
82
83 // Add each address's function name to the |result| vector in the same order.
84 for (uint64_t addr : address) {
85 SymbolizedFrame frame;
86 base::Optional<std::string> opt_func_name = parser.GetSymbol(addr);
87 if (opt_func_name) {
88 frame.function_name = *opt_func_name;
89 num_symbolized_frames++;
90 }
91 result.push_back({std::move(frame)});
92 }
93 PERFETTO_PLOG("Symbolized %zu of %zu frames.", num_symbolized_frames,
94 address.size());
95 return result;
96 }
97
98 } // namespace profiling
99 } // namespace perfetto
100