Blob Blame History Raw
--- crash/memory.c.orig	2005-02-09 16:13:25.000000000 -0500
+++ crash/memory.c	2005-01-06 14:56:46.000000000 -0500
@@ -88,7 +88,9 @@
 static void kmem_search(struct meminfo *);
 static void kmem_cache_init(void);
 static ulong max_cpudata_limit(ulong, ulong *);
+static int ignore_cache(struct meminfo *, char *);
 static char *is_kmem_cache_addr(ulong, char *);
+static void kmem_cache_list(void);
 static void dump_kmem_cache(struct meminfo *);
 static void dump_kmem_cache_percpu_v1(struct meminfo *);
 static void dump_kmem_cache_percpu_v2(struct meminfo *);
@@ -104,6 +106,8 @@
 static void dump_slab(struct meminfo *);
 static void dump_slab_percpu_v1(struct meminfo *);
 static void dump_slab_percpu_v2(struct meminfo *);
+static int verify_slab_v1(struct meminfo *, ulong, int);
+static int verify_slab_v2(struct meminfo *, ulong, int);
 static void gather_slab_free_list(struct meminfo *);
 static void gather_slab_free_list_percpu(struct meminfo *);
 static void gather_cpudata_list_v1(struct meminfo *);
@@ -3321,7 +3325,10 @@
                 if (vt->flags & KMEM_CACHE_UNAVAIL)
                      	error(FATAL, 
 			    "kmem cache slab subsystem not available\n");
-		vt->dump_kmem_cache(&meminfo);
+		if (STREQ(meminfo.reqname, "list"))
+			kmem_cache_list();
+		else
+			vt->dump_kmem_cache(&meminfo);
 	}
 
 	if (Sflag == 1) {
@@ -3329,7 +3336,10 @@
                      	error(FATAL, 
 			    "kmem cache slab subsystem not available\n");
 		meminfo.flags = VERBOSE;
-		vt->dump_kmem_cache(&meminfo);
+		if (STREQ(meminfo.reqname, "list"))
+			kmem_cache_list();
+		else
+			vt->dump_kmem_cache(&meminfo);
 	}
 
 	if (vflag == 1)
