blob: b5c331ed2c5f6d65e326fa0182e0b8858a005c55 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include <stdint.h>
#include "external/llvm_compiler_rt/lib/profile/InstrProfiling.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/runtime/print.h"
#include "sw/device/lib/testing/test_framework/coverage.h"
#include "sw/device/silicon_creator/lib/crc32.h"
/**
* When the linker finds a definition of this symbol, it knows to skip loading
* the object which contains the profiling runtime's static initializer. See
* https://clang.llvm.org/docs/SourceBasedCodeCoverage.html#using-the-profiling-runtime-without-static-initializers
* for more information.
*/
int __llvm_profile_runtime;
/**
* Coverage buffer in `.bss` to avoid stack issues.
*/
static char buf[0x8000] = {0};
/**
* Sends the given buffer as a hex string over UART.
*
* Lines are limited to 80 characters. Longer buffers will be broken to multiple
* lines.
*/
void coverage_send_buffer(void) {
// It looks like we don't have a way to read the profile buffer incrementally.
// Thus, we define the following buffer.
// Write the profile buffer to the buffer defined above.
uint64_t buf_size_u64 = __llvm_profile_get_size_for_buffer();
if (buf_size_u64 > sizeof(buf)) {
LOG_ERROR("ERROR: LLVM profile buffer is too large: %u bytes.",
(uint32_t)buf_size_u64);
} else {
size_t buf_size = (size_t)buf_size_u64;
__llvm_profile_write_buffer(buf);
// Send the buffer along with its length and CRC32.
uint32_t checksum = crc32(buf, buf_size);
LOG_INFO("LLVM profile data (length: %u bytes, CRC32: 0x%08x):",
(uint32_t)buf_size, checksum);
enum {
kBytesPerLine = 40,
// Print one less byte in the first line to account for "0x".
kBytesFirstLine = kBytesPerLine - 1,
};
size_t bytes_this_line =
buf_size < kBytesFirstLine ? buf_size : kBytesFirstLine;
char *read_ptr = (char *)buf + buf_size - bytes_this_line;
LOG_INFO("0x%!x", bytes_this_line, read_ptr);
buf_size -= bytes_this_line;
while (buf_size > 0) {
size_t bytes_this_line =
buf_size < kBytesPerLine ? buf_size : kBytesPerLine;
read_ptr -= bytes_this_line;
LOG_INFO("%!x", bytes_this_line, read_ptr);
buf_size -= bytes_this_line;
}
}
// Send `EOT` so that `cat` can exit. Note that this requires enabling
// `icanon` using `stty`.
base_printf("\x4");
base_printf("\r\n");
}