[DTrace-devel] [PATCH 2/2] Missing symbols for loadable modules when reading /proc/kallmodsyms

eugene.loh at oracle.com eugene.loh at oracle.com
Tue Oct 5 14:20:19 PDT 2021


From: Eugene Loh <eugene.loh at oracle.com>

As DTv2 (DTrace on BPF) development started, the patch
"dtrace: handle .init.scratch section in /proc/kallmodsyms" was applied,
but different versions were applied to DTv1 and DTv2: 81c6542 and f5c1f088,
respectively.  The patch applied to DTv2 was wrong.  In particular, once
dt_modsym_update() starts reading symbols for loadable modules, it sets
kernel_flag=-1.  If there is no .init.scratch section, the code will
forever think it is nonetheless in such a section and ignore all symbols.
Hence, symbols for loadable modules are never read.

Fix dt_modsym_update(), specifically more in line with DTv1.  Importantly,
  - handle .init.scratch first
  - make kernel_flag an unsigned int
  - signal the beginning of loadable modules by
      setting only one bit of kernel_flag, not all of them

Thanks to Rajan Shanmugavelu for reporting this problem.

Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
 libdtrace/dt_module.c                  | 59 ++++++++++++++------------
 test/unittest/aggs/tst.aggmod_full2.sh |  6 +--
 test/unittest/consumer/tst.symbols.c   |  6 +--
 3 files changed, 39 insertions(+), 32 deletions(-)

diff --git a/libdtrace/dt_module.c b/libdtrace/dt_module.c
index aaf125b8..fdc0886d 100644
--- a/libdtrace/dt_module.c
+++ b/libdtrace/dt_module.c
@@ -1066,6 +1066,27 @@ dt_kern_module_find_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
 	}
 }
 
+/*
+ * We will use kernel_flag to track which symbols we are reading.
+ *
+ * /proc/kallmodsyms starts with kernel (and built-in-module) symbols.
+ *
+ * The last kernel address is expected to have the name "_end",
+ * but there might also be a symbol "__brk_limit" with that address.
+ * Set the KERNEL_FLAG_KERNEL_END flag while these addresses are read.
+ *
+ * Otherwise, symbols in /proc/kallmodsyms will normally belong to
+ * loadable modules.  Set the KERNEL_FLAG_LOADABLE flag once these
+ * symbols are reached.
+ *
+ * Another odd case is the .init.scratch section introduced by e1bfa87
+ * ("x86/mm: Create a workarea in the kernel for SME early encryption"),
+ * which appears in 5.2-rc6.  We ignore this section by setting the
+ * KERNEL_FLAG_INIT_SCRATCH flag.
+ */
+#define KERNEL_FLAG_KERNEL_END 1
+#define KERNEL_FLAG_LOADABLE 2
+#define KERNEL_FLAG_INIT_SCRATCH 4
 /*
  * Update our module cache.  For each line, create or
  * populate the dt_module_t for this module (if necessary), extend its address
@@ -1078,7 +1099,7 @@ dt_kern_module_find_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
 static int
 dt_modsym_update(dtrace_hdl_t *dtp, const char *line, int flag)
 {
-	static int kernel_flag = 1;
+	static uint_t kernel_flag = 0;
 	static dt_module_t *last_dmp = NULL;
 	static int last_sym_text = -1;
 
@@ -1132,29 +1153,7 @@ dt_modsym_update(dtrace_hdl_t *dtp, const char *line, int flag)
 		return 0;
 
 	/*
-	 * The file starts with kernel (and built-in-module) symbols.
-	 * The last kernel address is expected to have the name "_end".
-	 * (There might also be a symbol "__brk_limit" with that address.)
-	 * Thereafter, symbols will belong to loadable modules.
-	 *
-	 * kernel_flag==+1 means normal kernel (and built-in-module) symbols
-	 * kernel_flag==-1 means loadable-module symbols
-	 * kernel_flag==0 is an odd in-between case for the section markers
-	 *   (they signal the imminent end of the kernel section)
-	 */
-
-	if ((strcmp(sym_name, "_end") == 0) ||
-	    (strcmp(sym_name, "__brk_limit") == 0))
-		kernel_flag = 0;
-	else if (kernel_flag == 0)
-		kernel_flag = -1;
-
-#define KERNEL_FLAG_INIT_SCRATCH 0x80
-	/*
-	 * Another odd case is the .init.scratch section introduced by e1bfa87
-	 * ("x86/mm: Create a workarea in the kernel for SME early encryption"),
-	 * which appears in 5.2-rc6.  We ignore this section by setting the
-	 * KERNEL_FLAG_INIT_SCRATCH flag in kernel_flag.
+	 * Skip over the .init.scratch section.
 	 */
 	if (strcmp(sym_name, "__init_scratch_begin") == 0) {
 		kernel_flag |= KERNEL_FLAG_INIT_SCRATCH;
@@ -1165,7 +1164,12 @@ dt_modsym_update(dtrace_hdl_t *dtp, const char *line, int flag)
 	} else if (kernel_flag & KERNEL_FLAG_INIT_SCRATCH) {
 		return 0;
 	}
