diff --git a/repos/gems/recipes/pkg/trace_recorder/runtime b/repos/gems/recipes/pkg/trace_recorder/runtime
index ac1937b812..9636c920bc 100644
--- a/repos/gems/recipes/pkg/trace_recorder/runtime
+++ b/repos/gems/recipes/pkg/trace_recorder/runtime
@@ -13,6 +13,7 @@
+
diff --git a/repos/gems/run/trace_recorder.run b/repos/gems/run/trace_recorder.run
new file mode 100644
index 0000000000..f29544d2e9
--- /dev/null
+++ b/repos/gems/run/trace_recorder.run
@@ -0,0 +1,194 @@
+assert_spec linux
+
+# check that babeltrace2 is present
+set babeltrace_missing [catch {
+ spawn babeltrace2 -V
+ expect {
+ {Babeltrace 2.*} { }
+ eof { return }
+ timeout { return }
+ }
+}]
+
+if {$babeltrace_missing} {
+ puts "\nPlease install babeltrace2 on your host system."
+ exit 1;
+}
+
+# check that python-pcapng is present
+set python_pcapng_missing [catch {
+ spawn -noecho sh -c "echo \"import pcapng\" | python"
+ expect {
+ {No module} { return }
+ {not found} { return }
+ eof { }
+ }
+}]
+
+if {$python_pcapng_missing} {
+ puts "\nPlease install python-pcapng on your host system."
+ exit 1;
+}
+
+build { app/ping server/lx_fs }
+
+create_boot_directory
+
+import_from_depot \
+ [depot_user]/src/[base_src] \
+ [depot_user]/src/init \
+ [depot_user]/src/libc \
+ [depot_user]/src/nic_router \
+ [depot_user]/src/report_rom \
+ [depot_user]/src/vfs \
+ [depot_user]/src/linux_rtc_drv \
+ [depot_user]/src/trace_recorder \
+ [depot_user]/raw/trace_recorder \
+ [depot_user]/src/trace_recorder_policy \
+ [depot_user]/src/dynamic_rom
+
+install_config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+exec rm -rf bin/fs
+exec mkdir -p bin/fs
+
+build_boot_image { lx_fs
+ fs
+ ping }
+
+append qemu_args " -nographic "
+
+run_genode_until {Enabled ctf writer for init -> ping -> ep} 20
+set spawn_id [output_spawn_id]
+run_genode_until {.*child "ping" exited with exit value 0.*} 60 $spawn_id
+
+#######################
+# validate CTF output #
+#######################
+
+set ctf_path [exec find bin/fs -type d -name nic_router]
+exec test -s $ctf_path/ep
+
+# check generated trace by reading CTF trace as fast as possible using a dummy output
+exec babeltrace2 $ctf_path --output-format=dummy
+
+
+##########################
+# validate PCAPNG output #
+##########################
+
+# create python script for pcapng parsing
+set fd [open [run_dir]/genode/check_pcapng.py "w"]
+puts $fd {
+import sys
+import pcapng
+
+with open(sys.argv[1], "rb") as fp:
+ scanner = pcapng.FileScanner(fp)
+ for block in pcapng.FileScanner(fp):
+ pass
+}
+close $fd
+
+set pcap_file [exec find bin/fs -name nic_router.pcapng]
+exec test -s $pcap_file
+
+# check generated trace by python script
+exec python [run_dir]/genode/check_pcapng.py $pcap_file
diff --git a/repos/gems/src/lib/trace_recorder/policy/ctf0_pcapng/policy.cc b/repos/gems/src/lib/trace_recorder/policy/ctf0_pcapng/policy.cc
new file mode 100644
index 0000000000..0f1e795d75
--- /dev/null
+++ b/repos/gems/src/lib/trace_recorder/policy/ctf0_pcapng/policy.cc
@@ -0,0 +1,83 @@
+#include
+#include
+#include
+#include
+
+using namespace Genode;
+using namespace Ctf;
+
+enum { MAX_CAPTURE_LEN = 100 };
+
+size_t max_event_size() {
+ return Trace_recorder::Pcapng_event::max_size(MAX_CAPTURE_LEN); }
+
+size_t trace_eth_packet(char *dst, char const *if_name, bool out, char *pkt_data, size_t pkt_len)
+{
+ using namespace Pcapng;
+ Trace_recorder::Pcapng_event *e =
+ new (dst) Trace_recorder::Pcapng_event(Link_type::ETHERNET, if_name, out, pkt_len, pkt_data, MAX_CAPTURE_LEN);
+
+ return e->total_length();
+}
+
+size_t checkpoint(char *dst, char const *name, unsigned long data, void *addr, unsigned char type)
+{
+ size_t len = strlen(name) + 1;
+
+ new (dst) Checkpoint(name, len, data, addr, type);
+
+ return len + sizeof(Checkpoint);
+}
+
+size_t log_output(char *dst, char const *log_message, size_t len) {
+ return 0;
+}
+
+size_t rpc_call(char *dst, char const *rpc_name, Msgbuf_base const &)
+{
+ size_t len = strlen(rpc_name) + 1;
+
+ new (dst) Rpc_call(rpc_name, len);
+
+ return len + sizeof(Rpc_call);
+}
+
+size_t rpc_returned(char *dst, char const *rpc_name, Msgbuf_base const &)
+{
+ size_t len = strlen(rpc_name) + 1;
+
+ new (dst) Rpc_returned(rpc_name, len);
+
+ return len + sizeof(Rpc_returned);
+}
+
+size_t rpc_dispatch(char *dst, char const *rpc_name)
+{
+ size_t len = strlen(rpc_name) + 1;
+
+ new (dst) Rpc_dispatch(rpc_name, len);
+
+ return len + sizeof(Rpc_dispatch);
+}
+
+size_t rpc_reply(char *dst, char const *rpc_name)
+{
+ size_t len = strlen(rpc_name) + 1;
+
+ new (dst) Rpc_reply(rpc_name, len);
+
+ return len + sizeof(Rpc_reply);
+}
+
+size_t signal_submit(char *dst, unsigned const num)
+{
+ new (dst) Signal_submit(num);
+
+ return sizeof(Signal_submit);
+}
+
+size_t signal_receive(char *dst, Signal_context const & context, unsigned num)
+{
+ new (dst) Signal_receive(num, (void*)&context);
+ return 0;
+}
diff --git a/repos/gems/src/lib/trace_recorder/policy/ctf0_pcapng/target.mk b/repos/gems/src/lib/trace_recorder/policy/ctf0_pcapng/target.mk
new file mode 100644
index 0000000000..078d1e4d65
--- /dev/null
+++ b/repos/gems/src/lib/trace_recorder/policy/ctf0_pcapng/target.mk
@@ -0,0 +1,5 @@
+TARGET = ctf0_pcapng
+
+TARGET_POLICY = ctf0_pcapng
+
+include $(PRG_DIR)/../policy.inc