| /* |
| * Copyright (C) 2021 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 "src/profiling/symbolizer/breakpad_symbolizer.h" |
| |
| #include <optional> |
| |
| #include "perfetto/base/build_config.h" |
| #include "perfetto/ext/base/file_utils.h" |
| #include "perfetto/ext/base/string_view.h" |
| #include "perfetto/ext/base/string_writer.h" |
| #include "src/profiling/symbolizer/breakpad_parser.h" |
| |
| namespace perfetto { |
| namespace profiling { |
| |
| namespace { |
| |
| // Returns the file path for a breakpad symbol file with the given |build_id|. |
| std::string MakeFilePath(const std::string& build_id, |
| const std::string& symbol_dir_path) { |
| // The directory of the symbol file is stored in an environment variable. |
| constexpr char kBreakpadSuffix[] = ".breakpad"; |
| std::string file_path; |
| // Append file name to symbol directory path using |build_id| and |
| // |kBreakpadSuffix|. |
| file_path.append(symbol_dir_path); |
| // TODO: Add a path utility for perfetto to use here. |
| #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) |
| file_path.append("\\"); |
| #else |
| file_path.append("/"); |
| #endif |
| file_path.append(build_id); |
| file_path.append(kBreakpadSuffix); |
| |
| return file_path; |
| } |
| |
| } // namespace |
| |
| BreakpadSymbolizer::BreakpadSymbolizer(const std::string& symbol_dir_path) |
| : symbol_dir_path_(symbol_dir_path) {} |
| |
| std::vector<std::vector<SymbolizedFrame>> BreakpadSymbolizer::Symbolize( |
| const std::string&, |
| const std::string& build_id, |
| uint64_t, |
| const std::vector<uint64_t>& address) { |
| std::vector<std::vector<SymbolizedFrame>> result; |
| size_t num_symbolized_frames = 0; |
| result.reserve(address.size()); |
| std::string file_path; |
| std::string raw_build_id = base::ToHex(build_id.c_str(), build_id.length()); |
| |
| // Check to see if the |file_path_for_testing_| member is populated. If it is, |
| // this file must be used. |
| if (file_path_for_testing_.empty()) { |
| file_path = MakeFilePath(raw_build_id, symbol_dir_path_).c_str(); |
| } else { |
| file_path = file_path_for_testing_; |
| } |
| |
| BreakpadParser parser(file_path); |
| if (!parser.ParseFile()) { |
| PERFETTO_ELOG("Failed to parse file %s.", file_path.c_str()); |
| PERFETTO_PLOG("Symbolized %zu of %zu frames.", num_symbolized_frames, |
| address.size()); |
| return result; |
| } |
| |
| // Add each address's function name to the |result| vector in the same order. |
| for (uint64_t addr : address) { |
| SymbolizedFrame frame; |
| std::optional<std::string> opt_func_name = parser.GetSymbol(addr); |
| if (opt_func_name) { |
| frame.function_name = *opt_func_name; |
| num_symbolized_frames++; |
| } |
| result.push_back({std::move(frame)}); |
| } |
| PERFETTO_PLOG("Symbolized %zu of %zu frames.", num_symbolized_frames, |
| address.size()); |
| return result; |
| } |
| |
| } // namespace profiling |
| } // namespace perfetto |