linux-arch.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v5 03/28] dyndbg: split struct _ddebug's display fields to new _ddebug_site
       [not found] <20210511185057.3815777-1-jim.cromie@gmail.com>
@ 2021-05-11 18:50 ` Jim Cromie
  2021-05-11 18:50 ` [RFC PATCH v5 18/28] dyndbg: RFC - DEFINE_DYNAMIC_DEBUG_TABLE Jim Cromie
  2021-05-11 18:50 ` [RFC PATCH v5 19/28] dyndbg: RFC handle __dyndbg* sections in module.lds.h Jim Cromie
  2 siblings, 0 replies; 3+ messages in thread
From: Jim Cromie @ 2021-05-11 18:50 UTC (permalink / raw)
  To: Arnd Bergmann, Jason Baron, linux-arch, linux-kernel; +Cc: linux-mm, Jim Cromie

Struct _ddebug has 2 kinds of fields: essential & optional/compressible.
Move the 3 optional fields: module, function, file into a new struct
_ddebug_site, and add pointer to it from _ddebug.

These fields are optional in that they are primarily used to generate
the optional "module:func:line" log prefix.  They're also used to
display control, and to select callsites to >control.  lineno is
arguably optional too, but it uses spare bytes in struct _ddebug, so
leaving it is free.

The "__dyndbg" ELF section contains the array of struct _ddebugs for
all the pr-debugs in the kernel/module.  Reuse this pattern for the
new "__dyndbg_sites" section.

The new ptr increases memory footprint, but it is temporary
scaffolding; once we can map from _ddebugs[N] --> _ddebug_sites[N]
indirectly, we can drop site pointer, regaining worst case memory
parity with master.

The indirection gives several advantages:

- site ptr lets us decouple the 2 arrays
  we can properly isolate dependencies by allowing null site

- the moved display fields are inherently hierarchical, and the linker
  section is ordered; so (module, file, function) have repeating
  values (90%, 85%, 45%).  This is readily compressible, even with a
  simple field-wise run length encoding.  Since I'm splitting the struct,
  I also reordered the fields to match the hierarchy.

- the separate linker section sets up naturally for block compression.
  section compression at build time is practical - how ?
  include/linux/decompress/generic.h has no corresponding compression

- we could drop sites and their storage opportunistically.
  this could reduce per-site mem by 24/56.

  Subsystems may not need/want "module:func:line:" in their logs.
  If they already use format-prefixes such as "drm:kms:",
  they can select on those, and don't need the site info for that.
  forex:
  #> echo module drm format "^drm:kms: " +p >control
  ie: dynamic_debug_exec_queries("format '^drm:kms: '", "drm");

Once we can map: ddebugs[N] -> ddebug_sites[N], we can:

- compress __dyndbg_sites during __init, and mark section __initdata
- store the compressed block instead.
- decompress on-demand, stream for `cat control`
- save chunks of decompressed buffer for enabled callsites
- free chunks on site disable, or on memory pressure.

Whats actually done here is ths rather mechanical, and preparatory.

dynamic_debug.h:

I cut struct _ddebug in half, renamed the optional top-half to
_ddebug_site, kept __align(8) for both halves.  I added a forward decl
for a unified comment for both head & body, and added _ddebug.site to
point at body.

DEFINE_DYNAMIC_DEBUG_METADATA now declares and initializes a 2nd
static struct var holding the _ddebug_site, and refs _ddebug to it.

dynamic_debug.c:

dynamic_debug_init() mem-usage now also counts sites.

dynamic_emit_prefix() & ddebug_change() use those moved fields; they
get a new initialized auto-var, and the field refs get adjusted as
needed to follow the field moves from one struct to the other.

   struct _ddebug_site *dc = dp->site;

ddebug_proc_show() differs slightly; it assigns to (not initializes)
the autovar, to avoid a panic when p == SEQ_START_TOKEN.

vmlinux.lds.h:

add __dyndbg_sites section, with the same align(8) and KEEP as
used in the __dyndbg section.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 include/asm-generic/vmlinux.lds.h |  3 +++
 include/linux/dynamic_debug.h     | 37 +++++++++++++++++---------
 lib/dynamic_debug.c               | 44 ++++++++++++++++++-------------
 3 files changed, 52 insertions(+), 32 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 0331d5d49551..4f2af9de2f03 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -353,6 +353,9 @@
 	*(__tracepoints)						\
 	/* implement dynamic printk debug */				\
 	. = ALIGN(8);							\
+	__start___dyndbg_sites = .;					\
+	KEEP(*(__dyndbg_sites))					\
+	__stop___dyndbg_sites = .;					\
 	__start___dyndbg = .;						\
 	KEEP(*(__dyndbg))						\
 	__stop___dyndbg = .;						\
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index dce631e678dd..d56c02ed0c45 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -7,20 +7,28 @@
 #endif
 
 /*
- * An instance of this structure is created in a special
- * ELF section at every dynamic debug callsite.  At runtime,
- * the special section is treated as an array of these.
+ * A pair of these structs are created in 2 special ELF sections
+ * (__dyndbg, __dyndbg_sites) for every dynamic debug callsite.
+ * At runtime, the sections are treated as arrays.
  */
-struct _ddebug {
+struct _ddebug;
+struct _ddebug_site {
 	/*
-	 * These fields are used to drive the user interface
-	 * for selecting and displaying debug callsites.
+	 * These fields (and lineno) are used to:
+	 * - decorate log messages per _ddebug.flags
+	 * - select callsites for modification via >control
+	 * - display callsites & settings in `cat control`
 	 */
 	const char *modname;
-	const char *function;
 	const char *filename;
+	const char *function;
+} __aligned(8);
+
+struct _ddebug {
+	struct _ddebug_site *site;
+	/* format is always needed, lineno shares word with flags */
 	const char *format;
-	unsigned int lineno:18;
+	const unsigned lineno:18;
 	/*
 	 * The flags field controls the behaviour at the callsite.
 	 * The bits here are changed dynamically when the user
@@ -49,8 +57,7 @@ struct _ddebug {
 		struct static_key_false dd_key_false;
 	} key;
 #endif
-} __attribute__((aligned(8)));
-
+} __aligned(8);
 
 
 #if defined(CONFIG_DYNAMIC_DEBUG_CORE)
@@ -88,11 +95,15 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
 			 const char *fmt, ...);
 
 #define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt)		\
-	static struct _ddebug  __aligned(8)			\
-	__section("__dyndbg") name = {				\
+	static struct _ddebug_site  __aligned(8)		\
+	__section("__dyndbg_sites") name##_site = {		\
 		.modname = KBUILD_MODNAME,			\
-		.function = __func__,				\
 		.filename = __FILE__,				\
+		.function = __func__,				\
+	};							\
+	static struct _ddebug  __aligned(8)			\
+	__section("__dyndbg") name = {				\
+		.site = &name##_site,				\
 		.format = (fmt),				\
 		.lineno = __LINE__,				\
 		.flags = _DPRINTK_FLAGS_DEFAULT,		\
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 3a7d1f9bcf4d..c1c2c90ed944 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -165,19 +165,20 @@ static int ddebug_change(const struct ddebug_query *query,
 
 		for (i = 0; i < dt->num_ddebugs; i++) {
 			struct _ddebug *dp = &dt->ddebugs[i];
+			struct _ddebug_site *dc = dp->site;
 
 			/* match against the source filename */
 			if (query->filename &&
-			    !match_wildcard(query->filename, dp->filename) &&
+			    !match_wildcard(query->filename, dc->filename) &&
 			    !match_wildcard(query->filename,
-					   kbasename(dp->filename)) &&
+					   kbasename(dc->filename)) &&
 			    !match_wildcard(query->filename,
-					   trim_prefix(dp->filename)))
+					   trim_prefix(dc->filename)))
 				continue;
 
 			/* match against the function */
 			if (query->function &&
-			    !match_wildcard(query->function, dp->function))
+			    !match_wildcard(query->function, dc->function))
 				continue;
 
 			/* match against the format */
@@ -214,8 +215,8 @@ static int ddebug_change(const struct ddebug_query *query,
 #endif
 			dp->flags = newflags;
 			v2pr_info("changed %s:%d [%s]%s =%s\n",
-				 trim_prefix(dp->filename), dp->lineno,
-				 dt->mod_name, dp->function,
+				 trim_prefix(dc->filename), dp->lineno,
+				 dt->mod_name, dc->function,
 				 ddebug_describe_flags(dp->flags, &fbuf));
 		}
 	}
@@ -586,12 +587,13 @@ static int remaining(int wrote)
 	return 0;
 }
 
-static char *__dynamic_emit_prefix(const struct _ddebug *desc, char *buf)
+static char *__dynamic_emit_prefix(const struct _ddebug *dp, char *buf)
 {
 	int pos_after_tid;
 	int pos = 0;
+	const struct _ddebug_site *desc = dp->site;
 
-	if (desc->flags & _DPRINTK_FLAGS_INCL_TID) {
+	if (dp->flags & _DPRINTK_FLAGS_INCL_TID) {
 		if (in_interrupt())
 			pos += snprintf(buf + pos, remaining(pos), "<intr> ");
 		else
@@ -599,15 +601,15 @@ static char *__dynamic_emit_prefix(const struct _ddebug *desc, char *buf)
 					task_pid_vnr(current));
 	}
 	pos_after_tid = pos;
-	if (desc->flags & _DPRINTK_FLAGS_INCL_MODNAME)
+	if (dp->flags & _DPRINTK_FLAGS_INCL_MODNAME)
 		pos += snprintf(buf + pos, remaining(pos), "%s:",
 				desc->modname);
-	if (desc->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
+	if (dp->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
 		pos += snprintf(buf + pos, remaining(pos), "%s:",
 				desc->function);
-	if (desc->flags & _DPRINTK_FLAGS_INCL_LINENO)
+	if (dp->flags & _DPRINTK_FLAGS_INCL_LINENO)
 		pos += snprintf(buf + pos, remaining(pos), "%d:",
-				desc->lineno);
+				dp->lineno);
 	if (pos - pos_after_tid)
 		pos += snprintf(buf + pos, remaining(pos), " ");
 	if (pos >= PREFIX_SIZE)
@@ -884,6 +886,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
 {
 	struct ddebug_iter *iter = m->private;
 	struct _ddebug *dp = p;
+	struct _ddebug_site *dc;
 	struct flagsbuf flags;
 
 	if (p == SEQ_START_TOKEN) {
@@ -892,9 +895,11 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
 		return 0;
 	}
 
+	dc = dp->site;
+
 	seq_printf(m, "%s:%u [%s]%s =%s \"",
-		   trim_prefix(dp->filename), dp->lineno,
-		   iter->table->mod_name, dp->function,
+		   trim_prefix(dc->filename), dp->lineno,
+		   iter->table->mod_name, dc->function,
 		   ddebug_describe_flags(dp->flags, &flags));
 	seq_escape(m, dp->format, "\t\r\n\"");
 	seq_puts(m, "\"\n");
@@ -1097,17 +1102,17 @@ static int __init dynamic_debug_init(void)
 		return 0;
 	}
 	iter = __start___dyndbg;
-	modname = iter->modname;
+	modname = iter->site->modname;
 	iter_start = iter;
 	for (; iter < __stop___dyndbg; iter++) {
 		entries++;
-		if (strcmp(modname, iter->modname)) {
+		if (strcmp(modname, iter->site->modname)) {
 			modct++;
 			ret = ddebug_add_module(iter_start, n, modname);
 			if (ret)
 				goto out_err;
 			n = 0;
-			modname = iter->modname;
+			modname = iter->site->modname;
 			iter_start = iter;
 		}
 		n++;
@@ -1117,9 +1122,10 @@ static int __init dynamic_debug_init(void)
 		goto out_err;
 
 	ddebug_init_success = 1;
-	vpr_info("%d modules, %d entries and %d bytes in ddebug tables, %d bytes in __dyndbg section\n",
+	vpr_info("%d modules, %d entries and %d bytes in ddebug tables, %d bytes in __dyndbg section, %d bytes in __dyndbg_sites section\n",
 		 modct, entries, (int)(modct * sizeof(struct ddebug_table)),
-		 (int)(entries * sizeof(struct _ddebug)));
+		 (int)(entries * sizeof(struct _ddebug)),
+		 (int)(entries * sizeof(struct _ddebug_site)));
 
 	/* apply ddebug_query boot param, dont unload tables on err */
 	if (ddebug_setup_string[0] != '\0') {
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [RFC PATCH v5 18/28] dyndbg: RFC - DEFINE_DYNAMIC_DEBUG_TABLE
       [not found] <20210511185057.3815777-1-jim.cromie@gmail.com>
  2021-05-11 18:50 ` [RFC PATCH v5 03/28] dyndbg: split struct _ddebug's display fields to new _ddebug_site Jim Cromie
