When generating syscall wrappers, call a tracing macro with the id, name, and all parameters of the syscall as params when entering and leaving the syscall. This can be disabled in certain call sites by defining DISABLE_SYSCALL_TRACING which is useful for certain tracing implementations which require syscalls themselves to work. Notably some syscalls *cannot* be automatically traced this way and headers where exclusions are set are in the gen_syscall.py as notracing. Includes a systemview and test format implementation. Tested with systemview, usb, and uart backends with the string formatter using the tracing sample app. Debugging the trace wrapper can be aided by setting the TRACE_DIAGNOSTIC env var and rebuilding from scratch, a warning is issued for every instance a syscall is traced. Automatically generating a name mapping for SYSVIEW_Zephyr.txt is a future item as is documenting how to capture and use the tracing data generated. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
105 lines
2.1 KiB
C
105 lines
2.1 KiB
C
/*
|
|
* Copyright (c) 2019 Intel corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/* Disable syscall tracing for all calls from this compilation unit to avoid
|
|
* undefined symbols as the macros are not expanded recursively
|
|
*/
|
|
#define DISABLE_SYSCALL_TRACING
|
|
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
#include <kernel.h>
|
|
#include <device.h>
|
|
#include <drivers/uart.h>
|
|
#include <sys/__assert.h>
|
|
#include <tracing_core.h>
|
|
#include <tracing_buffer.h>
|
|
#include <tracing_backend.h>
|
|
|
|
|
|
static const struct device *tracing_uart_dev;
|
|
|
|
#ifdef CONFIG_TRACING_HANDLE_HOST_CMD
|
|
static void uart_isr(const struct device *dev, void *user_data)
|
|
{
|
|
int rx;
|
|
uint8_t byte;
|
|
static uint8_t *cmd;
|
|
static uint32_t length, cur;
|
|
|
|
ARG_UNUSED(user_data);
|
|
|
|
while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
|
|
if (!uart_irq_rx_ready(dev)) {
|
|
continue;
|
|
}
|
|
|
|
rx = uart_fifo_read(dev, &byte, 1);
|
|
if (rx < 0) {
|
|
uart_irq_rx_disable(dev);
|
|
return;
|
|
}
|
|
|
|
if (!cmd) {
|
|
length = tracing_cmd_buffer_alloc(&cmd);
|
|
}
|
|
|
|
if (!isprint(byte)) {
|
|
if (byte == '\r') {
|
|
cmd[cur] = '\0';
|
|
tracing_cmd_handle(cmd, cur);
|
|
cmd = NULL;
|
|
cur = 0U;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (cur < length - 1) {
|
|
cmd[cur++] = byte;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void tracing_backend_uart_output(
|
|
const struct tracing_backend *backend,
|
|
uint8_t *data, uint32_t length)
|
|
{
|
|
for (uint32_t i = 0; i < length; i++) {
|
|
uart_poll_out(tracing_uart_dev, data[i]);
|
|
}
|
|
}
|
|
|
|
static void tracing_backend_uart_init(void)
|
|
{
|
|
tracing_uart_dev =
|
|
device_get_binding(CONFIG_TRACING_BACKEND_UART_NAME);
|
|
__ASSERT(tracing_uart_dev, "uart backend binding failed");
|
|
|
|
#ifdef CONFIG_TRACING_HANDLE_HOST_CMD
|
|
uart_irq_rx_disable(tracing_uart_dev);
|
|
uart_irq_tx_disable(tracing_uart_dev);
|
|
|
|
uart_irq_callback_set(tracing_uart_dev, uart_isr);
|
|
|
|
while (uart_irq_rx_ready(tracing_uart_dev)) {
|
|
uint8_t c;
|
|
|
|
uart_fifo_read(tracing_uart_dev, &c, 1);
|
|
}
|
|
|
|
uart_irq_rx_enable(tracing_uart_dev);
|
|
#endif
|
|
}
|
|
|
|
const struct tracing_backend_api tracing_backend_uart_api = {
|
|
.init = tracing_backend_uart_init,
|
|
.output = tracing_backend_uart_output
|
|
};
|
|
|
|
TRACING_BACKEND_DEFINE(tracing_backend_uart, tracing_backend_uart_api);
|