You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
5.2 KiB
146 lines
5.2 KiB
// Copyright 2022 The Centipede Authors.
|
|
//
|
|
// 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
|
|
//
|
|
// https://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 THIRD_PARTY_CENTIPEDE_SYMBOL_TABLE_H_
|
|
#define THIRD_PARTY_CENTIPEDE_SYMBOL_TABLE_H_
|
|
|
|
#include <cstddef>
|
|
#include <istream>
|
|
#include <ostream>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <vector>
|
|
|
|
#include "absl/container/node_hash_set.h"
|
|
#include "absl/strings/match.h"
|
|
#include "absl/strings/str_cat.h"
|
|
#include "absl/types/span.h"
|
|
#include "./centipede/control_flow.h"
|
|
#include "./centipede/pc_info.h"
|
|
|
|
namespace fuzztest::internal {
|
|
|
|
// Maps integer indices in [0, size) to debug symbols:
|
|
// function names, file names, line numbers, column numbers.
|
|
class SymbolTable {
|
|
public:
|
|
// Defines a symbol table entry.
|
|
struct Entry {
|
|
std::string_view func;
|
|
std::string_view file;
|
|
int line = -1;
|
|
int col = -1;
|
|
|
|
std::string file_line_col() const {
|
|
const bool file_known = !absl::StrContains(file, '?');
|
|
const std::string line_str =
|
|
(file_known && line >= 0) ? absl::StrCat(":", line) : "";
|
|
const std::string col_str =
|
|
(file_known && col >= 0) ? absl::StrCat(":", col) : "";
|
|
return absl::StrCat(file, line_str, col_str);
|
|
}
|
|
|
|
friend bool operator==(const Entry &lhs, const Entry &rhs) {
|
|
return lhs.func == rhs.func && lhs.file == rhs.file &&
|
|
lhs.line == rhs.line && lhs.col == rhs.col;
|
|
}
|
|
};
|
|
|
|
SymbolTable() = default;
|
|
SymbolTable(const SymbolTable &) = delete;
|
|
SymbolTable(SymbolTable &&) = default;
|
|
SymbolTable &operator=(SymbolTable &&) = default;
|
|
|
|
friend bool operator==(const SymbolTable &a, const SymbolTable &b) {
|
|
return a.entries_ == b.entries_;
|
|
}
|
|
|
|
// Reads the symbols from a stream produced by `llvm-symbolizer --no-inlines`.
|
|
// https://llvm.org/docs/CommandGuide/llvm-symbolizer.html.
|
|
// The input consists of tuples of 3 lines each:
|
|
// FunctionName
|
|
// SourceCodeLocation
|
|
// <empty line>
|
|
// If called multiple times, this function will append symbols to `this`.
|
|
void ReadFromLLVMSymbolizer(std::istream &in);
|
|
|
|
// Writes the contents of `this` to `path` in the same format as read by
|
|
// `ReadFromLLVMSymbolizer`.
|
|
void WriteToLLVMSymbolizer(std::ostream &out);
|
|
|
|
// Invokes `symbolizer_path --no-inlines` on all binaries from `dso_table`,
|
|
// pipes through it all the PCs in `pc_table` that correspond to each of the
|
|
// binaries, and calls `ReadFromLLVMSymbolizer()` on the output.
|
|
// Possibly uses files `pcs_tmp_path` and `symbols_tmp_path` for temporary
|
|
// storage.
|
|
void GetSymbolsFromBinary(const PCTable &pc_table, const DsoTable &dso_table,
|
|
std::string_view symbolizer_path,
|
|
std::string_view tmp_dir_path);
|
|
|
|
// Helper for `GetSymbolsFromBinary()`: symbolizes `pc_infos` for `dso_path`.
|
|
// Possibly uses files `pcs_tmp_path` and `symbols_tmp_path` for temporary
|
|
// storage.
|
|
void GetSymbolsFromOneDso(absl::Span<const PCInfo> pc_infos,
|
|
std::string_view dso_path,
|
|
std::string_view symbolizer_path,
|
|
std::string_view tmp_dir_path);
|
|
|
|
// Sets the table to `size` symbols all of which are unknown.
|
|
void SetAllToUnknown(size_t size);
|
|
|
|
// Returns the number of symbol entries.
|
|
size_t size() const { return entries_.size(); }
|
|
|
|
// Returns the function name for idx-th entry.
|
|
std::string_view func(size_t idx) const { return entries_[idx].func; }
|
|
|
|
Entry entry(size_t idx) const { return entries_[idx]; }
|
|
|
|
// Returns source code location for idx-th entry,
|
|
std::string location(size_t idx) const {
|
|
return entries_[idx].file_line_col();
|
|
}
|
|
|
|
// Returns a full human-readable description for idx-th entry.
|
|
std::string full_description(size_t idx) const {
|
|
return std::string{func(idx)} + " " + location(idx);
|
|
}
|
|
|
|
// Add function name and file location to symbol table.
|
|
void AddEntry(std::string_view func, std::string_view file_line_col);
|
|
|
|
// Add all the entries from the other symbol table into this one.
|
|
void AddEntries(const SymbolTable &other);
|
|
|
|
private:
|
|
void AddEntryInternal(std::string_view func, std::string_view file,
|
|
int line = -1, int col = -1);
|
|
|
|
std::string_view GetOrInsert(std::string_view str);
|
|
|
|
// Declaration order matters here, because we want `table_` to be deleted last
|
|
// in order to avoid having dangling ptrs in `entries_`.
|
|
|
|
// Holds the strings for files and function names of the stored symbols. This
|
|
// avoids storing duplicate values. `node_hash_set` was chosen in order to
|
|
// have pointer stability and not bother with storing strings in `unique_ptr`.
|
|
absl::node_hash_set<std::string> table_;
|
|
|
|
// Holds the the symbol entries.
|
|
std::vector<Entry> entries_;
|
|
};
|
|
|
|
} // namespace fuzztest::internal
|
|
|
|
#endif // THIRD_PARTY_CENTIPEDE_SYMBOL_TABLE_H_
|
|
|