@@ -5967,6 +5977,66 @@
 }
 
 /*
+ *  Note same functionality as above, but instead it just
+ *  dumps all slab cache names and their addresses.
+ */
+static void
+kmem_cache_list(void)
+{
+        ulong cache, cache_cache, name;
+	long next_offset, name_offset;
+	char *cache_buf;
+	char buf[BUFSIZE];
+
+	if (vt->flags & KMEM_CACHE_UNAVAIL) {
+		error(INFO, "kmem cache slab subsystem not available\n");
+		return;
+	}
+
+        name_offset = vt->flags & (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2) ?
+                OFFSET(kmem_cache_s_name) : OFFSET(kmem_cache_s_c_name);
+        next_offset = vt->flags & (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2) ?
+                OFFSET(kmem_cache_s_next) : OFFSET(kmem_cache_s_c_nextp);
+
+        cache = cache_cache = symbol_value("cache_cache");
+
+	cache_buf = GETBUF(SIZE(kmem_cache_s));
+
+        do {
+	        readmem(cache, KVADDR, cache_buf, SIZE(kmem_cache_s),
+	        	"kmem_cache_s buffer", FAULT_ON_ERROR);
+
+	        if (vt->kmem_cache_namelen) {
+			BCOPY(cache_buf+name_offset, buf, 
+				vt->kmem_cache_namelen);
+	        } else {
+			name = ULONG(cache_buf + name_offset);
+	                if (!read_string(name, buf, BUFSIZE-1)) {
+				if (vt->flags & 
+				    (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2))
+	                               	error(FATAL,
+	                      "cannot read kmem_cache_s.name string at %lx\n",
+	                                       	name);
+				else
+	                               	error(FATAL,
+	                      "cannot read kmem_cache_s.c_name string at %lx\n",
+	                                       	name);
+			}
+	        }
+
+		fprintf(fp, "%lx %s\n", cache, buf);
+
+		cache = ULONG(cache_buf + next_offset);
+
+		if (vt->flags & (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2))
+			cache -= next_offset;
+
+        } while (cache != cache_cache);
+
+	FREEBUF(cache_buf);
+}
+
+/*
  *  Translate an address to its physical page number, verify that the
  *  page in fact belongs to the slab subsystem, and if so, return the 
  *  name of the cache to which it belongs.
@@ -6040,11 +6110,14 @@
                 readmem(page+OFFSET(page_prev),
                         KVADDR, &slab, sizeof(void *),
                         "page.prev", FAULT_ON_ERROR);
-
         else if (VALID_MEMBER(page_list_prev))
                 readmem(page+OFFSET(page_list_prev),
                         KVADDR, &slab, sizeof(void *),
                         "page.list.prev", FAULT_ON_ERROR);
+	else if (VALID_MEMBER(page_lru))
+                readmem(page+OFFSET(page_lru)+OFFSET(list_head_prev),
+                        KVADDR, &slab, sizeof(void *),
+                        "page.lru.prev", FAULT_ON_ERROR);
         else
                 error(FATAL, "unknown definition of struct page?\n");
 
@@ -6231,6 +6304,41 @@
 	return max_limit;
 }
 
+/*
+ *  Determine whether the current slab cache is contained in
+ *  the comma-separated list from a "kmem -I list1,list2 ..."
+ *  command entry.
+ */
+static int
+ignore_cache(struct meminfo *si, char *name)
+{
+	int i, argc;
+	char *p1;
+	char *arglist[MAXARGS];
+	char buf[BUFSIZE];
+
+	if (!si->ignore)
+		return FALSE;
+
+	strcpy(buf, si->ignore);
+
+	p1 = buf;
+	while (*p1) {
+		if (*p1 == ',')
+			*p1 = ' ';
+		p1++;
+	}
+
+	argc = parse_line(buf, arglist);
+
+	for (i = 0; i < argc; i++) {
+		if (STREQ(name, arglist[i]))
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
 
 /*
  *  dump_kmem_cache() displays basic information about kmalloc() slabs.
@@ -6390,8 +6498,8 @@
 		if (reqname && !STREQ(reqname, buf)) 
 			goto next_cache;
 
-		if (STREQ(si->ignore, buf)) {
-			fprintf(fp, "%lx  %-19s [IGNORED]\n", si->cache, buf);
+		if (ignore_cache(si, buf)) {
+			fprintf(fp, "%lx %-18s [IGNORED]\n", si->cache, buf);
 			goto next_cache;
 		}
 
@@ -6588,16 +6696,13 @@
 		if (reqname && !STREQ(reqname, buf)) 
 			goto next_cache;
 
-                if (STREQ(si->ignore, buf)) {
-                        fprintf(fp, "%lx  %-19s [IGNORED]\n", si->cache, buf);
+                if (ignore_cache(si, buf)) {
+                        fprintf(fp, "%lx %-18s [IGNORED]\n", si->cache, buf);
                         goto next_cache;
                 }
 
 		si->curname = buf;
 
-		if (CRASHDEBUG(1))
-			fprintf(fp, "cache: %lx %s\n", si->cache, si->curname);
-
 	        readmem(si->cache+OFFSET(kmem_cache_s_objsize),
 	        	KVADDR, &tmp_val, sizeof(uint),
 	                "objsize", FAULT_ON_ERROR);
@@ -6804,16 +6909,13 @@
 		if (reqname && !STREQ(reqname, buf)) 
 			goto next_cache;
 
-                if (STREQ(si->ignore, buf)) {
-                        fprintf(fp, "%lx  %-19s [IGNORED]\n", si->cache, buf);
+                if (ignore_cache(si, buf)) {
+                        fprintf(fp, "%lx %-18s [IGNORED]\n", si->cache, buf);
                         goto next_cache;
                 }
 
 		si->curname = buf;
 
-		if (CRASHDEBUG(3))
-			fprintf(fp, "cache: %lx %s\n", si->cache, si->curname);
-
 	        readmem(si->cache+OFFSET(kmem_cache_s_objsize),
 	        	KVADDR, &tmp_val, sizeof(uint),
 	                "objsize", FAULT_ON_ERROR);
@@ -6883,7 +6985,7 @@
 				case KMEM_SLAB_ADDR:
 					fprintf(fp, "   %lx ", 
 						(ulong)si->spec_addr);
-					fprintf(fp, "(slab_s)\n");
+					fprintf(fp, "(slab)\n");
 					break;
 
 				case KMEM_ON_SLAB:
@@ -7073,6 +7175,8 @@
 
 #define SLAB_CHAINS (3)
 
+static char *slab_chain_name_v1[] = {"full", "partial", "free"};
+
 static void
 do_slab_chain_percpu_v1(long cmd, struct meminfo *si)
 {
@@ -7080,6 +7184,7 @@
 	int list_borked;
 	char *slab_s_buf;
 	ulong specified_slab;
+	ulong last;
 	ulong slab_chains[SLAB_CHAINS];
 
 	list_borked = 0;
@@ -7096,6 +7201,12 @@
 		slab_chains[2] = si->cache + OFFSET(kmem_cache_s_slabs_free);
 	}
 
+	if (CRASHDEBUG(1)) {
+		fprintf(fp, "[ %s: %lx ", si->curname, si->cache);
+		fprintf(fp, "full: %lx partial: %lx free: %lx ]\n",
+			slab_chains[0], slab_chains[1], slab_chains[2]);
+	}
+
 	switch (cmd)
 	{
 	case SLAB_GET_COUNTS:
@@ -7112,9 +7223,16 @@
 			if (!slab_chains[s])
 				continue;
 
-	                readmem(slab_chains[s],
-	                        KVADDR, &si->slab, sizeof(ulong),
-	                        "first slab", FAULT_ON_ERROR);
+	                if (!readmem(slab_chains[s],
+	                    KVADDR, &si->slab, sizeof(ulong),
+	                    "first slab", QUIET|RETURN_ON_ERROR)) {
+                		error(INFO, 
+				    "%s: %s list: bad slab pointer: %lx\n",
+                        		si->curname, slab_chain_name_v1[s],
+					slab_chains[s]);
+				list_borked = 1;
+				continue;
+			}
 	
 			if (slab_data_saved(si)) {
 				FREEBUF(slab_s_buf);
@@ -7124,11 +7242,19 @@
 			if (si->slab == slab_chains[s]) 
 				continue;
 	
+			last = slab_chains[s];
+
 			do {
 	                        if (received_SIGINT()) {
 					FREEBUF(slab_s_buf);
 	                                restart(0);
 				}
+
+				if (!verify_slab_v1(si, last, s)) {
+					list_borked = 1;
+					continue;
+				}
+				last = si->slab - OFFSET(slab_s_list);
 	
 		                readmem(si->slab, KVADDR, slab_s_buf, 
 					SIZE(slab_s), "slab_s buffer", 
@@ -7159,9 +7285,7 @@
        						error(NOTE, 
 	  	                      "%s: slab chain inconsistency: %s list\n",
 							si->curname,
-						    	s == 0 ?  "full" :
-						    	s == 1 ? "partial" : 
-							"free");
+							slab_chain_name_v1[s]);
        						list_borked = 1;
      					}
 				}
@@ -7170,7 +7294,8 @@
 		}
 
 		FREEBUF(slab_s_buf);
-		save_slab_data(si);
+		if (!list_borked)
+			save_slab_data(si);
 		break;
 
 	case SLAB_WALKTHROUGH:
@@ -7183,14 +7308,24 @@
 				continue;
 
 	        	if (!specified_slab) {
-	                	readmem(slab_chains[s],
-	                        	KVADDR, &si->slab, sizeof(ulong),
-	                        	"slabs", FAULT_ON_ERROR);
-			}
+	                	if (!readmem(slab_chains[s],
+	                            KVADDR, &si->slab, sizeof(ulong),
+	                            "slabs", QUIET|RETURN_ON_ERROR)) {
+                			error(INFO, 
+				         "%s: %s list: bad slab pointer: %lx\n",
+                        			si->curname, 
+						slab_chain_name_v1[s],
+						slab_chains[s]);
+					list_borked = 1;
+					continue;
+				}
+				last = slab_chains[s];
+			} else
+				last = 0;
 	
 			if (si->slab == slab_chains[s])
 				continue;
-	
+
 			if (CRASHDEBUG(1)) {
 				fprintf(fp, "search cache: [%s] ", si->curname);
 				if (si->flags & ADDRESS_SPECIFIED) 
@@ -7201,6 +7336,12 @@
 		        do {
 	                        if (received_SIGINT())
 	                                restart(0);
+
+				if (!verify_slab_v1(si, last, s)) {
+					list_borked = 1;
+					continue;
+				}
+				last = si->slab - OFFSET(slab_s_list);
 	
 		                dump_slab_percpu_v1(si);
 		
@@ -7214,7 +7355,7 @@
 		
 				si->slab -= OFFSET(slab_s_list);
 	
-		        } while (si->slab != slab_chains[s]);
+		        } while (si->slab != slab_chains[s] && !list_borked);
 		}
 
 		break;
@@ -7222,8 +7363,94 @@
 }
 
 /*
+ *  Try to preclude any attempt to translate a bogus slab structure.
+ */
+
+static int
+verify_slab_v1(struct meminfo *si, ulong last, int s)
+{
+	char slab_s_buf[BUFSIZE];
+	struct kernel_list_head *list_head;
+	unsigned int inuse;
+	ulong s_mem;
+	char *list;
+	int errcnt;
+
+	list = slab_chain_name_v1[s];
+
+	errcnt = 0;
+
+        if (!readmem(si->slab, KVADDR, slab_s_buf,
+            SIZE(slab_s), "slab_s buffer", QUIET|RETURN_ON_ERROR)) {
+                error(INFO, "%s: %s list: bad slab pointer: %lx\n",
+                        si->curname, list, si->slab);
+		return FALSE;
+        }                        
+
+        list_head = (struct kernel_list_head *)
+		(slab_s_buf + OFFSET(slab_s_list));
+
+	if (!IS_KVADDR((ulong)list_head->next) || 
+	    !accessible((ulong)list_head->next)) {
+                error(INFO, "%s: %s list: slab: %lx  bad next pointer: %lx\n",
+                        si->curname, list, si->slab,
+			(ulong)list_head->next);
+		errcnt++;
+	}
+
+	if (last && (last != (ulong)list_head->prev)) {
+                error(INFO, "%s: %s list: slab: %lx  bad prev pointer: %lx\n",
+                        si->curname, list, si->slab,
+                        (ulong)list_head->prev);
+		errcnt++;
+	}
+
+	inuse = UINT(slab_s_buf + OFFSET(slab_s_inuse));
+	if (inuse > si->c_num) {
+                error(INFO, "%s: %s list: slab: %lx  bad inuse counter: %ld\n",
+                        si->curname, list, si->slab, inuse);
+		errcnt++;
+	}
+	switch (s) 
+	{
+	case 0: /* full -- or one singular list, so we can't test this */
+		break;
+
+	case 1: /* partial */
+		if ((inuse == 0) || (inuse == si->c_num)) {
+                	error(INFO, 
+		 	    "%s: %s list: slab: %lx  bad inuse counter: %ld\n",
+                        	si->curname,  list, si->slab, inuse);
+			errcnt++;
+		}
+		break;
+
+	case 2: /* free */
+		if (inuse > 0) {
+                	error(INFO, 
+		 	    "%s: %s list: slab: %lx  bad inuse counter: %ld\n",
+                        	si->curname, list, si->slab, inuse);
+			errcnt++;
+		}
+		break;
+	}
+
+	s_mem = ULONG(slab_s_buf + OFFSET(slab_s_s_mem));
+	if (!IS_KVADDR(s_mem) || !accessible(s_mem)) {
+                error(INFO, "%s: %s list: slab: %lx  bad s_mem pointer: %lx\n",
+                        si->curname, list, si->slab, s_mem);
+		errcnt++;
+	}
+
+	return(errcnt ? FALSE : TRUE);
+}
+
+/*
  *  Updated for 2.6 slab substructure.
  */
+
+static char *slab_chain_name_v2[] = {"partial", "full", "free"};
+
 static void
 do_slab_chain_percpu_v2(long cmd, struct meminfo *si)
 {
@@ -7231,6 +7458,7 @@
 	int list_borked;
 	char *slab_buf;
 	ulong specified_slab;
+	ulong last;
 	ulong slab_chains[SLAB_CHAINS];
 
 	list_borked = 0;
@@ -7244,6 +7472,12 @@
         slab_chains[2] = si->cache + OFFSET(kmem_cache_s_lists) +
                 OFFSET(kmem_list3_slabs_free);
 
+        if (CRASHDEBUG(1)) {
+                fprintf(fp, "[ %s: %lx ", si->curname, si->cache);
+                fprintf(fp, "partial: %lx full: %lx free: %lx ]\n",
+                        slab_chains[0], slab_chains[1], slab_chains[2]);
+        }
+
 	switch (cmd)
 	{
 	case SLAB_GET_COUNTS:
@@ -7259,9 +7493,17 @@
 			if (!slab_chains[s])
 				continue;
 
-	                readmem(slab_chains[s],
-	                        KVADDR, &si->slab, sizeof(ulong),
-	                        "first slab", FAULT_ON_ERROR);
+	                if (!readmem(slab_chains[s],
+	                    KVADDR, &si->slab, sizeof(ulong),
+	                    "first slab", QUIET|RETURN_ON_ERROR)) {
+                                error(INFO, 
+				    "%s: %s list: bad slab pointer: %lx\n",
+                                        si->curname,
+					slab_chain_name_v2[s],
+                                        slab_chains[s]);
+				list_borked = 1;
+				continue;
+			}
 	
 			if (slab_data_saved(si)) {
 				FREEBUF(slab_buf);
@@ -7271,11 +7513,19 @@
 			if (si->slab == slab_chains[s]) 
 				continue;
 	
+			last = slab_chains[s];
+
 			do {
 	                        if (received_SIGINT()) {
 					FREEBUF(slab_buf);
 	                                restart(0);
 				}
+
+				if (!verify_slab_v2(si, last, s)) {
+					list_borked = 1;
+					continue;
+				}
+				last = si->slab - OFFSET(slab_list);
 	
 		                readmem(si->slab, KVADDR, slab_buf, 
 					SIZE(slab), "slab buffer", 
@@ -7306,9 +7556,7 @@
        						error(NOTE, 
 	  	                      "%s: slab chain inconsistency: %s list\n",
 							si->curname,
-						    	s == 0 ?  "full" :
-						    	s == 1 ? "partial" : 
-							"free");
+							slab_chain_name_v2[s]);
        						list_borked = 1;
      					}
 				}
@@ -7317,7 +7565,8 @@
 		}
 
 		FREEBUF(slab_buf);
-		save_slab_data(si);
+		if (!list_borked)
+			save_slab_data(si);
 		break;
 
 	case SLAB_WALKTHROUGH:
@@ -7330,11 +7579,21 @@
 				continue;
 
 	        	if (!specified_slab) {
-	                	readmem(slab_chains[s],
-	                        	KVADDR, &si->slab, sizeof(ulong),
-	                        	"slabs", FAULT_ON_ERROR);
-			}
-	
+	                	if (!readmem(slab_chains[s],
+	                            KVADDR, &si->slab, sizeof(ulong),
+	                            "slabs", QUIET|RETURN_ON_ERROR)) {
+                                        error(INFO,
+                                         "%s: %s list: bad slab pointer: %lx\n",
+                                                si->curname,
+						slab_chain_name_v2[s],
+                                                slab_chains[s]);
+					list_borked = 1;
+					continue;
+				}
+				last = slab_chains[s];
+			} else
+				last = 0;
+			
 			if (si->slab == slab_chains[s])
 				continue;
 	
@@ -7349,6 +7608,12 @@
 	                        if (received_SIGINT())
 	                                restart(0);
 	
+                                if (!verify_slab_v2(si, last, s)) {
+                                        list_borked = 1;
+                                        continue;
+                                }
+                                last = si->slab - OFFSET(slab_list);
+
 		                dump_slab_percpu_v2(si);
 		
 		                if (si->found) {
@@ -7361,13 +7626,98 @@
 		
 				si->slab -= OFFSET(slab_list);
 	
-		        } while (si->slab != slab_chains[s]);
+		        } while (si->slab != slab_chains[s] && !list_borked);
 		}
 
 		break;
 	}
 }
 
