diff options
author | Sam Leffler <sam@FreeBSD.org> | 2008-09-15 22:45:14 +0000 |
---|---|---|
committer | Sam Leffler <sam@FreeBSD.org> | 2008-09-15 22:45:14 +0000 |
commit | 39297ba45528361278dc0522b99c659f3a38cbb8 (patch) | |
tree | 6a6cd52918de6f264f6071e5f55fc410c7f1633d /sys/ddb/db_command.c | |
parent | ca3d37955c7c41e64a80c97b3f1c1fa4e9ff4897 (diff) | |
download | src-39297ba45528361278dc0522b99c659f3a38cbb8.tar.gz src-39297ba45528361278dc0522b99c659f3a38cbb8.zip |
Make ddb command registration dynamic so modules can extend
the command set (only so long as the module is present):
o add db_command_register and db_command_unregister to add and remove
commands, respectively
o replace linker sets with SYSINIT's (and SYSUINIT's) that register
commands
o expose 3 list heads: db_cmd_table, db_show_table, and db_show_all_table
for registering top-level commands, show operands, and show all operands,
respectively
While here also:
o sort command lists
o add DB_ALIAS, DB_SHOW_ALIAS, and DB_SHOW_ALL_ALIAS to add aliases
for existing commands
o add "show all trace" as an alias for "show alltrace"
o add "show all locks" as an alias for "show alllocks"
Submitted by: Guillaume Ballet <gballet@gmail.com> (original version)
Reviewed by: jhb
MFC after: 1 month
Notes
Notes:
svn path=/head/; revision=183054
Diffstat (limited to 'sys/ddb/db_command.c')
-rw-r--r-- | sys/ddb/db_command.c | 139 |
1 files changed, 86 insertions, 53 deletions
diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c index 0395e75df44e..bac7803ecdce 100644 --- a/sys/ddb/db_command.c +++ b/sys/ddb/db_command.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/cons.h> #include <sys/watchdog.h> +#include <sys/kernel.h> #include <ddb/ddb.h> #include <ddb/db_command.h> @@ -63,10 +64,6 @@ db_addr_t db_last_addr; db_addr_t db_prev; db_addr_t db_next; -SET_DECLARE(db_cmd_set, struct command); -SET_DECLARE(db_show_cmd_set, struct command); -SET_DECLARE(db_show_all_cmd_set, struct command); - static db_cmdfcn_t db_fncall; static db_cmdfcn_t db_gdb; static db_cmdfcn_t db_halt; @@ -81,30 +78,20 @@ static db_cmdfcn_t db_watchdog; */ static struct command db_show_all_cmds[] = { - { (char *)0 } -}; - -static struct command_table db_show_all_table = { - db_show_all_cmds, - SET_BEGIN(db_show_all_cmd_set), - SET_LIMIT(db_show_all_cmd_set) + { "trace", db_stack_trace_all, 0, 0 }, }; +struct command_table db_show_all_table = + LIST_HEAD_INITIALIZER(db_show_all_table); static struct command db_show_cmds[] = { { "all", 0, 0, &db_show_all_table }, { "registers", db_show_regs, 0, 0 }, { "breaks", db_listbreak_cmd, 0, 0 }, { "threads", db_show_threads, 0, 0 }, - { (char *)0, } }; +struct command_table db_show_table = LIST_HEAD_INITIALIZER(db_show_table); -static struct command_table db_show_table = { - db_show_cmds, - SET_BEGIN(db_show_cmd_set), - SET_LIMIT(db_show_cmd_set) -}; - -static struct command db_commands[] = { +static struct command db_cmds[] = { { "print", db_print_cmd, 0, 0 }, { "p", db_print_cmd, 0, 0 }, { "examine", db_examine_cmd, CS_SET_DOT, 0 }, @@ -130,6 +117,7 @@ static struct command db_commands[] = { { "match", db_trace_until_matching_cmd,0, 0 }, { "trace", db_stack_trace, CS_OWN, 0 }, { "t", db_stack_trace, CS_OWN, 0 }, + /* XXX alias for all trace */ { "alltrace", db_stack_trace_all, 0, 0 }, { "where", db_stack_trace, CS_OWN, 0 }, { "bt", db_stack_trace, CS_OWN, 0 }, @@ -149,14 +137,8 @@ static struct command db_commands[] = { { "unscript", db_unscript_cmd, CS_OWN, 0 }, { "capture", db_capture_cmd, CS_OWN, 0 }, { "textdump", db_textdump_cmd, CS_OWN, 0 }, - { (char *)0, } -}; - -static struct command_table db_command_table = { - db_commands, - SET_BEGIN(db_cmd_set), - SET_LIMIT(db_cmd_set) }; +struct command_table db_cmd_table = LIST_HEAD_INITIALIZER(db_cmd_table); static struct command *db_last_command = 0; @@ -197,6 +179,73 @@ static void db_command(struct command **last_cmdp, struct command_table *cmd_table, int dopager); /* + * Initialize the command lists from the static tables. + */ +static void +db_cmd_init(void) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + int i; + + for (i = 0; i < N(db_cmds); i++) + db_command_register(&db_cmd_table, &db_cmds[i]); + for (i = 0; i < N(db_show_cmds); i++) + db_command_register(&db_show_table, &db_show_cmds[i]); + for (i = 0; i < N(db_show_all_cmds); i++) + db_command_register(&db_show_all_table, &db_show_all_cmds[i]); +#undef N +} +SYSINIT(_cmd_init, SI_SUB_KLD, SI_ORDER_FIRST, db_cmd_init, NULL); + +/* + * Register a command. + */ +void +db_command_register(struct command_table *list, struct command *cmd) +{ + struct command *c, *last; + + last = NULL; + LIST_FOREACH(c, list, next) { + int n = strcmp(cmd->name, c->name); + + /* Check that the command is not already present. */ + if (n == 0) { + printf("%s: Warning, the command \"%s\" already exists;" + " ignoring request\n", __func__, cmd->name); + return; + } + if (n < 0) { + /* NB: keep list sorted lexicographically */ + LIST_INSERT_BEFORE(c, cmd, next); + return; + } + last = c; + } + if (last == NULL) + LIST_INSERT_HEAD(list, cmd, next); + else + LIST_INSERT_AFTER(last, cmd, next); +} + +/* + * Remove a command previously registered with db_command_register. + */ +void +db_command_unregister(struct command_table *list, struct command *cmd) +{ + struct command *c; + + LIST_FOREACH(c, list, next) { + if (cmd == c) { + LIST_REMOVE(cmd, next); + return; + } + } + /* NB: intentionally quiet */ +} + +/* * Helper function to match a single command. */ static void @@ -245,22 +294,14 @@ db_cmd_search(name, table, cmdp) struct command **cmdp; /* out */ { struct command *cmd; - struct command **aux_cmdp; int result = CMD_NONE; - for (cmd = table->table; cmd->name != 0; cmd++) { - db_cmd_match(name, cmd, cmdp, &result); + LIST_FOREACH(cmd, table, next) { + db_cmd_match(name,cmd,cmdp,&result); if (result == CMD_UNIQUE) - return (CMD_UNIQUE); + break; } - if (table->aux_tablep != NULL) - for (aux_cmdp = table->aux_tablep; - aux_cmdp < table->aux_tablep_end; - aux_cmdp++) { - db_cmd_match(name, *aux_cmdp, cmdp, &result); - if (result == CMD_UNIQUE) - return (CMD_UNIQUE); - } + if (result == CMD_NONE) { /* check for 'help' */ if (name[0] == 'h' && name[1] == 'e' @@ -274,19 +315,11 @@ static void db_cmd_list(table) struct command_table *table; { - register struct command *cmd; - register struct command **aux_cmdp; + register struct command *cmd; - for (cmd = table->table; cmd->name != 0; cmd++) { - db_printf("%-12s", cmd->name); - db_end_line(12); - } - if (table->aux_tablep == NULL) - return; - for (aux_cmdp = table->aux_tablep; aux_cmdp < table->aux_tablep_end; - aux_cmdp++) { - db_printf("%-12s", (*aux_cmdp)->name); - db_end_line(12); + LIST_FOREACH(cmd, table, next) { + db_printf("%-12s", cmd->name); + db_end_line(12); } } @@ -296,7 +329,7 @@ db_command(last_cmdp, cmd_table, dopager) struct command_table *cmd_table; int dopager; { - struct command *cmd; + struct command *cmd = NULL; int t; char modif[TOK_STRING_SIZE]; db_expr_t addr, count; @@ -463,7 +496,7 @@ db_command_loop() db_printf("db> "); (void) db_read_line(); - db_command(&db_last_command, &db_command_table, /* dopager */ 1); + db_command(&db_last_command, &db_cmd_table, /* dopager */ 1); } } @@ -481,7 +514,7 @@ db_command_script(const char *command) { db_prev = db_next = db_dot; db_inject_line(command); - db_command(&db_last_command, &db_command_table, /* dopager */ 0); + db_command(&db_last_command, &db_cmd_table, /* dopager */ 0); } void |