aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Thompson <daniel.thompson@linaro.org>2014-08-19 15:37:42 +0100
committerDaniel Thompson <daniel.thompson@linaro.org>2022-04-13 15:06:25 +0100
commit169ce1152ce2b13559814fa713c5b2a6ea8a4463 (patch)
tree67a7e72f77e382bd37bf3e441e717ed71093878c
parente333b2ce40d76f3250a29a610671861f5ad0689c (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.c2
-rw-r--r--kernel/debug/kdb/kdb_main.c67
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 = {