+/*
+ *  Try to preclude any attempt to translate a bogus slab structure.
+ */
+static int
+verify_slab_v2(struct meminfo *si, ulong last, int s)
+{
+	char slab_buf[BUFSIZE];
+	struct kernel_list_head *list_head;
+	unsigned int inuse;
+	ulong s_mem;
+	char *list;
+	int errcnt;
+
+	list = slab_chain_name_v2[s];
+
+	errcnt = 0;
+
+        if (!readmem(si->slab, KVADDR, slab_buf,
+            SIZE(slab), "slab buffer", QUIET|RETURN_ON_ERROR)) {
+                error(INFO, "%s: %s list: bad slab pointer: %lx\n",
+                        si->curname, list, si->slab);
+		return FALSE;
+        }                        
+
+        list_head = (struct kernel_list_head *)(slab_buf + OFFSET(slab_list));
+	if (!IS_KVADDR((ulong)list_head->next) || 
+	    !accessible((ulong)list_head->next)) {
+                error(INFO, "%s: %s list: slab: %lx  bad next pointer: %lx\n",
+                        si->curname, list, si->slab,
+			(ulong)list_head->next);
+		errcnt++;
+	}
+
+	if (last && (last != (ulong)list_head->prev)) {
+                error(INFO, "%s: %s list: slab: %lx  bad prev pointer: %lx\n",
+                        si->curname, list, si->slab,
+                        (ulong)list_head->prev);
+		errcnt++;
+	}
+
+	inuse = UINT(slab_buf + OFFSET(slab_inuse));
+	if (inuse > si->c_num) {
+                error(INFO, "%s: %s list: slab: %lx  bad inuse counter: %ld\n",
+                        si->curname, list, si->slab, inuse);
+		errcnt++;
+	}
+	switch (s) 
+	{
+	case 0: /* partial */
+                if ((inuse == 0) || (inuse == si->c_num)) {
+                	error(INFO, 
+		 	    "%s: %s list: slab: %lx  bad inuse counter: %ld\n",
+                        	si->curname, list, si->slab, inuse);
+			errcnt++;
+		}
+		break;
+
+	case 1: /* full */
+		if (inuse != si->c_num) {
+                	error(INFO, 
+		 	    "%s: %s list: slab: %lx  bad inuse counter: %ld\n",
+                        	si->curname, list, si->slab, inuse);
+			errcnt++;
+		}
+		break;
+
+	case 2: /* free */
+		if (inuse > 0) {
+                	error(INFO, 
+		 	    "%s: %s list: slab: %lx  bad inuse counter: %ld\n",
+                        	si->curname, list, si->slab, inuse);
+			errcnt++;
+		}
+		break;
+	}
+
+	s_mem = ULONG(slab_buf + OFFSET(slab_s_mem));
+	if (!IS_KVADDR(s_mem) || !accessible(s_mem)) {
+                error(INFO, "%s: %s list: slab: %lx  bad s_mem pointer: %lx\n",
+                        si->curname, list, si->slab, s_mem);
+		errcnt++;
+	}
+
+	return(errcnt ? FALSE : TRUE);
+}
 
 /*
  *  If it's a dumpfile, save the essential slab data to avoid re-reading 
@@ -7579,7 +7929,7 @@
                 if (INSLAB_PERCPU(si->slab, si) && 
 		    (si->spec_addr >= si->slab) &&
                     (si->spec_addr < (si->slab+tmp))) {
-			if (si->spec_addr >= (si->slab + SIZE(slab_s)))
+			if (si->spec_addr >= (si->slab + SIZE(slab)))
 				si->found = KMEM_BUFCTL_ADDR;
 			else
                 		si->found = KMEM_SLAB_ADDR;
--- crash/help.c.orig	2005-02-09 16:13:25.000000000 -0500
+++ crash/help.c	2005-01-28 15:26:13.000000000 -0500
@@ -3578,8 +3578,9 @@
 "       -li  walks through the inactive_list and verifies nr_inactive_pages.",
 "       -La  same as -la, but also dumps each page in the active_list.",
 "       -Li  same as -li, but also dumps each page in the inactive_list.",
-" slab-name  when used with -s or -S, limits the command to only the slab",
-"            of name \"slab-cache\".",
+" slab-name  when used with -s or -S, limits the command to only the slab cache",
+"            of name \"slab-name\".  If the slab-name argument is \"list\", then",
+"            all slab cache names and addresses are listed.",
 "        -P  declares that the following address argument is a physical address.",
 "   address  when used without any flag, the address can be a kernel virtual,",
 "            or physical address; a search is made through the symbol table,",
@@ -5257,8 +5258,8 @@
 " ",
 "  These are the current prerequisites: ",
 "",
-"  o  At this point, x86, ia64, x86_64, alpha and ppc-based kernels are ",
-"     supported.  Other architectures will be addressed in the future.",
+"  o  At this point, x86, ia64, x86_64, alpha and ppc64-based kernels are ",
+"     supported.  Other architectures may be addressed in the future.",
 "",
 "  o  One size fits all -- the utility can be run on any Linux kernel version ",
 "     from 2.2.5-15 through 2.6.*.",
--- crash/task.c.orig	2005-02-09 16:13:25.000000000 -0500
+++ crash/task.c	2005-01-28 15:26:13.000000000 -0500
@@ -2842,6 +2842,10 @@
 			fprintf(fp, "(HARDWARE RESET)");
 		else if (machdep->flags & SYSRQ)
 			fprintf(fp, "(SYSRQ)");
+		else if (machdep->flags & INIT)
+			fprintf(fp, "(INIT)");
+		else if (kt->cpu_flags[tc->processor] & NMI)
+			fprintf(fp, "(NMI)");
 		else if (tc->task == tt->panic_task)
 			fprintf(fp, "(PANIC)");
 		else
--- crash/kernel.c.orig	2005-02-09 16:13:25.000000000 -0500
+++ crash/kernel.c	2005-01-28 15:26:13.000000000 -0500
@@ -3252,6 +3252,9 @@
 	for (i = 0; i < NR_CPUS; i++) 
 		fprintf(fp, "%s%.*lx ", (i % 4) == 0 ? "\n    " : "",
 			LONG_PRLEN, kt->__per_cpu_offset[i]);
+	fprintf(fp, "\n cpu_flags[NR_CPUS]:");
+	for (i = 0; i < NR_CPUS; i++) 
+		fprintf(fp, "%lx ", kt->cpu_flags[i]);
 	fprintf(fp, "\n");
 }
 
--- crash/ia64.c.orig	2005-02-09 16:13:25.000000000 -0500
+++ crash/ia64.c	2005-02-09 16:12:05.000000000 -0500
@@ -56,6 +56,7 @@
 static struct line_number_hook ia64_line_number_hooks[];
 static ulong ia64_get_stackbase(ulong);
 static ulong ia64_get_stacktop(ulong);
+static void parse_cmdline_arg(void);
 
 struct unw_frame_info;
 static void dump_unw_frame_info(struct unw_frame_info *);
@@ -112,12 +113,11 @@
                 machdep->last_ptbl_read = 0;
 		machdep->verify_paddr = ia64_verify_paddr;
 		machdep->ptrs_per_pgd = PTRS_PER_PGD;
-                if (machdep->cmdline_arg)
-                        machdep->machspec->phys_start =
-                            htol(machdep->cmdline_arg, RETURN_ON_ERROR, NULL);
-                else
-                        machdep->machspec->phys_start = UNKNOWN_PHYS_START;
-		machdep->flags |= DEVMEMRD;
+                machdep->machspec->phys_start = UNKNOWN_PHYS_START;
+                if (machdep->cmdline_arg) 
+			parse_cmdline_arg();
+		if (ACTIVE())
+			machdep->flags |= DEVMEMRD;
                 break;     
 
         case PRE_GDB:
@@ -218,6 +218,108 @@
 	}
 }
 
+/*
+ *  --machdep <addr> defaults to the physical start location.
+ *
+ *  Otherwise, it's got to be a "item=value" string, separated
+ *  by commas if more than one is passed in.
+ */
+
+void
+parse_cmdline_arg(void)
+{
+	int i, c, errflag;
+	char *p;
+	char buf[BUFSIZE];
+	char *arglist[MAXARGS];
+	ulong value;
+        struct machine_specific *ms;
+
+        ms = &ia64_machine_specific;
+
+	if (!strstr(machdep->cmdline_arg, "=")) {
+		errflag = 0;
+        	value = htol(machdep->cmdline_arg,
+                	RETURN_ON_ERROR|QUIET, &errflag);
+		if (!errflag) {
+        		ms->phys_start = value;
+			error(NOTE, "setting phys_start to: 0x%lx\n",
+				ms->phys_start);
+		} else
+			error(WARNING, "ignoring --machdep option: %s\n\n",
+				machdep->cmdline_arg);
+		return;
+        }
+
+	strcpy(buf, machdep->cmdline_arg);
+
+	for (p = buf; *p; p++) {
+		if (*p == ',')
+			 *p = ' ';
+	}
+
+	c = parse_line(buf, arglist);
+
+	for (i = 0; i < c; i++) {
+		errflag = 0;
+
+		if (STRNEQ(arglist[i], "phys_start=")) {
+			p = arglist[i] + strlen("phys_start=");
+			if (strlen(p)) {
+        			value = htol(p, RETURN_ON_ERROR|QUIET, 
+					&errflag);
+				if (!errflag) {
+        				ms->phys_start = value;
+					error(NOTE, 
+					    "setting phys_start to: 0x%lx\n",
+						ms->phys_start);
+					continue;
+				}
+			}
+		} else if (STRNEQ(arglist[i], "init_stack_size=")) {
+			p = arglist[i] + strlen("init_stack_size=");
+			if (strlen(p)) {
+				value = stol(p, RETURN_ON_ERROR|QUIET, 
+					&errflag);
+				if (!errflag) {
+					ms->ia64_init_stack_size = (int)value;
+					error(NOTE, 
+		    	    	      "setting init_stack_size to: 0x%x (%d)\n",
+				    		ms->ia64_init_stack_size,
+				    		ms->ia64_init_stack_size);
+					continue;
+				}
+			}
+		}
+
+		error(WARNING, "ignoring --machdep option: %s\n", arglist[i]);
+	} 
+
+	if (c)
+		fprintf(fp, "\n");
+}
+
+
+int
+ia64_in_init_stack(ulong addr)
+{
+	ulong init_stack_addr;
+
+	if (!symbol_exists("ia64_init_stack"))
+		return FALSE;
+
+	/* 
+	 *  ia64_init_stack could be aliased to region 5 
+	 */
+	init_stack_addr = ia64_VTOP(symbol_value("ia64_init_stack"));
+	addr = ia64_VTOP(addr);
+	if ((addr < init_stack_addr) ||
+	    (addr >= (init_stack_addr+machdep->machspec->ia64_init_stack_size)))
+		return FALSE;
+
+	return TRUE;
+}
+
 void
 ia64_dump_machdep_table(ulong arg)
 {
@@ -309,6 +411,8 @@
 		fprintf(fp, "%sSYSRQ", others++ ? "|" : "");
 	if (machdep->flags & DEVMEMRD)
 		fprintf(fp, "%sDEVMEMRD", others++ ? "|" : "");
+	if (machdep->flags & INIT)
+		fprintf(fp, "%sINIT", others++ ? "|" : "");
         fprintf(fp, ")\n");
         fprintf(fp, "             kvbase: %lx\n", machdep->kvbase);
 	fprintf(fp, "  identity_map_base: %lx\n", machdep->identity_map_base);
@@ -446,6 +550,9 @@
         else
                 fprintf(fp, "%lx\n", (ulong)ms->unwind_debug);
 
+	fprintf(fp, "               ia64_init_stack_size: %d\n", 
+		ms->ia64_init_stack_size);
+
 	if (verbose)
 		ia64_display_memmap();
 }
