// Copyright 2023 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_PC_INFO_H_ #define THIRD_PARTY_CENTIPEDE_PC_INFO_H_ #include #include #include #include #include #include namespace fuzztest::internal { // PCInfo is a pair {PC, bit mask with PC flags}. // PCInfo objects are generated by the compiler and can be extracted from the // binary, see https://clang.llvm.org/docs/SanitizerCoverage.html#pc-table. // PCInfo objects can also be created by analyzing the binary with objdump. struct PCInfo { enum PCFlags : uintptr_t { kFuncEntry = 1 << 0, // The PC is the function entry block. }; uintptr_t pc{}; uintptr_t flags{}; bool has_flag(PCFlags f) const { return flags & f; } bool operator==(const PCInfo &rhs) const; }; // Array of PCInfo-s. // PCTable is created by the compiler/linker in the instrumented binary. // The order of elements is significant: each element corresponds // to the coverage counter with the same index. // Every PCInfo that is kFuncEntry is followed by PCInfo-s from the same // function. using PCTable = std::vector; // Reads a PCTable from `in`, returns it. Returns empty table on error. PCTable ReadPcTable(std::istream &in); // Writes the contents of `pc_table` in the format expected by `ReadPCTable`. void WritePcTable(const PCTable &pc_table, std::ostream &out); // PCGuard is used during run-time as a compressed reference to PCInfo. // The SanitizerCoverage's 'Tracing PCs with guards' // (https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards) // passes a pointer to a 32-bit object, unique for every instrumented PC. // At the DSO initialization time, we initialize these unique 32-bit objects // to represent the information about the PCs. struct PCGuard { // True if this is a function's entry PC. // This information may not be available, and so the code should tolerate // the situation where no PC is marked as a function entry. uint32_t is_function_entry : 1; // The index of the PC. uint32_t pc_index : 31; // pc_index is 31-bit, so we can't have more than this number of PCs. static constexpr size_t kMaxNumPCs = 1ULL << 31; // Invalid value of pc_index. static constexpr uint32_t kInvalidPcIndex = kMaxNumPCs - 1; // Returns true if `*this` is valid. bool IsValid() const { return pc_index != kInvalidPcIndex; } }; // DsoInfo represents a single SanCov-instrumented DSO (library or main binary). struct DsoInfo { // Path to the file on disk, which can be used for symbolization. std::string path; // Number of SanCov-instrumented PCs in this DSO. size_t num_instrumented_pcs = 0; }; // Array of DsoInfo. using DsoTable = std::vector; } // namespace fuzztest::internal #endif // THIRD_PARTY_CENTIPEDE_PC_INFO_H_