--- linux-kdb/kdb/kdbmain.c	Fri Dec 20 14:13:57 2002
+++ linux-kdb-cmdline/kdb/kdbmain.c	Fri Dec 20 14:27:42 2002
@@ -157,7 +157,7 @@
  "MDCOUNT=8",			/* lines of md output */
  "BTARGS=5",			/* 5 possible args in bt */
  KDB_PLATFORM_ENV,
- (char *)0,
+ "DTABCOUNT=30",
  (char *)0,
  (char *)0,
  (char *)0,
@@ -691,7 +691,7 @@
  */
 #define KDB_CMD_HISTORY_COUNT	32
 #define CMD_BUFLEN		200	/* kdb_printf: max printline size == 256 */
-static unsigned int cmd_head, cmd_tail;
+static unsigned int cmd_head=0, cmd_tail=0;
 static unsigned int cmdptr;
 static char cmd_hist[KDB_CMD_HISTORY_COUNT][CMD_BUFLEN];
 
@@ -887,22 +887,22 @@
 #define CTRL_N	14
 
 	/* initial situation */
-	if (cmd_head == cmd_tail) return 1;
+	if (cmd_head == cmd_tail) return 0;
 
 	switch(*cmd) {
-		case '\n':
 		case CTRL_P:
 			if (cmdptr != cmd_tail)
 				cmdptr = (cmdptr-1) % KDB_CMD_HISTORY_COUNT;
-			strcpy(cmd, cmd_hist[cmdptr]);
-			return 0;	
+			strncpy(cmd_hist[cmd_head], cmd_hist[cmdptr], CMD_BUFLEN);
+			return 1;
 		case CTRL_N:
+			if (cmdptr == cmd_head) return 0;
 			if (cmdptr != (cmd_head-1))
 				cmdptr = (cmdptr+1) % KDB_CMD_HISTORY_COUNT;
-			strcpy(cmd, cmd_hist[cmdptr]);
-			return 0;
+			strncpy(cmd_hist[cmd_head], cmd_hist[cmdptr], CMD_BUFLEN);
+			return 1;
 	}
-	return 1;
+	return 0;
 }
 
 
@@ -998,7 +998,7 @@
 			return KDB_CMD_GO;
 		}
 		break;
-	case KDB_REASON_CALL:	
+	case KDB_REASON_CALL:
 		if (!regs)
 			kdb_printf("kdb() called with no registers, restricted function\n");
 		break;
@@ -1059,6 +1059,10 @@
 			KDB_STATE_SET(LONGJMP);
 #endif	/* KDB_HAVE_LONGJMP */
 
+
+		cmdbuf = cmd_hist[cmd_head];
+		*cmdbuf = '\0';
+
 do_full_getstr:
 #if defined(CONFIG_SMP)
 		kdb_printf(kdbgetenv("PROMPT"), smp_processor_id());
@@ -1066,15 +1070,15 @@
 		kdb_printf(kdbgetenv("PROMPT"));
 #endif
 
-		cmdbuf = cmd_hist[cmd_head];
-		*cmdbuf = '\0';
 		/*
 		 * Fetch command from keyboard
 		 */
 		cmdbuf = kdb_getstr(cmdbuf, CMD_BUFLEN, defcmd_in_progress ? "[defcmd]" : "");
