lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20200613155738.2249399-21-jim.cromie@gmail.com>
Date:   Sat, 13 Jun 2020 09:57:34 -0600
From:   Jim Cromie <jim.cromie@...il.com>
To:     jbaron@...mai.com, linux-kernel@...r.kernel.org,
        akpm@...uxfoundation.org, gregkh@...uxfoundation.org
Cc:     linux@...musvillemoes.dk, Jim Cromie <jim.cromie@...il.com>
Subject: [PATCH v2 20/24] dyndbg: WIP towards debug-print-class based callsite controls

There are *lots* of ad-hoc debug printing solutions in kernel,
this is a 1st attempt at providing a common mechanism for many of them.

Basically, there are 2 styles of debug printing:
- levels, with increasing verbosity, 1-10 forex
- bits/flags, independently controlling separate groups of dprints

This patch does bits/flags only.

proposed API:

Usage model is for a module developer to create N exclusive subsets of
pr_debug()s by changing some of them to pr_debug_n(1,) .. pr_debug_n(N,).
Each callsite must be a single print-class, with 0 default.

No multi-type classification ala pr_debug_M(1|2, ...) is contemplated.

- change pr_debug(...)  -->  pr_debug_n(pr_class=0, ...)
- all existing uses have pr_class=0
- developer creates exclusive types of log messages with pr_class>0
  1, 2, 3 are disjoint groups, for example: hi, mid, low
  0 is reserved for existing uses.

- adds query term: "mflags $arg"
  rename keyword to prcls ?

  Qfoo() { echo module foo $* >/proc/dynamic_debug/control }
  Qfoo +p  		# all groups, including default 0
  Qfoo mflags 1 +p	# only group 1
  Qfoo mflags 12 +p	# TBD[1]: groups 1 or 2
  Qfoo mflags 0 +p	# ignored atm TBD[2]
  Qfoo mflags af +p	# TBD[3]: groups a or f (10 or 15)

so patch does:

- add unsigned int pr_classes into struct ddebug_query
  this is a bit-vector
  bit positions select which print-classes to filter callsites for

- add unsigned int pr_class:5 to struct _ddebug
  picks a single debugflag bit.  No subclass or multitype nonsense.
  nice and dense, packs with other members.
  if adoption is good, kernel will have a lot of struct _ddebugs.

- in ddebug_change()
  IFF query->module is given, and matches dt->mod_name
  print-classes are defined on a module, so we require one.
  this is fooled by "module *"
  simple fix is to exclude any wildcard when mflags given

- in parse_query()
  accept new query term: mflags $arg
  populate query->mflags
  arg-type needs some attention, but basic plumbing is there

WIP: not included:

- pr_debug_n( pr_class=0, ....)
  aka: pr_debug_class() or pr_debug_id()
  bikeshedding welcome.
  the bitpos is 1<<shift, allowing a single type. no ISA relations.
  this covers OP's high,mid,low case, many others

- no way to exersize new code in ddebug_change
  need pr_debug_n() to make a (not-null) typed callsite.
  yet - done in subsequent patches

- mflags arg-parse is primitive, placeholder

- module.debug vars
  I think this can be sanely handled with a callback to handle updates.
  Perhaps several to handle different debug/verbose flavors
  maybe we export ddebug_exec_queries.

Notes:

1- A query ANDs all its query terms together, so Qfoo() above
requires both "module foo" AND all additional query terms given in $*

But since callsite pr_class creates disjoint groups, "mflags 12" is
nonsense if it means groups 1 AND 2.  Here, 1 OR 2 is meaningful, if
its not judged to be too confusing.

2- im not sure what this does atm, or should do
   Qfoo mflags 0 +p 	 # select only untyped ? or no flags check at all ?

3- pr_class:5 gives 32 print-classes
   we can map [1-9a-w] to select any pr_class with 1 char
   then "12", "af" work as noted.
   it is succinct, but arcane.
   but it does allow mnemonic choices of pr_class
   - l,m,h	low, mid, hi
   - l,r	left right
   it also allows us to treat 1-9 as levels
   - by auto-setting 1-7 when 7 is enabled.
     ie: "mflags 7 +pu" in effect does "mflags 1234567 +pu"
     note that even if this is done,
     individual callsites or sets of them can be undone.
     you can even use 'u' as above to mark them for easier grepping
---
 include/linux/dynamic_debug.h |  1 +
 lib/dynamic_debug.c           | 33 +++++++++++++++++++++++++++++++--
 2 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 59960a8dd9f9..7ac822d6be87 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -20,6 +20,7 @@ struct _ddebug {
 	const char *function;
 	const char *filename;
 	const char *format;
+	unsigned int pr_class:5;	/* >0 for distinct developer groups */
 	unsigned int lineno:18;
 	/*
 	 * The flags field controls the behaviour at the callsite.
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index cb5c7480e026..0035218d7059 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -55,6 +55,7 @@ struct ddebug_query {
 	const char *function;
 	const char *format;
 	unsigned int first_lineno, last_lineno;
+	unsigned int pr_classes;
 };
 
 struct ddebug_iter {
@@ -132,13 +133,14 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 			fmtlen--;
 	}
 
-	vpr_info("%s: func=\"%s\" file=\"%s\" module=\"%s\" format=\"%.*s\" lineno=%u-%u\n",
+	vpr_info("%s: func=\"%s\" file=\"%s\" module=\"%s\" format=\"%.*s\" lineno=%u-%u prcls=0x%x\n",
 		 msg,
 		 maybe(query->function, ""),
 		 maybe(query->filename, ""),
 		 maybe(query->module, ""),
 		 fmtlen, maybe(query->format, ""),
-		 query->first_lineno, query->last_lineno);
+		 query->first_lineno, query->last_lineno,
+		 query->pr_classes);
 }
 
 /*
@@ -203,6 +205,27 @@ static int ddebug_change(const struct ddebug_query *query,
 			if ((~dp->flags & filter->mask) != filter->mask)
 				continue;
 
+			/* filter on non-zero print-classes */
+			if (query->pr_classes) {
+				if (!query->module) {
+					pr_err("using prcls requires module too");
+					return -EINVAL;
+				}
+				/* since print-classes are module
+				 * specific, require a module query
+				 * too.  For 'module kvm* mflags 1'
+				 * >control, this will enable
+				 * pr_class=1 in several matching modules
+				 */
+				if ((query->pr_classes & (1<<(dp->pr_class-1)))
+				    != (1<<(dp->pr_class-1))) {
+					v2pr_info("%s ~ %s mflags:0x%x !~ %d\n",
+						  dt->mod_name, query->module,
+						  query->pr_classes, dp->pr_class);
+					continue;
+				}
+			}
+
 			nfound++;
 
 			newflags = (dp->flags & mods->mask) | mods->flags;
@@ -427,6 +450,12 @@ 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, "mflags")) {
+			pr_info("handle mflags arg: %s\n", arg);
+			if (kstrtouint(arg, 4, &query->pr_classes) < 0) {
+				pr_err("bad arg for mflags: %s\n", arg);
+				return -EINVAL;
+			}
 		} else {
 			pr_err("unknown keyword \"%s\"\n", keyword);
 			return -EINVAL;
-- 
2.26.2

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