@@ -1077,9 +1184,9 @@
 {
         char buf1[BUFSIZE];
         char buf2[BUFSIZE];
-        char *colon, *p1;
+        char *colon, *p1, *p2;
         int argc;
-	int revise, stop_bit;
+	int revise_bracket, stop_bit;
         char *argv[MAXARGS];
         ulong value;
 
@@ -1105,25 +1212,24 @@
         strcpy(buf1, inbuf);
         argc = parse_line(buf1, argv);
 
-	revise = stop_bit = 0;
+	revise_bracket = stop_bit = 0;
 	if ((FIRSTCHAR(argv[argc-1]) == '<') &&
             (LASTCHAR(argv[argc-1]) == '>')) {
-		revise = TRUE;
+		revise_bracket = TRUE;
 		stop_bit = FALSE;
 	} else if ((FIRSTCHAR(argv[argc-1]) == '<') &&
             strstr(argv[argc-1], ">;;")) {
-		revise = TRUE;
+		revise_bracket = TRUE;
 		stop_bit = TRUE;
 	}
 
-        if (revise) {
+        if (revise_bracket) {
                 p1 = rindex(inbuf, '<');
-                while ((p1 > inbuf) && !STRNEQ(p1, " 0x"))
+                while ((p1 > inbuf) && !STRNEQ(p1, "0x"))
                         p1--;
 
-                if (!STRNEQ(p1, " 0x"))
+                if (!STRNEQ(p1, "0x"))
                         return FALSE;
-                p1++;
 
                 if (!extract_hex(p1, &value, NULLCHAR, TRUE))
                         return FALSE;
@@ -1133,10 +1239,46 @@
 			stop_bit ? ";;" : "");
 
                 sprintf(p1, "%s", buf1);
-        }
 
-        console("    %s", inbuf);
+        } else if (STRNEQ(argv[argc-2], "br.call.") &&
+		 STRNEQ(argv[argc-1], "b0=0x")) {
+		/*  
+		 *  Update module function calls of these formats:
+	 	 *
+		 *     br.call.sptk.many b0=0xa0000000003d5e40;;
+		 *     br.call.sptk.many b0=0xa00000000001dfc0
+		 *
+		 *  to show a bracketed function name if the destination
+		 *  address is a known symbol with no offset.
+		 */
+		if ((p1 = strstr(argv[argc-1], ";;")) &&
+		    (p2 = strstr(inbuf, ";;\n"))) {
+			*p1 = NULLCHAR;
+			p1 = &argv[argc-1][3];
+
+                	if (extract_hex(p1, &value, NULLCHAR, TRUE)) {
+				sprintf(buf1, " <%s>;;\n",
+					value_to_symstr(value, buf2, 
+					pc->output_radix));
+				if (IS_MODULE_VADDR(value) &&
+				    !strstr(buf2, "+"))
+					sprintf(p2, buf1);
+			} 
+		} else {
+			p1 = &argv[argc-1][3];
+			p2 = &LASTCHAR(inbuf);
+                	if (extract_hex(p1, &value, '\n', TRUE)) {
+				sprintf(buf1, " <%s>\n",
+					value_to_symstr(value, buf2, 
+					pc->output_radix));
+				if (IS_MODULE_VADDR(value) &&
+				    !strstr(buf2, "+"))
+					sprintf(p2, buf1);
+			}
+		}
+	}
 