-		if (*cmdbuf < 32 && *cmdbuf != '\n')
-			if (handle_ctrl_cmd(cmdbuf))
-				goto do_full_getstr;
+		if (*cmdbuf < 32 && *cmdbuf != '\n') {
+			if (!handle_ctrl_cmd(cmdbuf)) *cmdbuf = '\0';
+			cmdbuf = cmd_hist[cmd_head];
+			goto do_full_getstr;
+		}
 
 		if (*cmdbuf != '\n') {
 			cmd_head = (cmd_head+1) % KDB_CMD_HISTORY_COUNT;


--- linux-kdb/kdb/kdb_io.c	Wed Dec  4 16:09:02 2002
+++ linux-kdb-cmdline/kdb/kdb_io.c	Wed Jan 17 11:07:26 2003
@@ -42,9 +42,11 @@
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
+#include <linux/nmi.h>

 #include <linux/kdb.h>
 #include <linux/kdbprivate.h>
+#include <linux/kallsyms.h>

 #ifdef CONFIG_SPARC64
 #include <asm/oplib.h>
@@ -52,6 +54,29 @@
 static struct console *kdbcons;
 #endif

+
+#define CMD_BUFLEN 256
+
+static void kdb_printprompt(void)
+{
+#if defined(CONFIG_SMP)
+	kdb_printf(kdbgetenv("PROMPT"), smp_processor_id());
+#else
+	kdb_printf(kdbgetenv("PROMPT"));
+#endif
+}
+
+static int kdb_promptlength(void)
+{
+#if defined(CONFIG_SMP)
+	char promptstr[30];
+	snprintf(promptstr, 30, kdbgetenv("PROMPT"), smp_processor_id());
+	return strlen(promptstr);
+#else
+	return strlen(kdbgetenv("PROMPT");
+#endif
+}
+
 /*
  * kdb_read
  *
@@ -95,10 +120,208 @@
  * The bulk of this function is architecture dependent.
  */

+// The bufsize must >= 2 .
+// If bufsize == 2, that means this routine returns immediately after receiving one key.
+
 char *
 kdb_read(char *buffer, size_t bufsize)
 {
-	return(kdba_read(buffer, bufsize));
+	char	*cp = buffer;
+	char	*bufend = buffer+bufsize-2;	/* Reserve space for newline and null byte */
+
+	char	*lastchar;
+	char	*p_tmp;
+	char	tmp;
+	static char	tmpbuffer[CMD_BUFLEN];
+	int len = strlen(buffer);
+	int len_tmp;
+	int tab=0;
+	int count;
+	int i;
+	int diag, dtab_count;
+
+	diag = kdbgetintenv("DTABCOUNT",&dtab_count);
+	if (diag)
+		dtab_count = 30;
+
+	if (len > 0 ) {
+		cp += len;
+		if (*(buffer+len-1) == '\n')
+			cp--;
+	}
+
+	lastchar = cp;
+	*cp = '\0';
+	kdb_printf("%s", buffer);
+
+	for (;;) {
+		int key;
+		get_char_func *f;
+		for (f = &poll_funcs[0]; ; ++f) {
+			if (*f == NULL) {
+				/* Reset NMI watchdog once per poll loop */
+				touch_nmi_watchdog();
+				f = &poll_funcs[0];
+			}
+			key = (*f)();
+
+			if (key != -1) {
+				if (key == 9){
+					if (dtab_count>0) {
+						if(tab<2)++tab;
+					}
+				}
+				else {
+					tab = 0;
+				}
+				break;
+			}
+		}
+		if (bufsize <= 2) {
+			*buffer++ = (char)key;
+			*buffer = '\0';
+			return buffer;
+		}
+
+		switch (key) {
+		case 8: /* backspace */
+			if (cp > buffer) {
+				if (cp < lastchar) {
+					memcpy(tmpbuffer, cp, lastchar - cp);
+					memcpy(cp-1, tmpbuffer, lastchar - cp);
+				}
+				*(--lastchar) = '\0';
+				--cp;
+				kdb_printf("\b%s \r", cp);
+				tmp = *cp;
+				*cp = '\0';
+				kdb_printprompt();
+				kdb_printf("%s", buffer);
+				*cp = tmp;
+			}
+			break;
+		case 13: /* enter */
+			*lastchar++ = '\n';
+			*lastchar++ = '\0';
+			kdb_printf("\n");
+			return buffer;
+		case 4: /* Del */
+			if(cp < lastchar) {
+				memcpy(tmpbuffer, cp+1, lastchar - cp -1);
+				memcpy(cp, tmpbuffer, lastchar - cp -1);
+				*(--lastchar) = '\0';
+				kdb_printf("%s \r", cp);
+				tmp = *cp;
+				*cp = '\0';
+				kdb_printprompt();
+				kdb_printf("%s", buffer);
+				*cp = tmp;
+			}
+			break;
+		case 1: /* Home */
+			if(cp > buffer) {
+				kdb_printf("\r");
+				kdb_printprompt();
+				cp = buffer;
+			}
+			break;
+		case 5: /* End */
+			if(cp < lastchar) {
+				kdb_printf("%s", cp);
+				cp = lastchar;
+			}
+			break;
+		case 2: /* Left */
+			if (cp > buffer) {
+				kdb_printf("\b");
+				--cp;
+			}
+			break;
+		case 14: /* Down */
+			memset(tmpbuffer, ' ', kdb_promptlength()+(lastchar-buffer));
+			*(tmpbuffer+kdb_promptlength()+(lastchar-buffer)) = '\0';
+			kdb_printf("\r%s\r", tmpbuffer);
+			*lastchar = (char)key;
+			*(lastchar+1) = '\0';
+			return lastchar;
+		case 6: /* Right */
+			if (cp < lastchar) {
+				kdb_printf("%c", *cp);
+				++cp;
+			}
+			break;
+		case 16: /* Up */
+			memset(tmpbuffer, ' ', kdb_promptlength()+(lastchar-buffer));
+			*(tmpbuffer+kdb_promptlength()+(lastchar-buffer)) = '\0';
+			kdb_printf("\r%s\r", tmpbuffer);
+			*lastchar = (char)key;
+			*(lastchar+1) = '\0';
+			return lastchar;
+		case 9: /* Tab */
+			p_tmp = buffer;
+			while(*p_tmp==' ') p_tmp++;
+			if (p_tmp<=cp) {
+				memcpy(tmpbuffer, p_tmp, cp-p_tmp);
+				*(tmpbuffer + (cp-p_tmp)) = '\0';
+				p_tmp = strrchr(tmpbuffer, ' ');
+				if (p_tmp != NULL) {
+					++p_tmp;
+					len = strlen(p_tmp);
+					if (tab == 2) {
+						if((count=kallsyms_symbol_complete(p_tmp))>0) {
+							kdb_printf("\n%d symbols are found.", count);
+							if(count>dtab_count) {
+								count=dtab_count;
+								kdb_printf(" But only first %d symbols will be printed.\nYou can change the environment variable DTABCOUNT.", count);
+							}
+							kdb_printf("\n");
+							for(i=0;i<count;i++) {
+								if(kallsyms_symbol_next(p_tmp, i)<0)
+									break;
+								kdb_printf("%s ",p_tmp);
+								*(p_tmp+len)='\0';
+							}
+							if(i>=dtab_count)kdb_printf("...");
+							kdb_printf("\n");
+							kdb_printprompt();
+							kdb_printf("%s", buffer);
+						}
+					}
+					else {
+						if(kallsyms_symbol_complete(p_tmp)>0) {
+							len_tmp = strlen(p_tmp);
+							strncpy(p_tmp+len_tmp,cp, lastchar-cp+1);
+							len_tmp = strlen(p_tmp);
+							strncpy(cp, p_tmp+len, len_tmp-len+1);
+							len = len_tmp - len;
+							kdb_printf("%s", cp);
+							cp+=len;
+							lastchar+=len;
+						}
+					}
+					kdb_nextline = 1;		// reset output line number
+				}
+			}
+			break;
+		default:
+			if (key >= 32 &&lastchar < bufend) {
+				if (cp < lastchar) {
+					memcpy(tmpbuffer, cp, lastchar - cp);
+					memcpy(cp+1, tmpbuffer, lastchar - cp);
+				}
+				*(++lastchar) = '\0';
+				*cp = key;
+				kdb_printf("%s\r", cp);
+				++cp;
+				tmp = *cp;
+				*cp = '\0';
+				kdb_printprompt();
+				kdb_printf("%s", buffer);
+				*cp = tmp;
+			}
+			break;
+		}
+	}
 }

 /*
@@ -206,7 +429,7 @@

 	if (kdb_nextline == linecount) {
 #ifdef KDB_HAVE_LONGJMP
-		char buf1[16];
+		char buf1[16]="";
 #if defined(CONFIG_SMP)
 		char buf2[32];
 #endif
@@ -243,16 +466,19 @@
 			c->write(c, moreprompt, strlen(moreprompt));
 			c = c->next;
 		}
+
 		if (logging)
 			printk("%s", moreprompt);

-		kdb_read(buf1, sizeof(buf1));
+		kdb_read(buf1, 2); // '2' indicates to return immediately after getting one key.
 		kdb_nextline = 1;	/* Really set output line 1 */

-		if ((buf1[0] == 'q') || (buf1[0] == 'Q'))
+		if ((buf1[0] == 'q') || (buf1[0] == 'Q')) {
 			do_longjmp = 1;
+			kdb_printf("\n");
+		}
 		else if (buf1[0] && buf1[0] != '\n')
-			kdb_printf("Only 'q' or 'Q' are processed at more prompt, input ignored\n");
+			kdb_printf("\nOnly 'q' or 'Q' are processed at more prompt, input ignored\n");
 #endif	/* KDB_HAVE_LONGJMP */
 	}


--- linux-kdb/include/linux/kallsyms.h	Fri Dec 20 13:41:45 2002
+++ linux-kdb-cmdline/include/linux/kallsyms.h	Fri Dec 20 13:42:14 2002
@@ -136,4 +136,12 @@
 		      )
 		);

