Software APIs
coverage_llvm.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include <stdint.h>
6 
7 #include "external/llvm_compiler_rt/lib/profile/InstrProfiling.h"
8 #include "sw/device/lib/base/crc32.h"
11 #include "sw/device/lib/testing/test_framework/coverage.h"
12 
13 /**
14  * When the linker finds a definition of this symbol, it knows to skip loading
15  * the object which contains the profiling runtime's static initializer. See
16  * https://clang.llvm.org/docs/SourceBasedCodeCoverage.html#using-the-profiling-runtime-without-static-initializers
17  * for more information.
18  */
19 int __llvm_profile_runtime;
20 
21 /**
22  * Coverage buffer in `.bss` to avoid stack issues.
23  */
24 static char buf[0x8000] = {0};
25 
26 /**
27  * Sends the given buffer as a hex string over UART.
28  *
29  * Lines are limited to 80 characters. Longer buffers will be broken to multiple
30  * lines.
31  */
32 void coverage_send_buffer(void) {
33  // It looks like we don't have a way to read the profile buffer incrementally.
34  // Thus, we define the following buffer.
35  // Write the profile buffer to the buffer defined above.
36  uint64_t buf_size_u64 = __llvm_profile_get_size_for_buffer();
37  if (buf_size_u64 > sizeof(buf)) {
38  LOG_ERROR("ERROR: LLVM profile buffer is too large: %u bytes.",
39  (uint32_t)buf_size_u64);
41  } else {
42  size_t buf_size = (size_t)buf_size_u64;
43  __llvm_profile_write_buffer(buf);
44  // Send the buffer along with its length and CRC32.
45  uint32_t checksum = crc32(buf, buf_size);
46  LOG_INFO("LLVM profile data (length: %u bytes, CRC32: 0x%08x):",
47  (uint32_t)buf_size, checksum);
48  enum {
49  kBytesPerLine = 40,
50  // Print one less byte in the first line to account for "0x".
51  kBytesFirstLine = kBytesPerLine - 1,
52  };
53  size_t bytes_this_line =
54  buf_size < kBytesFirstLine ? buf_size : kBytesFirstLine;
55  char *read_ptr = (char *)buf + buf_size - bytes_this_line;
56  LOG_INFO("0x%!x", bytes_this_line, read_ptr);
57  buf_size -= bytes_this_line;
58  while (buf_size > 0) {
59  size_t bytes_this_line =
60  buf_size < kBytesPerLine ? buf_size : kBytesPerLine;
61  read_ptr -= bytes_this_line;
62  LOG_INFO("%!x", bytes_this_line, read_ptr);
63  buf_size -= bytes_this_line;
64  }
65  }
66  // Send `EOT` so that `cat` can exit. Note that this requires enabling
67  // `icanon` using `stty`.
68  base_printf("\x4");
69  base_printf("\r\n");
70 }