kgdb patches for 5.15
Changes for kgdb/kdb this cycle are dominated by a change from Sumit that removes as small (256K) private heap from kdb. This is change I've hoped for ever since I discovered how few users of this heap remained in the kernel, so many thanks to Sumit for hunting these down. Other change is an incremental step towards SPDX headers. Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org> -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEELzVBU1D3lWq6cKzwfOMlXTn3iKEFAmE2OuUACgkQfOMlXTn3 iKEcTQ/7BiMPnSzPeh7srNIG1a7/ig8CUtu+qMsrU50BUvCBzhas3+fGbzlZHV4p GwCGTuRDWhVJjntpCkLYroSSF0h/AhN68pxqUx6EJUWEYMGuuMBuVtAdXYMSYbse MW+Jw6Tec2fWPyw6lyWd0vwOKLzhf/pC8axbmGESzgdmZrsWeA4XEeF5XRHsHyJf pL4GvBXN/mzH2TSQNQmSgda5VLnK3m6B66tlT17mywG8QTKwID8I4LXs9doNwqeW 6fkwJswAsCa+nO1GjMsRcA8HoUd7mtqLCYbjZzFVQdFJ6kF9eBKSPvgbaqr6oNvv t6VBfm908+fM4/4yEQSuwVPT32IPe7I/Bk+aUqnSpPiXU8v75u0lIfB929O/DS07 X+NjqpXN7v6mEpLAFgWhqPyzTODw40OhpOi1uf9jzPB/OSNm9y1zs21FJQSx6KGa AahMHrRoeZwlxNdD/2RBf9pQCSBWF5R1DyIye2iQX+e/jrvTXHMCK33tpcbcE9Cl bMVqnnJ4Pnmul6hAAf9WlJduIrACV1Oq1iQrtXWE3wdFZdQuvqKvwHUK/Zko+O0f cdW6neyW7Slo+8q2qXuEE0Bp+Ae61oZTrGIdfj29ZdXwp0+sBzcA5CFO7MKPJllV yEq41Bxc3cgJPcsFMZWSaHcEAI5fq1iBmquVdCA0/vYbP9dsO1U= =iMIF -----END PGP SIGNATURE----- Merge tag 'kgdb-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/danielt/linux Pull kgdb updates from Daniel Thompson: "Changes for kgdb/kdb this cycle are dominated by a change from Sumit that removes as small (256K) private heap from kdb. This is change I've hoped for ever since I discovered how few users of this heap remained in the kernel, so many thanks to Sumit for hunting these down. The other change is an incremental step towards SPDX headers" * tag 'kgdb-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/danielt/linux: kernel: debug: Convert to SPDX identifier kdb: Rename members of struct kdbtab_t kdb: Simplify kdb_defcmd macro logic kdb: Get rid of redundant kdb_register_flags() kdb: Rename struct defcmd_set to struct kdb_macro kdb: Get rid of custom debug heap allocator
This commit is contained in:
		
						commit
						996fe06160
					
				| @ -13,6 +13,8 @@ | ||||
|  * Copyright (C) 2009 Jason Wessel <jason.wessel@windriver.com> | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/list.h> | ||||
| 
 | ||||
| /* Shifted versions of the command enable bits are be used if the command
 | ||||
|  * has no arguments (see kdb_check_flags). This allows commands, such as | ||||
|  * go, to have different permissions depending upon whether it is called | ||||
| @ -64,6 +66,17 @@ typedef enum { | ||||
| 
 | ||||
| typedef int (*kdb_func_t)(int, const char **); | ||||
| 
 | ||||
| /* The KDB shell command table */ | ||||
| typedef struct _kdbtab { | ||||
| 	char    *name;			/* Command name */ | ||||
| 	kdb_func_t func;		/* Function to execute command */ | ||||
| 	char    *usage;			/* Usage String for this command */ | ||||
| 	char    *help;			/* Help message for this command */ | ||||
| 	short    minlen;		/* Minimum legal # cmd chars required */ | ||||
| 	kdb_cmdflags_t flags;		/* Command behaviour flags */ | ||||
| 	struct list_head list_node;	/* Command list */ | ||||
| } kdbtab_t; | ||||
| 
 | ||||
| #ifdef	CONFIG_KGDB_KDB | ||||
| #include <linux/init.h> | ||||
| #include <linux/sched.h> | ||||
| @ -193,19 +206,13 @@ static inline const char *kdb_walk_kallsyms(loff_t *pos) | ||||
| #endif /* ! CONFIG_KALLSYMS */ | ||||
| 
 | ||||
