--- memory.c.orig	2011-01-25 14:26:55.000000000 -0700
+++ memory.c	2011-02-01 16:21:28.000000000 -0700
@@ -134,6 +134,7 @@ static int page_to_phys(ulong, physaddr_
 static int phys_to_page(physaddr_t, ulong *); 
 static void display_memory(ulonglong, long, ulong, int); 
 static void search(ulong, ulong, ulong, int, ulong *, int);
+static void string_search(ulong, ulong, int, char **, int);
 static int next_upage(struct task_context *, ulong, ulong *);
 static int next_kpage(ulong, ulong *);
 static ulong last_vmalloc_address(void);
@@ -11284,18 +11285,20 @@ void
 cmd_search(void)
 {
         int c;
+	int str_search = 0;
 	ulong start, end, mask, memtype, len;
 	ulong uvaddr_end;
 	int sflag;
 	struct meminfo meminfo;
 	ulong value_array[MAXARGS];
+	char *string_array[MAXARGS];
 	struct syment *sp;
 
 	start = end = mask = sflag = memtype = len = 0;
 	uvaddr_end = COMMON_VADDR_SPACE() ? (ulong)(-1) : machdep->kvbase;
 	BZERO(value_array, sizeof(ulong) * MAXARGS);
 
-        while ((c = getopt(argcnt, args, "l:uks:e:v:m:")) != EOF) {
+        while ((c = getopt(argcnt, args, "cl:uks:e:v:m:")) != EOF) {
                 switch(c)
                 {
 		case 'u':
@@ -11353,6 +11356,10 @@ cmd_search(void)
                         mask = htol(optarg, FAULT_ON_ERROR, NULL);
                         break;
 
+		case 'c':
+			str_search++;
+			break;
+
                 default:
                         argerrs++;
                         break;
@@ -11447,18 +11454,171 @@ cmd_search(void)
 
 	c = 0;
 	while (args[optind]) {
-		value_array[c] = htol(args[optind], FAULT_ON_ERROR, NULL);
+		if (str_search) 
+			string_array[c] = args[optind];
+		else
+			value_array[c] = htol(args[optind], FAULT_ON_ERROR, NULL);
 		c++;
 		optind++;
 	}
 
-	search(start, end, mask, memtype, value_array, c);
+	if (str_search)
+		string_search(start, end, memtype, string_array, c);
+	else
+		search(start, end, mask, memtype, value_array, c);
 }
 
 /*
  *  Do the work for cmd_search().
  */
 
+#define CONTEXT_SIZE 48
+static void
+string_search(ulong start, ulong end, int memtype, char **value, int vcnt)
+{
+	int i, j, k;
+	int len[MAXARGS];
+	ulong pp, next;
+	char *ubp, *prp, *lastp;
+	int charcnt, lastpage;
+	ulong page;
+	physaddr_t paddr;
+	char *pagebuf;
+
+	if (start & (sizeof(long)-1)) {
+		start &= ~(sizeof(long)-1);
+		error(INFO, "rounding down start address to: %lx\n", start);
+	}
+
+	pagebuf = GETBUF(PAGESIZE());
+	next = start;
+
+	for (pp = VIRTPAGEBASE(start); next < end; next = pp) {
+		lastpage = (VIRTPAGEBASE(next) == VIRTPAGEBASE(end));
+		if (LKCD_DUMPFILE())
+			set_lkcd_nohash();
+
+		/*
+		 *  Keep it virtual for Xen hypervisor.
+		 */
+
+		if (XEN_HYPER_MODE()) {
+                	if (!readmem(pp, KVADDR, pagebuf, PAGESIZE(),
+                    	    "search page", RETURN_ON_ERROR|QUIET)) {
+				if (CRASHDEBUG(1))
+					fprintf(fp, 
+					    "search suspended at: %lx\n", pp);
+				return;
+			}
+			goto virtual;
+		}
+
+                switch (memtype)
+                {
+                case UVADDR:
+                        if (!uvtop(CURRENT_CONTEXT(), pp, &paddr, 0) ||
+                            !phys_to_page(paddr, &page)) { 
+				if (!next_upage(CURRENT_CONTEXT(), pp, &pp)) 
+					return;
+                                continue;
+			}
+                        break;
+
+                case KVADDR:
+                        if (!kvtop(CURRENT_CONTEXT(), pp, &paddr, 0) ||
+                            !phys_to_page(paddr, &page)) {
+				if (!next_kpage(pp, &pp))
+					return;
+                                continue;
+			}
+                        break;
+                }
+
+                if (!readmem(paddr, PHYSADDR, pagebuf, PAGESIZE(),
+                    "search page", RETURN_ON_ERROR|QUIET)) {
+			pp += PAGESIZE();
+			continue;
+		}
+virtual:
+		ubp = (char *)&pagebuf[next - pp];
+		if (lastpage) {
+			if (end == (ulong)(-1))
+				charcnt = PAGESIZE();
+			else
+				charcnt = end - next;
+		} else
+			charcnt = PAGESIZE() - (next - pp);
+
+		for (j = 0; j < vcnt; j++) {
+			len[j] = strlen(value[j]);
+		}
+
+		lastp = &ubp[charcnt];
+
+		/* pre-search for the last half or more of the string at start of area */
+		for (j = 0; j < vcnt; j++) {
+			int min_len = len[j]/2 + len[j]%2;  /* need the big half of odd lengths */
+			if (min_len < 1) 
+				min_len = 1;
+			for (k = len[j] - min_len; k > 0; k--) {
+				if ((charcnt > len[j] - k) && 
+				    (strncmp(value[j]+k, ubp, len[j]-k) == 0)) {
+					int ii = 0;
+					prp = ubp;
+					/* report findings on aligned addresses */
+					if ((ulong)prp & (sizeof(long) - 1))
+						prp = (char *)
+						    ((ulong)prp & ~(sizeof(long) - 1));
+					fprintf(fp, "%lx: ", next & ~(sizeof(long) - 1));
+					while ((ii < CONTEXT_SIZE) && (&prp[ii] < lastp)) {
+						if (isprint(prp[ii]))
+							fprintf(fp, "%c", prp[ii]);
+						else
+							fprintf(fp, ".");
+						ii++;
+					}
+					fprintf(fp, "\n");
+				}
+			}
+		}
+			
+		/* search for full string, and partial string at end of search area */
+		for (i = 0; i < charcnt; i++, ubp++, next++) {
+			for (j = 0; j < vcnt; j++) {
+				int min_len = len[j]/2 + len[j]%2;  /* need the big half of odd lengths */
+				if (min_len < 1) 
+					min_len = 1;
+				if (charcnt >= (i + min_len)) {
+					int slen = (len[j] < (charcnt - i)? len[j]:(charcnt - i));
+					if (strncmp(value[j], ubp, slen) == 0) {
+						int ii = 0;
+						prp = ubp;
+						/* report findings on aligned addresses */
+						if ((ulong)prp & (sizeof(long) - 1))
+							prp = (char *)
+							    ((ulong)prp & ~(sizeof(long) - 1));
+						fprintf(fp, "%lx: ", next & ~(sizeof(long) - 1));
+						while ((ii < CONTEXT_SIZE) && (&prp[ii] < lastp)) {
+							if (isprint(prp[ii]))
+								fprintf(fp, "%c", prp[ii]);
+							else
+								fprintf(fp, ".");
+							ii++;
+						}
+						fprintf(fp, "\n");
+					}
+				} 
+			}
+		}
+
+		if (CRASHDEBUG(1))
+			if ((pp % (1024*1024)) == 0)
+				console("%lx\n", pp);
+
+		pp += PAGESIZE();
+	}
+}
+
 #define SEARCHMASK(X) ((X) | mask) 
 
 static void
