diff --git a/NEWS.md b/NEWS.md
index 1327165..461758e 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,15 @@
+## 0.9 (2022-01-19)
+
+* With `-t`, print time when process execed.
+* Fix `-p` flag, which was a regression in 0.8.
+* Quit when parent specified in `-p` exits.
+* Fix likely root cause for pid_db overflow.
+
+## 0.8 (2021-08-05)
+
+* extrace: add option -Q to suppress runtime errors.
+* Small fixes.
+
 ## 0.7 (2019-02-08)
 
 * pwait: detect and warn for non-existing PID.
diff --git a/debian/changelog b/debian/changelog
index 09f0a30..8ccb419 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+extrace (0.9+git20220416.1.9a0e8ce+ds-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Fri, 26 Aug 2022 00:49:30 -0000
+
 extrace (0.7-2) unstable; urgency=low
 
   [ nicoo ]
diff --git a/extrace-bpf b/extrace-bpf
new file mode 100755
index 0000000..d72f847
--- /dev/null
+++ b/extrace-bpf
@@ -0,0 +1,134 @@
+#!/usr/bin/env ruby
+
+require 'optparse'
+require 'etc'
+
+# TODO: -p / cmd... (how?)
+
+BPF = <<'EOF'
+BEGIN {
+  printf("SEP2\n");
+}
+tracepoint:syscalls:sys_enter_execve {
+  printf("%ld +%d %d", elapsed, pid, uid);
+  join(args->argv, "SEP1");
+  printf("SEP2\n");
+}
+tracepoint:syscalls:sys_enter_exit_group {
+  printf("%ld -%d %d\nSEP2\n", elapsed, pid, args->error_code);
+}
+EOF
+
+SEP1 = "\xff\xff\xff".b
+SEP2 = "\xff\xfe\xff".b
+
+Procc = Struct.new(:pid, :uid, :name, :args, :start_time, :ppid, :depth)
+
+PIDS = {}
+
+def pid_depth(pid)
+  procc = PIDS[pid]
+  if procc && procc.depth
+    procc.depth
+  else
+    procc = (PIDS[pid] ||= Procc.new(pid))
+    stat = File.read("/proc/#{pid}/stat").b
+    if stat =~ /.*\) . (\d+)/
+      ppid = $1.to_i
+      if ppid == 0
+        return 0
+      else
+        procc.ppid = ppid
+        procc.depth = pid_depth(ppid) + 1
+      end
+    end
+  end
+rescue Errno::ENOENT, Errno::ESRCH => e
+  puts "failed to get pid #{pid} info: #{e}"
+  0
+end
+
+def fmtcmd(c)
+  if c.empty? || c =~ /[\001-\040`^#*\[\]|\\?${}()'\"<>&;\177]/
+    "'" + c.gsub("'", "'\\''").gsub("\n", "'$'\\n''") + "'"
+  else
+    c
+  end
+end
+
+def fmtcmds(cmds)
+  cmds.map { |cmd| fmtcmd(cmd) }.join(' ')
+end
+
+params = ARGV.getopts("deflqtu")
+dflag = params['d']
+eflag = params['e']
+fflag = params['f']
+lflag = params['l']
+qflag = params['q']
+tflag = params['t']
+uflag = params['u']
+
+IO.popen(["bpftrace", "-e", BPF.gsub("SEP1", SEP1).gsub("SEP2", SEP2)],
+         "r:BINARY") { |output|
+  while line = output.gets("\n#{SEP2}\n")
+    line.chomp!("\n#{SEP2}\n")
+    case line
+    when /\A(\d+) \+(\d+) (\d+)/
+      elapsed = $1.to_i
+      pid = $2.to_i
+      uid = $3.to_i
+      comm = $'.split(SEP1)
+      
+      next  unless comm.first
+
+      PIDS[pid] = Procc.new(pid, uid, comm.first, comm[1..-1], elapsed)
+
+      print "  " * pid_depth(pid)  unless fflag
+      print pid
+      print "+"  if tflag
+      print " "
+      print "<#{Etc.getpwuid(uid).name}> "  if uflag
+      if dflag
+        print (File.readlink("/proc/#{pid}/cwd") rescue "-")
+        print " % "
+      end
+      comm[0] = (File.readlink("/proc/#{pid}/exe") rescue comm[0])  if lflag
+      if qflag
+        print fmtcmd(comm[0])
+      else
+        print fmtcmds(comm)
+      end
+      if eflag
+        print "   "
+        print (File.read("/proc/#{pid}/environ") rescue "-").
+                b.split("\x00").map { |e|
+          if e =~ /\A[a-zA-Z0-9_]+=/
+            $& + fmtcmd($')
+          else
+            fmtcmd(e)
+          end
+        }.join(" ")
+      end
+      puts
+    when /\A(\d+) -(\d+) (\d+)/
+      elapsed = $1.to_i
+      pid = $2.to_i
+      status = $3.to_i
+
+      if procc = PIDS[pid]
+        PIDS.delete(pid)
+        next  unless procc.name
+        if tflag
+          dur = (elapsed - procc.start_time) / 1e9
+          print "  " * pid_depth(pid)  unless fflag
+          puts "#{pid}- #{procc.name} exited status=#{status} time=#{"%.3f" % dur}s"
+        end
+      end
+    when /^Attaching/
+      # ignore
+    else
+      warn "can't parse #{line}"
+    end
+  end
+}
diff --git a/extrace.1 b/extrace.1
index 7cec42d..3a36882 100644
--- a/extrace.1
+++ b/extrace.1
@@ -6,7 +6,7 @@
 .Nd trace exec() calls system-wide
 .Sh SYNOPSIS
 .Nm
-.Op Fl deflqtu
+.Op Fl deflqQtu
 .Op Fl o Ar file
 .Op Fl p Ar pid | cmd\ ...
 .Sh DESCRIPTION
@@ -33,6 +33,8 @@ is shown.
 Suppress printing of
 .Xr exec 3
 arguments.
+.It Fl Q
+Suppress printing of runtime errors.
 .It Fl t
 Also display process exit status and duration.
 .It Fl u
diff --git a/extrace.c b/extrace.c
index 5e01efc..2e457f9 100644
--- a/extrace.c
+++ b/extrace.c
@@ -3,7 +3,7 @@
  * Requires CONFIG_CONNECTOR=y and CONFIG_PROC_EVENTS=y.
  * Requires root or "setcap cap_net_admin+ep extrace".
  *
- * Usage: extrace [-deflqu] [-o FILE] [-p PID|CMD...]
+ * Usage: extrace [-deflqQtu] [-o FILE] [-p PID|CMD...]
  * default: show all exec(), globally
  * -p PID   only show exec() descendant of PID
  * CMD...   run CMD... and only show exec() descendant of it
@@ -13,6 +13,7 @@
  * -f       flat output: no indentation
  * -l       print full path of argv[0]
  * -q       don't print exec() arguments
+ * -Q       don't print error messages
  * -u       print user of process
  *
  * Copyright (C) 2014-2019 Leah Neukirchen <leah@vuxu.org>
@@ -66,6 +67,7 @@
 #include <limits.h>
 #include <pwd.h>
 #include <signal.h>
+#include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -90,16 +92,18 @@
 #define CMDLINE_MAX 32768
 #define CMDLINE_DB_MAX 32
 pid_t parent = 1;
+pid_t child;
 int flat = 0;
 int run = 0;
 int full_path = 0;
 int show_args = 1;
+int show_errors = 1;
 int show_cwd = 0;
 int show_env = 0;
 int show_exit = 0;
 int show_user = 0;
 FILE *output;
-sig_atomic_t quit = 0;
+volatile sig_atomic_t quit = 0;
 #define CPU_MAX 4096
 uint32_t last_seq[CPU_MAX];
 
@@ -111,6 +115,16 @@ struct {
 	char cmdline[CMDLINE_DB_MAX];
 } pid_db[PID_DB_SIZE];
 
+static void
+print_runtime_error(const char* fmt, ...) {
+	va_list ap;
+	if (show_errors) {
+		va_start(ap, fmt);
+		vfprintf(stderr, fmt, ap);
+		va_end(ap);
+	}
+}
+
 static int
 open_proc_dir(pid_t pid) {
 	char name[48];
@@ -127,6 +141,9 @@ pid_depth(pid_t pid)
 	char *s;
 	int fd, d, i;
 
+	if (pid == 1 && parent == 1)
+		return 0;
+
 	snprintf(name, sizeof name, "/proc/%d/stat", pid);
 
 	if ((fd = open(name, O_RDONLY)) < 0)
@@ -226,10 +243,16 @@ sig2name(int sig)
 static void
 sigchld(int sig)
 {
+        int old_errno = errno;
+	pid_t pid;
+
 	(void)sig;
-	while (waitpid(-1, NULL, WNOHANG) > 0)
-		;
-	quit = 1;
+
+	while ((pid = waitpid(-1, NULL, WNOHANG)) > 0)
+		if (pid == child)
+			quit = 1;
+
+	errno = old_errno;
 }
 
 static void
@@ -303,7 +326,7 @@ handle_msg(struct cn_msg *cn_hdr)
 		int i = 0;
 		int proc_dir_fd = open_proc_dir(pid);
 		if (proc_dir_fd < 0) {
-			fprintf(stderr,
+			print_runtime_error(
 			    "extrace: process vanished before notification: pid %d\n",
 			    pid);
 			return;
@@ -329,14 +352,16 @@ handle_msg(struct cn_msg *cn_hdr)
 
 		d = pid_depth(pid);
 		if (d < 0) {
-			if (*cmdline) {
-				fprintf(stderr,
-				    "extrace: process vanished before we found its parent: pid %d: %s\n",
-				    pid, cmdline);
-			} else {
-				fprintf(stderr,
-				    "extrace: process vanished without a name: pid %d\n",
-				    pid);
+			if (parent == 1) {
+				if (*cmdline) {
+					print_runtime_error(
+					    "extrace: process vanished before we found its parent: pid %d: %s\n",
+					    pid, cmdline);
+				} else {
+					print_runtime_error(
+					    "extrace: process vanished without a name: pid %d\n",
+					    pid);
+				}
 			}
 			close(proc_dir_fd);
 			return;
@@ -344,12 +369,21 @@ handle_msg(struct cn_msg *cn_hdr)
 
 		if (show_exit || !flat) {
 			for (i = 0; i < PID_DB_SIZE - 1; i++)
-				if (pid_db[i].pid == 0)
+				if (pid_db[i].pid == 0 || pid_db[i].pid == pid)
 					break;
 			if (i == PID_DB_SIZE - 1)
-				fprintf(stderr, "extrace: warning: pid_db of "
+				print_runtime_error("extrace: warning: pid_db of "
 				    "size %d overflowed\n", PID_DB_SIZE);
 
+			if (show_exit && pid_db[i].pid == pid) {
+				if (!flat)
+					fprintf(output, "%*s", 2*d, "");
+				fprintf(output, "%d- %s execed time=%.3fs\n",
+				    pid,
+				    pid_db[i].cmdline,
+				    (ev->timestamp_ns - pid_db[i].start) / 1e9);
+			}
+
 			pid_db[i].pid = pid;
 			pid_db[i].depth = d;
 			pid_db[i].start = ev->timestamp_ns;
@@ -413,6 +447,9 @@ handle_msg(struct cn_msg *cn_hdr)
 		pid_t pid = ev->event_data.exit.process_pid;
 		int i;
 
+		if (pid == parent)
+			quit = 1;
+
 		for (i = 0; i < PID_DB_SIZE; i++)
 			if (pid_db[i].pid == pid)
 				break;
@@ -482,7 +519,7 @@ main(int argc, char *argv[])
 
 	output = stdout;
 
-	while ((opt = getopt(argc, argv, "+deflo:p:qtwu")) != -1)
+	while ((opt = getopt(argc, argv, "+deflo:p:qQtwu")) != -1)
 		switch (opt) {
 		case 'd': show_cwd = 1; break;
 		case 'e': show_env = 1; break;
@@ -490,6 +527,7 @@ main(int argc, char *argv[])
 		case 'l': full_path = 1; break;
 		case 'p': parent = parse_pid(optarg); break;
 		case 'q': show_args = 0; break;
+		case 'Q': show_errors = 0; break;
 		case 't': show_exit = 1; break;
 		case 'o':
 			output = fopen(optarg, "w");
@@ -505,7 +543,7 @@ main(int argc, char *argv[])
 
 	if (parent != 1 && optind != argc) {
 usage:
-		fprintf(stderr, "Usage: extrace [-deflqt] [-o FILE] [-p PID|CMD...]\n");
+		fprintf(stderr, "Usage: extrace [-deflqQtu] [-o FILE] [-p PID|CMD...]\n");
 		exit(1);
 	}
 
@@ -557,8 +595,6 @@ usage:
 	}
 
 	if (optind != argc) {
-		pid_t child;
-
 		parent = getpid();
 		signal(SIGCHLD, sigchld);
 
@@ -593,7 +629,7 @@ usage:
 	
 		if (last_seq[cproc->cpu] &&
 		    cmsg->seq != last_seq[cproc->cpu] + 1)
-			fprintf(stderr,
+			print_runtime_error(
 			    "extrace: out of order message on cpu %d\n",
 			    cproc->cpu);
 		last_seq[cproc->cpu] = cmsg->seq;