-#undef KERNEL_FLAG_INIT_SCRATCH
+
+	if ((strcmp(sym_name, "_end") == 0) ||
+	    (strcmp(sym_name, "__brk_limit") == 0))
+		kernel_flag |= KERNEL_FLAG_KERNEL_END;
+	else if (kernel_flag & KERNEL_FLAG_KERNEL_END)
+		kernel_flag = KERNEL_FLAG_LOADABLE;
 
 	/*
 	 * Special case: rename the 'ctf' module to 'shared_ctf': the
@@ -1247,7 +1251,7 @@ dt_modsym_update(dtrace_hdl_t *dtp, const char *line, int flag)
 	if (sym_size == 0)
 		return 0;
 
-	if (kernel_flag >= 0) {
+	if ((kernel_flag & KERNEL_FLAG_LOADABLE) == 0) {
 		/*
 		 * The kernel and built-in modules are in address order.
 		 */
@@ -1299,6 +1303,9 @@ dt_modsym_update(dtrace_hdl_t *dtp, const char *line, int flag)
 
 	return 0;
 }
+#undef KERNEL_FLAG_KERNEL_END
+#undef KERNEL_FLAG_LOADABLE
+#undef KERNEL_FLAG_INIT_SCRATCH
 
 /*
  * Unload all the loaded modules and then refresh the module cache with the
diff --git a/test/unittest/aggs/tst.aggmod_full2.sh b/test/unittest/aggs/tst.aggmod_full2.sh
index 30642310..6baea432 100755
--- a/test/unittest/aggs/tst.aggmod_full2.sh
+++ b/test/unittest/aggs/tst.aggmod_full2.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 #
 # Oracle Linux DTrace.
-# Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
 # Licensed under the Universal Permissive License v 1.0 as shown at
 # http://oss.oracle.com/licenses/upl.
 #
@@ -56,7 +56,7 @@ int main(int argc, char **argv) {
 	char *line = NULL;
 	size_t line_n = 0;
 	FILE *fd;
-	int kernel_flag = 0;
+	unsigned int kernel_flag = 0;
 
 	if ((fd = fopen("/proc/kallmodsyms", "r")) == NULL) return 1;
 	while ((getline(&line, &line_n, fd)) > 0) {
@@ -77,7 +77,7 @@ int main(int argc, char **argv) {
 		/* see dt_module.c dt_modsym_update() */
 		if (type == 'a' || type == 'A')
 			continue;
-#define KERNEL_FLAG_INIT_SCRATCH 0x80
+#define KERNEL_FLAG_INIT_SCRATCH 4
 		if (strcmp(symname, "__init_scratch_begin") == 0) {
 			kernel_flag |= KERNEL_FLAG_INIT_SCRATCH;
 			continue;
diff --git a/test/unittest/consumer/tst.symbols.c b/test/unittest/consumer/tst.symbols.c
index d1ece5c7..f6d8d5da 100644
--- a/test/unittest/consumer/tst.symbols.c
+++ b/test/unittest/consumer/tst.symbols.c
@@ -4,7 +4,6 @@
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * Check mappings between symbol names and addresses using /proc/kallmodsyms.
@@ -53,7 +52,8 @@ int read_symbols() {
 	char *line = NULL;
 	size_t line_n = 0;
 	FILE *fd;
-	int n_skip = 0, n_absolute = 0, kernel_flag = 0;
+	int n_skip = 0, n_absolute = 0;
+	unsigned int kernel_flag = 0;
 
 	printf("read_symbols():\n");
 	if ((fd = fopen("/proc/kallmodsyms", "r")) == NULL) return 1;
@@ -96,7 +96,7 @@ int read_symbols() {
 		if (symbols[nsymbols].type == 'a' ||
 		    symbols[nsymbols].type == 'A')
 			continue;
-#define KERNEL_FLAG_INIT_SCRATCH 0x80
+#define KERNEL_FLAG_INIT_SCRATCH 4
 		if (strcmp(symname, "__init_scratch_begin") == 0) {
 			kernel_flag |= KERNEL_FLAG_INIT_SCRATCH;
 			continue;
-- 
2.18.4




More information about the DTrace-devel mailing list