This patchset started out as a simple patch to introduce the irqs command from Android's FIQ debugger to kdb. However it has since grown more powerful because allowing kdb to reuse existing kernel infrastructure gives us extra opportunities.
Based on the comments at the top of irqdesc.h (plotting to take the irq_desc structure private to kernel/irq) and the relative similarity between FIQ debugger's irqs command and the contents /proc/interrupts we start by adding a kdb feature to print seq_files. This forms the foundation for a new command, interrupts.
I have also been able to implement a much more generic command, seq_file, that can display a good number of files from pseudo filesystems. This command is very powerful although that power does mean care must be taken to deploy it safely. It is deliberately and by default aimed at your foot!
Note that the risk associated with the seq_file command is why I implemented the interrupts command in C (in principle it could have been a kdb macro). Doing it in C codifies the need for show_interrupts() to continue using spin locks as its locking strategy.
To give an idea of what can be done with this command. The following seq_operations structures worked correctly and report no errors:
cpuinfo_op extfrag_op fragmentation_op gpiolib_seq_ops int_seq_ops (a.k.a. /proc/interrupts) pagetypeinfo_op unusable_op vmalloc_op zoneinfo_op
The following display the information correctly but triggered errors (sleeping function called from invalid context) with lock debugging enabled:
consoles_op crypto_seq_ops diskstats_op partitions_op slabinfo_op vmstat_op
All tests are run on an ARM multi_v7_defconfig kernel (plus lots of debug features) and halted using magic SysRq so that kdb has interrupt context. Note also that some of the seq_operations structures hook into driver supplied code that will only be called if that driver is enabled so the test above are useful but cannot be exhaustive.
Daniel Thompson (3): kdb: Add framework to display sequence files proc: Provide access to /proc/interrupts from kdb kdb: Implement seq_file command
fs/proc/interrupts.c | 10 +++++++++ include/linux/kdb.h | 3 +++ kernel/debug/kdb/kdb_io.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ kernel/debug/kdb/kdb_main.c | 28 +++++++++++++++++++++++++ 4 files changed, 92 insertions(+)
Lots of useful information about the system is held in pseudo filesystems and presented using the seq_file mechanism. Unfortunately during both boot up and kernel panic (both good times to break out kdb) it is difficult to examine these files. This patch introduces a means to display sequence files via kdb.
Signed-off-by: Daniel Thompson daniel.thompson@linaro.org --- include/linux/kdb.h | 3 +++ kernel/debug/kdb/kdb_io.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+)
diff --git a/include/linux/kdb.h b/include/linux/kdb.h index 290db12..2607893 100644 --- a/include/linux/kdb.h +++ b/include/linux/kdb.h @@ -25,6 +25,7 @@ typedef int (*kdb_func_t)(int, const char **); #include <linux/init.h> #include <linux/sched.h> #include <linux/atomic.h> +#include <linux/seq_file.h>
#define KDB_POLL_FUNC_MAX 5 extern int kdb_poll_idx; @@ -117,6 +118,8 @@ extern __printf(1, 0) int vkdb_printf(const char *fmt, va_list args); extern __printf(1, 2) int kdb_printf(const char *, ...); typedef __printf(1, 2) int (*kdb_printf_t)(const char *, ...);
+extern int kdb_print_seq_file(const struct seq_operations *ops); + extern void kdb_init(int level);
/* Access to kdb specific polling devices */ diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c index 14ff484..c68c223 100644 --- a/kernel/debug/kdb/kdb_io.c +++ b/kernel/debug/kdb/kdb_io.c @@ -850,3 +850,54 @@ int kdb_printf(const char *fmt, ...) return r; } EXPORT_SYMBOL_GPL(kdb_printf); + +/* + * Display a seq_file on the kdb console. + */ + +static int __kdb_print_seq_file(struct seq_file *m, void *v) +{ + int i, res; + + res = m->op->show(m, v); + if (0 != res) + return KDB_BADLENGTH; + + for (i = 0; i < m->count && !KDB_FLAG(CMD_INTERRUPT); i++) + kdb_printf("%c", m->buf[i]); + m->count = 0; + + return 0; +} + +int kdb_print_seq_file(const struct seq_operations *ops) +{ + static char seq_buf[4096]; + static DEFINE_SPINLOCK(seq_buf_lock); + unsigned long flags; + struct seq_file m = { + .buf = seq_buf, + .size = sizeof(seq_buf), + /* .lock is deliberately uninitialized to help reveal + * unsupportable show methods + */ + .op = ops, + }; + loff_t pos = 0; + void *v; + int res = 0; + + v = ops->start(&m, &pos); + while (v) { + spin_lock_irqsave(&seq_buf_lock, flags); + res = __kdb_print_seq_file(&m, v); + spin_unlock_irqrestore(&seq_buf_lock, flags); + if (res != 0 || KDB_FLAG(CMD_INTERRUPT)) + break; + + v = ops->next(&m, v, &pos); + } + ops->stop(&m, v); + + return res; +}
The contents of /proc/interrupts is useful to diagnose problems during boot up or when the system becomes unresponsive (or at least it can be if failure is causes by interrupt problems). This command is also seen in out-of-tree debug systems such as Android's FIQ debugger.
This change allows the file to be displayed from kdb.
Signed-off-by: Daniel Thompson daniel.thompson@linaro.org --- fs/proc/interrupts.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/fs/proc/interrupts.c b/fs/proc/interrupts.c index a352d57..1f8eeaf 100644 --- a/fs/proc/interrupts.c +++ b/fs/proc/interrupts.c @@ -4,6 +4,7 @@ #include <linux/irqnr.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/kdb.h>
/* * /proc/interrupts @@ -45,9 +46,18 @@ static const struct file_operations proc_interrupts_operations = { .release = seq_release, };
+#ifdef CONFIG_KGDB_KDB +static int kdb_interrupts(int argc, const char **argv) +{ + return kdb_print_seq_file(&int_seq_ops); +} +#endif + static int __init proc_interrupts_init(void) { proc_create("interrupts", 0, NULL, &proc_interrupts_operations); + kdb_register("interrupts", kdb_interrupts, "", + "Show /proc/interrupts", 3); return 0; } fs_initcall(proc_interrupts_init);
On 29/04/14 15:30, Daniel Thompson wrote:
The contents of /proc/interrupts is useful to diagnose problems during boot up or when the system becomes unresponsive (or at least it can be if failure is causes by interrupt problems). This command is also seen in out-of-tree debug systems such as Android's FIQ debugger.
This change allows the file to be displayed from kdb.
Oops... two different PATCH 2/3 sent to the Linaro lists.
This was the bad one. Please ignore this patch and this thread.
Daniel.
The contents of /proc/interrupts is useful to diagnose problems during boot up or when the system becomes unresponsive (or at least it can be if failure is causes by interrupt problems). This command is also seen in out-of-tree debug systems such as Android's FIQ debugger.
This change allows the file to be displayed from kdb.
Signed-off-by: Daniel Thompson daniel.thompson@linaro.org --- fs/proc/interrupts.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/fs/proc/interrupts.c b/fs/proc/interrupts.c index a352d57..1f8eeaf 100644 --- a/fs/proc/interrupts.c +++ b/fs/proc/interrupts.c @@ -4,6 +4,7 @@ #include <linux/irqnr.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/kdb.h>
/* * /proc/interrupts @@ -45,9 +46,18 @@ static const struct file_operations proc_interrupts_operations = { .release = seq_release, };
+#ifdef CONFIG_KGDB_KDB +static int kdb_interrupts(int argc, const char **argv) +{ + return kdb_print_seq_file(&int_seq_ops); +} +#endif + static int __init proc_interrupts_init(void) { proc_create("interrupts", 0, NULL, &proc_interrupts_operations); + kdb_register("interrupts", kdb_interrupts, "", + "Show /proc/interrupts", 3); return 0; } fs_initcall(proc_interrupts_init);
Combining the kdb seq_file infrastructure with its symbolic lookups allows a good sub-set of files held in pseudo filesystems to be displayed by kdb. The seq_file command does exactly this and allows a significant subset of pseudo files to be safely examined whilst debugging (and in the hands of a brave expert an even bigger subset can be unsafely examined).
Good arguments to try with this command include: cpuinfo_op, gpiolib_seq_ops and vmalloc_op.
Signed-off-by: Daniel Thompson daniel.thompson@linaro.org --- kernel/debug/kdb/kdb_main.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 0b097c8..d87731c 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -1734,6 +1734,32 @@ static int kdb_mm(int argc, const char **argv) }
/* + * kdb_seq_file - This function implements the 'seq_file' command. + * seq_file address-expression + */ +static int kdb_seq_file(int argc, const char **argv) +{ + int diag; + unsigned long addr; + int nextarg; + long offset; + char *name; + const struct seq_operations *ops; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, &name); + if (diag) + return diag; + + if (nextarg != argc+1) + return KDB_ARGCOUNT; + + ops = (const struct seq_operations *) (addr + offset); + kdb_printf("Using sequence_ops at 0x%p (%s)\n", ops, name); + return kdb_print_seq_file(ops); +} + +/* * kdb_go - This function implements the 'go' command. * go [address-expression] */ @@ -2838,6 +2864,8 @@ static void __init kdb_inittab(void) "Display per_cpu variables", 3, KDB_REPEAT_NONE); kdb_register_repeat("grephelp", kdb_grep_help, "", "Display help on | grep", 0, KDB_REPEAT_NONE); + kdb_register_repeat("seq_file", kdb_seq_file, "", + "Show a seq_file using struct seq_operations", 3, KDB_REPEAT_NONE); }
/* Execute any commands defined in kdb_cmds. */
This patchset started out as a simple patch to introduce the irqs command from Android's FIQ debugger to kdb. However it has since grown more powerful because allowing kdb to reuse existing kernel infrastructure gives us extra opportunities.
Based on the comments at the top of irqdesc.h (plotting to take the irq_desc structure private to kernel/irq) and the relative similarity between FIQ debugger's irqs command and the contents /proc/interrupts we start by adding a kdb feature to print seq_files. This forms the foundation for a new command, interrupts.
I have also been able to implement a much more generic command, seq_file, that can display a good number of files from pseudo filesystems. This command is very powerful although that power does mean care must be taken to deploy it safely. It is deliberately and by default aimed at your foot!
Note that the risk associated with the seq_file command is why I implemented the interrupts command in C (in principle it could have been a kdb macro). Doing it in C codifies the need for show_interrupts() to continue using spin locks as its locking strategy.
To give an idea of what can be done with this command. The following seq_operations structures worked correctly and report no errors:
cpuinfo_op extfrag_op fragmentation_op gpiolib_seq_ops int_seq_ops (a.k.a. /proc/interrupts) pagetypeinfo_op unusable_op vmalloc_op zoneinfo_op
The following display the information correctly but triggered errors (sleeping function called from invalid context) with lock debugging enabled:
consoles_op crypto_seq_ops diskstats_op partitions_op slabinfo_op vmstat_op
All tests are run on an ARM multi_v7_defconfig kernel (plus lots of debug features) and halted using magic SysRq so that kdb has interrupt context. Note also that some of the seq_operations structures hook into driver supplied code that will only be called if that driver is enabled so the test above are useful but cannot be exhaustive.
Changes since v1: * Added nop inline version of kdb_print_seq_file() and used it to fix build error when CONFIG_KGDB_KDB is not set (oops). * Better comment explaining why seq_file's lock member can be left uninitialized (its will not detect errors because we know it is already not allowed for seq_file ops to use it).
Daniel Thompson (3): kdb: Add framework to display sequence files proc: Provide access to /proc/interrupts from kdb kdb: Implement seq_file command
fs/proc/interrupts.c | 8 +++++++ include/linux/kdb.h | 5 +++++ kernel/debug/kdb/kdb_io.c | 53 +++++++++++++++++++++++++++++++++++++++++++++ kernel/debug/kdb/kdb_main.c | 28 ++++++++++++++++++++++++ 4 files changed, 94 insertions(+)
Lots of useful information about the system is held in pseudo filesystems and presented using the seq_file mechanism. Unfortunately during both boot up and kernel panic (both good times to break out kdb) it is difficult to examine these files. This patch introduces a means to display sequence files via kdb.
Signed-off-by: Daniel Thompson daniel.thompson@linaro.org --- include/linux/kdb.h | 5 +++++ kernel/debug/kdb/kdb_io.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+)
diff --git a/include/linux/kdb.h b/include/linux/kdb.h index 290db12..fb46dd4 100644 --- a/include/linux/kdb.h +++ b/include/linux/kdb.h @@ -25,6 +25,7 @@ typedef int (*kdb_func_t)(int, const char **); #include <linux/init.h> #include <linux/sched.h> #include <linux/atomic.h> +#include <linux/seq_file.h>
#define KDB_POLL_FUNC_MAX 5 extern int kdb_poll_idx; @@ -117,6 +118,8 @@ extern __printf(1, 0) int vkdb_printf(const char *fmt, va_list args); extern __printf(1, 2) int kdb_printf(const char *, ...); typedef __printf(1, 2) int (*kdb_printf_t)(const char *, ...);
+extern int kdb_print_seq_file(const struct seq_operations *ops); + extern void kdb_init(int level);
/* Access to kdb specific polling devices */ @@ -151,6 +154,8 @@ extern int kdb_register_repeat(char *, kdb_func_t, char *, char *, extern int kdb_unregister(char *); #else /* ! CONFIG_KGDB_KDB */ static inline __printf(1, 2) int kdb_printf(const char *fmt, ...) { return 0; } +static inline int +kdb_print_seq_file(const struct seq_operations *ops) { return 0; } static inline void kdb_init(int level) {} static inline int kdb_register(char *cmd, kdb_func_t func, char *usage, char *help, short minlen) { return 0; } diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c index 14ff484..c68c223 100644 --- a/kernel/debug/kdb/kdb_io.c +++ b/kernel/debug/kdb/kdb_io.c @@ -850,3 +850,54 @@ int kdb_printf(const char *fmt, ...) return r; } EXPORT_SYMBOL_GPL(kdb_printf); + +/* + * Display a seq_file on the kdb console. + */ + +static int __kdb_print_seq_file(struct seq_file *m, void *v) +{ + int i, res; + + res = m->op->show(m, v); + if (0 != res) + return KDB_BADLENGTH; + + for (i = 0; i < m->count && !KDB_FLAG(CMD_INTERRUPT); i++) + kdb_printf("%c", m->buf[i]); + m->count = 0; + + return 0; +} + +int kdb_print_seq_file(const struct seq_operations *ops) +{ + static char seq_buf[4096]; + static DEFINE_SPINLOCK(seq_buf_lock); + unsigned long flags; + struct seq_file m = { + .buf = seq_buf, + .size = sizeof(seq_buf), + /* .lock is deliberately uninitialized to help reveal + * unsupportable show methods + */ + .op = ops, + }; + loff_t pos = 0; + void *v; + int res = 0; + + v = ops->start(&m, &pos); + while (v) { + spin_lock_irqsave(&seq_buf_lock, flags); + res = __kdb_print_seq_file(&m, v); + spin_unlock_irqrestore(&seq_buf_lock, flags); + if (res != 0 || KDB_FLAG(CMD_INTERRUPT)) + break; + + v = ops->next(&m, v, &pos); + } + ops->stop(&m, v); + + return res; +}
The contents of /proc/interrupts is useful to diagnose problems during boot up or when the system becomes unresponsive (or at least it can be if failure is causes by interrupt problems). This command is also seen in out-of-tree debug systems such as Android's FIQ debugger.
This change allows the file to be displayed from kdb.
Signed-off-by: Daniel Thompson daniel.thompson@linaro.org --- fs/proc/interrupts.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/fs/proc/interrupts.c b/fs/proc/interrupts.c index a352d57..d8b64f0 100644 --- a/fs/proc/interrupts.c +++ b/fs/proc/interrupts.c @@ -4,6 +4,7 @@ #include <linux/irqnr.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/kdb.h>
/* * /proc/interrupts @@ -45,9 +46,16 @@ static const struct file_operations proc_interrupts_operations = { .release = seq_release, };
+static int kdb_interrupts(int argc, const char **argv) +{ + return kdb_print_seq_file(&int_seq_ops); +} + static int __init proc_interrupts_init(void) { proc_create("interrupts", 0, NULL, &proc_interrupts_operations); + kdb_register("interrupts", kdb_interrupts, "", + "Show /proc/interrupts", 3); return 0; } fs_initcall(proc_interrupts_init);
Combining the kdb seq_file infrastructure with its symbolic lookups allows a good sub-set of files held in pseudo filesystems to be displayed by kdb. The seq_file command does exactly this and allows a significant subset of pseudo files to be safely examined whilst debugging (and in the hands of a brave expert an even bigger subset can be unsafely examined).
Good arguments to try with this command include: cpuinfo_op, gpiolib_seq_ops and vmalloc_op.
Signed-off-by: Daniel Thompson daniel.thompson@linaro.org --- kernel/debug/kdb/kdb_io.c | 6 ++++-- kernel/debug/kdb/kdb_main.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c index c68c223..5863180 100644 --- a/kernel/debug/kdb/kdb_io.c +++ b/kernel/debug/kdb/kdb_io.c @@ -878,8 +878,10 @@ int kdb_print_seq_file(const struct seq_operations *ops) struct seq_file m = { .buf = seq_buf, .size = sizeof(seq_buf), - /* .lock is deliberately uninitialized to help reveal - * unsupportable show methods + /* .lock is deliberately left uninitialized because it is + * used by seq_file read/lseek wrapper functions. It cannot be + * used from any of the seq_operations (assuming the ops are + * deadlock free with the normal interface). */ .op = ops, }; diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 0b097c8..d87731c 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -1734,6 +1734,32 @@ static int kdb_mm(int argc, const char **argv) }
/* + * kdb_seq_file - This function implements the 'seq_file' command. + * seq_file address-expression + */ +static int kdb_seq_file(int argc, const char **argv) +{ + int diag; + unsigned long addr; + int nextarg; + long offset; + char *name; + const struct seq_operations *ops; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, &name); + if (diag) + return diag; + + if (nextarg != argc+1) + return KDB_ARGCOUNT; + + ops = (const struct seq_operations *) (addr + offset); + kdb_printf("Using sequence_ops at 0x%p (%s)\n", ops, name); + return kdb_print_seq_file(ops); +} + +/* * kdb_go - This function implements the 'go' command. * go [address-expression] */ @@ -2838,6 +2864,8 @@ static void __init kdb_inittab(void) "Display per_cpu variables", 3, KDB_REPEAT_NONE); kdb_register_repeat("grephelp", kdb_grep_help, "", "Display help on | grep", 0, KDB_REPEAT_NONE); + kdb_register_repeat("seq_file", kdb_seq_file, "", + "Show a seq_file using struct seq_operations", 3, KDB_REPEAT_NONE); }
/* Execute any commands defined in kdb_cmds. */
This patchset started out as a simple patch to introduce the irqs command from Android's FIQ debugger to kdb. However it has since grown more powerful because allowing kdb to reuse existing kernel infrastructure gives us extra opportunities.
Based on the comments at the top of irqdesc.h (plotting to take the irq_desc structure private to kernel/irq) and the relative similarity between FIQ debugger's irqs command and the contents /proc/interrupts we start by adding a kdb feature to print seq_files. This forms the foundation for a new command, interrupts.
I have also been able to implement a much more generic command, seq_file, that can display a good number of files from pseudo filesystems. This command is very powerful although that power does mean care must be taken to deploy it safely. It is deliberately and by default aimed at your foot!
Note that the risk associated with the seq_file command is why I implemented the interrupts command in C (in principle it could have been a kdb macro). Doing it in C codifies the need for show_interrupts() to continue using spin locks as its locking strategy.
To give an idea of what can be done with this command. The following seq_operations structures worked correctly and report no errors:
cpuinfo_op extfrag_op fragmentation_op gpiolib_seq_ops int_seq_ops (a.k.a. /proc/interrupts) pagetypeinfo_op unusable_op vmalloc_op zoneinfo_op
The following display the information correctly but triggered errors (sleeping function called from invalid context) with lock debugging enabled:
consoles_op crypto_seq_ops diskstats_op partitions_op slabinfo_op vmstat_op
All tests are run on an ARM multi_v7_defconfig kernel (plus lots of debug features) and halted using magic SysRq so that kdb has interrupt context. Note also that some of the seq_operations structures hook into driver supplied code that will only be called if that driver is enabled so the test above are useful but cannot be exhaustive.
Changes since v2: * Moved comment explaining why seq_file's lock member can be left uninitialized to the right patch.
Changes since v1: * Added nop inline version of kdb_print_seq_file() and used it to fix build error when CONFIG_KGDB_KDB is not set (oops). * Better comment explaining why seq_file's lock member can be left uninitialized.
Daniel Thompson (3): kdb: Add framework to display sequence files proc: Provide access to /proc/interrupts from kdb kdb: Implement seq_file command
fs/proc/interrupts.c | 8 +++++++ include/linux/kdb.h | 5 +++++ kernel/debug/kdb/kdb_io.c | 53 +++++++++++++++++++++++++++++++++++++++++++++ kernel/debug/kdb/kdb_main.c | 28 ++++++++++++++++++++++++ 4 files changed, 94 insertions(+)
-- 1.9.3
Lots of useful information about the system is held in pseudo filesystems and presented using the seq_file mechanism. Unfortunately during both boot up and kernel panic (both good times to break out kdb) it is difficult to examine these files. This patch introduces a means to display sequence files via kdb.
Signed-off-by: Daniel Thompson daniel.thompson@linaro.org --- include/linux/kdb.h | 5 +++++ kernel/debug/kdb/kdb_io.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+)
diff --git a/include/linux/kdb.h b/include/linux/kdb.h index 290db12..fb46dd4 100644 --- a/include/linux/kdb.h +++ b/include/linux/kdb.h @@ -25,6 +25,7 @@ typedef int (*kdb_func_t)(int, const char **); #include <linux/init.h> #include <linux/sched.h> #include <linux/atomic.h> +#include <linux/seq_file.h>
#define KDB_POLL_FUNC_MAX 5 extern int kdb_poll_idx; @@ -117,6 +118,8 @@ extern __printf(1, 0) int vkdb_printf(const char *fmt, va_list args); extern __printf(1, 2) int kdb_printf(const char *, ...); typedef __printf(1, 2) int (*kdb_printf_t)(const char *, ...);
+extern int kdb_print_seq_file(const struct seq_operations *ops); + extern void kdb_init(int level);
/* Access to kdb specific polling devices */ @@ -151,6 +154,8 @@ extern int kdb_register_repeat(char *, kdb_func_t, char *, char *, extern int kdb_unregister(char *); #else /* ! CONFIG_KGDB_KDB */ static inline __printf(1, 2) int kdb_printf(const char *fmt, ...) { return 0; } +static inline int +kdb_print_seq_file(const struct seq_operations *ops) { return 0; } static inline void kdb_init(int level) {} static inline int kdb_register(char *cmd, kdb_func_t func, char *usage, char *help, short minlen) { return 0; } diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c index 7c70812..46aae57 100644 --- a/kernel/debug/kdb/kdb_io.c +++ b/kernel/debug/kdb/kdb_io.c @@ -850,3 +850,56 @@ int kdb_printf(const char *fmt, ...) return r; } EXPORT_SYMBOL_GPL(kdb_printf); + +/* + * Display a seq_file on the kdb console. + */ + +static int __kdb_print_seq_file(struct seq_file *m, void *v) +{ + int i, res; + + res = m->op->show(m, v); + if (0 != res) + return KDB_BADLENGTH; + + for (i = 0; i < m->count && !KDB_FLAG(CMD_INTERRUPT); i++) + kdb_printf("%c", m->buf[i]); + m->count = 0; + + return 0; +} + +int kdb_print_seq_file(const struct seq_operations *ops) +{ + static char seq_buf[4096]; + static DEFINE_SPINLOCK(seq_buf_lock); + unsigned long flags; + struct seq_file m = { + .buf = seq_buf, + .size = sizeof(seq_buf), + /* .lock is deliberately left uninitialized because it is + * used by seq_file read/lseek wrapper functions. It cannot be + * used from any of the seq_operations (assuming the ops are + * deadlock free with the normal interface). + */ + .op = ops, + }; + loff_t pos = 0; + void *v; + int res = 0; + + v = ops->start(&m, &pos); + while (v) { + spin_lock_irqsave(&seq_buf_lock, flags); + res = __kdb_print_seq_file(&m, v); + spin_unlock_irqrestore(&seq_buf_lock, flags); + if (res != 0 || KDB_FLAG(CMD_INTERRUPT)) + break; + + v = ops->next(&m, v, &pos); + } + ops->stop(&m, v); + + return res; +}
The contents of /proc/interrupts is useful to diagnose problems during boot up or when the system becomes unresponsive (or at least it can be if failure is causes by interrupt problems). This command is also seen in out-of-tree debug systems such as Android's FIQ debugger.
This change allows the file to be displayed from kdb.
Signed-off-by: Daniel Thompson daniel.thompson@linaro.org --- fs/proc/interrupts.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/fs/proc/interrupts.c b/fs/proc/interrupts.c index a352d57..d8b64f0 100644 --- a/fs/proc/interrupts.c +++ b/fs/proc/interrupts.c @@ -4,6 +4,7 @@ #include <linux/irqnr.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/kdb.h>
/* * /proc/interrupts @@ -45,9 +46,16 @@ static const struct file_operations proc_interrupts_operations = { .release = seq_release, };
+static int kdb_interrupts(int argc, const char **argv) +{ + return kdb_print_seq_file(&int_seq_ops); +} + static int __init proc_interrupts_init(void) { proc_create("interrupts", 0, NULL, &proc_interrupts_operations); + kdb_register("interrupts", kdb_interrupts, "", + "Show /proc/interrupts", 3); return 0; } fs_initcall(proc_interrupts_init);
Combining the kdb seq_file infrastructure with its symbolic lookups allows a good sub-set of files held in pseudo filesystems to be displayed by kdb. The seq_file command does exactly this and allows a significant subset of pseudo files to be safely examined whilst debugging (and in the hands of a brave expert an even bigger subset can be unsafely examined).
Good arguments to try with this command include: cpuinfo_op, gpiolib_seq_ops and vmalloc_op.
Signed-off-by: Daniel Thompson daniel.thompson@linaro.org --- kernel/debug/kdb/kdb_main.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 379650b..f11db91 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -1734,6 +1734,32 @@ static int kdb_mm(int argc, const char **argv) }
/* + * kdb_seq_file - This function implements the 'seq_file' command. + * seq_file address-expression + */ +static int kdb_seq_file(int argc, const char **argv) +{ + int diag; + unsigned long addr; + int nextarg; + long offset; + char *name; + const struct seq_operations *ops; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, &name); + if (diag) + return diag; + + if (nextarg != argc+1) + return KDB_ARGCOUNT; + + ops = (const struct seq_operations *) (addr + offset); + kdb_printf("Using sequence_ops at 0x%p (%s)\n", ops, name); + return kdb_print_seq_file(ops); +} + +/* * kdb_go - This function implements the 'go' command. * go [address-expression] */ @@ -2838,6 +2864,8 @@ static void __init kdb_inittab(void) "Display per_cpu variables", 3, KDB_REPEAT_NONE); kdb_register_repeat("grephelp", kdb_grep_help, "", "Display help on | grep", 0, KDB_REPEAT_NONE); + kdb_register_repeat("seq_file", kdb_seq_file, "", + "Show a seq_file using struct seq_operations", 3, KDB_REPEAT_NONE); }
/* Execute any commands defined in kdb_cmds. */
linaro-kernel@lists.linaro.org