[PATCH v6 43/57] dyndbg: add _index,_map to struct _ddebug

From: Jim Cromie
Date: Sun Sep 04 2022 - 17:45:57 EST


We now have 2 vectors of data: (__dyndbg, __dyndbg_sites), known to be
equal-length, with _ddebug.site connecting them, like rungs on a
ladder. In order to drop _ddebug.site, we need to replace the
absolute ptr with a cheap relative-address computation:

struct _ddebug_site *site = _ddebug_map_site(desc);

1st step: (done here)

add ._index, ._map fields, and initialize them in __debug_add_module()
to N (and = each other), where N is each element's position in the
builtins (or loaded-module). Then _ddebug_map_site(desc) can compute
&descs[0], and then use container_of() to go up 1 struct.

RFC: Next steps: (outlined here, not done):

1. UPLINK:

Define 2 new header structs, with _uplink fields, pointing at _ddebug_info:

struct _ddebug_site_hdr {
union {
struct _ddebug_info _uplink*;
struct _ddebug_site __; // sizeof this
};
};

struct _ddebug_hdr {
union {
struct _ddebug_info _uplink*;
struct _ddebug __; // sizeof this
};
};

the union forces the allocation to be the bigger of the 2, with the
expectation that the pointer will always fit.

2. Reserve a record in front of the __dyndbg* sections.

can be done in {module,vmlinux}.lds.h, something like:

SECTIONS {
__dyndbg_sites : ALIGN(8) { *(.gnu.linkonce.dyndbg_site) *(__dyndbg_sites) }
__dyndbg : ALIGN(8) { *(.gnu.linkonce.dyndbg) *(__dyndbg) }
}
KEEP( *(.gnu.linkonce.__dyndbg_site) *(__dyndbg_sites))

3. specialize DYNAMIC_DEBUG_METADATA_CLS as DYNAMIC_DEBUG_TABLE.

This special macro version creates header records, and puts them into
.gnu.linkonce section. Unusually (uniquely?), it is tacitly invoked
by dynamic_debug.h on behalf of all printk.h includers. This can
result in multiple "declarations" in the same scope, so macro uses
__weak and/or __unused to suppress linkage & errors.

This created mumble-RELATIVE linkage errors in a few parts of the
kernel, I worked around this by just suppressing the declaration if
cflags includes -DDYNDBG_NO_TABLE.

The up-link is init'd in 2 cases:

The file static struct _ddebug_info builtins is initialized by
dynamic_debug_init(), with the 3 ELF sections addresses+lengths
composing the builtin dyndbg-state. It will be able to also
initialize the header.UPLINK fields, as long as the storage space is
available. Then rel_map() can rely upon it to provide the &site ref
for a callsite's desc*, if it is enabled.

Then at runtime (assuming initialization is correct):

- use _index to get &descs[0]
- container-of gets .UPLINK to &dyndbg_info
- info->sites[_index] - replaces .sites
- info->sites[_map] - allows de-duplicated vector position. M<N

But thats all talk; this patch just adds and initializes the index and
map fields.

._index:14 allows ~16k entries, more than enough for ~3k built-in
callsites, or ~4k in amdgpu (with dyn-drm-trc commitset). It is
initialized in __ddebug_add_module(), a new refactorization.

ddebug_add_module() is called from kernel/module.c, that interface is
preserved. It just passes 0 to inner fn when loading modules.

Signed-off-by: Jim Cromie <jim.cromie@xxxxxxxxx>
---
include/linux/dynamic_debug.h | 3 +++
lib/dynamic_debug.c | 8 ++++++++
2 files changed, 11 insertions(+)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index c05148dab367..268e903b7c4e 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -31,6 +31,8 @@ struct _ddebug {
/* format is always needed, lineno shares word with flags */
const char *format;
const unsigned lineno:16;
+ unsigned _index:14;
+ unsigned _map:14;
#define CLS_BITS 6
unsigned int class_id:CLS_BITS;
#define _DPRINTK_CLASS_DFLT ((1 << CLS_BITS) - 1)
@@ -60,6 +62,7 @@ struct _ddebug {
#define _DPRINTK_FLAGS_DEFAULT 0
#endif
unsigned int flags:8;
+
#ifdef CONFIG_JUMP_LABEL
union {
struct static_key_true dd_key_true;
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index f1f354efed5a..506a7e2e59d6 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1344,6 +1344,7 @@ static int __ddebug_add_module(struct _ddebug_info *di, unsigned int base,
const char *modname)
{
struct ddebug_table *dt;
+ int i;

v3pr_info("add-module: %s.%d sites\n", modname, di->num_descs);
if (!di->num_descs) {
@@ -1364,6 +1365,7 @@ static int __ddebug_add_module(struct _ddebug_info *di, unsigned int base,
*/
dt->mod_name = modname;
dt->ddebugs = di->descs;
+ dt->sites = di->sites;
dt->num_ddebugs = di->num_descs;

INIT_LIST_HEAD(&dt->link);
@@ -1372,6 +1374,12 @@ static int __ddebug_add_module(struct _ddebug_info *di, unsigned int base,
if (di->classes && di->num_classes)
ddebug_attach_module_classes(dt, di->classes, di->num_classes);

+ for (i = 0; i < di->num_descs; i++) {
+ di->descs[i]._index = base + i;
+ v3pr_info(" %d %d %s.%s.%d\n", i, base, modname,
+ di->descs[i].site->_function, di->descs[i].lineno);
+ }
+
mutex_lock(&ddebug_lock);
list_add_tail(&dt->link, &ddebug_tables);
mutex_unlock(&ddebug_lock);
--
2.37.2