@ 2021-05-11 18:50 ` Jim Cromie
  2021-05-11 18:50 ` [RFC PATCH v5 19/28] dyndbg: RFC handle __dyndbg* sections in module.lds.h Jim Cromie
  2 siblings, 0 replies; 3+ messages in thread
From: Jim Cromie @ 2021-05-11 18:50 UTC (permalink / raw)
  To: Arnd Bergmann, Jason Baron, linux-arch, linux-kernel; +Cc: linux-mm, Jim Cromie

DEFINE_DYNAMIC_DEBUG_TABLE is based on DEFINE_DYNAMIC_DEBUG_METADATA.
Like its model, it creates/allocates a pair of structs: _ddebug &
_ddebug_site.  It inits them distinctively, so is_dyndbg_header_pair()
macro can verify them.

Its purpose is to reserve a single pair of header records in the front
of the "__dyndbg" & "__dyndbg_sites" sections.  This has several parts;

- the pair of structs are placed into 2 .gnu.linkonce.dyndbg* sections
  corresponding to the 2 dyndbg* sections populated by _METADATA

- vmlinux.lds.h places these 2 new sections into the dyndbg* sections,
  at the start___dyndbg*s.

- the pair has "__used __weak" to qualm compiler concerns.
  explicit externs were problematic with initialization, static decls too.

