diff options
author | Daniel Thompson <daniel.thompson@linaro.org> | 2014-08-19 15:37:42 +0100 |
---|---|---|
committer | Daniel Thompson <daniel.thompson@linaro.org> | 2022-04-13 15:06:25 +0100 |
commit | 169ce1152ce2b13559814fa713c5b2a6ea8a4463 (patch) | |
tree | 67a7e72f77e382bd37bf3e441e717ed71093878c | |
parent | e333b2ce40d76f3250a29a610671861f5ad0689c (diff) |
kdb: Implement seq_file command
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 subset of pseudo
files to be safely examined whilst debugging (although in the hands of a
thoughtless development they may also hit the bigger subset that can only
be safely examined if you check the lock status first).
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>
-rw-r--r-- | kernel/debug/kdb/kdb_io.c | 2 | ||||
-rw-r--r-- | kernel/debug/kdb/kdb_main.c | 67 |
2 files changed, 69 insertions, 0 deletions
diff --git a/kernel/debug/kdb/kdb_io.c b/kernel/debug/kdb/kdb_io.c index dfd3798f2b29..25c6b17c0642 100644 --- a/kernel/debug/kdb/kdb_io.c +++ b/kernel/debug/kdb/kdb_io.c @@ -891,6 +891,7 @@ static int __kdb_print_seq_file(struct seq_file *m, void *v) int kdb_print_seq_file(const struct seq_operations *ops) { static char seq_buf[4096]; + static char private[256] = { 0 }; static DEFINE_SPINLOCK(seq_buf_lock); unsigned long flags; struct seq_file m = { @@ -902,6 +903,7 @@ int kdb_print_seq_file(const struct seq_operations *ops) * deadlock free with the normal interface). */ .op = ops, + .private = private, }; loff_t pos = 0; void *v; diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 0852a537dad4..4edbe81f879a 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -1775,6 +1775,67 @@ static int kdb_mm(int argc, const char **argv) return 0; } +static int kdb_validate_function_pointer(unsigned long addr) +{ + kdb_symtab_t sym; + int found; + + found = kdbnearsym(addr, &sym); + if (!found || sym.sym_start != addr) { + kdb_printf("Bad function pointer 0x%lx\n", addr); + return KDB_BADADDR; + } + + return 0; +} + +/* + * kdb_seq_file - This function implements the 'seq_file' command. + * seq_file address-expression + * Remarks: + * We cannot fully validate the user supplied pointer (in particular we + * cannot check that the locking is safe). However we will do our best + * to check it really is an operations table since, if it isn't, we'll + * probably panic the kernel when we follow those function pointers. + */ +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; + struct seq_operations ops_copy; + + 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); + + /* Check we can read the pointer address OK */ + if (kdb_getarea(ops_copy, (unsigned long) ops)) { + kdb_printf("Cannot access sequence ops at 0x%px\n", ops); + return KDB_BADADDR; + } + + kdb_printf("Using sequence_ops at 0x%px (%s)\n", ops, name); + + /* Validate the function pointers we expect to find at this address */ + if (kdb_validate_function_pointer((unsigned long) ops->start) || + kdb_validate_function_pointer((unsigned long) ops->next) || + kdb_validate_function_pointer((unsigned long) ops->stop) || + kdb_validate_function_pointer((unsigned long) ops->show)) + return KDB_BADADDR; + + return kdb_print_seq_file(ops); +} + /* * kdb_go - This function implements the 'go' command. * go [address-expression] @@ -2875,6 +2936,12 @@ static kdbtab_t maintab[] = { .help = "Display help on | grep", .flags = KDB_ENABLE_ALWAYS_SAFE, }, + { .name = "seq_file", + .func = kdb_seq_file, + .usage = "<seq_ops>", + .help = "Show a seq_file using struct seq_operations", + .flags = KDB_ENABLE_REG_WRITE, + }, }; static kdbtab_t nmicmd = { |