+        console("    %s", inbuf);
 
 	return TRUE;
 }
@@ -2540,6 +2682,13 @@
 	                                "unimpl_pa_mask", FAULT_ON_ERROR);
 		}
 	}
+
+        if (symbol_exists("ia64_init_stack") && !ms->ia64_init_stack_size) 
+		ms->ia64_init_stack_size = get_array_length("ia64_init_stack", 
+			NULL, 0);
+
+	if (DUMPFILE() && ia64_in_init_stack(SWITCH_STACK_ADDR(CURRENT_TASK())))
+		machdep->flags |= INIT;
 }
 
 /*
--- crash/x86_64.c.orig	2005-02-09 16:13:25.000000000 -0500
+++ crash/x86_64.c	2005-01-28 15:26:13.000000000 -0500
@@ -64,6 +64,7 @@
 static void x86_64_init_kernel_pgd(void);
 static void x86_64_cpu_pda_init(void);
 static void x86_64_ist_init(void);
+static void x86_64_post_init(void);
 
 
 struct machine_specific x86_64_machine_specific = { 0 };
@@ -172,6 +173,7 @@
 		break;
 
 	case POST_INIT:
+		x86_64_post_init();
 		break;
 	}
 }
@@ -482,6 +484,55 @@
 	}
 }
 
+static void 
+x86_64_post_init(void)
+{ 
+        int c, i, clues;
+        struct machine_specific *ms;
+	ulong *up;
+	struct syment *spt, *spc;
+	ulong offset;
+
+	/*
+	 *  Check whether each cpu was stopped by an NMI.
+	 */
+        ms = machdep->machspec;
+
+        for (c = 0; c < kt->cpus; c++) {
+                if (ms->stkinfo.ebase[c][NMI_STACK] == 0)
+                        break;
+
+                if (!readmem(ms->stkinfo.ebase[c][NMI_STACK], 
+		    KVADDR, ms->irqstack,
+		    ms->stkinfo.esize,
+                    "NMI exception stack contents", 
+		    RETURN_ON_ERROR|QUIET)) 
+			continue;
+
+       		for (i = clues = 0; i < (ms->stkinfo.esize)/sizeof(ulong); i++){
+                	up = (ulong *)(&ms->irqstack[i*sizeof(ulong)]);
+
+                	if (!is_kernel_text(*up) ||
+                            !(spt = value_search(*up, &offset)))
+				continue;
+
+			if (STREQ(spt->name, "try_crashdump") ||
+			    STREQ(spt->name, "die_nmi")) 
+				clues++;
+
+                    	if ((STREQ(spt->name, "nmi_watchdog_tick") ||
+                     	     STREQ(spt->name, "default_do_nmi"))) {
+                        	spc = x86_64_function_called_by((*up)-5);
+                        	if (spc && STREQ(spc->name, "die_nmi"))
+                                	clues += 2;
+			}
+		}
+
+		if (clues >= 2) 
+			kt->cpu_flags[c] |= NMI;
+        }
+}
+
 /*
  *  No x86_64 swapper_pg_dir; initialize the vt->kernel_pgd[NR_CPUS] array
  *  with the lazily-sync'd init_level4_pgt page address.  The level4 page
@@ -1128,7 +1179,8 @@
 		return BACKTRACE_ENTRY_DISPLAYED;
 	}
 
-	if (!offset && !(bt->flags & BT_EXCEPTION_FRAME)) { 
+	if (!offset && !(bt->flags & BT_EXCEPTION_FRAME) &&
+	    !(bt->flags & BT_START)) { 
 		if (STREQ(name, "child_rip")) {
 			if (symbol_exists("kernel_thread"))
 				name = "kernel_thread";
@@ -1164,6 +1216,8 @@
 
 	if (bt->flags & BT_EXCEPTION_FRAME)
 		rsp = bt->stkptr;
+	else if (bt->flags & BT_START)
+		rsp = bt->stkptr;
 	else
 		rsp = bt->stackbase + (stkindex * sizeof(long));
 
@@ -1320,6 +1374,10 @@
 	irq_eframe = 0;
 	bt->call_target = NULL;
 	rsp = bt->stkptr;
+	if (!rsp) {
+		error(INFO, "cannot determine starting stack pointer\n");
+		return;
+	}
 	ms = machdep->machspec;
 	if (BT_REFERENCE_CHECK(bt))
 		ofp = pc->nullfp;
@@ -1333,7 +1391,12 @@
 			STREQ(closest_symbol(bt->instptr), "thread_return") ?
 			" (schedule)" : "",
 			bt->instptr);
-        }
+        } else if (bt->flags & BT_START) {
+                x86_64_print_stack_entry(bt, ofp, level,
+                        0, bt->instptr);
+		bt->flags &= ~BT_START;
+		level++;
+	}
 
 
         if ((estack = x86_64_in_exception_stack(bt))) {
@@ -1403,7 +1466,8 @@
 			bt->stackbuf + (bt->stacktop - bt->stackbase) - 
 			SIZE(pt_regs), bt, ofp);
 
-		fprintf(fp, "--- <exception stack> ---\n");
+		if (!BT_REFERENCE_CHECK(bt))
+			fprintf(fp, "--- <exception stack> ---\n");
 
                 /* 
 		 *  stack = (unsigned long *) estack_end[-2]; 
@@ -1411,13 +1475,24 @@
 		up = (ulong *)(&bt->stackbuf[bt->stacktop - bt->stackbase]);
 		up -= 2;
 		rsp = bt->stkptr = *up;
-		up -= 5;
+		up -= 3;
 		bt->instptr = *up;  
 		if (cs & 3)
 			done = TRUE;   /* user-mode exception */
 		else
 			done = FALSE;  /* kernel-mode exception */
 		bt->frameptr = 0;