With this, the header record is now really __dyndbg[0].

Notes:

DYNAMIC_DEBUG is a 'transparent' facility, in that pr_debug() users
get extra features without additional api.  Because of this,
DEFINE_DYNAMIC_DEBUG_TABLE is invoked by dynamic_debug.h on behalf of
all its (indirect) users, including printk.h.

IOW this has wide effects; it results in multiple redundant
declarations of header records, even single object files may get
multiple copies.  Placing these records into .gnu.linkonce. sections
with "__used __weak " seems to resolve the redundancies.  This may
well be the cause of the need for HEAD~1.

In vmlinux-lds.h, I added 2 more KEEPs to place the .gnu.linkonce.*
headers at the front of their respective __dyndbg* sections.  I moved
the __dyndbg lines into a new macro, which maybe should be done as a
separate commit, or in the earlier commit that touched it. RFC.

The headers are really just struct _ddebug*s, they are initialized
distinctively so that they're recogizable by code, using macro
is_dyndbg_header_pair(dbg, dbgsite).

DECLARE_DYNAMIC_DEBUG_TABLE() initializes the header record pairs with
values which are "impossible" for pr_debug()s:

- lineno == 0
- site == iter->site
- modname == function		not possible in proper linkage
- modname == format		not possible in normal linkage
- filename = (void*) iter	forced loopback

