[PATCH] powerpc/xmon: add debugfs entry for xmon

Guilherme G. Piccoli gpiccoli at linux.vnet.ibm.com
Tue Feb 14 08:00:42 AEDT 2017


Currently the xmon debugger is set only via kernel boot command-line.
It's disabled by default, and can be enabled with "xmon=on" on the
command-line. Also, xmon may be accessed via sysrq mechanism, but once
we enter xmon via sysrq,  it's  kept enabled until system is rebooted,
even if we exit the debugger. A kernel crash will then lead to xmon
instance, instead of triggering a kdump procedure (if configured), for
example.

This patch introduces a debugfs entry for xmon, allowing user to query
its current state and change it if desired. Basically, the "xmon" file
to read from/write to is under the debugfs mount point, on powerpc
directory. Reading this file will provide the current state of the
debugger, one of the following: "on", "off", "early" or "nobt". Writing
one of these states to the file will take immediate effect on the debugger.

Signed-off-by: Guilherme G. Piccoli <gpiccoli at linux.vnet.ibm.com>
---
* I had this patch partially done for some time, and after a discussion
at the kernel slack channel latest week, I decided to rebase and fix
some remaining bugs. I'd change 'x' option to always disable the debugger,
since with this patch we can always re-enable xmon, but today I noticed
Pan's patch on the mailing list, so perhaps his approach of adding a flag
to 'x' option is preferable. I can change this in a V2, if requested.
Thanks in advance!

 arch/powerpc/xmon/xmon.c | 124 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 105 insertions(+), 19 deletions(-)

diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 9c0e17c..5fb39db 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -29,6 +29,12 @@
 #include <linux/nmi.h>
 #include <linux/ctype.h>
 
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#endif
+
 #include <asm/ptrace.h>
 #include <asm/string.h>
 #include <asm/prom.h>
@@ -184,7 +190,12 @@ static void dump_tlb_44x(void);
 static void dump_tlb_book3e(void);
 #endif
 
-static int xmon_no_auto_backtrace;
+/* xmon_state values */
+#define XMON_OFF	0
+#define XMON_ON	1
+#define XMON_EARLY	2
+#define XMON_NOBT	3
+static int xmon_state;
 
 #ifdef CONFIG_PPC64
 #define REG		"%.16lx"
@@ -880,8 +891,8 @@ cmds(struct pt_regs *excp)
 	last_cmd = NULL;
 	xmon_regs = excp;
 
-	if (!xmon_no_auto_backtrace) {
-		xmon_no_auto_backtrace = 1;
+	if (xmon_state != XMON_NOBT) {
+		xmon_state = XMON_NOBT;
 		xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
 	}
 
@@ -3244,6 +3255,26 @@ static void xmon_init(int enable)
 	}
 }
 
+static int parse_xmon(char *p)
+{
+	if (!p || strncmp(p, "early", 5) == 0) {
+		/* just "xmon" is equivalent to "xmon=early" */
+		xmon_init(1);
+		xmon_state = XMON_EARLY;
+	} else if (strncmp(p, "on", 2) == 0) {
+		xmon_init(1);
+		xmon_state = XMON_ON;
+	} else if (strncmp(p, "off", 3) == 0) {
+		xmon_init(0);
+		xmon_state = XMON_OFF;
+	} else if (strncmp(p, "nobt", 4) == 0)
+		xmon_state = XMON_NOBT;
+	else
+		return 1;
+
+	return 0;
+}
+
 #ifdef CONFIG_MAGIC_SYSRQ
 static void sysrq_handle_xmon(int key)
 {
@@ -3266,34 +3297,89 @@ static int __init setup_xmon_sysrq(void)
 __initcall(setup_xmon_sysrq);
 #endif /* CONFIG_MAGIC_SYSRQ */
 
-static int __initdata xmon_early, xmon_off;
+#ifdef CONFIG_DEBUG_FS
+static ssize_t xmon_dbgfs_read(struct file *file, char __user *ubuffer,
+				size_t len, loff_t *offset)
+{
+	int buf_len = 0;
+	char buf[6] = { 0 };
 
-static int __init early_parse_xmon(char *p)
+	switch (xmon_state) {
+	case XMON_OFF:
+		buf_len = sprintf(buf, "off");
+		break;
+	case XMON_ON:
+		buf_len = sprintf(buf, "on");
+		break;
+	case XMON_EARLY:
+		buf_len = sprintf(buf, "early");
+		break;
+	case XMON_NOBT:
+		buf_len = sprintf(buf, "nobt");
+		break;
+	}
+
+	return simple_read_from_buffer(ubuffer, len, offset, buf, buf_len);
+}
+
+static ssize_t xmon_dbgfs_write(struct file *file, const char __user *ubuffer,
+				size_t len, loff_t *offset)
 {
-	if (!p || strncmp(p, "early", 5) == 0) {
-		/* just "xmon" is equivalent to "xmon=early" */
-		xmon_init(1);
-		xmon_early = 1;
-	} else if (strncmp(p, "on", 2) == 0)
-		xmon_init(1);
-	else if (strncmp(p, "off", 3) == 0)
-		xmon_off = 1;
-	else if (strncmp(p, "nobt", 4) == 0)
-		xmon_no_auto_backtrace = 1;
-	else
-		return 1;
+	int ret, not_copied;
+	char *buf;
+
+	/* Valid states are on, off, early and nobt. */
+	if ((*offset != 0) || (len <= 0) || (len > 6))
+                return -EINVAL;
+
+	buf = kzalloc(len + 1, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	not_copied = copy_from_user(buf, ubuffer, len);
+	if (not_copied) {
+		kfree(buf);
+		return -EFAULT;
+        }
 
+	ret = parse_xmon(buf);
+	kfree(buf);
+
+	/* parse_xmon returns 0 on success. */
+	if (ret)
+		return -EINVAL;
+	return len;
+}
+
+static const struct file_operations xmon_dbgfs_ops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = xmon_dbgfs_read,
+	.write = xmon_dbgfs_write,
+};
+
+static int __init setup_xmon_dbgfs(void)
+{
+	debugfs_create_file("xmon", 0600, powerpc_debugfs_root, NULL,
+			    &xmon_dbgfs_ops);
 	return 0;
 }
+__initcall(setup_xmon_dbgfs);
+#endif /*CONFIG_DEBUG_FS*/
+
+static int __init early_parse_xmon(char *p)
+{
+	return parse_xmon(p);
+}
 early_param("xmon", early_parse_xmon);
 
 void __init xmon_setup(void)
 {
 #ifdef CONFIG_XMON_DEFAULT
-	if (!xmon_off)
+	if (xmon_state) /* XMON_OFF */
 		xmon_init(1);
 #endif
-	if (xmon_early)
+	if (xmon_state == XMON_EARLY)
 		debugger(NULL);
 }
 
-- 
2.7.4



More information about the Linuxppc-dev mailing list