+
+		/*
+		 *  Print the return values from the estack end.
+		 */
+		if (!done) {
+                	bt->flags |= BT_START;
+                	x86_64_print_stack_entry(bt, ofp, level,
+                        	0, bt->instptr);
+                	bt->flags &= ~BT_START;
+			level++;
+		}
 	}
 
 	/*
@@ -1466,7 +1541,8 @@
                         }
                 }
 
-                fprintf(fp, "--- <IRQ stack> ---\n");
+		if (!BT_REFERENCE_CHECK(bt))
+                	fprintf(fp, "--- <IRQ stack> ---\n");
 
                 /*
 		 *  stack = (unsigned long *) (irqstack_end[-1]);
@@ -1950,6 +2026,7 @@
 	int panic_task;
         int i, panic, stage;
         char *sym;
+	struct syment *sp;
         ulong *up;
 	struct bt_info bt_local, *bt;
         struct machine_specific *ms;
@@ -1999,12 +2076,27 @@
                 if (STREQ(sym, "netconsole_netdump") || 
 		    STREQ(sym, "netpoll_start_netdump") ||
 		    STREQ(sym, "start_disk_dump") ||
-		    STREQ(sym, "disk_dump")) {
+		    STREQ(sym, "disk_dump") ||
+		    STREQ(sym, "try_crashdump")) {
                         *rip = *up;
                         *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf);
                         return;
                 }
 
+                if ((stage == 2) && 
+                    (STREQ(sym, "nmi_watchdog_tick") ||
+                     STREQ(sym, "default_do_nmi"))) {
+			sp = x86_64_function_called_by((*up)-5);
+			if (!sp || !STREQ(sp->name, "die_nmi")) 
+				continue;
+                        *rip = *up;
+                        *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf);
+			bt_in->flags |= BT_START;
+			*rip = symbol_value("die_nmi");
+			*rsp = (*rsp) - (7*sizeof(ulong));
+                        return;
+                }
+
                 if (STREQ(sym, "panic")) {
                         *rip = *up;
                         *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf);
@@ -2062,7 +2154,19 @@
 		stage = 1;
 		goto next_stack;
 
+        /*
+         *  Check the NMI exception stack.
+         */
 	case 1:
+		bt->stackbase = ms->stkinfo.ebase[bt->tc->processor][NMI_STACK];
+		bt->stacktop = ms->stkinfo.ebase[bt->tc->processor][NMI_STACK] +
+                       ms->stkinfo.esize;
+		bt->stackbuf = ms->irqstack;
+		alter_stackbuf(bt);
+		stage = 2;
+		goto next_stack;
+
+	case 2:
 		break;
 	}
 
--- crash/unwind.c.orig	2005-02-09 16:13:26.000000000 -0500
+++ crash/unwind.c	2005-02-07 16:02:44.000000000 -0500
@@ -31,6 +31,10 @@
  *  unwind_v[123].o object files.
  */
 
+/*
+ *  2004-09-14 J. Nomura    Added OS_INIT handling
+ */
+
 /* #include <asm/ptrace.h>  can't include this -- it's changing over time! */
 
 #include "defs.h"
@@ -56,6 +60,13 @@
 static void dump_unwind_table(struct unw_table *);
 static int unw_init_from_blocked_task(struct unw_frame_info *, 
 	struct bt_info *);
+static void unw_init_from_interruption(struct unw_frame_info *,
+	struct bt_info *, ulong, ulong);
+static int unw_switch_from_osinit_v1(struct unw_frame_info *,
+	struct bt_info *);
+static int unw_switch_from_osinit_v2(struct unw_frame_info *,
+	struct bt_info *);
+static unsigned long get_init_stack_ulong(unsigned long addr);
 static void unw_init_frame_info(struct unw_frame_info *, 
 	struct bt_info *, ulong);
 static int find_save_locs(struct unw_frame_info *);
@@ -406,8 +417,8 @@
 		else
 			*nat_addr &= ~nat_mask;
 	} else {
-		if ((GET_STACK_ULONG(nat_addr) & nat_mask) == 0) {
-			*val = GET_STACK_ULONG(addr);
+		if ((IA64_GET_STACK_ULONG(nat_addr) & nat_mask) == 0) {
+			*val = IA64_GET_STACK_ULONG(addr);
 			*nat = 0;
 		} else {
 			*val = 0;	/* if register is a NaT, *addr may contain kernel data! */
@@ -457,7 +468,7 @@
 	if (write)
 		*addr = *val;
 	else
-		*val = GET_STACK_ULONG(addr);
+		*val = IA64_GET_STACK_ULONG(addr);
 	return 0;
 }
 
@@ -695,7 +706,7 @@
 			*info->cfm_loc =
 				(*info->cfm_loc & ~(0x3fUL << 52)) | ((*val & 0x3f) << 52);
 		else
-			*val = (GET_STACK_ULONG(info->cfm_loc) >> 52) & 0x3f;
+			*val = (IA64_GET_STACK_ULONG(info->cfm_loc) >> 52) & 0x3f;
 		return 0;
 
 	      case UNW_AR_FPSR:
@@ -739,7 +750,7 @@
 	if (write)
 		*addr = *val;
 	else
-		*val = GET_STACK_ULONG(addr);
+		*val = IA64_GET_STACK_ULONG(addr);
 	return 0;
 }
 
@@ -764,7 +775,7 @@
 	if (write)
 		*addr = *val;
 	else
-		*val = GET_STACK_ULONG(addr);
+		*val = IA64_GET_STACK_ULONG(addr);
 	return 0;
 }
 