Next:

Get __dyndbg[0] from any *dp within __dyndbg[N].  Then with
__dyndbg[0].site, we can get __dyndbg_sites[N].  This is a little
slower than a direct pointer, but this is an unlikely debug path, so
this 'up-N-over-down-N' access is ok.

Eventually we can adapt the header (as a new struct/union) to keep its
pointer to the __dyndbg_sites[] section/block, while allowing us to
drop it from struct _ddebug, regaining memory parity with master.  But
for now, we keep .site, and will soon use it to validate the
'up-N-over-down-N' computation.

For clarity, N is _ddebug._index.  For both builtins & loadable
modules, it is init'd to remember the fixed offset from the beginning
of the section/block/memory-allocation (actual elf sections for *ko's,
and a __start/__stop delineated part of .data for builtins).

N/_index will be used solely to get to __debugs[0] and over to
__debug_sites[N].  It is distinct from a module's numdbgs, which is
used mainly when walking control, and is kept in struct _ddeug_table.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 include/asm-generic/vmlinux.lds.h | 27 ++++++++++++-------
 include/linux/dynamic_debug.h     | 45 +++++++++++++++++++++++++++++++
 lib/dynamic_debug.c               | 18 ++++++-------
 3 files changed, 72 insertions(+), 18 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 4f2af9de2f03..189286405b40 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -335,6 +335,22 @@
 	KEEP(*(.dtb.init.rodata))					\
 	__dtb_end = .;
 
