/*
* Copyright ( C ) 2020 The Android Open Source Project
*
* 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
*
* http : //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 .
*/
#define TLOG_TAG "sancov-rt"
#include <assert.h>
#include <interface/coverage/aggregator.h>
#include <lib/coverage/common/ipc.h>
#include <lib/coverage/common/record.h>
#include <lib/coverage/common/cov_shm.h>
#include <lib/tipc/tipc.h>
#include <lk/macros.h>
#include <stdbool.h>
#include <stdlib.h>
#include <sys/auxv.h>
#include <sys/mman.h>
#include <trusty_log.h>
#include <uapi/err.h>
#define PAGE_SIZE getauxval(AT_PAGESZ)
typedef uint8_t counter_t;
struct sancov_ctx {
handle_t coverage_srv;
size_t idx;
struct cov_shm mailbox;
struct cov_shm data;
volatile struct coverage_record_header* headers;
volatile counter_t* counters;
volatile uintptr_t* pcs;
size_t record_len;
size_t num_counters;
};
static bool in_sancov = false ;
#define SANCOV_START \
if (in_sancov) { \
return ; \
} \
in_sancov = true ;
#define SANCOV_FINISH in_sancov = false ;
static size_t header_len(void ) {
return sizeof (struct coverage_record_header) + /* COV_START */
sizeof (struct coverage_record_header) + /* COV_8BIT_COUNTERS */
sizeof (struct coverage_record_header) + /* COV_INSTR_PCS */
sizeof (struct coverage_record_header); /* COV_TOTAL_LENGTH */
}
static size_t counters_data_len(size_t num_counters) {
return sizeof (counter_t) * num_counters;
}
static size_t pcs_data_len(size_t num_counters) {
return sizeof (uintptr_t) * num_counters;
}
static size_t record_len(size_t num_counters) {
return header_len() + counters_data_len(num_counters) +
pcs_data_len(num_counters);
}
static void initialize_header(volatile struct coverage_record_header* headers,
size_t num_counters) {
uint32_t offset = header_len();
headers[1 ].type = COV_8BIT_COUNTERS;
headers[1 ].offset = offset;
offset += sizeof (counter_t) * num_counters;
headers[2 ].type = COV_INSTR_PCS;
headers[2 ].offset = offset;
offset += sizeof (uintptr_t) * num_counters;
headers[3 ].type = COV_TOTAL_LENGTH;
headers[3 ].offset = offset;
/* Mark the header as finished */
headers[0 ].offset = 0 ;
headers[0 ].type = COV_START;
}
static int init(struct sancov_ctx* ctx, size_t num_counters) {
int rc;
handle_t chan;
handle_t memref;
struct coverage_aggregator_req req;
struct coverage_aggregator_resp resp;
rc = tipc_connect(&chan, COVERAGE_AGGREGATOR_PORT);
if (rc != NO_ERROR) {
TLOGE("failed (%d) to connect to coverage aggregator service\n" , rc);
return rc;
}
req.hdr.cmd = COVERAGE_AGGREGATOR_CMD_REGISTER;
req.register_args.record_len = round_up(record_len(num_counters), PAGE_SIZE);
rc = coverage_aggregator_rpc(chan, &req, NULL, &resp, &memref);
if (rc != NO_ERROR) {
TLOGE("failed (%d) coverage aggregator RPC\n" , rc);
goto err_rpc;
}
rc = cov_shm_mmap(&ctx->mailbox, memref, resp.register_args.mailbox_len);
if (rc != NO_ERROR) {
TLOGE("failed to mmap() mailbox shared memory\n" );
goto err_mmap;
}
ctx->num_counters = num_counters;
ctx->record_len = record_len(num_counters);
ctx->coverage_srv = chan;
ctx->idx = resp.register_args.idx;
close(memref);
return NO_ERROR;
err_mmap:
close(memref);
err_rpc:
close(chan);
return rc;
}
static int get_record(struct sancov_ctx* ctx) {
int rc;
handle_t memref;
struct coverage_aggregator_req req;
struct coverage_aggregator_resp resp;
size_t shm_len;
if (cov_shm_is_mapped(&ctx->data)) {
cov_shm_munmap(&ctx->data);
}
ctx->counters = NULL;
ctx->pcs = NULL;
req.hdr.cmd = COVERAGE_AGGREGATOR_CMD_GET_RECORD;
rc = coverage_aggregator_rpc(ctx->coverage_srv, &req, NULL, &resp, &memref);
if (rc != NO_ERROR) {
TLOGE("failed (%d) coverage aggregator RPC\n" , rc);
return rc;
}
shm_len = resp.get_record_args.shm_len;
if (shm_len < ctx->record_len) {
TLOGE("not enough shared memory, received: %zu, need at least: %zu\n" ,
shm_len, ctx->record_len);
rc = ERR_BAD_LEN;
goto out;
}
rc = cov_shm_mmap(&ctx->data, memref, resp.get_record_args.shm_len);
if (rc != NO_ERROR) {
TLOGE("failed to mmap() coverage record shared memory\n" );
goto out;
}
ctx->headers = ctx->data.base;
initialize_header(ctx->headers, ctx->num_counters);
ctx->counters = ctx->data.base + header_len();
ctx->pcs = ctx->data.base + header_len() +
counters_data_len(ctx->num_counters);
rc = NO_ERROR;
out:
close(memref);
return rc;
}
static void update_record(struct sancov_ctx* ctx, size_t idx, uintptr_t pc) {
assert(idx < ctx->num_counters);
/*
* Since counters are fixed - sized , there is always a chance of overflowing .
* Cap maximum counter value instead of overflowing .
*/
if (ctx->counters[idx] < (counter_t)(-1 )) {
ctx->counters[idx]++;
}
if (!ctx->pcs[idx]) {
ctx->pcs[idx] = pc - getauxval(AT_BASE);
}
}
static int get_event(struct sancov_ctx* ctx) {
int * app_mailbox = (int *)(ctx->mailbox.base) + ctx->idx;
int event = READ_ONCE(*app_mailbox);
WRITE_ONCE(*app_mailbox, COVERAGE_MAILBOX_EMPTY);
return event;
};
static struct sancov_ctx ctx;
__attribute__((__weak__)) void __sanitizer_cov_trace_pc_guard_init(
uint32_t* start,
uint32_t* stop) {
SANCOV_START;
static size_t num_counters = 0 ;
int rc;
/* Initialize only once */
if (start == stop || *start) {
goto out;
}
for (uint32_t* x = start; x < stop; x++) {
*x = ++num_counters;
}
TLOGI("sancov initialized with %lu counters\n" , num_counters);
rc = init(&ctx, num_counters * sizeof (counter_t));
assert(rc == NO_ERROR);
out:
SANCOV_FINISH;
}
__attribute__((__weak__)) void __sanitizer_cov_trace_pc_guard(uint32_t* guard) {
SANCOV_START;
int rc;
int event = get_event(&ctx);
/* Guards start at 1, and indices start at 0 */
assert(*guard > 0 );
size_t idx = *guard - 1 ;
switch (event) {
case COVERAGE_MAILBOX_EMPTY:
break ;
case COVERAGE_MAILBOX_RECORD_READY:
rc = get_record(&ctx);
assert(rc == NO_ERROR);
break ;
default :
TLOGE("unknown event: %d\n" , event);
abort();
}
if (cov_shm_is_mapped(&ctx.data)) {
uintptr_t ret_address = (uintptr_t)__builtin_return_address(0 );
/* The sancov tool expects the address of the instruction before the
* call to this function on ARM and AArch64. */
#if defined (__aarch64__)
ret_address -= 4 ;
#elif defined (__arm__)
ret_address = (ret_address - 3 ) & (~1 );
#else
#error Only ARM and AArch64 are supported by the Trusty sancov runtime
#endif
update_record(&ctx, idx, ret_address);
}
SANCOV_FINISH;
}
Messung V0.5 in Prozent C=85 H=86 G=85
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-26)
¤
*© Formatika GbR, Deutschland