@@ -1644,6 +1655,7 @@
         frame = 0;
 
         do {
+restart:
                 unw_get_ip(info, &ip);
                 unw_get_sp(info, &sp);
                 unw_get_bsp(info, &bsp);
@@ -1695,6 +1707,26 @@
 		    STREQ(name, "start_kernel_thread"))
                         break;
 
+		/* 
+		 * "init_handler_platform" indicates that this task was
+		 * interrupted by INIT and its stack was switched. 
+		 */
+		if (STREQ(name, "init_handler_platform")) {
+			unw_switch_from_osinit_v1(info, bt);
+			frame++;
+			goto restart;
+		}
+
+		/*
+		 * In some cases, init_handler_platform is inlined into
+		 * ia64_init_handler.  
+		 */
+		if (STREQ(name, "ia64_init_handler")) {
+			unw_switch_from_osinit_v2(info, bt);
+			frame++;
+			goto restart;
+		}
+
                 frame++;
 
         } while (unw_unwind(info) >= 0);
@@ -1797,6 +1829,16 @@
 	dump_struct("unw_table", (ulong)table, RADIX(16));
 }
 
+static unsigned long 
+get_init_stack_ulong(unsigned long addr) 
+{
+        unsigned long tmp;
+
+        readmem(addr, KVADDR, &tmp, sizeof(unsigned long),
+                "get_init_stack_ulong", FAULT_ON_ERROR);
+
+        return tmp;
+}
 
 static int
 unw_init_from_blocked_task(struct unw_frame_info *info, struct bt_info *bt)
@@ -1804,13 +1846,129 @@
 	ulong sw;
 
 	sw = SWITCH_STACK_ADDR(bt->task);
-	if (!INSTACK(sw, bt))
+	if (!INSTACK(sw, bt) && !ia64_in_init_stack(sw))
 		return FALSE;
 
         unw_init_frame_info(info, bt, sw);
 	return TRUE;
 }
 
+/*
+ * unw_init_from_interruption
+ *   Initialize frame info from specified pt_regs/switch_stack.
+ *
+ *   Similar to unw_init_frame_info() except that:
+ *     - do not use readmem to access stack
+ *       (because stack may be modified by unw_init_from_saved_regs)
+ *     - use ar.ifs and ar.iip instead of ar.pfs and b0, respectively
+ *     - use sof(size-of-frame) of ar.ifs to caluculate bsp,
+ *       instead of sol(size-of-local) of ar.pfs
+ *       (because of cover instruction in kernel minstate save macro)
+ */
+static void
+unw_init_from_interruption(struct unw_frame_info *info, struct bt_info *bt, ulong pt, ulong sw)
+{
+//	unsigned long rbslimit, rbstop, stklimit, stktop, sof, ar_pfs;
+	unsigned long rbslimit, rbstop, stklimit, stktop, sof;
+	ulong t;
+
+	t = bt->task;
+
+	memset(info, 0, sizeof(*info));
+
+	rbslimit = (unsigned long) t + IA64_RBS_OFFSET;
+	rbstop = IA64_GET_STACK_ULONG(sw + OFFSET(switch_stack_ar_bspstore));
+	if (rbstop - (unsigned long) t >= IA64_STK_OFFSET)
+		rbstop = rbslimit;
+
+	stklimit = (unsigned long) t + IA64_STK_OFFSET;
+	stktop   = IA64_GET_STACK_ULONG(pt + offsetof(struct pt_regs, r12));
+	if (stktop <= rbstop)
+		stktop = rbstop;
+
+	info->regstk.limit = rbslimit;
+	info->regstk.top   = rbstop;
+	info->memstk.limit = stklimit;
+	info->memstk.top   = stktop;
+	info->task = (struct task_struct *)bt;
+	info->sw  = (struct switch_stack *)sw;
+	info->sp = info->psp = stktop;
+	info->pr = IA64_GET_STACK_ULONG(sw + OFFSET(switch_stack_pr));
+
+	info->cfm_loc = (unsigned long *) (pt + offsetof(struct pt_regs, cr_ifs));
+	info->unat_loc = (unsigned long *) (pt + offsetof(struct pt_regs, ar_unat));
+	info->pfs_loc = (unsigned long *) (pt + offsetof(struct pt_regs, ar_pfs));
+	/* register stack is covered */
+	sof = IA64_GET_STACK_ULONG(info->cfm_loc) & 0x7f;
+	info->bsp = (unsigned long)
+		ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sof);
+	/* interrupted ip is saved in iip */
+	info->ip = IA64_GET_STACK_ULONG(pt + offsetof(struct pt_regs, cr_iip));
+#if defined(UNWIND_V2) || defined(UNWIND_V3)
+	info->pt = pt;
+#endif
+
+	find_save_locs(info);
+}
+
+/*
+ * unw_switch_from_osinit
+ *   switch back to interrupted context
+ *
+ *   assumption: init_handler_platform() has 3 arguments,
+ *               2nd arg is pt_regs and 3rd arg is switch_stack.
+ */
+static int
+unw_switch_from_osinit_v1(struct unw_frame_info *info, struct bt_info *bt)
+{
+	unsigned long pt, sw;
+	char is_nat;
+
+	/* pt_regs is the 2nd argument of init_handler_platform */
+	if (unw_get_gr(info, 33, &pt, &is_nat)) {
+		fprintf(fp, "gr 33 get error\n");
+		return FALSE;
+	}
+	/* switch_stack is the 3rd argument of init_handler_platform */
+	if (unw_get_gr(info, 34, &sw, &is_nat)) {
+		fprintf(fp, "gr 33 get error\n");
+		return FALSE;
+	}
+
+	unw_init_from_interruption(info, bt, pt, sw);
+	ia64_exception_frame(pt, bt);
+
+	return TRUE;
+}
+
+static int
+unw_switch_from_osinit_v2(struct unw_frame_info *info, struct bt_info *bt)
+{
+	unsigned long pt, sw;
+	char is_nat;
+
+	/* pt_regs is the 1st argument of ia64_init_handler */
+	if (unw_get_gr(info, 32, &pt, &is_nat)) {
+		fprintf(fp, "gr 32 get error\n");
+
+		return FALSE;
+	}
+	/* switch_stack is the 2nd argument of ia64_init_handler */
+	if (unw_get_gr(info, 33, &sw, &is_nat)) {
+		fprintf(fp, "gr 33 get error\n");
+		return FALSE;
+	}
+
+	/* Fix me! */
+	sw = info->psp + 16;
+	pt = sw + STRUCT_SIZE("switch_stack");
+
+	unw_init_from_interruption(info, bt, pt, sw);
+	ia64_exception_frame(pt, bt);
+
+	return TRUE;
+}
+
 static void
 unw_init_frame_info (struct unw_frame_info *info, struct bt_info *bt, ulong sw)
 {
@@ -1851,12 +2009,12 @@
 	info->sw  = (struct switch_stack *)sw;
 	info->sp = info->psp = (unsigned long) (sw + SIZE(switch_stack)) - 16;
         info->cfm_loc = (ulong *)(sw + OFFSET(switch_stack_ar_pfs));
-    	ar_pfs = GET_STACK_ULONG(info->cfm_loc); 
+    	ar_pfs = IA64_GET_STACK_ULONG(info->cfm_loc); 
 	sol = (ar_pfs >> 7) & 0x7f;
 	info->bsp = (unsigned long) 
 		ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol);
-        info->ip = GET_STACK_ULONG(sw + OFFSET(switch_stack_b0)); 
-        info->pr = GET_STACK_ULONG(sw + OFFSET(switch_stack_pr)); 
+        info->ip = IA64_GET_STACK_ULONG(sw + OFFSET(switch_stack_b0)); 
+        info->pr = IA64_GET_STACK_ULONG(sw + OFFSET(switch_stack_pr)); 
 
 	find_save_locs(info);
 }
@@ -1973,7 +2131,7 @@
 		       	info->ip);
 		return -1;
 	}
