Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions demo/automated-demo-strip.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/bin/bash
# Automated xcover demo for asciinema
# Run as: sudo bash automated-demo.sh

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEMO_APP="./demo-app"
XCOVER="xcover"
PATH="/home/linuxbrew/.linuxbrew/bin:${PATH}"
export $PATH

function main() {
# Check if running as root
if [ "$EUID" -ne 0 ]; then
echo "Please run as root: sudo bash $0"
exit 1
fi

clear
runCmd "# === xcover: Functional Test Coverage Profiler ==="
runCmd "# Profile coverage without instrumenting your binaries!"
echo
runCmd "# Let's test a demo C application"
runCmd "bat demo-app.c"
sleep 2
clear
runCmd "gcc -O0 -o demo-app demo-app.c"
runCmd "ls demo-app"
runCmd "readelf --symbols demo-app | wc -l"
runCmd "# Let's strip the binary, because this must be a production binary"
runCmd "strip --strip-all demo-app"
runCmd "readelf --symbols demo-app | wc -l"
runCmd "# Start the profiler before running the functional tests"
runCmd "xcover run --detach --path demo-app --include '^main\.'"
runCmd "# Wait for the profiler to be ready"
runCmd "xcover wait"
runCmd "# Run test scenarios - xcover is tracing all function calls"
clear
runCmd "./demo-app add"
runCmd "./demo-app multiply"
runCmd "./demo-app greet"
runCmd "# Now let's stop the profiler"
clear
runCmd "xcover stop"
runCmd "# Collect the coverage results:"
runCmd "cat xcover-report.json | jq '.cov_by_func'"
runCmd "cat xcover-report.json | jq '.funcs_traced | length'"
runCmd "cat xcover-report.json | jq '.funcs_ack | length'"
runCmd "cat xcover-report.json | jq"
runCmd "# Coverage profiled without source code changes or recompilation on production binaries!"
}

function runCmd() {
cmd=$1
echo "$ ${cmd}"
eval "${cmd}"
sleep 2
}

main $@
72 changes: 72 additions & 0 deletions demo/demo-app.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* demo-app.c — xcover userspace BPF demo target
*
* A simple C program with several distinct functions so xcover can measure
* which ones were executed. Build with:
*
* gcc -O0 -o demo-app demo-app.c
*
* -O0 ensures every function gets a proper prologue that Frida-GUM can
* intercept (avoids trivially short leaf functions).
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int add(int a, int b) {
return a + b;
}

int multiply(int a, int b) {
return a * b;
}

int subtract(int a, int b) {
return a - b;
}

int divide(int a, int b) {
if (b == 0) {
fprintf(stderr, "division by zero\n");
return 0;
}
return a / b;
}

void greet(const char *name) {
printf("Hello, %s!\n", name);
}

int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: demo-app <command>\n");
fprintf(stderr, "Commands: add, multiply, subtract, divide, greet, all\n");
return 1;
}

const char *cmd = argv[1];

if (strcmp(cmd, "add") == 0) {
printf("10 + 20 = %d\n", add(10, 20));
} else if (strcmp(cmd, "multiply") == 0) {
printf("5 * 6 = %d\n", multiply(5, 6));
} else if (strcmp(cmd, "subtract") == 0) {
printf("30 - 10 = %d\n", subtract(30, 10));
} else if (strcmp(cmd, "divide") == 0) {
printf("100 / 5 = %d\n", divide(100, 5));
} else if (strcmp(cmd, "greet") == 0) {
greet("xcover");
} else if (strcmp(cmd, "all") == 0) {
printf("Running all functions:\n");
printf("Add: %d\n", add(10, 20));
printf("Multiply: %d\n", multiply(5, 6));
printf("Subtract: %d\n", subtract(30, 10));
printf("Divide: %d\n", divide(100, 5));
greet("xcover");
} else {
fprintf(stderr, "Unknown command: %s\n", cmd);
return 1;
}

return 0;
}
Loading
Loading