+int kallsyms_symbol_complete(
+	char	 *prefix_name	// Prefix of a symbol name to lookup
+	);
+int kallsyms_symbol_next(
+	char	 *prefix_name,	// Prefix of a symbol name to lookup
+	int flag			// Indicate if search from the head
+	);
+
 #endif /* kallsyms.h */


--- linux-kdb/kernel/kallsyms.c	Fri Dec 20 13:40:49 2002
+++ linux-kdb-cmdline/kernel/kallsyms.c	Fri Dec 20 13:42:39 2002
@@ -38,6 +38,7 @@
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/kallsyms.h>
+#include <linux/kdb.h>

 /* These external symbols are only set on kernels compiled with
  * CONFIG_KALLSYMS.
@@ -302,3 +303,118 @@
 	}
 	return(1);
 }
+
+
+// paramter prefix_name is a buffer provided by the caller, it must ends with '\0'.
+// return the extra string together with the given prefix of a symbol name.
+// return 0 means no prefix string is found.
+// return >0 means prefix string is found.
+int kallsyms_symbol_complete(
+	char	 *prefix_name	// Prefix of a symbol name to lookup
+	)
+{
+	const struct kallsyms_header	*ka_hdr = NULL;	// stupid gcc
+	const struct kallsyms_symbol	*ka_sym = NULL;
+	const char			*ka_str = NULL;
+	const struct module *m;
+	int i = 0;
+	int prefix_len=strlen(prefix_name);
+	int cur_pos=0, last_pos=0;
+	int find=0;
+	int number=0;
+	const char *p;
+
+	kallsyms_do_first_time();
+	if (!kallsyms_module_list)
+		return(0);
+
+	for (m = *kallsyms_module_list; m; m = m->next) {
+		if (!mod_member_present(m, kallsyms_start) ||
+		    !mod_member_present(m, kallsyms_end) ||
+		    m->kallsyms_start >= m->kallsyms_end)
+			continue;
+		ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
+		ka_sym = (struct kallsyms_symbol *)
+			((char *)(ka_hdr) + ka_hdr->symbol_off);
+		ka_str =
+			((char *)(ka_hdr) + ka_hdr->string_off);
+		for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) {
+			p = ka_str + ka_sym->name_off;
+			if (strncmp(p, prefix_name,prefix_len) == 0) {
+				++number;
+				if (find == 0) {
+					last_pos = strlen(p);
+					strncpy(prefix_name, p, last_pos+1);
+					find = 1;
+				}
+				else {
+					for (cur_pos = prefix_len ; cur_pos < last_pos; cur_pos++) {
+						if (*(p + cur_pos) == '\0'
+							|| *(p + cur_pos) != prefix_name[cur_pos]) {
+							last_pos = cur_pos;
+							prefix_name[cur_pos] = '\0';
+							break;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	return number;
+}
+
+// paramter prefix_name is a buffer provided by the caller, it must ends with '\0'.
+// parameter flag = 0 means search from the head, flag = 1 means continue search.
+// return a symbol string which matches the given prefix.
+// return 0 means no prefix string is found.
+// return >0 means prefix string is found.
+int kallsyms_symbol_next(
+	char	 *prefix_name,	// Prefix of a symbol name to lookup
+	int flag			// Indicate if search from the head
+	)
+{
+	const struct kallsyms_header	*ka_hdr = NULL;	// stupid gcc
+	const char			*ka_str = NULL;
+	static const struct kallsyms_symbol	*ka_sym;
+	static const struct module *m;
+	static int i;
+	int prefix_len=strlen(prefix_name);
+	const char *p;
+
+	kallsyms_do_first_time();
+	if (!kallsyms_module_list)
+		return(0);
+
+	if(!flag) {
+		m = *kallsyms_module_list;
+	}
+
+	for (; m; m = m->next) {
+		if (!mod_member_present(m, kallsyms_start) ||
+		    !mod_member_present(m, kallsyms_end) ||
+		    m->kallsyms_start >= m->kallsyms_end)
+			continue;
+		ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
+		if(!flag) {
+			ka_sym = (struct kallsyms_symbol *)
+				((char *)(ka_hdr) + ka_hdr->symbol_off);
+			i = 0;
+		}
+		ka_str = ((char *)(ka_hdr) + ka_hdr->string_off);
+
+		for (; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) {
+			p = ka_str + ka_sym->name_off;
+			if (strncmp(p, prefix_name,prefix_len) == 0) {
+				strncpy(prefix_name, p, strlen(p)+1);
+				++i;
+				kallsyms_next_sym(ka_hdr, ka_sym);
+				return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+

--- linux-kdb/include/linux/kdbprivate.h	Wed Jan 15 17:31:25 2003
+++ linux-kdb-cmdline/include/linux/kdbprivate.h	Wed Jan 17 11:55:12 2003
@@ -160,7 +160,8 @@
 	/*
 	 * Architecture specific function to read a string.
 	 */
-extern char *	     kdba_read(char *, size_t);
+typedef int (*get_char_func)(void);
+extern get_char_func poll_funcs[];

 	/*
 	 * Data for a single activation record on stack.
