Improve compiler logging

This change adds line numbers to the logs emitted when compiling syscall
filter policy files.

Bug: None
Test: See filenames+line numbers in syslog
Change-Id: Id6fb7d097f60e317269b5abd03b5a6929db6cd40
diff --git a/libminijail.c b/libminijail.c
index c31af06..d06aeeb 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -870,14 +870,16 @@
 	return 1;
 }
 
-static int parse_seccomp_filters(struct minijail *j, FILE *policy_file)
+static int parse_seccomp_filters(struct minijail *j, const char *filename,
+				 FILE *policy_file)
 {
 	struct sock_fprog *fprog = malloc(sizeof(struct sock_fprog));
 	int use_ret_trap =
 	    j->flags.seccomp_filter_tsync || j->flags.seccomp_filter_logging;
 	int allow_logging = j->flags.seccomp_filter_logging;
 
-	if (compile_filter(policy_file, fprog, use_ret_trap, allow_logging)) {
+	if (compile_filter(filename, policy_file, fprog, use_ret_trap,
+			   allow_logging)) {
 		free(fprog);
 		return -1;
 	}
@@ -897,7 +899,7 @@
 		pdie("failed to open seccomp filter file '%s'", path);
 	}
 
-	if (parse_seccomp_filters(j, file) != 0) {
+	if (parse_seccomp_filters(j, path, file) != 0) {
 		die("failed to compile seccomp filter BPF program in '%s'",
 		    path);
 	}
@@ -906,18 +908,29 @@
 
 void API minijail_parse_seccomp_filters_from_fd(struct minijail *j, int fd)
 {
+	char *fd_path, *path;
+	FILE *file;
+
 	if (!seccomp_should_parse_filters(j))
 		return;
 
-	FILE *file = fdopen(fd, "r");
+	file = fdopen(fd, "r");
 	if (!file) {
 		pdie("failed to associate stream with fd %d", fd);
 	}
 
-	if (parse_seccomp_filters(j, file) != 0) {
+	if (asprintf(&fd_path, "/proc/self/fd/%d", fd) == -1)
+		pdie("failed to create path for fd %d", fd);
+	path = realpath(fd_path, NULL);
+	if (path == NULL)
+		pwarn("failed to get path of fd %d", fd);
+	free(fd_path);
+
+	if (parse_seccomp_filters(j, path ? path : "<fd>", file) != 0) {
 		die("failed to compile seccomp filter BPF program from fd %d",
 		    fd);
 	}
+	free(path);
 	fclose(file);
 }
 
diff --git a/parse_seccomp_policy.cc b/parse_seccomp_policy.cc
index a9daed0..32b2853 100644
--- a/parse_seccomp_policy.cc
+++ b/parse_seccomp_policy.cc
@@ -32,7 +32,7 @@
 	}
 
 	struct sock_fprog fp;
-	int res = compile_filter(f, &fp, 0, 0);
+	int res = compile_filter(argv[1], f, &fp, 0, 0);
 	if (res != 0) {
 		die("compile_filter failed");
 	}
diff --git a/syscall_filter.c b/syscall_filter.c
index c338e90..f90878a 100644
--- a/syscall_filter.c
+++ b/syscall_filter.c
@@ -16,6 +16,13 @@
 
 #define ONE_INSTR	1
 #define TWO_INSTRS	2
+
+#define compiler_warn(_state, _msg, ...)                                       \
+	warn("%s: %s(%zd): " _msg, __func__, (_state)->filename,               \
+	     (_state)->line_number, ## __VA_ARGS__)
+
+#define compiler_pwarn(_state, _msg, ...)                                      \
+	compiler_warn(_state, _msg ": %m", ## __VA_ARGS__)
 /* clang-format on */
 
 int seccomp_can_softfail(void)
@@ -169,38 +176,39 @@
 	return filename[0] != '/' && (filename[0] != '.' || filename[1] != '/');
 }
 
-int compile_atom(struct filter_block *head, char *atom,
-		 struct bpf_labels *labels, int nr, int grp_idx)
+int compile_atom(struct parser_state *state, struct filter_block *head,
+		 char *atom, struct bpf_labels *labels, int nr, int grp_idx)
 {
 	/* Splits the atom. */
 	char *atom_ptr = NULL;
 	char *argidx_str = strtok_r(atom, " ", &atom_ptr);
 	if (argidx_str == NULL) {
-		warn("empty atom");
+		compiler_warn(state, "empty atom");
 		return -1;
 	}
 
 	char *operator_str = strtok_r(NULL, " ", &atom_ptr);
 	if (operator_str == NULL) {
-		warn("invalid atom '%s'", argidx_str);
+		compiler_warn(state, "invalid atom '%s'", argidx_str);
 		return -1;
 	}
 
 	char *constant_str = strtok_r(NULL, " ", &atom_ptr);
 	if (constant_str == NULL) {
-		warn("invalid atom '%s %s'", argidx_str, operator_str);
+		compiler_warn(state, "invalid atom '%s %s'", argidx_str,
+			      operator_str);
 		return -1;
 	}
 
 	/* Checks that there are no extra tokens. */
 	const char *extra = strtok_r(NULL, " ", &atom_ptr);
 	if (extra != NULL) {
-		warn("extra token '%s'", extra);
+		compiler_warn(state, "extra token '%s'", extra);
 		return -1;
 	}
 
 	if (strncmp(argidx_str, "arg", 3)) {
-		warn("invalid argument token '%s'", argidx_str);
+		compiler_warn(state, "invalid argument token '%s'", argidx_str);
 		return -1;
 	}
 
@@ -211,20 +219,21 @@
 	 * and that there was nothing left after the index.
 	 */
 	if (argidx_ptr == argidx_str + 3 || *argidx_ptr != '\0') {
-		warn("invalid argument index '%s'", argidx_str + 3);
+		compiler_warn(state, "invalid argument index '%s'",
+			      argidx_str + 3);
 		return -1;
 	}
 
 	int op = str_to_op(operator_str);
 	if (op < MIN_OPERATOR) {
-		warn("invalid operator '%s'", operator_str);
+		compiler_warn(state, "invalid operator '%s'", operator_str);
 		return -1;
 	}
 
 	char *constant_str_ptr;
 	long int c = parse_constant(constant_str, &constant_str_ptr);
 	if (constant_str_ptr == constant_str) {
-		warn("invalid constant '%s'", constant_str);
+		compiler_warn(state, "invalid constant '%s'", constant_str);
 		return -1;
 	}
 
@@ -252,7 +261,8 @@
 	return 0;
 }
 
-int compile_errno(struct filter_block *head, char *ret_errno, int use_ret_trap)
+int compile_errno(struct parser_state *state, struct filter_block *head,
+		  char *ret_errno, int use_ret_trap)
 {
 	char *errno_ptr = NULL;
 
@@ -268,7 +278,8 @@
 		int errno_val = parse_constant(errno_val_str, &errno_val_ptr);
 		/* Checks to see if we parsed an actual errno. */
 		if (errno_val_ptr == errno_val_str || errno_val == -1) {
-			warn("invalid errno value '%s'", errno_val_ptr);
+			compiler_warn(state, "invalid errno value '%s'",
+				      errno_val_ptr);
 			return -1;
 		}
 
@@ -282,7 +293,8 @@
 	return 0;
 }
 
-struct filter_block *compile_policy_line(int nr, const char *policy_line,
+struct filter_block *compile_policy_line(struct parser_state *state, int nr,
+					 const char *policy_line,
 					 unsigned int entry_lbl_id,
 					 struct bpf_labels *labels,
 					 int use_ret_trap)
@@ -324,7 +336,7 @@
 
 	/* Checks for empty policy lines. */
 	if (strlen(policy_line) == 0) {
-		warn("empty policy line");
+		compiler_warn(state, "empty policy line");
 		return NULL;
 	}
 
@@ -353,7 +365,7 @@
 
 	/* Checks whether we're unconditionally blocking this syscall. */
 	if (strncmp(line, "return", strlen("return")) == 0) {
-		if (compile_errno(head, line, use_ret_trap) < 0) {
+		if (compile_errno(state, head, line, use_ret_trap) < 0) {
 			free_block_list(head);
 			free(line);
 			return NULL;
@@ -378,7 +390,8 @@
 		char *comp;
 		while ((comp = tokenize(&group_str, "&&")) != NULL) {
 			/* Compiles each atom into a BPF block. */
-			if (compile_atom(head, comp, labels, nr, grp_idx) < 0) {
+			if (compile_atom(state, head, comp, labels, nr,
+					 grp_idx) < 0) {
 				free_block_list(head);
 				free(line);
 				return NULL;
@@ -407,7 +420,7 @@
 	 * otherwise just kill the task.
 	 */
 	if (ret_errno) {
-		if (compile_errno(head, ret_errno, use_ret_trap) < 0) {
+		if (compile_errno(state, head, ret_errno, use_ret_trap) < 0) {
 			free_block_list(head);
 			free(line);
 			return NULL;
@@ -433,16 +446,18 @@
 	return head;
 }
 
-int parse_include_statement(char *policy_line, unsigned int include_level,
+int parse_include_statement(struct parser_state *state, char *policy_line,
+			    unsigned int include_level,
 			    const char **ret_filename)
 {
 	if (strncmp("@include", policy_line, strlen("@include")) != 0) {
-		warn("invalid statement '%s'", policy_line);
+		compiler_warn(state, "invalid statement '%s'", policy_line);
 		return -1;
 	}
 
 	if (policy_line[strlen("@include")] != ' ') {
-		warn("invalid include statement '%s'", policy_line);
+		compiler_warn(state, "invalid include statement '%s'",
+			      policy_line);
 		return -1;
 	}
 
@@ -453,7 +468,7 @@
 	 * harder to understand.
 	 */
 	if (include_level > 0) {
-		warn("@include statement nested too deep");
+		compiler_warn(state, "@include statement nested too deep");
 		return -1;
 	}
 
@@ -470,9 +485,10 @@
 	 */
 	const char *filename = statement;
 	if (is_implicit_relative_path(filename)) {
-		warn("compile_file: implicit relative path '%s' not supported, "
-		     "use './%s'",
-		     filename, filename);
+		compiler_warn(
+		    state,
+		    "implicit relative path '%s' not supported, use './%s'",
+		    filename, filename);
 		return -1;
 	}
 
@@ -480,11 +496,17 @@
 	return 0;
 }
 
-int compile_file(FILE *policy_file, struct filter_block *head,
-		 struct filter_block **arg_blocks, struct bpf_labels *labels,
-		 int use_ret_trap, int allow_logging,
+int compile_file(const char *filename, FILE *policy_file,
+		 struct filter_block *head, struct filter_block **arg_blocks,
+		 struct bpf_labels *labels, int use_ret_trap, int allow_logging,
 		 unsigned int include_level)
 {
+	/* clang-format off */
+	struct parser_state state = {
+		.filename = filename,
+		.line_number = 0,
+	};
+	/* clang-format on */
 	/*
 	 * Loop through all the lines in the policy file.
 	 * Build a jump table for the syscall number.
@@ -501,6 +523,8 @@
 		char *policy_line = line;
 		policy_line = strip(policy_line);
 
+		state.line_number++;
+
 		/* Allow comments and empty lines. */
 		if (*policy_line == '#' || *policy_line == '\0') {
 			/* Reuse |line| in the next getline() call. */
@@ -510,26 +534,29 @@
 		/* Allow @include statements. */
 		if (*policy_line == '@') {
 			const char *filename = NULL;
-			if (parse_include_statement(policy_line, include_level,
+			if (parse_include_statement(&state, policy_line,
+						    include_level,
 						    &filename) != 0) {
-				warn("compile_file: failed to parse include "
-				     "statement");
+				compiler_warn(
+				    &state,
+				    "failed to parse include statement");
 				ret = -1;
 				goto free_line;
 			}
 
 			FILE *included_file = fopen(filename, "re");
 			if (included_file == NULL) {
-				pwarn("compile_file: fopen('%s') failed",
-				      filename);
+				compiler_pwarn(&state, "fopen('%s') failed",
+					       filename);
 				ret = -1;
 				goto free_line;
 			}
-			if (compile_file(included_file, head, arg_blocks,
-					 labels, use_ret_trap, allow_logging,
+			if (compile_file(filename, included_file, head,
+					 arg_blocks, labels, use_ret_trap,
+					 allow_logging,
 					 ++include_level) == -1) {
-				warn("compile_file: '@include %s' failed",
-				     filename);
+				compiler_warn(&state, "'@include %s' failed",
+					      filename);
 				fclose(included_file);
 				ret = -1;
 				goto free_line;
@@ -552,7 +579,7 @@
 
 		policy_line = strip(policy_line);
 		if (*policy_line == '\0') {
-			warn("compile_file: empty policy line");
+			compiler_warn(&state, "empty policy line");
 			ret = -1;
 			goto free_line;
 		}
@@ -560,8 +587,8 @@
 		syscall_name = strip(syscall_name);
 		int nr = lookup_syscall(syscall_name);
 		if (nr < 0) {
-			warn("compile_file: nonexistent syscall '%s'",
-			     syscall_name);
+			compiler_warn(&state, "nonexistent syscall '%s'",
+				      syscall_name);
 			if (allow_logging) {
 				/*
 				 * If we're logging failures, assume we're in a
@@ -601,7 +628,7 @@
 
 			/* Build the arg filter block. */
 			struct filter_block *block = compile_policy_line(
-			    nr, policy_line, id, labels, use_ret_trap);
+			    &state, nr, policy_line, id, labels, use_ret_trap);
 
 			if (!block) {
 				if (*arg_blocks) {
@@ -626,8 +653,8 @@
 	return ret;
 }
 
-int compile_filter(FILE *initial_file, struct sock_fprog *prog,
-		   int use_ret_trap, int allow_logging)
+int compile_filter(const char *filename, FILE *initial_file,
+		   struct sock_fprog *prog, int use_ret_trap, int allow_logging)
 {
 	int ret = 0;
 	struct bpf_labels labels;
@@ -655,8 +682,9 @@
 	if (allow_logging)
 		allow_logging_syscalls(head);
 
-	if (compile_file(initial_file, head, &arg_blocks, &labels, use_ret_trap,
-			 allow_logging, 0 /* include_level */) != 0) {
+	if (compile_file(filename, initial_file, head, &arg_blocks, &labels,
+			 use_ret_trap, allow_logging,
+			 0 /* include_level */) != 0) {
 		warn("compile_filter: compile_file() failed");
 		ret = -1;
 		goto free_filter;
diff --git a/syscall_filter.h b/syscall_filter.h
index d15e8a9..737ef49 100644
--- a/syscall_filter.h
+++ b/syscall_filter.h
@@ -24,17 +24,24 @@
 	size_t total_len;
 };
 
+struct parser_state {
+	const char *filename;
+	size_t line_number;
+};
+
 struct bpf_labels;
 
-struct filter_block *compile_policy_line(int nr, const char *policy_line,
+struct filter_block *compile_policy_line(struct parser_state *state, int nr,
+					 const char *policy_line,
 					 unsigned int label_id,
 					 struct bpf_labels *labels,
 					 int do_ret_trap);
-int compile_file(FILE *policy_file, struct filter_block *head,
-		 struct filter_block **arg_blocks, struct bpf_labels *labels,
-		 int use_ret_trap, int allow_logging,
+int compile_file(const char *filename, FILE *policy_file,
+		 struct filter_block *head, struct filter_block **arg_blocks,
+		 struct bpf_labels *labels, int use_ret_trap, int allow_logging,
 		 unsigned int include_level);
-int compile_filter(FILE *policy_file, struct sock_fprog *prog, int do_ret_trap,
+int compile_filter(const char *filename, FILE *policy_file,
+		   struct sock_fprog *prog, int do_ret_trap,
 		   int add_logging_syscalls);
 
 struct filter_block *new_filter_block(void);
diff --git a/syscall_filter_unittest.cc b/syscall_filter_unittest.cc
index 8dd1828..6bc044d 100644
--- a/syscall_filter_unittest.cc
+++ b/syscall_filter_unittest.cc
@@ -336,57 +336,55 @@
 
 class ArgFilterTest : public ::testing::Test {
  protected:
-  virtual void SetUp() { labels_.count = 0; }
+  virtual void SetUp() {
+    labels_.count = 0;
+    state_.filename = "policy";
+    state_.line_number = 1;
+  }
   virtual void TearDown() { free_label_strings(&labels_); }
   struct bpf_labels labels_;
+  int nr_ = 1;
+  unsigned int id_ = 0;
+  struct parser_state state_;
 };
 
 TEST_F(ArgFilterTest, empty_atom) {
   const char* fragment = "";
-  int nr = 1;
-  unsigned int id = 0;
 
   struct filter_block* block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
 TEST_F(ArgFilterTest, whitespace_atom) {
   const char* fragment = "\t    ";
-  int nr = 1;
-  unsigned int id = 0;
 
   struct filter_block* block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
 TEST_F(ArgFilterTest, no_comparison) {
   const char* fragment = "arg0";
-  int nr = 1;
-  unsigned int id = 0;
 
   struct filter_block* block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
 TEST_F(ArgFilterTest, no_constant) {
   const char* fragment = "arg0 ==";
-  int nr = 1;
-  unsigned int id = 0;
 
   struct filter_block* block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
 TEST_F(ArgFilterTest, arg0_equals) {
   const char *fragment = "arg0 == 0";
-  int nr = 1;
-  unsigned int id = 0;
-  struct filter_block *block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+
+  struct filter_block* block =
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
 
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
@@ -424,10 +422,9 @@
 
 TEST_F(ArgFilterTest, arg0_mask) {
   const char *fragment = "arg1 & O_RDWR";
-  int nr = 1;
-  unsigned int id = 0;
-  struct filter_block *block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+
+  struct filter_block* block =
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
 
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
@@ -465,10 +462,9 @@
 
 TEST_F(ArgFilterTest, arg0_flag_set_inclusion) {
   const char *fragment = "arg0 in O_RDONLY|O_CREAT";
-  int nr = 1;
-  unsigned int id = 0;
-  struct filter_block *block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+
+  struct filter_block* block =
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
 
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
@@ -507,11 +503,9 @@
 
 TEST_F(ArgFilterTest, arg0_eq_mask) {
   const char *fragment = "arg1 == O_WRONLY|O_CREAT";
-  int nr = 1;
-  unsigned int id = 0;
 
-  struct filter_block *block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+  struct filter_block* block =
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
 
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
@@ -552,11 +546,9 @@
 
 TEST_F(ArgFilterTest, and_or) {
   const char *fragment = "arg0 == 0 && arg1 == 0 || arg0 == 1";
-  int nr = 1;
-  unsigned int id = 0;
 
-  struct filter_block *block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+  struct filter_block* block =
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + 3 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
   EXPECT_EQ(block->total_len, exp_total_len);
@@ -609,11 +601,9 @@
 
 TEST_F(ArgFilterTest, ret_errno) {
   const char *fragment = "arg0 == 0 || arg0 == 1; return 1";
-  int nr = 1;
-  unsigned int id = 0;
 
-  struct filter_block *block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+  struct filter_block* block =
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + 2 * (BPF_ARG_COMP_LEN + 1) + 2 + 2 + 1 + 2;
   EXPECT_EQ(block->total_len, exp_total_len);
@@ -664,11 +654,9 @@
 
 TEST_F(ArgFilterTest, unconditional_errno) {
   const char *fragment = "return 1";
-  int nr = 1;
-  unsigned int id = 0;
 
-  struct filter_block *block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+  struct filter_block* block =
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 2;
   EXPECT_EQ(block->total_len, exp_total_len);
@@ -694,80 +682,65 @@
 
 TEST_F(ArgFilterTest, invalid_arg_token) {
   const char *fragment = "org0 == 0";
-  int nr = 1;
-  unsigned int id = 0;
 
-  struct filter_block *block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+  struct filter_block* block =
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
 TEST_F(ArgFilterTest, invalid_arg_number) {
   const char *fragment = "argnn == 0";
-  int nr = 1;
-  unsigned int id = 0;
 
-  struct filter_block *block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+  struct filter_block* block =
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
 TEST_F(ArgFilterTest, extra_chars_in_arg_token) {
   const char* fragment = "arg0n == 0";
-  int nr = 1;
-  unsigned int id = 0;
 
   struct filter_block* block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
 TEST_F(ArgFilterTest, invalid_operator) {
   const char* fragment = "arg0 invalidop 0";
-  int nr = 1;
-  unsigned int id = 0;
 
   struct filter_block* block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
 TEST_F(ArgFilterTest, invalid_constant) {
   const char *fragment = "arg0 == INVALIDCONSTANT";
-  int nr = 1;
-  unsigned int id = 0;
 
   struct filter_block* block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
 TEST_F(ArgFilterTest, extra_tokens) {
   const char* fragment = "arg0 == 0 EXTRATOKEN";
-  int nr = 1;
-  unsigned int id = 0;
 
   struct filter_block* block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
 TEST_F(ArgFilterTest, invalid_errno) {
   const char *fragment = "arg0 == 0 && arg1 == 1; return errno";
-  int nr = 1;
-  unsigned int id = 0;
 
-  struct filter_block *block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+  struct filter_block* block =
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
   ASSERT_EQ(block, nullptr);
 }
 
 TEST_F(ArgFilterTest, log_no_ret_error) {
   const char *fragment = "arg0 == 0";
-  int nr = 1;
-  unsigned int id = 0;
-  struct filter_block *block =
-      compile_policy_line(nr, fragment, id, &labels_, USE_LOGGING);
+
+  struct filter_block* block =
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, USE_LOGGING);
 
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
@@ -806,11 +779,9 @@
 
 TEST_F(ArgFilterTest, log_bad_ret_error) {
   const char *fragment = "arg0 == 0; return";
-  int nr = 1;
-  unsigned int id = 0;
 
-  struct filter_block *block =
-      compile_policy_line(nr, fragment, id, &labels_, NO_LOGGING);
+  struct filter_block* block =
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, NO_LOGGING);
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
   EXPECT_EQ(block->total_len, exp_total_len);
@@ -850,11 +821,9 @@
 
 TEST_F(ArgFilterTest, no_log_bad_ret_error) {
   const char *fragment = "arg0 == 0; return";
-  int nr = 1;
-  unsigned int id = 0;
 
-  struct filter_block *block =
-      compile_policy_line(nr, fragment, id, &labels_, USE_LOGGING);
+  struct filter_block* block =
+      compile_policy_line(&state_, nr_, fragment, id_, &labels_, USE_LOGGING);
   ASSERT_NE(block, nullptr);
   size_t exp_total_len = 1 + (BPF_ARG_COMP_LEN + 1) + 2 + 1 + 2;
   EXPECT_EQ(block->total_len, exp_total_len);
@@ -953,8 +922,8 @@
 
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
-  int res = compile_file(
-      policy_file, head_, &arg_blocks_, &labels_, USE_RET_KILL, NO_LOGGING, 0);
+  int res = compile_file("policy", policy_file, head_, &arg_blocks_, &labels_,
+                         USE_RET_KILL, NO_LOGGING, 0);
   fclose(policy_file);
 
   /*
@@ -970,8 +939,8 @@
 
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
-  int res = compile_file(
-      policy_file, head_, &arg_blocks_, &labels_, USE_RET_KILL, NO_LOGGING, 0);
+  int res = compile_file("policy", policy_file, head_, &arg_blocks_, &labels_,
+                         USE_RET_KILL, NO_LOGGING, 0);
   fclose(policy_file);
 
   /*
@@ -986,8 +955,8 @@
 
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
-  int res = compile_file(
-      policy_file, head_, &arg_blocks_, &labels_, USE_RET_KILL, NO_LOGGING, 0);
+  int res = compile_file("policy", policy_file, head_, &arg_blocks_, &labels_,
+                         USE_RET_KILL, NO_LOGGING, 0);
   fclose(policy_file);
 
   /*
@@ -1005,8 +974,8 @@
 
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
-  int res = compile_file(
-      policy_file, head_, &arg_blocks_, &labels_, USE_RET_KILL, NO_LOGGING, 0);
+  int res = compile_file("policy", policy_file, head_, &arg_blocks_, &labels_,
+                         USE_RET_KILL, NO_LOGGING, 0);
   fclose(policy_file);
 
   /*
@@ -1040,8 +1009,8 @@
 
     FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
-  int res = compile_file(
-      policy_file, head_, &arg_blocks_, &labels_, USE_RET_KILL, NO_LOGGING, 0);
+  int res = compile_file("policy", policy_file, head_, &arg_blocks_, &labels_,
+                         USE_RET_KILL, NO_LOGGING, 0);
   fclose(policy_file);
 
   /*
@@ -1109,7 +1078,8 @@
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
 
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
 
   /*
@@ -1146,7 +1116,8 @@
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
 
-  int res = compile_filter(policy_file, &actual, USE_RET_TRAP, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_TRAP, NO_LOGGING);
   fclose(policy_file);
 
   /*
@@ -1184,7 +1155,8 @@
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
 
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
 
   /*
@@ -1225,7 +1197,8 @@
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
 
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
 
   /* Checks return value and filter length. */
@@ -1243,7 +1216,8 @@
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
 
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
   ASSERT_NE(res, 0);
 }
@@ -1255,7 +1229,8 @@
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
 
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
   ASSERT_NE(res, 0);
 }
@@ -1267,7 +1242,8 @@
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
 
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
   ASSERT_NE(res, 0);
 }
@@ -1279,14 +1255,15 @@
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
 
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
   ASSERT_NE(res, 0);
 }
 
 TEST(FilterTest, nonexistent) {
   struct sock_fprog actual;
-  int res = compile_filter(NULL, &actual, USE_RET_KILL, NO_LOGGING);
+  int res = compile_filter("policy", NULL, &actual, USE_RET_KILL, NO_LOGGING);
   ASSERT_NE(res, 0);
 }
 
@@ -1301,7 +1278,8 @@
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
 
-  int res = compile_filter(policy_file, &actual, USE_RET_TRAP, USE_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_TRAP, USE_LOGGING);
   fclose(policy_file);
 
   size_t i;
@@ -1347,7 +1325,8 @@
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
 
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, USE_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, USE_LOGGING);
   fclose(policy_file);
 
   size_t i;
@@ -1389,7 +1368,8 @@
   FILE *policy_file =
       write_policy_to_pipe(invalid_token, strlen(invalid_token));
   ASSERT_NE(policy_file, nullptr);
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
   EXPECT_NE(res, 0);
 }
@@ -1400,7 +1380,8 @@
 
   FILE *policy_file = write_policy_to_pipe(no_space, strlen(no_space));
   ASSERT_NE(policy_file, nullptr);
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
   EXPECT_NE(res, 0);
 }
@@ -1411,7 +1392,8 @@
 
   FILE *policy_file = write_policy_to_pipe(double_token, strlen(double_token));
   ASSERT_NE(policy_file, nullptr);
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
   EXPECT_NE(res, 0);
 }
@@ -1422,7 +1404,8 @@
 
   FILE *policy_file = write_policy_to_pipe(no_file, strlen(no_file));
   ASSERT_NE(policy_file, nullptr);
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
   EXPECT_NE(res, 0);
 }
@@ -1434,7 +1417,8 @@
   FILE *policy_file =
       write_policy_to_pipe(space_no_file, strlen(space_no_file));
   ASSERT_NE(policy_file, nullptr);
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
   EXPECT_NE(res, 0);
 }
@@ -1446,7 +1430,8 @@
   FILE *policy_file = write_policy_to_pipe(implicit_relative_path,
                                            strlen(implicit_relative_path));
   ASSERT_NE(policy_file, nullptr);
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
   EXPECT_NE(res, 0);
 }
@@ -1458,7 +1443,8 @@
   FILE *policy_file =
       write_policy_to_pipe(extra_text, strlen(extra_text));
   ASSERT_NE(policy_file, nullptr);
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
   EXPECT_NE(res, 0);
 }
@@ -1470,7 +1456,8 @@
   FILE *policy_file =
       write_policy_to_pipe(split_filename, strlen(split_filename));
   ASSERT_NE(policy_file, nullptr);
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
   EXPECT_NE(res, 0);
 }
@@ -1483,7 +1470,8 @@
       write_policy_to_pipe(include_policy, strlen(include_policy));
   ASSERT_NE(policy_file, nullptr);
 
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
 
   ASSERT_NE(res, 0);
@@ -1507,15 +1495,16 @@
 
   FILE *file_plain = write_policy_to_pipe(policy_plain, strlen(policy_plain));
   ASSERT_NE(file_plain, nullptr);
-  int res_plain =
-      compile_filter(file_plain, &compiled_plain, USE_RET_KILL, NO_LOGGING);
+  int res_plain = compile_filter("policy", file_plain, &compiled_plain,
+                                 USE_RET_KILL, NO_LOGGING);
   fclose(file_plain);
 
   FILE *file_with_include =
       write_policy_to_pipe(policy_with_include, strlen(policy_with_include));
   ASSERT_NE(file_with_include, nullptr);
-  int res_with_include = compile_filter(
-      file_with_include, &compiled_with_include, USE_RET_KILL, NO_LOGGING);
+  int res_with_include =
+      compile_filter("policy", file_with_include, &compiled_with_include,
+                     USE_RET_KILL, NO_LOGGING);
   fclose(file_with_include);
 
   /*
@@ -1563,7 +1552,8 @@
       write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
 
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
 
   ASSERT_EQ(res, 0);
@@ -1591,7 +1581,8 @@
   ASSERT_NE(included_file, nullptr);
   fclose(included_file);
 
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
 
   ASSERT_NE(res, 0);
@@ -1610,7 +1601,8 @@
   ASSERT_NE(included_file, nullptr);
   fclose(included_file);
 
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
 
   ASSERT_NE(res, 0);
@@ -1624,7 +1616,8 @@
 
   FILE *policy_file = write_policy_to_pipe(policy, strlen(policy));
   ASSERT_NE(policy_file, nullptr);
-  int res = compile_filter(policy_file, &actual, USE_RET_KILL, NO_LOGGING);
+  int res =
+      compile_filter("policy", policy_file, &actual, USE_RET_KILL, NO_LOGGING);
   fclose(policy_file);
 
   /*