diff options
author | Stephen Crane <sjc@immunant.com> | 2020-11-16 18:00:53 -0800 |
---|---|---|
committer | Stephen Crane <sjc@immunant.com> | 2020-12-14 22:06:13 -0800 |
commit | e962930d19efd198920df2f77b95f78f3b394751 (patch) | |
tree | bdd8b656e76f06e92e37ed0a3fb8689bb329b3e7 /trusty/coverage/coverage.cpp | |
parent | 5a611cb8346877493929582855d8bcbbfd8f3dbf (diff) |
trusty: Retrieve coverage PCs from coverage record
Adds the ability to retrieve and save program counter information from
the trusty coverage record data. PC information is saved to a .sancov
file, parseable by the LLVM sancov tool. Sancov can then symbolize and
display this coverage information for consumption by humans.
Adds a sancov dump to the libtrusty_coverage_test for testing.
Bug: 175221942
Test: atest libtrusty_coverage_test
Test: Retrieve sancov file and manually symbolize with sancov
Change-Id: I342ea2ca9abb87986b2904ff69415544ee6070fc
Diffstat (limited to 'trusty/coverage/coverage.cpp')
-rw-r--r-- | trusty/coverage/coverage.cpp | 115 |
1 files changed, 111 insertions, 4 deletions
diff --git a/trusty/coverage/coverage.cpp b/trusty/coverage/coverage.cpp index 1162f42aa..9413ce385 100644 --- a/trusty/coverage/coverage.cpp +++ b/trusty/coverage/coverage.cpp @@ -16,12 +16,15 @@ #define LOG_TAG "coverage" +#include <android-base/file.h> #include <android-base/logging.h> #include <android-base/unique_fd.h> #include <assert.h> +#include <stdio.h> #include <sys/mman.h> #include <sys/uio.h> #include <trusty/coverage/coverage.h> +#include <trusty/coverage/record.h> #include <trusty/coverage/tipc.h> #include <trusty/tipc.h> @@ -137,12 +140,59 @@ Result<void> CoverageRecord::Open() { return {}; } -void CoverageRecord::Reset() { - for (size_t i = 0; i < shm_len_; i++) { +void CoverageRecord::ResetFullRecord() { + auto header_region = GetRegionBounds(COV_START); + if (!header_region) { + // If the header cannot be parsed, we can't reset the proper region yet. + return; + } + + for (size_t i = header_region->second; i < shm_len_; i++) { *((volatile uint8_t*)shm_ + i) = 0; } } +void CoverageRecord::ResetCounts() { + volatile uint8_t* begin = nullptr; + volatile uint8_t* end = nullptr; + GetRawCounts(&begin, &end); + + for (volatile uint8_t* x = begin; x < end; x++) { + *x = 0; + } +} + +void CoverageRecord::ResetPCs() { + volatile uintptr_t* begin = nullptr; + volatile uintptr_t* end = nullptr; + GetRawPCs(&begin, &end); + + for (volatile uintptr_t* x = begin; x < end; x++) { + *x = 0; + } +} + +Result<std::pair<size_t, size_t>> CoverageRecord::GetRegionBounds(uint32_t region_type) { + assert(shm_); + + auto header = (volatile struct coverage_record_header*)shm_; + + if (header->type != COV_START) { + return Error() << "Header not yet valid"; + } + + for (++header; header->type != COV_TOTAL_LENGTH; ++header) { + if (header->type == region_type) { + // Coverage record must end with a COV_TOTAL_LENGTH header entry, so + // it is always safe to read the next entry since we don't iterate + // over the COV_TOTAL_LENGTH entry. + return {{header->offset, (header + 1)->offset}}; + } + } + + return Error() << "Could not find coverage region type: " << region_type; +} + void CoverageRecord::GetRawData(volatile void** begin, volatile void** end) { assert(shm_); @@ -150,7 +200,35 @@ void CoverageRecord::GetRawData(volatile void** begin, volatile void** end) { *end = (uint8_t*)(*begin) + record_len_; } -uint64_t CoverageRecord::CountEdges() { +void CoverageRecord::GetRawCounts(volatile uint8_t** begin, volatile uint8_t** end) { + auto region = GetRegionBounds(COV_8BIT_COUNTERS); + if (!region) { + *begin = 0; + *end = 0; + return; + } + + assert(region->second <= record_len_); + + *begin = (volatile uint8_t*)shm_ + region->first; + *end = (volatile uint8_t*)shm_ + region->second; +} + +void CoverageRecord::GetRawPCs(volatile uintptr_t** begin, volatile uintptr_t** end) { + auto region = GetRegionBounds(COV_INSTR_PCS); + if (!region) { + *begin = 0; + *end = 0; + return; + } + + assert(region->second <= record_len_); + + *begin = (volatile uintptr_t*)((volatile uint8_t*)shm_ + region->first); + *end = (volatile uintptr_t*)((volatile uint8_t*)shm_ + region->second); +} + +uint64_t CoverageRecord::TotalEdgeCounts() { assert(shm_); uint64_t counter = 0; @@ -158,7 +236,7 @@ uint64_t CoverageRecord::CountEdges() { volatile uint8_t* begin = NULL; volatile uint8_t* end = NULL; - GetRawData((volatile void**)&begin, (volatile void**)&end); + GetRawCounts(&begin, &end); for (volatile uint8_t* x = begin; x < end; x++) { counter += *x; @@ -167,6 +245,35 @@ uint64_t CoverageRecord::CountEdges() { return counter; } +Result<void> CoverageRecord::SaveSancovFile(const std::string& filename) { + android::base::unique_fd output_fd(TEMP_FAILURE_RETRY(creat(filename.c_str(), 00644))); + if (!output_fd.ok()) { + return ErrnoError() << "Could not open sancov file"; + } + + uint64_t magic; + if (sizeof(uintptr_t) == 8) { + magic = 0xC0BFFFFFFFFFFF64; + } else if (sizeof(uintptr_t) == 4) { + magic = 0xC0BFFFFFFFFFFF32; + } + WriteFully(output_fd, &magic, sizeof(magic)); + + volatile uintptr_t* begin = nullptr; + volatile uintptr_t* end = nullptr; + + GetRawPCs(&begin, &end); + + for (volatile uintptr_t* pc_ptr = begin; pc_ptr < end; pc_ptr++) { + uintptr_t pc = *pc_ptr; + if (pc) { + WriteFully(output_fd, &pc, sizeof(pc)); + } + } + + return {}; +} + } // namespace coverage } // namespace trusty } // namespace android |