-	ip = info->ip = GET_STACK_ULONG(info->rp_loc);
+	ip = info->ip = IA64_GET_STACK_ULONG(info->rp_loc);
 	if (ip < GATE_ADDR + PAGE_SIZE) {
 		/*
 		 * We don't have unwind info for the gate page, 
@@ -1997,26 +2155,26 @@
 	if ((info->flags & UNW_FLAG_INTERRUPT_FRAME)) {
 #ifdef UNWIND_V1
 		if ((pr & (1UL << pNonSys)) != 0)
-			num_regs = GET_STACK_ULONG(info->cfm_loc) & 0x7f;		/* size of frame */
+			num_regs = IA64_GET_STACK_ULONG(info->cfm_loc) & 0x7f;		/* size of frame */
 		info->pfs_loc =
 			(unsigned long *) (info->sp + 16 + struct_offset(struct pt_regs, ar_pfs));
 #endif
 #ifdef UNWIND_V2
                 info->pt = info->sp + 16;
                 if ((pr & (1UL << pNonSys)) != 0)
-                        num_regs = GET_STACK_ULONG(info->cfm_loc) & 0x7f;               /* size of frame */
+                        num_regs = IA64_GET_STACK_ULONG(info->cfm_loc) & 0x7f;               /* size of frame */
                 info->pfs_loc =
                         (unsigned long *) (info->pt + offsetof(struct pt_regs, ar_pfs));
 #endif
 #ifdef UNWIND_V3
                 info->pt = info->sp + 16;
                 if ((pr & (1UL << pNonSys)) != 0)
-                        num_regs = GET_STACK_ULONG(info->cfm_loc) & 0x7f;               /* size of frame */
+                        num_regs = IA64_GET_STACK_ULONG(info->cfm_loc) & 0x7f;               /* size of frame */
                 info->pfs_loc =
                         (unsigned long *) (info->pt + offsetof(struct pt_regs, ar_pfs));
 #endif
 	} else
-		num_regs = (GET_STACK_ULONG(info->cfm_loc) >> 7) & 0x7f;	/* size of locals */
+		num_regs = (IA64_GET_STACK_ULONG(info->cfm_loc) >> 7) & 0x7f;	/* size of locals */
 	info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -num_regs);
 	if (info->bsp < info->regstk.limit || info->bsp > info->regstk.top) {
 		error(INFO, "unwind: bsp (0x%lx) out of range [0x%lx-0x%lx]\n",
@@ -2026,7 +2184,8 @@
 
 	/* restore the sp: */
 	info->sp = info->psp;
-	if (info->sp < info->memstk.top || info->sp > info->memstk.limit) {
+	if ((info->sp < info->memstk.top || info->sp > info->memstk.limit)
+		&& !ia64_in_init_stack(info->sp)) {
 		error(INFO, "unwind: sp (0x%lx) out of range [0x%lx-0x%lx]\n",
 			info->sp, info->memstk.top, info->memstk.limit);
 		return -1;
@@ -2135,7 +2294,7 @@
 				break;
 			}
 #endif
-			s[dst] = GET_STACK_ULONG(s[val]);
+			s[dst] = IA64_GET_STACK_ULONG(s[val]);
 			break;
 		}
 	}
--- crash/defs.h.orig	2005-02-09 16:13:26.000000000 -0500
+++ crash/defs.h	2005-01-28 15:26:12.000000000 -0500
@@ -62,7 +62,7 @@
 #include <sys/wait.h>
 #include <sys/time.h>
 
-#define BASELEVEL_REVISION  "3.8"
+#define BASELEVEL_REVISION  "3.10"
 
 #undef TRUE
 #undef FALSE
@@ -446,6 +446,8 @@
 	long __rq_idx[NR_CPUS];
 	long __cpu_idx[NR_CPUS];
 	long __per_cpu_offset[NR_CPUS];
+	long cpu_flags[NR_CPUS];
+#define NMI 0x1
 };
 
 /*
@@ -674,6 +676,7 @@
 #define FRAMESIZE_DEBUG (0x10000000)
 #define MACHDEP_BT_TEXT  (0x8000000)
 #define DEVMEMRD         (0x4000000)
+#define INIT             (0x2000000)
 #define SYSRQ_TASK(X)   ((machdep->flags & SYSRQ) && is_task_active(X))
 
 extern struct machdep_table *machdep;
@@ -2030,6 +2033,9 @@
 #define UNKNOWN_PHYS_START ((ulong)(-1))
 #define DEFAULT_PHYS_START (KERNEL_TR_PAGE_SIZE * 1)
 
+#define IA64_GET_STACK_ULONG(OFF) \
+        ((INSTACK(OFF,bt)) ? (GET_STACK_ULONG(OFF)) : get_init_stack_ulong((unsigned long)OFF))
+
 #endif  /* IA64 */
 
 #ifdef PPC64
@@ -3106,6 +3112,7 @@
 #define BT_IRQSTACK        (0x200000000ULL)
 #define BT_DUMPFILE_SEARCH (0x400000000ULL)
 #define BT_EFRAME_SEARCH2  (0x800000000ULL)
+#define BT_START          (0x1000000000ULL)
 
 #define BT_REF_HEXVAL         (0x1)
 #define BT_REF_SYMBOL         (0x2)
@@ -3229,6 +3236,8 @@
 	int isize;
 };
 
+#define NMI_STACK 2    /* ebase[] offset to NMI exception stack */
+
 struct machine_specific {
         char *pml4;
 	char *irqstack;
@@ -3318,6 +3327,7 @@
 int ia64_IS_VMALLOC_ADDR(ulong);
 #define display_idt_table() \
 	error(FATAL, "-d option TBD on ia64 architecture\n");
+int ia64_in_init_stack(ulong addr);
 
 #define OLD_UNWIND       (0x1)   /* CONFIG_IA64_NEW_UNWIND not turned on */
 #define NEW_UNWIND       (0x2)   /* CONFIG_IA64_NEW_UNWIND turned on */
@@ -3359,8 +3369,10 @@
 	void (*unwind)(struct bt_info *);
 	void (*dump_unwind_stats)(void);
 	int (*unwind_debug)(ulong);
+	int ia64_init_stack_size;
 };
 
+
 /*
  *  unwind.c
  */
--- crash/Makefile.orig	2005-02-09 16:13:26.000000000 -0500
+++ crash/Makefile	2005-02-09 16:13:25.000000000 -0500
@@ -153,10 +153,10 @@
 GDB_6.1_FILES=${GDB}/gdb/Makefile.in ${GDB}/Makefile.in \
           ${GDB}/gdb/main.c ${GDB}/gdb/symtab.c ${GDB}/gdb/target.c \
           ${GDB}/gdb/symfile.c ${GDB}/gdb/elfread.c \
-          ${GDB}/gdb/ui-file.c ${GDB}/gdb/utils.c
+          ${GDB}/gdb/ui-file.c ${GDB}/gdb/utils.c ${GDB}/gdb/dwarf2read.c
 GDB_6.1_OFILES=${GDB}/gdb/main.o ${GDB}/gdb/symtab.o \
           ${GDB}/gdb/target.o ${GDB}/gdb/symfile.o ${GDB}/gdb/elfread.o \
-          ${GDB}/gdb/ui-file.o ${GDB}/gdb/utils.o 
+          ${GDB}/gdb/ui-file.o ${GDB}/gdb/utils.o ${GDB}/gdb/dwarf2read.o
 
 # 
 # GDB_FLAGS is passed up from the gdb Makefile.
--- crash/crash.8.orig	2005-02-09 16:13:26.000000000 -0500
+++ crash/crash.8	2005-01-31 10:55:43.000000000 -0500
@@ -104,9 +104,8 @@
 .TP
 .BI \-d \ num
 .B Crash
-sets its internal debug level
-.I num
-.  The higher the number, the more debugging data will be printed while
+sets its internal debug level.
+The higher the number, the more debugging data will be printed while
 .B crash
 runs.
 .TP