--- /dev/null
+barectf-tracepoint-barectf-linux-fs
+barectf-tracepoint-barectf-qemu-arm-uart
+barectf-tracepoint-lttng-ust
+ctf-linux-fs
+ctf-qemu-arm-uart
--- /dev/null
+BARECTF ?= barectf
+ARCH = arm-none-eabi
+
+RM = rm -rf
+MKDIR = mkdir -p
+CC = $(ARCH)-gcc
+
+VERSION = qemu-arm-uart
+CPU=arm926ej-s
+EXTRA_DIR = ../../../extra
+CFLAGS = -DWITH_QEMU_ARM_UART=1 -ffunction-sections -mcpu=$(CPU) -O2 -Wall -pedantic -std=gnu99 -I$(EXTRA_DIR) -I.
+LDFLAGS= -T barectf-platform-$(VERSION).ld -lc -lnosys
+
+TARGET = barectf-tracepoint-barectf-$(VERSION)
+OBJS = $(TARGET).o barectf-$(VERSION).o barectf-platform-$(VERSION).o
+TRACEDIR = ctf-$(VERSION)
+
+.PHONY: all clean sim
+
+all: $(TARGET)
+
+$(TRACEDIR):
+ $(MKDIR) $@
+
+$(TARGET): $(OBJS)
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+$(TRACEDIR)/metadata barectf-bitfield.h barectf.h barectf.c: config.yaml $(TRACEDIR)
+ $(BARECTF) $< -m $(TRACEDIR)
+
+barectf-$(VERSION).o: barectf.c
+ $(CC) -o $@ $(CFLAGS) -c $<
+
+barectf-platform-$(VERSION).o: barectf-platform-$(VERSION).c
+ $(CC) $(CFLAGS) -c $<
+
+$(TARGET).o: barectf-tracepoint.c barectf-tracepoint-$(VERSION).h barectf.h barectf-bitfield.h
+ $(CC) -o $@ $(CFLAGS) -c $<
+
+clean:
+ $(RM) $(TARGET) $(OBJS) $(TRACEDIR)
+ $(RM) barectf.h barectf-bitfield.h barectf.c
+
+sim: $(TARGET)
+ ./barectf-tracepoint-barectf-qemu-arm-uart.sh
# Example using `barectf-tracepoint.h`
-This example is based on the [linux-fs-simple example](../linux-fs-simple),
-but it uses the `tracepoint()` macro defined in
+This example is based on the [linux-fs-simple example](../linux-fs-simple)
+example, but it uses the `tracepoint()` macro defined in
[`barectf-tracepoint.h`](../../../extra/barectf-tracepoint.h) instead of
calling the generated tracing functions directly.
This example also shows the compatibility with
[LTTng-UST](http://lttng.org/) that this `barectf-tracepoint.h` allows.
+This example also includes a QEMU ARM target to simulate barectf used by
+a true bare-metal application.
-## Building
+All the targets of this example use the same application source:
+[`barectf-tracepoint.c`](barectf-tracepoint.c).
-To build both barectf and LTTng-UST targets, make sure both tools are
-installed, and do:
- make
+## barectf tracing
-To build only the example using barectf:
+### linux-fs platform
- make -f Makefile.barectf-linux-fs
+#### Building
-To build only the example using LTTng-UST:
+Do:
- make -f Makefile.lttng-ust
+ make -f Makefile.barectf-linux-fs
-## barectf tracing
+#### Running
Run this example:
./barectf-tracepoint-barectf-linux-fs this argument and this one will be recorded
+### QEMU ARM platform
+
+#### Building
+
+To build this example, you need an ARM cross-compiler toolchain
+(`gcc-arm-none-eabi`, `binutils-arm-none-eabi`, and
+`libnewlib-arm-none-eabi` Ubuntu packages), then do:
+
+ make -f Makefile.barectf-qemu-arm-uart
+
+
+#### Running
+
+To run this example, you need `qemu-system-arm` (`qemu-system-arm`
+Ubuntu package).
+
+Run this example:
+
+ make -f Makefile.barectf-qemu-arm-uart sim
+
+The complete CTF trace is written to the `ctf-qemu-arm-uart` directory.
+
+
+#### What happens when running?
+
+When you run this example, here's what happens:
+
+ 1. The `barectf-tracepoint-barectf-qemu-arm-uart.sh` Bash script
+ is executed.
+ 2. This Bash script executes `qemu-system-arm` with the appropriate
+ options to simulate the bare-metal application on an ARM system.
+ The simulated board is a Versatile platform baseboard from ARM. The
+ simulated CPU is an ARM926EJ-S. This is a 2001 ARM9 core
+ implementing the ARMv5TE architecture. QEMU is set to execute the
+ `barectf-tracepoint-barectf-qemu-arm-uart` ELF file (previously
+ built), and to connect the board's first UART with QEMU's standard
+ input/output streams, and the board's second UART to the
+ `ctf-qemu-arm-uart/stream` file (output only). The Bash script
+ reads each line printed by QEMU, and kills the QEMU process when
+ it reads the ending line written by the bare-metal application.
+ 3. QEMU starts. Eventually, the bare-metal application's
+ `main()` function is called.
+ 4. `main()` calls `init_tracing()`, which for this example, calls
+ `barectf_platform_qemu_arm_uart_init()`. This is a custom barectf
+ platform created specifically for this example. The platform
+ initializes a barectf context to get its clock source from a timer
+ on the simulated board, and to flush its packets by writing the
+ bytes to the second UART (which is connected to the
+ `ctf-qemu-arm-uart/stream` file by QEMU). The platform uses a
+ global buffer of 4 kiB to hold the current packet.
+ 5. `main()` calls `trace_stuff()` which contains the `tracepoint()`
+ macro invocations. Events are recorded to the current packet by
+ the barectf machinery. When this packet is full, it is flushed
+ by the platform to the second UART.
+ 6. `main()` calls `fini_tracing()`, which calls
+ `barectf_platform_qemu_arm_uart_fini()`, which prints the
+ ending line that `barectf-tracepoint-barectf-qemu-arm-uart.sh`
+ is waiting for to kill QEMU.
+
+
## LTTng-UST tracing
+### Building
+
+Make sure [LTTng-UST](http://lttng.org/) is installed.
+
+Do:
+
+ make -f Makefile.lttng-ust
+
+
+### Running
+
Create an LTTng tracing session:
lttng create my-session
--- /dev/null
+#include <stdint.h>
+#include <stdio.h>
+#include <barectf.h>
+
+#include "barectf-platform-qemu-arm-uart.h"
+
+#define BUF_SIZE 4096
+#define TIMER_CTRL_32BIT (1 << 1)
+#define TIMER_CTRL_ENABLE (1 << 7)
+
+volatile uint32_t * const uart0 = (uint32_t *) 0x101f1000;
+volatile uint32_t * const uart1 = (uint32_t *) 0x101f2000;
+volatile uint32_t * const timer0_ctrl = (uint32_t *) 0x101e2008;
+volatile uint32_t * const timer0_value = (uint32_t *) 0x101e2004;
+
+static struct barectf_default_ctx barectf_ctx;
+
+static uint8_t buf[BUF_SIZE];
+
+static uint64_t get_clock(void* data)
+{
+ return (uint64_t) -*timer0_value;
+}
+
+static void flush_packet(void)
+{
+ size_t i;
+
+ /* flush packet to UART 1 */
+ for (i = 0; i < BUF_SIZE; ++i) {
+ *uart1 = (uint32_t) buf[i];
+ }
+}
+
+static int is_backend_full(void *data)
+{
+ return 0;
+}
+
+static void open_packet(void *data)
+{
+ barectf_default_open_packet(&barectf_ctx);
+}
+
+static void close_packet(void *data)
+{
+ /* close packet now */
+ barectf_default_close_packet(&barectf_ctx);
+
+ /* flush current packet */
+ flush_packet();
+}
+
+void barectf_platform_qemu_arm_uart_init(void)
+{
+ struct barectf_platform_callbacks cbs = {
+ .default_clock_get_value = get_clock,
+ .is_backend_full = is_backend_full,
+ .open_packet = open_packet,
+ .close_packet = close_packet,
+ };
+
+ /* enable/start timer (clock source) */
+ *timer0_ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE;
+
+ /* initialize barectf context */
+ barectf_init(&barectf_ctx, buf, BUF_SIZE, cbs, NULL);
+
+ /* open first packet */
+ open_packet(NULL);
+
+ /* indicate that tracing is starting */
+ puts("tracing: starting");
+}
+
+void barectf_platform_qemu_arm_uart_fini(void)
+{
+ /* close last packet if it contains at least one event */
+ if (barectf_packet_is_open(&barectf_ctx) &&
+ !barectf_packet_is_empty(&barectf_ctx)) {
+ close_packet(NULL);
+ }
+
+ /* indicate that tracing is done */
+ puts("tracing: done");
+}
+
+struct barectf_default_ctx *barectf_platform_qemu_arm_uart_get_barectf_ctx()
+{
+ return &barectf_ctx;
+}
+
+#define STDOUT 1
+#define STDERR 2
+
+/* custom write "syscall" for newlib's stdio: write to UART 0 */
+int _write(int file, char *ptr, int len) {
+ if (file == STDOUT || file == STDERR) {
+ int i;
+
+ for (i = 0; i < len; i++) {
+ *uart0 = (uint32_t) ptr[i];
+ }
+ }
+
+ return 0;
+}
--- /dev/null
+#ifndef _BARECTF_PLATFORM_QEMU_ARM_UART
+#define _BARECTF_PLATFORM_QEMU_ARM_UART
+
+#include <barectf.h>
+
+void barectf_platform_qemu_arm_uart_init(void);
+void barectf_platform_qemu_arm_uart_fini(void);
+struct barectf_default_ctx *barectf_platform_qemu_arm_uart_get_barectf_ctx(void);
+
+#endif /* _BARECTF_PLATFORM_QEMU_ARM_UART */
--- /dev/null
+MEMORY {
+ SDRAM (XRW) : ORIGIN = 0x00000000, LENGTH = 0x08000000
+}
+
+/* heap size */
+heap_size = 0x10000;
+
+/* define stack base (grows downwards), used in newlib's crt0.S */
+__stack = ORIGIN(SDRAM) + LENGTH(SDRAM);
+
+/* libc's entry point */
+ENTRY(_mainCRTStartup);
+
+SECTIONS {
+ /* QEMU starts executing at 0x10000 */
+ . = 0x10000;
+
+ .text : {
+ *(.text)
+ *(.text.*)
+ } > SDRAM
+
+ .data : {
+ *(.data)
+ *(.data.*)
+ } > SDRAM
+
+ .bss : {
+ __bss_start__ = .;
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ __bss_end__ = .;
+ } > SDRAM
+
+ /* "end" symbol needed by newlib's _sbrk */
+ end = .;
+}
--- /dev/null
+#!/usr/bin/env bash
+
+qemu-system-arm -M versatilepb -m 128M -nographic -monitor none \
+ -kernel barectf-tracepoint-barectf-qemu-arm-uart \
+ -serial stdio -serial file:ctf-qemu-arm-uart/stream |
+{
+ while read line; do
+ echo "$line"
+
+ if [ x"$line" = x"tracing: done" ]; then
+ pkill -nf file:ctf-qemu-arm-uart
+ fi
+ done
+}
--- /dev/null
+#ifndef _BARECTF_TRACEPOINT_QEMU_ARM_UART
+#define _BARECTF_TRACEPOINT_QEMU_ARM_UART
+
+#include <barectf-platform-qemu-arm-uart.h>
+
+/*
+ * Include generated barectf header file: this contains the prefix and
+ * default stream name to be used by the tracepoint() macro.
+ */
+#include "barectf.h"
+
+/* define how the context is to be found by tracepoint() calls */
+#define BARECTF_TRACEPOINT_CTX (global_barectf_ctx)
+
+/* then include this: */
+#include <barectf-tracepoint.h>
+
+/* global barectf context (default stream) */
+static struct barectf_default_ctx *global_barectf_ctx;
+
+/* init function for this version */
+static void init_tracing(void)
+{
+ /* initialize platform */
+ barectf_platform_qemu_arm_uart_init();
+ global_barectf_ctx = barectf_platform_qemu_arm_uart_get_barectf_ctx();
+}
+
+/* finalization function for this version */
+static void fini_tracing(void)
+{
+ /* finalize platform */
+ barectf_platform_qemu_arm_uart_fini();
+}
+
+#endif /* _BARECTF_TRACEPOINT_QEMU_ARM_UART */
#if defined(WITH_LTTNG_UST)
#include "barectf-tracepoint-lttng-ust.h"
+#elif defined(WITH_QEMU_ARM_UART)
+#include "barectf-tracepoint-qemu-arm-uart.h"
#else
#include "barectf-tracepoint-linux-fs.h"
#endif
/* record 40000 events */
for (i = 0; i < 5000; ++i) {
+ str = argv[i % argc];
tracepoint(barectf_tp, simple_uint32, i * 1500);
tracepoint(barectf_tp, simple_int16, -i * 2);
tracepoint(barectf_tp, simple_float, (float) i / 1.23);
-
- if (argc > 0) {
- str = argv[i % argc];
- } else {
- str = "hello there!";
- }
-
tracepoint(barectf_tp, simple_string, str);
tracepoint(barectf_tp, simple_enum, RUNNING);
tracepoint(barectf_tp, a_few_fields, -1, 301, -3.14159,
}
}
+#define NUM_STRINGS 5
+
+static char *strings[] = {
+ "orange",
+ "mandarine",
+ "lemon",
+ "lime",
+ "grapefruit",
+};
+
int main(int argc, char *argv[])
{
init_tracing();
+
+ if (argc <= 1) {
+ /* use static strings if there's nothing interesting in argv */
+ argc = NUM_STRINGS;
+ argv = strings;
+ }
+
trace_stuff(argc, argv);
fini_tracing();