[PATCH v2 07/27] dyndbg: validate class FOO on module
Jim Cromie
jim.cromie at gmail.com
Mon May 16 15:56:20 PDT 2022
Add module-to-class validation, in
#> echo class DRM_UT_KMS +p > /proc/dynamic_debug/control
If a query has "class FOO", ddebug_validate_classname (called from
ddebug_change) requires that FOO is known to module X, otherwize X is
skipped entirely.
The choice of FOO is highly selective, giving isolation and/or
coordinated sharing of FOOs. For example, only DRM modules should
know and respond to DRM_UT_KMS.
So this, combined with module's opt-in declaration of known classes,
effectively privatizes the .class_id space for each module (or
coordinated set of modules).
Ignoring a bad query, with dynamic_debug.verbose=3:
(lots of modules will not know other module's classes)
bash-5.1# echo module drm class FOO +p > /proc/dynamic_debug/control
[ 54.507983] dyndbg: read 24 bytes from userspace
[ 54.509549] dyndbg: query 0: "module drm class FOO +p" mod:*
[ 54.511502] dyndbg: split into words: "module" "drm" "class" "FOO" "+p"
[ 54.513672] dyndbg: op='+'
[ 54.514575] dyndbg: flags=0x1
[ 54.515547] dyndbg: *flagsp=0x1 *maskp=0xffffffff
[ 54.517112] dyndbg: parsed: func="" file="" module="drm" format="" lineno=0-0 class=FOO
[ 54.519707] dyndbg: class: drm.FOO unknown
[ 54.521302] dyndbg: no matches for query
[ 54.522581] dyndbg: no-match: func="" file="" module="drm" format="" lineno=0-0 class=FOO
[ 54.525236] dyndbg: processed 1 queries, with 0 matches, 0 errs
Also add a new column to control-file output, displaying the
class-name when its not default. If a module has pr_debugs with
non-default .class_id's, and has not registered them, "<unregistered>"
is issued.
Signed-off-by: Jim Cromie <jim.cromie at gmail.com>
---
. split out validate_classnames()
---
lib/dynamic_debug.c | 70 +++++++++++++++++++++++++++++++++++++++------
1 file changed, 62 insertions(+), 8 deletions(-)
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 8f600c13048a..b1aaf8893cdf 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -56,6 +56,7 @@ struct ddebug_query {
const char *module;
const char *function;
const char *format;
+ const char *class_string;
unsigned int first_lineno, last_lineno;
};
@@ -136,13 +137,40 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
fmtlen--;
}
- v3pr_info("%s: func=\"%s\" file=\"%s\" module=\"%s\" format=\"%.*s\" lineno=%u-%u\n",
- msg,
- query->function ?: "",
- query->filename ?: "",
- query->module ?: "",
- fmtlen, query->format ?: "",
- query->first_lineno, query->last_lineno);
+ v3pr_info("%s: func=\"%s\" file=\"%s\" module=\"%s\" format=\"%.*s\" lineno=%u-%u class=%s\n",
+ msg,
+ query->function ?: "",
+ query->filename ?: "",
+ query->module ?: "",
+ fmtlen, query->format ?: "",
+ query->first_lineno, query->last_lineno, query->class_string);
+}
+
+/* return <0 if class-name is unknown/invalid, 0..CLASS_DFLT otherwise */
+static int ddebug_validate_classname(struct ddebug_table *dt, const char *class_string)
+{
+ int query_class = -ENOENT;
+ int idx;
+
+ if (!class_string)
+ /* all queries w/o class given work only on default class */
+ return _DPRINTK_CLASS_DFLT;
+
+ /*
+ * XXX single list will need to be a for-list
+ * so that modules can have 2 sets of class-decls
+ */
+ if (!dt->map)
+ return -ENOENT;
+
+ idx = match_string(dt->map->classes, dt->map->length, class_string);
+ if (idx < 0) {
+ v3pr_info("class: %s.%s unknown\n", dt->mod_name, class_string);
+ return -ENOENT;
+ }
+ query_class = idx + dt->map->base;
+
+ return query_class;
}
/*
@@ -159,6 +187,7 @@ static int ddebug_change(const struct ddebug_query *query,
unsigned int newflags;
unsigned int nfound = 0;
struct flagsbuf fbuf, nbuf;
+ int query_class;
/* search for matching ddebugs */
mutex_lock(&ddebug_lock);
@@ -169,9 +198,18 @@ static int ddebug_change(const struct ddebug_query *query,
!match_wildcard(query->module, dt->mod_name))
continue;
+ /* validate class-string against module's known classes */
+ query_class = ddebug_validate_classname(dt, query->class_string);
+ if (query_class < 0)
+ continue;
+
for (i = 0; i < dt->num_ddebugs; i++) {
struct _ddebug *dp = &dt->ddebugs[i];
+ /* match against query-class, either valid input or default */
+ if (query_class != dp->class_id)
+ continue;
+
/* match against the source filename */
if (query->filename &&
!match_wildcard(query->filename, dp->filename) &&
@@ -424,6 +462,8 @@ static int ddebug_parse_query(char *words[], int nwords,
} else if (!strcmp(keyword, "line")) {
if (parse_linerange(query, arg))
return -EINVAL;
+ } else if (!strcmp(keyword, "class")) {
+ rc = check_set(&query->class_string, arg, "class");
} else {
pr_err("unknown keyword \"%s\"\n", keyword);
return -EINVAL;
@@ -851,6 +891,13 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
return dp;
}
+static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp)
+{
+ if (iter->table->map)
+ return iter->table->map->classes[dp->class_id];
+ return NULL;
+}
+
/*
* Seq_ops show method. Called several times within a read()
* call from userspace, with ddebug_lock held. Formats the
@@ -862,6 +909,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
struct ddebug_iter *iter = m->private;
struct _ddebug *dp = p;
struct flagsbuf flags;
+ char const *class;
if (p == SEQ_START_TOKEN) {
seq_puts(m,
@@ -874,7 +922,13 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
iter->table->mod_name, dp->function,
ddebug_describe_flags(dp->flags, &flags));
seq_escape(m, dp->format, "\t\r\n\"");
- seq_puts(m, "\"\n");
+ seq_puts(m, "\"");
+
+ if (dp->class_id != _DPRINTK_CLASS_DFLT) {
+ class = ddebug_class_name(iter, dp);
+ seq_printf(m, " class:%s", class ?: "<unregistered>");
+ }
+ seq_puts(m, "\n");
return 0;
}
--
2.35.3
More information about the linux-arm-kernel
mailing list