+/* implement dynamic printk debug */
+#if defined(CONFIG_DYNAMIC_DEBUG) || defined(CONFIG_DYNAMIC_DEBUG_CORE)
+#define DYNAMIC_DEBUG_DATA()						\
+	. = ALIGN(8);							\
+	__start___dyndbg_sites = .;					\
+	KEEP(*(.gnu.linkonce.dyndbg_site))				\
+	KEEP(*(__dyndbg_sites))						\
+	__stop___dyndbg_sites = .;					\
+	__start___dyndbg = .;						\
+	KEEP(*(.gnu.linkonce.dyndbg))					\
+	KEEP(*(__dyndbg))						\
+	__stop___dyndbg = .;
+#else
+#define DYNAMIC_DEBUG_DATA()
+#endif
+
 /*
  * .data section
  */
@@ -351,15 +367,8 @@
 	__end_once = .;							\
 	STRUCT_ALIGN();							\
 	*(__tracepoints)						\
-	/* implement dynamic printk debug */				\
-	. = ALIGN(8);							\
-	__start___dyndbg_sites = .;					\
-	KEEP(*(__dyndbg_sites))					\
-	__stop___dyndbg_sites = .;					\
-	__start___dyndbg = .;						\
-	KEEP(*(__dyndbg))						\
-	__stop___dyndbg = .;						\
-	LIKELY_PROFILE()		       				\
+	DYNAMIC_DEBUG_DATA()						\
+	LIKELY_PROFILE()						\
 	BRANCH_PROFILE()						\
 	TRACE_PRINTKS()							\
 	BPF_RAW_TP()							\
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index a15e417cbba8..06ae1d8d8c10 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -113,6 +113,43 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
 		_DPRINTK_KEY_INIT				\
 	}
 
+/*
+ * DEFINE_DYNAMIC_DEBUG_TABLE(): This is a special version of
+ * DEFINE_DYNAMIC_DEBUG_METADATA().  It creates a single pair of
+ * header records, which linker scripts place into __dyndbg[0] &
+ * __dyndbg_sites[0].
+ * To allow a robust runtime test for is_dyndbg_header_pair(I,S),
+ * force-initialize S->filename to point back to I, an otherwize
+ * pathological condition.
+ */
+#define DEFINE_DYNAMIC_DEBUG_TABLE()				\
+	/* forward decl, allowing loopback pointer */		\
+	__weak struct _ddebug __used __aligned(8)		\
+		__section(".gnu.linkonce.dyndbg")		\
+		_LINKONCE_dyndbg_header;			\
+	__weak struct _ddebug_site __used __aligned(8)		\
+		__section(".gnu.linkonce.dyndbg_site")		\
+	_LINKONCE_dyndbg_site_header = {			\
+		.modname = KBUILD_MODNAME,			\
+		.function = KBUILD_MODNAME,			\
+		/* forced pointer loopback, for distinction */	\
+		.filename = (void *) &_LINKONCE_dyndbg_header	\
+	};							\
+	__weak struct _ddebug __used __aligned(8)		\
+		__section(".gnu.linkonce.dyndbg")		\
+	_LINKONCE_dyndbg_header = {				\
+		.site = &_LINKONCE_dyndbg_site_header,		\
+		.format = KBUILD_MODNAME			\
+	}
+
+/* The header initializations as a distinguishing predicate */
+#define is_dyndbg_header_pair(iter, sitep)			\
+	(sitep == iter->site					\
+	 && (!iter->lineno)					\
+	 && (iter->format == sitep->modname)			\
+	 && (sitep->modname == sitep->function)			\
+	 && ((void *)sitep->filename == (void *)iter))
+
 #ifdef CONFIG_JUMP_LABEL
 
 #ifdef DEBUG
@@ -243,4 +280,12 @@ static inline int dynamic_debug_exec_queries(const char *query, const char *modn
 
 #endif /* !CONFIG_DYNAMIC_DEBUG_CORE */
 
+#if ((defined(CONFIG_DYNAMIC_DEBUG) ||						\
+      (defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE)))	\
+     && defined(KBUILD_MODNAME) && !defined(NO_DYNAMIC_DEBUG_TABLE))
+
+/* transparently invoked, except when -DNO_DYNAMIC_DEBUG_TABLE */
+DEFINE_DYNAMIC_DEBUG_TABLE();
+#endif
+
 #endif
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index c5927b6c1c0c..9d9cb36f40a6 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1190,8 +1190,7 @@ static int __init dynamic_debug_init(void)
 	const char *modname = NULL;
 	char *cmdline;
 	int ret = 0;