| /* Dynamic kdb shell command registration */ | ||||
| extern int kdb_register(char *, kdb_func_t, char *, char *, short); | ||||
| extern int kdb_register_flags(char *, kdb_func_t, char *, char *, | ||||
| 			      short, kdb_cmdflags_t); | ||||
| extern int kdb_unregister(char *); | ||||
| extern int kdb_register(kdbtab_t *cmd); | ||||
| extern void kdb_unregister(kdbtab_t *cmd); | ||||
| #else /* ! CONFIG_KGDB_KDB */ | ||||
| static inline __printf(1, 2) int kdb_printf(const char *fmt, ...) { 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; } | ||||
| static inline int kdb_register_flags(char *cmd, kdb_func_t func, char *usage, | ||||
| 				     char *help, short minlen, | ||||
| 				     kdb_cmdflags_t flags) { return 0; } | ||||
| static inline int kdb_unregister(char *cmd) { return 0; } | ||||
| static inline int kdb_register(kdbtab_t *cmd) { return 0; } | ||||
| static inline void kdb_unregister(kdbtab_t *cmd) {} | ||||
| #endif	/* CONFIG_KGDB_KDB */ | ||||
| enum { | ||||
| 	KDB_NOT_INITIALIZED, | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-only
 | ||||
| /*
 | ||||
|  * Kernel Debug Core | ||||
|  * | ||||
| @ -22,10 +23,6 @@ | ||||
|  * | ||||
|  * Original KGDB stub: David Grothe <dave@gcom.com>, | ||||
|  * Tigran Aivazian <tigran@sco.com> | ||||
|  * | ||||
|  * This file is licensed under the terms of the GNU General Public License | ||||
|  * version 2. This program is licensed "as is" without any warranty of any | ||||
|  * kind, whether express or implied. | ||||
|  */ | ||||
| 
 | ||||
| #define pr_fmt(fmt) "KGDB: " fmt | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-only
 | ||||
| /*
 | ||||
|  * Kernel Debug Core | ||||
|  * | ||||
| @ -22,10 +23,6 @@ | ||||
|  * | ||||
|  * Original KGDB stub: David Grothe <dave@gcom.com>, | ||||
|  * Tigran Aivazian <tigran@sco.com> | ||||
|  * | ||||
|  * This file is licensed under the terms of the GNU General Public License | ||||
|  * version 2. This program is licensed "as is" without any warranty of any | ||||
|  * kind, whether express or implied. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/kernel.h> | ||||
|  | ||||
| @ -523,51 +523,51 @@ static int kdb_ss(int argc, const char **argv) | ||||
| } | ||||
| 
 | ||||
| static kdbtab_t bptab[] = { | ||||
| 	{	.cmd_name = "bp", | ||||
| 		.cmd_func = kdb_bp, | ||||
| 		.cmd_usage = "[<vaddr>]", | ||||
| 		.cmd_help = "Set/Display breakpoints", | ||||
| 		.cmd_flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS, | ||||
| 	{	.name = "bp", | ||||
| 		.func = kdb_bp, | ||||
| 		.usage = "[<vaddr>]", | ||||
| 		.help = "Set/Display breakpoints", | ||||
| 		.flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS, | ||||
| 	}, | ||||
| 	{	.cmd_name = "bl", | ||||
| 		.cmd_func = kdb_bp, | ||||
| 		.cmd_usage = "[<vaddr>]", | ||||
| 		.cmd_help = "Display breakpoints", | ||||
| 		.cmd_flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS, | ||||
| 	{	.name = "bl", | ||||
| 		.func = kdb_bp, | ||||
| 		.usage = "[<vaddr>]", | ||||
| 		.help = "Display breakpoints", | ||||
| 		.flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS, | ||||
| 	}, | ||||
| 	{	.cmd_name = "bc", | ||||
| 		.cmd_func = kdb_bc, | ||||
| 		.cmd_usage = "<bpnum>", | ||||
| 		.cmd_help = "Clear Breakpoint", | ||||
| 		.cmd_flags = KDB_ENABLE_FLOW_CTRL, | ||||
| 	{	.name = "bc", | ||||
| 		.func = kdb_bc, | ||||
| 		.usage = "<bpnum>", | ||||
| 		.help = "Clear Breakpoint", | ||||
| 		.flags = KDB_ENABLE_FLOW_CTRL, | ||||
| 	}, | ||||
| 	{	.cmd_name = "be", | ||||
| 		.cmd_func = kdb_bc, | ||||
| 		.cmd_usage = "<bpnum>", | ||||
| 		.cmd_help = "Enable Breakpoint", | ||||
| 		.cmd_flags = KDB_ENABLE_FLOW_CTRL, | ||||
| 	{	.name = "be", | ||||
| 		.func = kdb_bc, | ||||
| 		.usage = "<bpnum>", | ||||
| 		.help = "Enable Breakpoint", | ||||
| 		.flags = KDB_ENABLE_FLOW_CTRL, | ||||
| 	}, | ||||
| 	{	.cmd_name = "bd", | ||||
| 		.cmd_func = kdb_bc, | ||||
| 		.cmd_usage = "<bpnum>", | ||||
| 		.cmd_help = "Disable Breakpoint", | ||||
| 		.cmd_flags = KDB_ENABLE_FLOW_CTRL, | ||||
| 	{	.name = "bd", | ||||
| 		.func = kdb_bc, | ||||
| 		.usage = "<bpnum>", | ||||
| 		.help = "Disable Breakpoint", | ||||
| 		.flags = KDB_ENABLE_FLOW_CTRL, | ||||
| 	}, | ||||
| 	{	.cmd_name = "ss", | ||||
| 		.cmd_func = kdb_ss, | ||||
| 		.cmd_usage = "", | ||||
| 		.cmd_help = "Single Step", | ||||
| 		.cmd_minlen = 1, | ||||
| 		.cmd_flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS, | ||||
| 	{	.name = "ss", | ||||
| 		.func = kdb_ss, | ||||
| 		.usage = "", | ||||
| 		.help = "Single Step", | ||||
| 		.minlen = 1, | ||||
| 		.flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static kdbtab_t bphcmd = { | ||||
| 	.cmd_name = "bph", | ||||
| 	.cmd_func = kdb_bp, | ||||
| 	.cmd_usage = "[<vaddr>]", | ||||
| 	.cmd_help = "[datar [length]|dataw [length]]   Set hw brk", | ||||
| 	.cmd_flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS, | ||||
| 	.name = "bph", | ||||
| 	.func = kdb_bp, | ||||
| 	.usage = "[<vaddr>]", | ||||
| 	.help = "[datar [length]|dataw [length]]   Set hw brk", | ||||
| 	.flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS, | ||||
| }; | ||||
| 
 | ||||
| /* Initialize the breakpoint table and register	breakpoint commands. */ | ||||
|  | ||||
| @ -140,7 +140,6 @@ int kdb_stub(struct kgdb_state *ks) | ||||
| 	 */ | ||||
| 	kdb_common_deinit_state(); | ||||
| 	KDB_STATE_CLEAR(PAGER); | ||||
| 	kdbnearsym_cleanup(); | ||||
| 	if (error == KDB_CMD_KGDB) { | ||||
| 		if (KDB_STATE(DOING_KGDB)) | ||||
| 			KDB_STATE_CLEAR(DOING_KGDB); | ||||
|  | ||||
| @ -33,7 +33,6 @@ | ||||
| #include <linux/kallsyms.h> | ||||
| #include <linux/kgdb.h> | ||||
| #include <linux/kdb.h> | ||||
| #include <linux/list.h> | ||||
| #include <linux/notifier.h> | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/delay.h> | ||||
| @ -654,16 +653,17 @@ static void kdb_cmderror(int diag) | ||||
|  * Returns: | ||||
|  *	zero for success, a kdb diagnostic if error | ||||
|  */ | ||||
| struct defcmd_set { | ||||
| 	int count; | ||||
| 	bool usable; | ||||
| 	char *name; | ||||
| 	char *usage; | ||||
| 	char *help; | ||||
| 	char **command; | ||||
| struct kdb_macro { | ||||
| 	kdbtab_t cmd;			/* Macro command */ | ||||
| 	struct list_head statements;	/* Associated statement list */ | ||||
| }; | ||||
| static struct defcmd_set *defcmd_set; | ||||
| static int defcmd_set_count; | ||||
| 
 | ||||
| struct kdb_macro_statement { | ||||
| 	char *statement;		/* Statement text */ | ||||
| 	struct list_head list_node;	/* Statement list node */ | ||||
| }; | ||||
| 
 | ||||
| static struct kdb_macro *kdb_macro; | ||||
| static bool defcmd_in_progress; | ||||
| 
 | ||||
| /* Forward references */ | ||||
| @ -671,53 +671,55 @@ static int kdb_exec_defcmd(int argc, const char **argv); | ||||
| 
 | ||||
| static int kdb_defcmd2(const char *cmdstr, const char *argv0) | ||||
| { | ||||
| 	struct defcmd_set *s = defcmd_set + defcmd_set_count - 1; | ||||
| 	char **save_command = s->command; | ||||
| 	struct kdb_macro_statement *kms; | ||||
| 
 | ||||
| 	if (!kdb_macro) | ||||
| 		return KDB_NOTIMP; | ||||
| 
 | ||||
| 	if (strcmp(argv0, "endefcmd") == 0) { | ||||
| 		defcmd_in_progress = false; | ||||
| 		if (!s->count) | ||||
| 			s->usable = false; | ||||
| 		if (s->usable) | ||||
| 			/* macros are always safe because when executed each
 | ||||
| 			 * internal command re-enters kdb_parse() and is | ||||
| 			 * safety checked individually. | ||||
| 			 */ | ||||
| 			kdb_register_flags(s->name, kdb_exec_defcmd, s->usage, | ||||
| 					   s->help, 0, | ||||
| 					   KDB_ENABLE_ALWAYS_SAFE); | ||||
| 		if (!list_empty(&kdb_macro->statements)) | ||||
| 			kdb_register(&kdb_macro->cmd); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	if (!s->usable) | ||||
| 		return KDB_NOTIMP; | ||||
| 	s->command = kcalloc(s->count + 1, sizeof(*(s->command)), GFP_KDB); | ||||
| 	if (!s->command) { | ||||
| 		kdb_printf("Could not allocate new kdb_defcmd table for %s\n", | ||||
| 
 | ||||
| 	kms = kmalloc(sizeof(*kms), GFP_KDB); | ||||
| 	if (!kms) { | ||||
| 		kdb_printf("Could not allocate new kdb macro command: %s\n", | ||||
| 			   cmdstr); | ||||
| 		s->usable = false; | ||||
| 		return KDB_NOTIMP; | ||||
| 	} | ||||
| 	memcpy(s->command, save_command, s->count * sizeof(*(s->command))); | ||||
| 	s->command[s->count++] = kdb_strdup(cmdstr, GFP_KDB); | ||||
| 	kfree(save_command); | ||||
| 
 | ||||
| 	kms->statement = kdb_strdup(cmdstr, GFP_KDB); | ||||
| 	list_add_tail(&kms->list_node, &kdb_macro->statements); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int kdb_defcmd(int argc, const char **argv) | ||||
| { | ||||
| 	struct defcmd_set *save_defcmd_set = defcmd_set, *s; | ||||
| 	kdbtab_t *mp; | ||||
| 
 | ||||
| 	if (defcmd_in_progress) { | ||||
| 		kdb_printf("kdb: nested defcmd detected, assuming missing " | ||||
| 			   "endefcmd\n"); | ||||
| 		kdb_defcmd2("endefcmd", "endefcmd"); | ||||
| 	} | ||||
| 	if (argc == 0) { | ||||
| 		int i; | ||||
| 		for (s = defcmd_set; s < defcmd_set + defcmd_set_count; ++s) { | ||||
| 			kdb_printf("defcmd %s \"%s\" \"%s\"\n", s->name, | ||||
| 				   s->usage, s->help); | ||||
| 			for (i = 0; i < s->count; ++i) | ||||
| 				kdb_printf("%s", s->command[i]); | ||||
| 			kdb_printf("endefcmd\n"); | ||||
| 		kdbtab_t *kp; | ||||
| 		struct kdb_macro *kmp; | ||||
| 		struct kdb_macro_statement *kms; | ||||
| 
 | ||||
| 		list_for_each_entry(kp, &kdb_cmds_head, list_node) { | ||||
| 			if (kp->func == kdb_exec_defcmd) { | ||||
| 				kdb_printf("defcmd %s \"%s\" \"%s\"\n", | ||||
| 					   kp->name, kp->usage, kp->help); | ||||
| 				kmp = container_of(kp, struct kdb_macro, cmd); | ||||
| 				list_for_each_entry(kms, &kmp->statements, | ||||
| 						    list_node) | ||||
| 					kdb_printf("%s", kms->statement); | ||||
| 				kdb_printf("endefcmd\n"); | ||||
| 			} | ||||
| 		} | ||||
| 		return 0; | ||||
| 	} | ||||
| @ -727,45 +729,43 @@ static int kdb_defcmd(int argc, const char **argv) | ||||
| 		kdb_printf("Command only available during kdb_init()\n"); | ||||
| 		return KDB_NOTIMP; | ||||
| 	} | ||||
| 	defcmd_set = kmalloc_array(defcmd_set_count + 1, sizeof(*defcmd_set), | ||||
| 				   GFP_KDB); | ||||
| 	if (!defcmd_set) | ||||
| 	kdb_macro = kzalloc(sizeof(*kdb_macro), GFP_KDB); | ||||
| 	if (!kdb_macro) | ||||
| 		goto fail_defcmd; | ||||
| 	memcpy(defcmd_set, save_defcmd_set, | ||||
| 	       defcmd_set_count * sizeof(*defcmd_set)); | ||||
| 	s = defcmd_set + defcmd_set_count; | ||||
| 	memset(s, 0, sizeof(*s)); | ||||
| 	s->usable = true; | ||||
| 	s->name = kdb_strdup(argv[1], GFP_KDB); | ||||
| 	if (!s->name) | ||||
| 
 | ||||
| 	mp = &kdb_macro->cmd; | ||||
| 	mp->func = kdb_exec_defcmd; | ||||
| 	mp->minlen = 0; | ||||
| 	mp->flags = KDB_ENABLE_ALWAYS_SAFE; | ||||
| 	mp->name = kdb_strdup(argv[1], GFP_KDB); | ||||
| 	if (!mp->name) | ||||
| 		goto fail_name; | ||||
| 	s->usage = kdb_strdup(argv[2], GFP_KDB); | ||||
| 	if (!s->usage) | ||||
| 	mp->usage = kdb_strdup(argv[2], GFP_KDB); | ||||
| 	if (!mp->usage) | ||||
| 		goto fail_usage; | ||||
| 	s->help = kdb_strdup(argv[3], GFP_KDB); | ||||
| 	if (!s->help) | ||||
| 	mp->help = kdb_strdup(argv[3], GFP_KDB); | ||||
| 	if (!mp->help) | ||||
| 		goto fail_help; | ||||
| 	if (s->usage[0] == '"') { | ||||
| 		strcpy(s->usage, argv[2]+1); | ||||
| 		s->usage[strlen(s->usage)-1] = '\0'; | ||||
| 	if (mp->usage[0] == '"') { | ||||
| 		strcpy(mp->usage, argv[2]+1); | ||||
| 		mp->usage[strlen(mp->usage)-1] = '\0'; | ||||
| 	} | ||||
| 	if (s->help[0] == '"') { | ||||
| 		strcpy(s->help, argv[3]+1); | ||||
| 		s->help[strlen(s->help)-1] = '\0'; | ||||
| 	if (mp->help[0] == '"') { | ||||
| 		strcpy(mp->help, argv[3]+1); | ||||
| 		mp->help[strlen(mp->help)-1] = '\0'; | ||||
| 	} | ||||
| 	++defcmd_set_count; | ||||
| 
 | ||||
| 	INIT_LIST_HEAD(&kdb_macro->statements); | ||||
| 	defcmd_in_progress = true; | ||||
| 	kfree(save_defcmd_set); | ||||
| 	return 0; | ||||
| fail_help: | ||||
| 	kfree(s->usage); | ||||
| 	kfree(mp->usage); | ||||
| fail_usage: | ||||
| 	kfree(s->name); | ||||
| 	kfree(mp->name); | ||||
| fail_name: | ||||
| 	kfree(defcmd_set); | ||||
| 	kfree(kdb_macro); | ||||
| fail_defcmd: | ||||
| 	kdb_printf("Could not allocate new defcmd_set entry for %s\n", argv[1]); | ||||
| 	defcmd_set = save_defcmd_set; | ||||
| 	kdb_printf("Could not allocate new kdb_macro entry for %s\n", argv[1]); | ||||
| 	return KDB_NOTIMP; | ||||
| } | ||||
| 
 | ||||
| @ -780,25 +780,31 @@ fail_defcmd: | ||||
|  */ | ||||
| static int kdb_exec_defcmd(int argc, const char **argv) | ||||
| { | ||||
| 	int i, ret; | ||||
| 	struct defcmd_set *s; | ||||
| 	int ret; | ||||
| 	kdbtab_t *kp; | ||||
| 	struct kdb_macro *kmp; | ||||
| 	struct kdb_macro_statement *kms; | ||||
| 
 | ||||
| 	if (argc != 0) | ||||
| 		return KDB_ARGCOUNT; | ||||
| 	for (s = defcmd_set, i = 0; i < defcmd_set_count; ++i, ++s) { | ||||
| 		if (strcmp(s->name, argv[0]) == 0) | ||||
| 
 | ||||
| 	list_for_each_entry(kp, &kdb_cmds_head, list_node) { | ||||
| 		if (strcmp(kp->name, argv[0]) == 0) | ||||
| 			break; | ||||
| 	} | ||||
| 	if (i == defcmd_set_count) { | ||||
| 	if (list_entry_is_head(kp, &kdb_cmds_head, list_node)) { | ||||
| 		kdb_printf("kdb_exec_defcmd: could not find commands for %s\n", | ||||
| 			   argv[0]); | ||||
| 		return KDB_NOTIMP; | ||||
| 	} | ||||
| 	for (i = 0; i < s->count; ++i) { | ||||
| 		/* Recursive use of kdb_parse, do not use argv after
 | ||||
| 		 * this point */ | ||||
| 	kmp = container_of(kp, struct kdb_macro, cmd); | ||||
| 	list_for_each_entry(kms, &kmp->statements, list_node) { | ||||
| 		/*
 | ||||
| 		 * Recursive use of kdb_parse, do not use argv after this point. | ||||
| 		 */ | ||||
| 		argv = NULL; | ||||
| 		kdb_printf("[%s]kdb> %s\n", s->name, s->command[i]); | ||||
| 		ret = kdb_parse(s->command[i]); | ||||
| 		kdb_printf("[%s]kdb> %s\n", kmp->cmd.name, kms->statement); | ||||
| 		ret = kdb_parse(kms->statement); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 	} | ||||
| @ -1009,11 +1015,11 @@ int kdb_parse(const char *cmdstr) | ||||
| 		 * If this command is allowed to be abbreviated, | ||||
| 		 * check to see if this is it. | ||||
| 		 */ | ||||
| 		if (tp->cmd_minlen && (strlen(argv[0]) <= tp->cmd_minlen) && | ||||
| 		    (strncmp(argv[0], tp->cmd_name, tp->cmd_minlen) == 0)) | ||||
| 		if (tp->minlen && (strlen(argv[0]) <= tp->minlen) && | ||||
| 		    (strncmp(argv[0], tp->name, tp->minlen) == 0)) | ||||
| 			break; | ||||
| 
 | ||||
| 		if (strcmp(argv[0], tp->cmd_name) == 0) | ||||
| 		if (strcmp(argv[0], tp->name) == 0) | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| @ -1024,8 +1030,7 @@ int kdb_parse(const char *cmdstr) | ||||
| 	 */ | ||||
| 	if (list_entry_is_head(tp, &kdb_cmds_head, list_node)) { | ||||
| 		list_for_each_entry(tp, &kdb_cmds_head, list_node) { | ||||
| 			if (strncmp(argv[0], tp->cmd_name, | ||||
| 				    strlen(tp->cmd_name)) == 0) | ||||
| 			if (strncmp(argv[0], tp->name, strlen(tp->name)) == 0) | ||||
| 				break; | ||||
| 		} | ||||
| 	} | ||||
| @ -1033,19 +1038,19 @@ int kdb_parse(const char *cmdstr) | ||||
| 	if (!list_entry_is_head(tp, &kdb_cmds_head, list_node)) { | ||||
| 		int result; | ||||
| 
 | ||||
| 		if (!kdb_check_flags(tp->cmd_flags, kdb_cmd_enabled, argc <= 1)) | ||||
| 		if (!kdb_check_flags(tp->flags, kdb_cmd_enabled, argc <= 1)) | ||||
| 			return KDB_NOPERM; | ||||
| 
 | ||||
| 		KDB_STATE_SET(CMD); | ||||
| 		result = (*tp->cmd_func)(argc-1, (const char **)argv); | ||||
| 		result = (*tp->func)(argc-1, (const char **)argv); | ||||
| 		if (result && ignore_errors && result > KDB_CMD_GO) | ||||
| 			result = 0; | ||||
| 		KDB_STATE_CLEAR(CMD); | ||||
| 
 | ||||
| 		if (tp->cmd_flags & KDB_REPEAT_WITH_ARGS) | ||||
| 		if (tp->flags & KDB_REPEAT_WITH_ARGS) | ||||
| 			return result; | ||||
| 
 | ||||
| 		argc = tp->cmd_flags & KDB_REPEAT_NO_ARGS ? 1 : 0; | ||||
| 		argc = tp->flags & KDB_REPEAT_NO_ARGS ? 1 : 0; | ||||
| 		if (argv[argc]) | ||||
| 			*(argv[argc]) = '\0'; | ||||
| 		return result; | ||||
| @ -2412,12 +2417,12 @@ static int kdb_help(int argc, const char **argv) | ||||
| 		char *space = ""; | ||||
| 		if (KDB_FLAG(CMD_INTERRUPT)) | ||||
| 			return 0; | ||||
| 		if (!kdb_check_flags(kt->cmd_flags, kdb_cmd_enabled, true)) | ||||
| 		if (!kdb_check_flags(kt->flags, kdb_cmd_enabled, true)) | ||||
| 			continue; | ||||
| 		if (strlen(kt->cmd_usage) > 20) | ||||
| 		if (strlen(kt->usage) > 20) | ||||
| 			space = "\n                                    "; | ||||
| 		kdb_printf("%-15.15s %-20s%s%s\n", kt->cmd_name, | ||||
| 			   kt->cmd_usage, space, kt->cmd_help); | ||||
| 		kdb_printf("%-15.15s %-20s%s%s\n", kt->name, | ||||
| 			   kt->usage, space, kt->help); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| @ -2613,56 +2618,32 @@ static int kdb_grep_help(int argc, const char **argv) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * kdb_register_flags - This function is used to register a kernel | ||||
|  * 	debugger command. | ||||
|  * Inputs: | ||||
|  *	cmd	Command name | ||||
|  *	func	Function to execute the command | ||||
|  *	usage	A simple usage string showing arguments | ||||
|  *	help	A simple help string describing command | ||||
|  *	repeat	Does the command auto repeat on enter? | ||||
|  * Returns: | ||||
|  *	zero for success, one if a duplicate command. | ||||
| /**
 | ||||
|  * kdb_register() - This function is used to register a kernel debugger | ||||
|  *                  command. | ||||
|  * @cmd: pointer to kdb command | ||||
|  * | ||||
|  * Note that it's the job of the caller to keep the memory for the cmd | ||||
|  * allocated until unregister is called. | ||||
|  */ | ||||
| int kdb_register_flags(char *cmd, | ||||
| 		       kdb_func_t func, | ||||
| 		       char *usage, | ||||
| 		       char *help, | ||||
| 		       short minlen, | ||||
| 		       kdb_cmdflags_t flags) | ||||
| int kdb_register(kdbtab_t *cmd) | ||||
| { | ||||
| 	kdbtab_t *kp; | ||||
| 
 | ||||
| 	list_for_each_entry(kp, &kdb_cmds_head, list_node) { | ||||
| 		if (strcmp(kp->cmd_name, cmd) == 0) { | ||||
| 			kdb_printf("Duplicate kdb command registered: " | ||||
| 				"%s, func %px help %s\n", cmd, func, help); | ||||
| 		if (strcmp(kp->name, cmd->name) == 0) { | ||||
| 			kdb_printf("Duplicate kdb cmd: %s, func %p help %s\n", | ||||
| 				   cmd->name, cmd->func, cmd->help); | ||||
| 			return 1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	kp = kmalloc(sizeof(*kp), GFP_KDB); | ||||
| 	if (!kp) { | ||||
| 		kdb_printf("Could not allocate new kdb_command table\n"); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	kp->cmd_name   = cmd; | ||||
| 	kp->cmd_func   = func; | ||||
| 	kp->cmd_usage  = usage; | ||||
| 	kp->cmd_help   = help; | ||||
| 	kp->cmd_minlen = minlen; | ||||
| 	kp->cmd_flags  = flags; | ||||
| 	kp->is_dynamic = true; | ||||
| 
 | ||||
| 	list_add_tail(&kp->list_node, &kdb_cmds_head); | ||||
| 
 | ||||
| 	list_add_tail(&cmd->list_node, &kdb_cmds_head); | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kdb_register_flags); | ||||
| EXPORT_SYMBOL_GPL(kdb_register); | ||||
| 
 | ||||
| /*
 | ||||
| /**
 | ||||
|  * kdb_register_table() - This function is used to register a kdb command | ||||
|  *                        table. | ||||
|  * @kp: pointer to kdb command table | ||||
| @ -2676,266 +2657,231 @@ void kdb_register_table(kdbtab_t *kp, size_t len) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * kdb_register - Compatibility register function for commands that do | ||||
|  *	not need to specify a repeat state.  Equivalent to | ||||
|  *	kdb_register_flags with flags set to 0. | ||||
|  * Inputs: | ||||
|  *	cmd	Command name | ||||
|  *	func	Function to execute the command | ||||
|  *	usage	A simple usage string showing arguments | ||||
|  *	help	A simple help string describing command | ||||
|  * Returns: | ||||
|  *	zero for success, one if a duplicate command. | ||||
| /**
 | ||||
|  * kdb_unregister() - This function is used to unregister a kernel debugger | ||||
|  *                    command. It is generally called when a module which | ||||
|  *                    implements kdb command is unloaded. | ||||
|  * @cmd: pointer to kdb command | ||||
|  */ | ||||
| int kdb_register(char *cmd, | ||||
| 	     kdb_func_t func, | ||||
| 	     char *usage, | ||||
| 	     char *help, | ||||
| 	     short minlen) | ||||
| void kdb_unregister(kdbtab_t *cmd) | ||||
| { | ||||
| 	return kdb_register_flags(cmd, func, usage, help, minlen, 0); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kdb_register); | ||||
| 
 | ||||
| /*
 | ||||
|  * kdb_unregister - This function is used to unregister a kernel | ||||
|  *	debugger command.  It is generally called when a module which | ||||
|  *	implements kdb commands is unloaded. | ||||
|  * Inputs: | ||||
|  *	cmd	Command name | ||||
|  * Returns: | ||||
|  *	zero for success, one command not registered. | ||||
|  */ | ||||
| int kdb_unregister(char *cmd) | ||||
| { | ||||
| 	kdbtab_t *kp; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 *  find the command. | ||||
| 	 */ | ||||
| 	list_for_each_entry(kp, &kdb_cmds_head, list_node) { | ||||
| 		if (strcmp(kp->cmd_name, cmd) == 0) { | ||||
| 			list_del(&kp->list_node); | ||||
| 			if (kp->is_dynamic) | ||||
| 				kfree(kp); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* Couldn't find it.  */ | ||||
| 	return 1; | ||||
| 	list_del(&cmd->list_node); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(kdb_unregister); | ||||
| 
 | ||||
| static kdbtab_t maintab[] = { | ||||
| 	{	.cmd_name = "md", | ||||
| 		.cmd_func = kdb_md, | ||||
| 		.cmd_usage = "<vaddr>", | ||||
| 		.cmd_help = "Display Memory Contents, also mdWcN, e.g. md8c1", | ||||
| 		.cmd_minlen = 1, | ||||
| 		.cmd_flags = KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS, | ||||
| 	{	.name = "md", | ||||
| 		.func = kdb_md, | ||||
| 		.usage = "<vaddr>", | ||||
| 		.help = "Display Memory Contents, also mdWcN, e.g. md8c1", | ||||
| 		.minlen = 1, | ||||
| 		.flags = KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS, | ||||
| 	}, | ||||
| 	{	.cmd_name = "mdr", | ||||
| 		.cmd_func = kdb_md, | ||||
| 		.cmd_usage = "<vaddr> <bytes>", | ||||
| 		.cmd_help = "Display Raw Memory", | ||||
| 		.cmd_flags = KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS, | ||||
| 	{	.name = "mdr", | ||||
| 		.func = kdb_md, | ||||
| 		.usage = "<vaddr> <bytes>", | ||||
| 		.help = "Display Raw Memory", | ||||
| 		.flags = KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS, | ||||
| 	}, | ||||
| 	{	.cmd_name = "mdp", | ||||
| 		.cmd_func = kdb_md, | ||||
| 		.cmd_usage = "<paddr> <bytes>", | ||||
| 		.cmd_help = "Display Physical Memory", | ||||
| 		.cmd_flags = KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS, | ||||
| 	{	.name = "mdp", | ||||
| 		.func = kdb_md, | ||||
| 		.usage = "<paddr> <bytes>", | ||||
| 		.help = "Display Physical Memory", | ||||
| 		.flags = KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS, | ||||
| 	}, | ||||
| 	{	.cmd_name = "mds", | ||||
| 		.cmd_func = kdb_md, | ||||
| 		.cmd_usage = "<vaddr>", | ||||
| 		.cmd_help = "Display Memory Symbolically", | ||||
| 		.cmd_flags = KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS, | ||||
| 	{	.name = "mds", | ||||
| 		.func = kdb_md, | ||||
| 		.usage = "<vaddr>", | ||||
| 		.help = "Display Memory Symbolically", | ||||
| 		.flags = KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS, | ||||
| 	}, | ||||
| 	{	.cmd_name = "mm", | ||||
| 		.cmd_func = kdb_mm, | ||||
| 		.cmd_usage = "<vaddr> <contents>", | ||||
| 		.cmd_help = "Modify Memory Contents", | ||||
| 		.cmd_flags = KDB_ENABLE_MEM_WRITE | KDB_REPEAT_NO_ARGS, | ||||
| 	{	.name = "mm", | ||||
| 		.func = kdb_mm, | ||||
| 		.usage = "<vaddr> <contents>", | ||||
| 		.help = "Modify Memory Contents", | ||||
| 		.flags = KDB_ENABLE_MEM_WRITE | KDB_REPEAT_NO_ARGS, | ||||
| 	}, | ||||
| 	{	.cmd_name = "go", | ||||
| 		.cmd_func = kdb_go, | ||||
| 		.cmd_usage = "[<vaddr>]", | ||||
| 		.cmd_help = "Continue Execution", | ||||
| 		.cmd_minlen = 1, | ||||
| 		.cmd_flags = KDB_ENABLE_REG_WRITE | | ||||
| 	{	.name = "go", | ||||
| 		.func = kdb_go, | ||||
| 		.usage = "[<vaddr>]", | ||||
| 		.help = "Continue Execution", | ||||
| 		.minlen = 1, | ||||
| 		.flags = KDB_ENABLE_REG_WRITE | | ||||
| 			     KDB_ENABLE_ALWAYS_SAFE_NO_ARGS, | ||||
| 	}, | ||||
| 	{	.cmd_name = "rd", | ||||
| 		.cmd_func = kdb_rd, | ||||
| 		.cmd_usage = "", | ||||
| 		.cmd_help = "Display Registers", | ||||
| 		.cmd_flags = KDB_ENABLE_REG_READ, | ||||
| 	{	.name = "rd", | ||||
| 		.func = kdb_rd, | ||||
| 		.usage = "", | ||||
| 		.help = "Display Registers", | ||||
| 		.flags = KDB_ENABLE_REG_READ, | ||||
| 	}, | ||||
| 	{	.cmd_name = "rm", | ||||
| 		.cmd_func = kdb_rm, | ||||
| 		.cmd_usage = "<reg> <contents>", | ||||
| 		.cmd_help = "Modify Registers", | ||||
| 		.cmd_flags = KDB_ENABLE_REG_WRITE, | ||||
| 	{	.name = "rm", | ||||
| 		.func = kdb_rm, | ||||
| 		.usage = "<reg> <contents>", | ||||
| 		.help = "Modify Registers", | ||||
| 		.flags = KDB_ENABLE_REG_WRITE, | ||||
| 	}, | ||||
| 	{	.cmd_name = "ef", | ||||
| 		.cmd_func = kdb_ef, | ||||
| 		.cmd_usage = "<vaddr>", | ||||
| 		.cmd_help = "Display exception frame", | ||||
| 		.cmd_flags = KDB_ENABLE_MEM_READ, | ||||
| 	{	.name = "ef", | ||||
| 		.func = kdb_ef, | ||||
| 		.usage = "<vaddr>", | ||||
| 		.help = "Display exception frame", | ||||
| 		.flags = KDB_ENABLE_MEM_READ, | ||||
| 	}, | ||||
| 	{	.cmd_name = "bt", | ||||
| 		.cmd_func = kdb_bt, | ||||
| 		.cmd_usage = "[<vaddr>]", | ||||
| 		.cmd_help = "Stack traceback", | ||||
| 		.cmd_minlen = 1, | ||||
| 		.cmd_flags = KDB_ENABLE_MEM_READ | KDB_ENABLE_INSPECT_NO_ARGS, | ||||
| 	{	.name = "bt", | ||||
| 		.func = kdb_bt, | ||||
| 		.usage = "[<vaddr>]", | ||||
| 		.help = "Stack traceback", | ||||
| 		.minlen = 1, | ||||
| 		.flags = KDB_ENABLE_MEM_READ | KDB_ENABLE_INSPECT_NO_ARGS, | ||||
| 	}, | ||||
| 	{	.cmd_name = "btp", | ||||
| 		.cmd_func = kdb_bt, | ||||
| 		.cmd_usage = "<pid>", | ||||
| 		.cmd_help = "Display stack for process <pid>", | ||||
| 		.cmd_flags = KDB_ENABLE_INSPECT, | ||||
| 	{	.name = "btp", | ||||
| 		.func = kdb_bt, | ||||
| 		.usage = "<pid>", | ||||
| 		.help = "Display stack for process <pid>", | ||||
| 		.flags = KDB_ENABLE_INSPECT, | ||||
| 	}, | ||||
| 	{	.cmd_name = "bta", | ||||
| 		.cmd_func = kdb_bt, | ||||
| 		.cmd_usage = "[D|R|S|T|C|Z|E|U|I|M|A]", | ||||
| 		.cmd_help = "Backtrace all processes matching state flag", | ||||
| 		.cmd_flags = KDB_ENABLE_INSPECT, | ||||
| 	{	.name = "bta", | ||||
| 		.func = kdb_bt, | ||||
| 		.usage = "[D|R|S|T|C|Z|E|U|I|M|A]", | ||||
| 		.help = "Backtrace all processes matching state flag", | ||||
| 		.flags = KDB_ENABLE_INSPECT, | ||||
| 	}, | ||||
| 	{	.cmd_name = "btc", | ||||
| 		.cmd_func = kdb_bt, | ||||
| 		.cmd_usage = "", | ||||
| 		.cmd_help = "Backtrace current process on each cpu", | ||||
| 		.cmd_flags = KDB_ENABLE_INSPECT, | ||||
| 	{	.name = "btc", | ||||
| 		.func = kdb_bt, | ||||
| 		.usage = "", | ||||
| 		.help = "Backtrace current process on each cpu", | ||||
| 		.flags = KDB_ENABLE_INSPECT, | ||||
| 	}, | ||||
| 	{	.cmd_name = "btt", | ||||
| 		.cmd_func = kdb_bt, | ||||
| 		.cmd_usage = "<vaddr>", | ||||
| 		.cmd_help = "Backtrace process given its struct task address", | ||||
| 		.cmd_flags = KDB_ENABLE_MEM_READ | KDB_ENABLE_INSPECT_NO_ARGS, | ||||
| 	{	.name = "btt", | ||||
| 		.func = kdb_bt, | ||||
| 		.usage = "<vaddr>", | ||||
| 		.help = "Backtrace process given its struct task address", | ||||
| 		.flags = KDB_ENABLE_MEM_READ | KDB_ENABLE_INSPECT_NO_ARGS, | ||||
| 	}, | ||||
| 	{	.cmd_name = "env", | ||||
| 		.cmd_func = kdb_env, | ||||
| 		.cmd_usage = "", | ||||
| 		.cmd_help = "Show environment variables", | ||||
| 		.cmd_flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	{	.name = "env", | ||||
| 		.func = kdb_env, | ||||
| 		.usage = "", | ||||
| 		.help = "Show environment variables", | ||||
| 		.flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	}, | ||||
| 	{	.cmd_name = "set", | ||||
| 		.cmd_func = kdb_set, | ||||
| 		.cmd_usage = "", | ||||
| 		.cmd_help = "Set environment variables", | ||||
| 		.cmd_flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	{	.name = "set", | ||||
| 		.func = kdb_set, | ||||
| 		.usage = "", | ||||
| 		.help = "Set environment variables", | ||||
| 		.flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	}, | ||||
| 	{	.cmd_name = "help", | ||||
| 		.cmd_func = kdb_help, | ||||
| 		.cmd_usage = "", | ||||
| 		.cmd_help = "Display Help Message", | ||||
| 		.cmd_minlen = 1, | ||||
| 		.cmd_flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	{	.name = "help", | ||||
| 		.func = kdb_help, | ||||
| 		.usage = "", | ||||
| 		.help = "Display Help Message", | ||||
| 		.minlen = 1, | ||||
| 		.flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	}, | ||||
| 	{	.cmd_name = "?", | ||||
| 		.cmd_func = kdb_help, | ||||
| 		.cmd_usage = "", | ||||
| 		.cmd_help = "Display Help Message", | ||||
| 		.cmd_flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	{	.name = "?", | ||||
| 		.func = kdb_help, | ||||
| 		.usage = "", | ||||
| 		.help = "Display Help Message", | ||||
| 		.flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	}, | ||||
| 	{	.cmd_name = "cpu", | ||||
| 		.cmd_func = kdb_cpu, | ||||
| 		.cmd_usage = "<cpunum>", | ||||
| 		.cmd_help = "Switch to new cpu", | ||||
| 		.cmd_flags = KDB_ENABLE_ALWAYS_SAFE_NO_ARGS, | ||||
| 	{	.name = "cpu", | ||||
| 		.func = kdb_cpu, | ||||
| 		.usage = "<cpunum>", | ||||
| 		.help = "Switch to new cpu", | ||||
| 		.flags = KDB_ENABLE_ALWAYS_SAFE_NO_ARGS, | ||||
| 	}, | ||||
| 	{	.cmd_name = "kgdb", | ||||
| 		.cmd_func = kdb_kgdb, | ||||
| 		.cmd_usage = "", | ||||
| 		.cmd_help = "Enter kgdb mode", | ||||
| 		.cmd_flags = 0, | ||||
| 	{	.name = "kgdb", | ||||
| 		.func = kdb_kgdb, | ||||
| 		.usage = "", | ||||
| 		.help = "Enter kgdb mode", | ||||
| 		.flags = 0, | ||||
| 	}, | ||||
| 	{	.cmd_name = "ps", | ||||
| 		.cmd_func = kdb_ps, | ||||
| 		.cmd_usage = "[<flags>|A]", | ||||
| 		.cmd_help = "Display active task list", | ||||
| 		.cmd_flags = KDB_ENABLE_INSPECT, | ||||
| 	{	.name = "ps", | ||||
| 		.func = kdb_ps, | ||||
| 		.usage = "[<flags>|A]", | ||||
| 		.help = "Display active task list", | ||||
| 		.flags = KDB_ENABLE_INSPECT, | ||||
| 	}, | ||||
| 	{	.cmd_name = "pid", | ||||
| 		.cmd_func = kdb_pid, | ||||
| 		.cmd_usage = "<pidnum>", | ||||
| 		.cmd_help = "Switch to another task", | ||||
| 		.cmd_flags = KDB_ENABLE_INSPECT, | ||||
| 	{	.name = "pid", | ||||
| 		.func = kdb_pid, | ||||
| 		.usage = "<pidnum>", | ||||
| 		.help = "Switch to another task", | ||||
| 		.flags = KDB_ENABLE_INSPECT, | ||||
| 	}, | ||||
| 	{	.cmd_name = "reboot", | ||||
| 		.cmd_func = kdb_reboot, | ||||
| 		.cmd_usage = "", | ||||
| 		.cmd_help = "Reboot the machine immediately", | ||||
| 		.cmd_flags = KDB_ENABLE_REBOOT, | ||||
| 	{	.name = "reboot", | ||||
| 		.func = kdb_reboot, | ||||
| 		.usage = "", | ||||
| 		.help = "Reboot the machine immediately", | ||||
| 		.flags = KDB_ENABLE_REBOOT, | ||||
| 	}, | ||||
| #if defined(CONFIG_MODULES) | ||||
| 	{	.cmd_name = "lsmod", | ||||
| 		.cmd_func = kdb_lsmod, | ||||
| 		.cmd_usage = "", | ||||
| 		.cmd_help = "List loaded kernel modules", | ||||
| 		.cmd_flags = KDB_ENABLE_INSPECT, | ||||
| 	{	.name = "lsmod", | ||||
| 		.func = kdb_lsmod, | ||||
| 		.usage = "", | ||||
| 		.help = "List loaded kernel modules", | ||||
| 		.flags = KDB_ENABLE_INSPECT, | ||||
| 	}, | ||||
| #endif | ||||
| #if defined(CONFIG_MAGIC_SYSRQ) | ||||
| 	{	.cmd_name = "sr", | ||||
| 		.cmd_func = kdb_sr, | ||||
| 		.cmd_usage = "<key>", | ||||
| 		.cmd_help = "Magic SysRq key", | ||||
| 		.cmd_flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	{	.name = "sr", | ||||
| 		.func = kdb_sr, | ||||
| 		.usage = "<key>", | ||||
| 		.help = "Magic SysRq key", | ||||
| 		.flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	}, | ||||
| #endif | ||||
| #if defined(CONFIG_PRINTK) | ||||
| 	{	.cmd_name = "dmesg", | ||||
| 		.cmd_func = kdb_dmesg, | ||||
| 		.cmd_usage = "[lines]", | ||||
| 		.cmd_help = "Display syslog buffer", | ||||
| 		.cmd_flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	{	.name = "dmesg", | ||||
| 		.func = kdb_dmesg, | ||||
| 		.usage = "[lines]", | ||||
| 		.help = "Display syslog buffer", | ||||
| 		.flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	}, | ||||
| #endif | ||||
| 	{	.cmd_name = "defcmd", | ||||
| 		.cmd_func = kdb_defcmd, | ||||
| 		.cmd_usage = "name \"usage\" \"help\"", | ||||
| 		.cmd_help = "Define a set of commands, down to endefcmd", | ||||
| 		.cmd_flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	{	.name = "defcmd", | ||||
| 		.func = kdb_defcmd, | ||||
| 		.usage = "name \"usage\" \"help\"", | ||||
| 		.help = "Define a set of commands, down to endefcmd", | ||||
| 		/*
 | ||||
| 		 * Macros are always safe because when executed each | ||||
| 		 * internal command re-enters kdb_parse() and is safety | ||||
| 		 * checked individually. | ||||
| 		 */ | ||||
| 		.flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	}, | ||||
| 	{	.cmd_name = "kill", | ||||
| 		.cmd_func = kdb_kill, | ||||
| 		.cmd_usage = "<-signal> <pid>", | ||||
| 		.cmd_help = "Send a signal to a process", | ||||
| 		.cmd_flags = KDB_ENABLE_SIGNAL, | ||||
| 	{	.name = "kill", | ||||
| 		.func = kdb_kill, | ||||
| 		.usage = "<-signal> <pid>", | ||||
| 		.help = "Send a signal to a process", | ||||
| 		.flags = KDB_ENABLE_SIGNAL, | ||||
| 	}, | ||||
| 	{	.cmd_name = "summary", | ||||
| 		.cmd_func = kdb_summary, | ||||
| 		.cmd_usage = "", | ||||
| 		.cmd_help = "Summarize the system", | ||||
| 		.cmd_minlen = 4, | ||||
| 		.cmd_flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	{	.name = "summary", | ||||
| 		.func = kdb_summary, | ||||
| 		.usage = "", | ||||
| 		.help = "Summarize the system", | ||||
| 		.minlen = 4, | ||||
| 		.flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	}, | ||||
| 	{	.cmd_name = "per_cpu", | ||||
| 		.cmd_func = kdb_per_cpu, | ||||
| 		.cmd_usage = "<sym> [<bytes>] [<cpu>]", | ||||
| 		.cmd_help = "Display per_cpu variables", | ||||
| 		.cmd_minlen = 3, | ||||
| 		.cmd_flags = KDB_ENABLE_MEM_READ, | ||||
| 	{	.name = "per_cpu", | ||||
| 		.func = kdb_per_cpu, | ||||
| 		.usage = "<sym> [<bytes>] [<cpu>]", | ||||
| 		.help = "Display per_cpu variables", | ||||
| 		.minlen = 3, | ||||
| 		.flags = KDB_ENABLE_MEM_READ, | ||||
| 	}, | ||||
| 	{	.cmd_name = "grephelp", | ||||
| 		.cmd_func = kdb_grep_help, | ||||
| 		.cmd_usage = "", | ||||
| 		.cmd_help = "Display help on | grep", | ||||
| 		.cmd_flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	{	.name = "grephelp", | ||||
| 		.func = kdb_grep_help, | ||||
| 		.usage = "", | ||||
| 		.help = "Display help on | grep", | ||||
| 		.flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static kdbtab_t nmicmd = { | ||||
| 	.cmd_name = "disable_nmi", | ||||
| 	.cmd_func = kdb_disable_nmi, | ||||
| 	.cmd_usage = "", | ||||
| 	.cmd_help = "Disable NMI entry to KDB", | ||||
| 	.cmd_flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| 	.name = "disable_nmi", | ||||
| 	.func = kdb_disable_nmi, | ||||
| 	.usage = "", | ||||
| 	.help = "Disable NMI entry to KDB", | ||||
| 	.flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| }; | ||||
| 
 | ||||
| /* Initialize the kdb command table. */ | ||||
|  | ||||
| @ -109,7 +109,6 @@ extern int kdbgetaddrarg(int, const char **, int*, unsigned long *, | ||||
| 			 long *, char **); | ||||
| extern int kdbgetsymval(const char *, kdb_symtab_t *); | ||||
| extern int kdbnearsym(unsigned long, kdb_symtab_t *); | ||||
| extern void kdbnearsym_cleanup(void); | ||||
| extern char *kdb_strdup(const char *str, gfp_t type); | ||||
| extern void kdb_symbol_print(unsigned long, const kdb_symtab_t *, unsigned int); | ||||
| 
 | ||||
| @ -165,19 +164,6 @@ typedef struct _kdb_bp { | ||||
| #ifdef CONFIG_KGDB_KDB | ||||
| extern kdb_bp_t kdb_breakpoints[/* KDB_MAXBPT */]; | ||||
| 
 | ||||
| /* The KDB shell command table */ | ||||
| typedef struct _kdbtab { | ||||
| 	char    *cmd_name;		/* Command name */ | ||||
| 	kdb_func_t cmd_func;		/* Function to execute command */ | ||||
| 	char    *cmd_usage;		/* Usage String for this command */ | ||||
| 	char    *cmd_help;		/* Help message for this command */ | ||||
| 	short    cmd_minlen;		/* Minimum legal # command
 | ||||
| 					 * chars required */ | ||||
| 	kdb_cmdflags_t cmd_flags;	/* Command behaviour flags */ | ||||
| 	struct list_head list_node;	/* Command list */ | ||||
| 	bool    is_dynamic;		/* Command table allocation type */ | ||||
| } kdbtab_t; | ||||
| 
 | ||||
| extern void kdb_register_table(kdbtab_t *kp, size_t len); | ||||
| extern int kdb_bt(int, const char **);	/* KDB display back trace */ | ||||
| 
 | ||||
| @ -233,10 +219,6 @@ extern struct task_struct *kdb_curr_task(int); | ||||
| 
 | ||||
| #define GFP_KDB (in_dbg_master() ? GFP_ATOMIC : GFP_KERNEL) | ||||
| 
 | ||||
| extern void *debug_kmalloc(size_t size, gfp_t flags); | ||||
| extern void debug_kfree(void *); | ||||
| extern void debug_kusage(void); | ||||
| 
 | ||||
| extern struct task_struct *kdb_current_task; | ||||
| extern struct pt_regs *kdb_current_regs; | ||||
| 
 | ||||
|  | ||||
| @ -51,48 +51,48 @@ int kdbgetsymval(const char *symname, kdb_symtab_t *symtab) | ||||
| } | ||||
| EXPORT_SYMBOL(kdbgetsymval); | ||||
| 
 | ||||
| static char *kdb_name_table[100];	/* arbitrary size */ | ||||
| 
 | ||||
| /*
 | ||||
|  * kdbnearsym -	Return the name of the symbol with the nearest address | ||||
|  *	less than 'addr'. | ||||
| /**
 | ||||
|  * kdbnearsym() - Return the name of the symbol with the nearest address | ||||
|  *                less than @addr. | ||||
|  * @addr: Address to check for near symbol | ||||
|  * @symtab: Structure to receive results | ||||
|  * | ||||
|  * Parameters: | ||||
|  *	addr	Address to check for symbol near | ||||
|  *	symtab  Structure to receive results | ||||
|  * Returns: | ||||
|  *	0	No sections contain this address, symtab zero filled | ||||
|  *	1	Address mapped to module/symbol/section, data in symtab | ||||
|  * Remarks: | ||||
|  *	2.6 kallsyms has a "feature" where it unpacks the name into a | ||||
|  *	string.  If that string is reused before the caller expects it | ||||
|  *	then the caller sees its string change without warning.  To | ||||
|  *	avoid cluttering up the main kdb code with lots of kdb_strdup, | ||||
|  *	tests and kfree calls, kdbnearsym maintains an LRU list of the | ||||
|  *	last few unique strings.  The list is sized large enough to | ||||
|  *	hold active strings, no kdb caller of kdbnearsym makes more | ||||
|  *	than ~20 later calls before using a saved value. | ||||
|  * WARNING: This function may return a pointer to a single statically | ||||
|  * allocated buffer (namebuf). kdb's unusual calling context (single | ||||
|  * threaded, all other CPUs halted) provides us sufficient locking for | ||||
|  * this to be safe. The only constraint imposed by the static buffer is | ||||
|  * that the caller must consume any previous reply prior to another call | ||||
|  * to lookup a new symbol. | ||||
|  * | ||||
|  * Note that, strictly speaking, some architectures may re-enter the kdb | ||||
|  * trap if the system turns out to be very badly damaged and this breaks | ||||
|  * the single-threaded assumption above. In these circumstances successful | ||||
|  * continuation and exit from the inner trap is unlikely to work and any | ||||
|  * user attempting this receives a prominent warning before being allowed | ||||
|  * to progress. In these circumstances we remain memory safe because | ||||
|  * namebuf[KSYM_NAME_LEN-1] will never change from '\0' although we do | ||||
|  * tolerate the possibility of garbled symbol display from the outer kdb | ||||
|  * trap. | ||||
|  * | ||||
|  * Return: | ||||
|  * * 0 - No sections contain this address, symtab zero filled | ||||
|  * * 1 - Address mapped to module/symbol/section, data in symtab | ||||
|  */ | ||||
| int kdbnearsym(unsigned long addr, kdb_symtab_t *symtab) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	unsigned long symbolsize = 0; | ||||
| 	unsigned long offset = 0; | ||||
| #define knt1_size 128		/* must be >= kallsyms table size */ | ||||
| 	char *knt1 = NULL; | ||||
| 	static char namebuf[KSYM_NAME_LEN]; | ||||
| 
 | ||||
| 	kdb_dbg_printf(AR, "addr=0x%lx, symtab=%px\n", addr, symtab); | ||||
| 	memset(symtab, 0, sizeof(*symtab)); | ||||
| 
 | ||||
| 	if (addr < 4096) | ||||
| 		goto out; | ||||
| 	knt1 = debug_kmalloc(knt1_size, GFP_ATOMIC); | ||||
| 	if (!knt1) { | ||||
| 		kdb_func_printf("addr=0x%lx cannot kmalloc knt1\n", addr); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	symtab->sym_name = kallsyms_lookup(addr, &symbolsize , &offset, | ||||
| 				(char **)(&symtab->mod_name), knt1); | ||||
| 				(char **)(&symtab->mod_name), namebuf); | ||||
| 	if (offset > 8*1024*1024) { | ||||
| 		symtab->sym_name = NULL; | ||||
| 		addr = offset = symbolsize = 0; | ||||
| @ -101,63 +101,14 @@ int kdbnearsym(unsigned long addr, kdb_symtab_t *symtab) | ||||
| 	symtab->sym_end = symtab->sym_start + symbolsize; | ||||
| 	ret = symtab->sym_name != NULL && *(symtab->sym_name) != '\0'; | ||||
| 
 | ||||
| 	if (ret) { | ||||
| 		int i; | ||||
| 		/* Another 2.6 kallsyms "feature".  Sometimes the sym_name is
 | ||||
| 		 * set but the buffer passed into kallsyms_lookup is not used, | ||||
| 		 * so it contains garbage.  The caller has to work out which | ||||
| 		 * buffer needs to be saved. | ||||
| 		 * | ||||
| 		 * What was Rusty smoking when he wrote that code? | ||||
| 		 */ | ||||
| 		if (symtab->sym_name != knt1) { | ||||
| 			strncpy(knt1, symtab->sym_name, knt1_size); | ||||
| 			knt1[knt1_size-1] = '\0'; | ||||
| 		} | ||||
| 		for (i = 0; i < ARRAY_SIZE(kdb_name_table); ++i) { | ||||
| 			if (kdb_name_table[i] && | ||||
| 			    strcmp(kdb_name_table[i], knt1) == 0) | ||||
| 				break; | ||||
| 		} | ||||
| 		if (i >= ARRAY_SIZE(kdb_name_table)) { | ||||
| 			debug_kfree(kdb_name_table[0]); | ||||
| 			memmove(kdb_name_table, kdb_name_table+1, | ||||
| 			       sizeof(kdb_name_table[0]) * | ||||
| 			       (ARRAY_SIZE(kdb_name_table)-1)); | ||||
| 		} else { | ||||
| 			debug_kfree(knt1); | ||||
| 			knt1 = kdb_name_table[i]; | ||||
| 			memmove(kdb_name_table+i, kdb_name_table+i+1, | ||||
| 			       sizeof(kdb_name_table[0]) * | ||||
| 			       (ARRAY_SIZE(kdb_name_table)-i-1)); | ||||
| 		} | ||||
| 		i = ARRAY_SIZE(kdb_name_table) - 1; | ||||
| 		kdb_name_table[i] = knt1; | ||||
| 		symtab->sym_name = kdb_name_table[i]; | ||||
| 		knt1 = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (symtab->mod_name == NULL) | ||||
| 		symtab->mod_name = "kernel"; | ||||
| 	kdb_dbg_printf(AR, "returns %d symtab->sym_start=0x%lx, symtab->mod_name=%px, symtab->sym_name=%px (%s)\n", | ||||
| 		       ret, symtab->sym_start, symtab->mod_name, symtab->sym_name, symtab->sym_name); | ||||
| 
 | ||||
| out: | ||||
| 	debug_kfree(knt1); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| void kdbnearsym_cleanup(void) | ||||
| { | ||||
| 	int i; | ||||
| 	for (i = 0; i < ARRAY_SIZE(kdb_name_table); ++i) { | ||||
| 		if (kdb_name_table[i]) { | ||||
| 			debug_kfree(kdb_name_table[i]); | ||||
| 			kdb_name_table[i] = NULL; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static char ks_namebuf[KSYM_NAME_LEN+1], ks_namebuf_prev[KSYM_NAME_LEN+1]; | ||||
| 
 | ||||
| /*
 | ||||
| @ -655,230 +606,6 @@ unsigned long kdb_task_state(const struct task_struct *p, unsigned long mask) | ||||
| 	return (mask & kdb_task_state_string(state)) != 0; | ||||
| } | ||||
| 
 | ||||
| /* Last ditch allocator for debugging, so we can still debug even when
 | ||||
|  * the GFP_ATOMIC pool has been exhausted.  The algorithms are tuned | ||||
|  * for space usage, not for speed.  One smallish memory pool, the free | ||||
|  * chain is always in ascending address order to allow coalescing, | ||||
|  * allocations are done in brute force best fit. | ||||
|  */ | ||||
| 
 | ||||
| struct debug_alloc_header { | ||||
| 	u32 next;	/* offset of next header from start of pool */ | ||||
| 	u32 size; | ||||
| 	void *caller; | ||||
| }; | ||||
| 
 | ||||
| /* The memory returned by this allocator must be aligned, which means
 | ||||
|  * so must the header size.  Do not assume that sizeof(struct | ||||
|  * debug_alloc_header) is a multiple of the alignment, explicitly | ||||
|  * calculate the overhead of this header, including the alignment. | ||||
|  * The rest of this code must not use sizeof() on any header or | ||||
|  * pointer to a header. | ||||
|  */ | ||||
| #define dah_align 8 | ||||
| #define dah_overhead ALIGN(sizeof(struct debug_alloc_header), dah_align) | ||||
| 
 | ||||
| static u64 debug_alloc_pool_aligned[256*1024/dah_align];	/* 256K pool */ | ||||
| static char *debug_alloc_pool = (char *)debug_alloc_pool_aligned; | ||||
| static u32 dah_first, dah_first_call = 1, dah_used, dah_used_max; | ||||
| 
 | ||||
| /* Locking is awkward.  The debug code is called from all contexts,
 | ||||
|  * including non maskable interrupts.  A normal spinlock is not safe | ||||
|  * in NMI context.  Try to get the debug allocator lock, if it cannot | ||||
|  * be obtained after a second then give up.  If the lock could not be | ||||
|  * previously obtained on this cpu then only try once. | ||||
|  * | ||||
|  * sparse has no annotation for "this function _sometimes_ acquires a | ||||
|  * lock", so fudge the acquire/release notation. | ||||
|  */ | ||||
| static DEFINE_SPINLOCK(dap_lock); | ||||
| static int get_dap_lock(void) | ||||
| 	__acquires(dap_lock) | ||||
| { | ||||
| 	static int dap_locked = -1; | ||||
| 	int count; | ||||
| 	if (dap_locked == smp_processor_id()) | ||||
| 		count = 1; | ||||
| 	else | ||||
| 		count = 1000; | ||||
| 	while (1) { | ||||
| 		if (spin_trylock(&dap_lock)) { | ||||
| 			dap_locked = -1; | ||||
| 			return 1; | ||||
| 		} | ||||
| 		if (!count--) | ||||
| 			break; | ||||
| 		udelay(1000); | ||||
| 	} | ||||
| 	dap_locked = smp_processor_id(); | ||||
| 	__acquire(dap_lock); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void *debug_kmalloc(size_t size, gfp_t flags) | ||||
| { | ||||
| 	unsigned int rem, h_offset; | ||||
| 	struct debug_alloc_header *best, *bestprev, *prev, *h; | ||||
| 	void *p = NULL; | ||||
| 	if (!get_dap_lock()) { | ||||
| 		__release(dap_lock);	/* we never actually got it */ | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	h = (struct debug_alloc_header *)(debug_alloc_pool + dah_first); | ||||
| 	if (dah_first_call) { | ||||
| 		h->size = sizeof(debug_alloc_pool_aligned) - dah_overhead; | ||||
| 		dah_first_call = 0; | ||||
| 	} | ||||
| 	size = ALIGN(size, dah_align); | ||||
| 	prev = best = bestprev = NULL; | ||||
| 	while (1) { | ||||
| 		if (h->size >= size && (!best || h->size < best->size)) { | ||||
| 			best = h; | ||||
| 			bestprev = prev; | ||||
| 			if (h->size == size) | ||||
| 				break; | ||||
| 		} | ||||
| 		if (!h->next) | ||||
| 			break; | ||||
| 		prev = h; | ||||
| 		h = (struct debug_alloc_header *)(debug_alloc_pool + h->next); | ||||
| 	} | ||||
| 	if (!best) | ||||
| 		goto out; | ||||
| 	rem = best->size - size; | ||||
| 	/* The pool must always contain at least one header */ | ||||
| 	if (best->next == 0 && bestprev == NULL && rem < dah_overhead) | ||||
| 		goto out; | ||||
| 	if (rem >= dah_overhead) { | ||||
| 		best->size = size; | ||||
| 		h_offset = ((char *)best - debug_alloc_pool) + | ||||
| 			   dah_overhead + best->size; | ||||
| 		h = (struct debug_alloc_header *)(debug_alloc_pool + h_offset); | ||||
| 		h->size = rem - dah_overhead; | ||||
| 		h->next = best->next; | ||||
| 	} else | ||||
| 		h_offset = best->next; | ||||
| 	best->caller = __builtin_return_address(0); | ||||
| 	dah_used += best->size; | ||||
| 	dah_used_max = max(dah_used, dah_used_max); | ||||
| 	if (bestprev) | ||||
| 		bestprev->next = h_offset; | ||||
| 	else | ||||
| 		dah_first = h_offset; | ||||
| 	p = (char *)best + dah_overhead; | ||||
| 	memset(p, POISON_INUSE, best->size - 1); | ||||
| 	*((char *)p + best->size - 1) = POISON_END; | ||||
| out: | ||||
| 	spin_unlock(&dap_lock); | ||||
| 	return p; | ||||
| } | ||||
| 
 | ||||
| void debug_kfree(void *p) | ||||
| { | ||||
| 	struct debug_alloc_header *h; | ||||
| 	unsigned int h_offset; | ||||
| 	if (!p) | ||||
| 		return; | ||||
| 	if ((char *)p < debug_alloc_pool || | ||||
| 	    (char *)p >= debug_alloc_pool + sizeof(debug_alloc_pool_aligned)) { | ||||
| 		kfree(p); | ||||
| 		return; | ||||
| 	} | ||||
| 	if (!get_dap_lock()) { | ||||
| 		__release(dap_lock);	/* we never actually got it */ | ||||
| 		return;		/* memory leak, cannot be helped */ | ||||
| 	} | ||||
| 	h = (struct debug_alloc_header *)((char *)p - dah_overhead); | ||||
| 	memset(p, POISON_FREE, h->size - 1); | ||||
| 	*((char *)p + h->size - 1) = POISON_END; | ||||
| 	h->caller = NULL; | ||||
| 	dah_used -= h->size; | ||||
| 	h_offset = (char *)h - debug_alloc_pool; | ||||
| 	if (h_offset < dah_first) { | ||||
| 		h->next = dah_first; | ||||
| 		dah_first = h_offset; | ||||
| 	} else { | ||||
| 		struct debug_alloc_header *prev; | ||||
| 		unsigned int prev_offset; | ||||
| 		prev = (struct debug_alloc_header *)(debug_alloc_pool + | ||||
| 						     dah_first); | ||||
| 		while (1) { | ||||
| 			if (!prev->next || prev->next > h_offset) | ||||
| 				break; | ||||
| 			prev = (struct debug_alloc_header *) | ||||
| 				(debug_alloc_pool + prev->next); | ||||
| 		} | ||||
| 		prev_offset = (char *)prev - debug_alloc_pool; | ||||
| 		if (prev_offset + dah_overhead + prev->size == h_offset) { | ||||
| 			prev->size += dah_overhead + h->size; | ||||
| 			memset(h, POISON_FREE, dah_overhead - 1); | ||||
| 			*((char *)h + dah_overhead - 1) = POISON_END; | ||||
| 			h = prev; | ||||
| 			h_offset = prev_offset; | ||||
| 		} else { | ||||
| 			h->next = prev->next; | ||||
| 			prev->next = h_offset; | ||||
| 		} | ||||
| 	} | ||||
| 	if (h_offset + dah_overhead + h->size == h->next) { | ||||
| 		struct debug_alloc_header *next; | ||||
| 		next = (struct debug_alloc_header *) | ||||
| 			(debug_alloc_pool + h->next); | ||||
| 		h->size += dah_overhead + next->size; | ||||
| 		h->next = next->next; | ||||
| 		memset(next, POISON_FREE, dah_overhead - 1); | ||||
| 		*((char *)next + dah_overhead - 1) = POISON_END; | ||||
| 	} | ||||
| 	spin_unlock(&dap_lock); | ||||
| } | ||||
| 
 | ||||
| void debug_kusage(void) | ||||
| { | ||||
| 	struct debug_alloc_header *h_free, *h_used; | ||||
| #ifdef	CONFIG_IA64 | ||||
| 	/* FIXME: using dah for ia64 unwind always results in a memory leak.
 | ||||
| 	 * Fix that memory leak first, then set debug_kusage_one_time = 1 for | ||||
| 	 * all architectures. | ||||
| 	 */ | ||||
| 	static int debug_kusage_one_time; | ||||
| #else | ||||
| 	static int debug_kusage_one_time = 1; | ||||
| #endif | ||||
| 	if (!get_dap_lock()) { | ||||
| 		__release(dap_lock);	/* we never actually got it */ | ||||
| 		return; | ||||
| 	} | ||||
| 	h_free = (struct debug_alloc_header *)(debug_alloc_pool + dah_first); | ||||
| 	if (dah_first == 0 && | ||||
| 	    (h_free->size == sizeof(debug_alloc_pool_aligned) - dah_overhead || | ||||
| 	     dah_first_call)) | ||||
| 		goto out; | ||||
| 	if (!debug_kusage_one_time) | ||||
| 		goto out; | ||||
| 	debug_kusage_one_time = 0; | ||||
| 	kdb_func_printf("debug_kmalloc memory leak dah_first %d\n", dah_first); | ||||
| 	if (dah_first) { | ||||
| 		h_used = (struct debug_alloc_header *)debug_alloc_pool; | ||||
| 		kdb_func_printf("h_used %px size %d\n", h_used, h_used->size); | ||||
| 	} | ||||
| 	do { | ||||
| 		h_used = (struct debug_alloc_header *) | ||||
| 			  ((char *)h_free + dah_overhead + h_free->size); | ||||
| 		kdb_func_printf("h_used %px size %d caller %px\n", | ||||
| 				h_used, h_used->size, h_used->caller); | ||||
| 		h_free = (struct debug_alloc_header *) | ||||
| 			  (debug_alloc_pool + h_free->next); | ||||
| 	} while (h_free->next); | ||||
| 	h_used = (struct debug_alloc_header *) | ||||
| 		  ((char *)h_free + dah_overhead + h_free->size); | ||||
| 	if ((char *)h_used - debug_alloc_pool != | ||||
| 	    sizeof(debug_alloc_pool_aligned)) | ||||
| 		kdb_func_printf("h_used %px size %d caller %px\n", | ||||
| 				h_used, h_used->size, h_used->caller); | ||||
| out: | ||||
| 	spin_unlock(&dap_lock); | ||||
| } | ||||
| 
 | ||||
| /* Maintain a small stack of kdb_flags to allow recursion without disturbing
 | ||||
|  * the global kdb state. | ||||
|  */ | ||||
|  | ||||
| @ -147,11 +147,17 @@ static int kdb_ftdump(int argc, const char **argv) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static kdbtab_t ftdump_cmd = { | ||||
| 	.name = "ftdump", | ||||
| 	.func = kdb_ftdump, | ||||
| 	.usage = "[skip_#entries] [cpu]", | ||||
| 	.help = "Dump ftrace log; -skip dumps last #entries", | ||||
| 	.flags = KDB_ENABLE_ALWAYS_SAFE, | ||||
| }; | ||||
| 
 | ||||
| static __init int kdb_ftrace_register(void) | ||||
| { | ||||
| 	kdb_register_flags("ftdump", kdb_ftdump, "[skip_#entries] [cpu]", | ||||
| 			    "Dump ftrace log; -skip dumps last #entries", 0, | ||||
| 			    KDB_ENABLE_ALWAYS_SAFE); | ||||
| 	kdb_register(&ftdump_cmd); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -28,28 +28,26 @@ static int kdb_hello_cmd(int argc, const char **argv) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static kdbtab_t hello_cmd = { | ||||
| 	.name = "hello", | ||||
| 	.func = kdb_hello_cmd, | ||||
| 	.usage = "[string]", | ||||
| 	.help = "Say Hello World or Hello [string]", | ||||
| }; | ||||
| 
 | ||||
| static int __init kdb_hello_cmd_init(void) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * Registration of a dynamically added kdb command is done with | ||||
| 	 * kdb_register() with the arguments being: | ||||
| 	 *   1: The name of the shell command | ||||
| 	 *   2: The function that processes the command | ||||
| 	 *   3: Description of the usage of any arguments | ||||
| 	 *   4: Descriptive text when you run help | ||||
| 	 *   5: Number of characters to complete the command | ||||
| 	 *      0 == type the whole command | ||||
| 	 *      1 == match both "g" and "go" for example | ||||
| 	 * kdb_register(). | ||||
| 	 */ | ||||
| 	kdb_register("hello", kdb_hello_cmd, "[string]", | ||||
| 		     "Say Hello World or Hello [string]", 0); | ||||
| 	kdb_register(&hello_cmd); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void __exit kdb_hello_cmd_exit(void) | ||||
| { | ||||
| 	kdb_unregister("hello"); | ||||
| 	kdb_unregister(&hello_cmd); | ||||
| } | ||||
| 
 | ||||
| module_init(kdb_hello_cmd_init); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user