-	int site_ct = 0, entries = 0, modct = 0;
-	int mod_index = 0;
+	int i, site_ct = 0, modct = 0, mod_index = 0;
 
 	if (&__start___dyndbg == &__stop___dyndbg) {
 		if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
@@ -1207,10 +1206,9 @@ static int __init dynamic_debug_init(void)
 	site = site_mod_start = __start___dyndbg_sites;
 	modname = site->modname;
 
-	for (; iter < __stop___dyndbg; iter++, site++) {
+	for (i = 0; iter < __stop___dyndbg; iter++, site++, i++) {
 
-		BUG_ON(site != iter->site);
-		entries++;
+		WARN_ON(site != iter->site);
 
 		if (strcmp(modname, site->modname)) {
 			modct++;
@@ -1219,10 +1217,12 @@ static int __init dynamic_debug_init(void)
 						  site_ct, mod_index, modname);
 			if (ret)
 				goto out_err;
-			site_ct = 0;
+
 			modname = site->modname;
 			iter_mod_start = iter;
 			site_mod_start = site;
+			mod_index += site_ct;
+			site_ct = 0;
 		}
 		site_ct++;
 	}
@@ -1232,9 +1232,9 @@ static int __init dynamic_debug_init(void)
 
 	ddebug_init_success = 1;
 	vpr_info("%d modules, %d entries and %d bytes in ddebug tables, %d bytes in __dyndbg section, %d bytes in __dyndbg_sites section\n",
-		 modct, entries, (int)(modct * sizeof(struct ddebug_table)),
-		 (int)(entries * sizeof(struct _ddebug)),
-		 (int)(entries * sizeof(struct _ddebug_site)));
+		 modct, i, (int)(modct * sizeof(struct ddebug_table)),
+		 (int)(i * sizeof(struct _ddebug)),
+		 (int)(i * sizeof(struct _ddebug_site)));
 
 	/* apply ddebug_query boot param, dont unload tables on err */
 	if (ddebug_setup_string[0] != '\0') {
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [RFC PATCH v5 19/28] dyndbg: RFC handle __dyndbg* sections in module.lds.h
       [not found] <20210511185057.3815777-1-jim.cromie@gmail.com>
  2021-05-11 18:50 ` [RFC PATCH v5 03/28] dyndbg: split struct _ddebug's display fields to new _ddebug_site Jim Cromie
  2021-05-11 18:50 ` [RFC PATCH v5 18/28] dyndbg: RFC - DEFINE_DYNAMIC_DEBUG_TABLE Jim Cromie
@ 2021-05-11 18:50 ` Jim Cromie
  2 siblings, 0 replies; 3+ messages in thread
From: Jim Cromie @ 2021-05-11 18:50 UTC (permalink / raw)
  To: Arnd Bergmann, linux-arch, linux-kernel; +Cc: linux-mm, Jim Cromie

Up until now, loadable modules have tacitly linked the 2 __dyndbg*
sections into the .ko, as observable in log by enabling module.c's
pr_debugs and loading a module.

But now, we need to explicitly place the header sections in front of
their respective __dyndbg* sections, so we reuse input section names
for the output.

This gives us the placement we need for the header record, which we
can see in the "add-module:"s and elements "0 0" below:

    "0 0" lines are headers: predicate (function==module && !lineno)
    "X debug prints in" are 1 too high, they count headers.
    we are adding tables for empty modules (1st 2 below)

[    7.578873] dyndbg: add-module: ghash_clmulni_intel
[    7.579716] dyndbg:  0 0 ghash_clmulni_intel.ghash_clmulni_intel.0
[    7.608995] dyndbg:   1 debug prints in module ghash_clmulni_intel
[    8.078085] dyndbg: add-module: rapl
[    8.078977] dyndbg:  0 0 rapl.rapl.0
[    8.079584] dyndbg:   1 debug prints in module rapl
[    8.082009] RAPL PMU: API unit is 2^-32 Joules, 0 fixed counters, 10737418240 ms ovfl timer
[    8.099294] dyndbg: add-module: intel_rapl_common
[    8.100177] dyndbg:  0 0 intel_rapl_common.intel_rapl_common.0
[    8.101026] dyndbg:  1 1 intel_rapl_common.rapl_remove_package.1279
[    8.101931] dyndbg:  2 2 intel_rapl_common.rapl_detect_domains.1245
[    8.102836] dyndbg:  3 3 intel_rapl_common.rapl_detect_domains.1242
[    8.103778] dyndbg:  4 4 intel_rapl_common.rapl_package_register_powercap.1159
[    8.104960] dyndbg:  5 5 intel_rapl_common.rapl_package_register_powercap.1145
[    8.106246] dyndbg:  6 6 intel_rapl_common.rapl_package_register_powercap.1114
[    8.107302] dyndbg:  7 7 intel_rapl_common.rapl_package_register_powercap.1108
[    8.108338] dyndbg:  8 8 intel_rapl_common.rapl_update_domain_data.1083
[    8.109278] dyndbg:  9 9 intel_rapl_common.rapl_check_unit_atom.824
[    8.110255] dyndbg:  10 10 intel_rapl_common.rapl_check_unit_core.796
[    8.111361] dyndbg:  11 11 intel_rapl_common.rapl_read_data_raw.722
[    8.112301] dyndbg:  12 12 intel_rapl_common.contraint_to_pl.303
[    8.113276] dyndbg:  13 debug prints in module intel_rapl_common
[    8.130452] dyndbg: add-module: intel_rapl_msr
[    8.131140] dyndbg:  0 0 intel_rapl_msr.intel_rapl_msr.0
[    8.132026] dyndbg:  1 1 intel_rapl_msr.rapl_msr_probe.172
[    8.132818] dyndbg:  2 2 intel_rapl_msr.rapl_msr_read_raw.104
[    8.133794] dyndbg:   3 debug prints in module intel_rapl_msr

This gives us the property we need:

   fixed offset from &__dyndbg[N] to &__dyndbg[0]
   container_of gets &header
   header has ptr to __dyndbg_sites[]
   we can (in principle) drop __dyndbg.site ptr
   (after we adapt header to keep it)

TODO:

At this point, for loaded modules, ddebug_add_module() sees the header
as 0'th element, as we need in order to drop site (and regain worst
case footprint parity).

It could/should properly init this header to support the _sites[n]
lookup for loaded mods.  Or at least handle it explicitly.  Or at
least see what proc-show does with it currently.

Note that for builtins, decided by (__start <= dp < __stop), we use
__start___dyndbg_sites[N] directly, and dont need the header.

But maybe we should use it anyway, double-checking/BUGing when wrong.

Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
 include/asm-generic/module.lds.h | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/include/asm-generic/module.lds.h b/include/asm-generic/module.lds.h
index f210d5c1b78b..328c48dfc88c 100644
--- a/include/asm-generic/module.lds.h
+++ b/include/asm-generic/module.lds.h
@@ -4,7 +4,17 @@
 
 /*
  * <asm/module.lds.h> can specify arch-specific sections for linking modules.
- * Empty for the asm-generic header.
+ *
+ * For loadable modules with CONFIG_DYNAMIC_DEBUG, we need to keep the
+ * 2 __dyndbg* ELF sections, which are loaded by module.c
+ *
+ * Pack the 2 __dyndbg* input sections with their respective
+ * .gnu.linkonce. header records into 2 output sections, with those
+ * header records in the 0th element.
  */
+SECTIONS {
+__dyndbg_sites	: ALIGN(8) { *(.gnu.linkonce.dyndbg_site) *(__dyndbg_sites) }
+__dyndbg	: ALIGN(8) { *(.gnu.linkonce.dyndbg)	  *(__dyndbg) }
+}
 
 #endif /* __ASM_GENERIC_MODULE_LDS_H */
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-05-11 18:52 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20210511185057.3815777-1-jim.cromie@gmail.com>
2021-05-11 18:50 ` [RFC PATCH v5 03/28] dyndbg: split struct _ddebug's display fields to new _ddebug_site Jim Cromie
2021-05-11 18:50 ` [RFC PATCH v5 18/28] dyndbg: RFC - DEFINE_DYNAMIC_DEBUG_TABLE Jim Cromie
2021-05-11 18:50 ` [RFC PATCH v5 19/28] dyndbg: RFC handle __dyndbg* sections in module.lds.h Jim Cromie

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).