Blob Blame History Raw
--- crash-7.0.2/main.c	2013-10-25 15:28:55.938879568 -0400
+++ crash-7.0.3/main.c	2013-10-15 15:55:10.136390264 -0400
@@ -1335,6 +1335,8 @@ dump_program_context(void)
 		fprintf(fp, "%sGET_LOG", others++ ? "|" : "");
 	if (pc->flags2 & VMCOREINFO)
 		fprintf(fp, "%sVMCOREINFO", others++ ? "|" : "");
+	if (pc->flags2 & ALLOW_FP)
+		fprintf(fp, "%sALLOW_FP", others++ ? "|" : "");
 	fprintf(fp, ")\n");
 
 	fprintf(fp, "         namelist: %s\n", pc->namelist);
--- crash-7.0.2/tools.c	2013-10-25 15:28:55.922879569 -0400
+++ crash-7.0.3/tools.c	2013-10-25 10:09:31.938757537 -0400
@@ -989,7 +989,7 @@ dtoi(char *s, int flags, int *errptr)
                 if ((s[j] < '0' || s[j] > '9'))
                         break ;
 
-        if (s[j] != '\0' || (sscanf(s, "%d", &retval) != 1)) {
+        if (s[j] != '\0' || (sscanf(s, "%d", (int *)&retval) != 1)) {
 		if (!(flags & QUIET))
                 	error(INFO, "%s: \"%c\" is not a digit 0 - 9\n", 
 				s, s[j]);
@@ -5489,6 +5489,19 @@ swap32(uint32_t val, int swap)
 		return val;
 }
 
+/*
+ *  Get a sufficiently large buffer for cpumask.
+ *  You should call FREEBUF() on the result when you no longer need it.
+ */
+ulong *
+get_cpumask_buf(void)
+{
+	int cpulen;
+	if ((cpulen = STRUCT_SIZE("cpumask_t")) < 0)
+		cpulen = DIV_ROUND_UP(kt->cpus, BITS_PER_LONG) * sizeof(ulong);
+	return (ulong *)GETBUF(cpulen);
+}
+
 int
 make_cpumask(char *s, ulong *mask, int flags, int *errptr)
 {
@@ -5505,14 +5518,20 @@ make_cpumask(char *s, ulong *mask, int f
 	p = strtok(s, ",");
 	while (p) {
 		s = strtok(NULL, "");
-		start = end = -1;
-		q = strtok(p, "-");
-		start = dtoi(q, flags, errptr);
-		if ((q = strtok(NULL, "-")))
-			end = dtoi(q, flags, errptr);
 
-		if (end == -1)
-			end = start;
+		if (STREQ(p, "a") || STREQ(p, "all")) {
+			start = 0;
+			end = kt->cpus - 1;
+		} else {
+			start = end = -1;
+			q = strtok(p, "-");
+			start = dtoi(q, flags, errptr);
+			if ((q = strtok(NULL, "-")))
+				end = dtoi(q, flags, errptr);
+
+			if (end == -1)
+				end = start;
+		}
 
 		for (i = start; i <= end; i++)
 			SET_BIT(mask, i);
--- crash-7.0.2/memory.c	2013-10-25 15:28:55.934879568 -0400
+++ crash-7.0.3/memory.c	2013-10-25 10:09:35.641757367 -0400
@@ -134,6 +134,10 @@ static char *error_handle_string(ulong);
 static void dump_mem_map(struct meminfo *);
 static void dump_mem_map_SPARSEMEM(struct meminfo *);
 static void fill_mem_map_cache(ulong, ulong, char *);
+static void page_flags_init(void);
+static int page_flags_init_from_pageflag_names(void);
+static int page_flags_init_from_pageflags_enum(void);
+static int translate_page_flags(char *, ulong);
 static void dump_free_pages(struct meminfo *);
 static int dump_zone_page_usage(void);
 static void dump_multidimensional_free_pages(struct meminfo *);
@@ -613,6 +617,13 @@ vm_init(void)
 		MEMBER_OFFSET_INIT(kmem_list3_free_objects, 
 			kmem_cache_node_struct, "free_objects");
 		MEMBER_OFFSET_INIT(kmem_list3_shared, kmem_cache_node_struct, "shared");
+		/*
+		 *  Common to slab/slub
+		 */
+		ANON_MEMBER_OFFSET_INIT(page_slab, "page", "slab_cache");
+		ANON_MEMBER_OFFSET_INIT(page_slab_page, "page", "slab_page");
+		ANON_MEMBER_OFFSET_INIT(page_first_page, "page", "first_page");
+
 	} else if (MEMBER_EXISTS("kmem_cache", "cpu_slab") &&
 		STRUCT_EXISTS("kmem_cache_node")) {
 		vt->flags |= KMALLOC_SLUB;
@@ -642,6 +653,7 @@ vm_init(void)
 		ANON_MEMBER_OFFSET_INIT(page_slab, "page", "slab");
 		if (INVALID_MEMBER(page_slab))
 			ANON_MEMBER_OFFSET_INIT(page_slab, "page", "slab_cache");
+		ANON_MEMBER_OFFSET_INIT(page_slab_page, "page", "slab_page");
 		ANON_MEMBER_OFFSET_INIT(page_first_page, "page", "first_page");
 		ANON_MEMBER_OFFSET_INIT(page_freelist, "page", "freelist");
 		if (INVALID_MEMBER(kmem_cache_objects)) {
@@ -703,16 +715,16 @@ vm_init(void)
 	}
 
 	if (!kt->kernel_NR_CPUS) {
-		if (ARRAY_LENGTH(kmem_cache_s_cpudata))
+		if (enumerator_value("WORK_CPU_UNBOUND", (long *)&value1))
+			kt->kernel_NR_CPUS = (int)value1;
+		else if ((i = get_array_length("__per_cpu_offset", NULL, 0)))
+			kt->kernel_NR_CPUS = i;
+		else if (ARRAY_LENGTH(kmem_cache_s_cpudata))
 			kt->kernel_NR_CPUS = ARRAY_LENGTH(kmem_cache_s_cpudata);
 		else if (ARRAY_LENGTH(kmem_cache_s_array))
 			kt->kernel_NR_CPUS = ARRAY_LENGTH(kmem_cache_s_array);
 		else if (ARRAY_LENGTH(kmem_cache_cpu_slab))
 			kt->kernel_NR_CPUS = ARRAY_LENGTH(kmem_cache_cpu_slab);
-		else if (enumerator_value("WORK_CPU_UNBOUND", (long *)&value1))
-			kt->kernel_NR_CPUS = (int)value1;
-		else if ((i = get_array_length("__per_cpu_offset", NULL, 0)))
-			kt->kernel_NR_CPUS = i;
 	}
 
 	if (CRASHDEBUG(1))
@@ -1025,8 +1037,7 @@ vm_init(void)
 
 	kmem_cache_init();
 
-	PG_reserved_flag_init();
-	PG_slab_flag_init();
+	page_flags_init();
 
 	vt->flags |= VM_INIT;
 }
@@ -4533,15 +4544,37 @@ PG_slab_flag_init(void)
         char buf[BUFSIZE];  /* safe for a page struct */
 
 	/*
-	 *  Set the old defaults in case the search below fails.
+	 *  Set the old defaults in case all else fails.
 	 */
-        if (VALID_MEMBER(page_pte)) {
+	if (enumerator_value("PG_slab", (long *)&flags)) {
+		vt->PG_slab = flags;
+		if (CRASHDEBUG(2))
+			fprintf(fp, "PG_slab (enum): %lx\n", vt->PG_slab);
+	} else if (VALID_MEMBER(page_pte)) {
                 if (THIS_KERNEL_VERSION < LINUX(2,6,0))
                         vt->PG_slab = 10;
                 else if (THIS_KERNEL_VERSION >= LINUX(2,6,0))
                         vt->PG_slab = 7;
-        } else if (THIS_KERNEL_VERSION >= LINUX(2,6,0))
-                vt->PG_slab = 7;
+        } else if (THIS_KERNEL_VERSION >= LINUX(2,6,0)) {
+		vt->PG_slab = 7;
+	} else {
+		if (try_get_symbol_data("vm_area_cachep", sizeof(void *), &vaddr) &&
+            	    phys_to_page((physaddr_t)VTOP(vaddr), &pageptr) &&
+                    readmem(pageptr, KVADDR, buf, SIZE(page),
+		    "vm_area_cachep page", RETURN_ON_ERROR|QUIET)) {
+
+			flags = ULONG(buf + OFFSET(page_flags));
+
+			if ((bit = ffsl(flags))) {
+				vt->PG_slab = bit - 1;
+	
+				if (CRASHDEBUG(2))
+					fprintf(fp,
+			"PG_slab bit: vaddr: %lx page: %lx flags: %lx => %ld\n",
+					vaddr, pageptr, flags, vt->PG_slab);
+			}
+		}
+	}
 
 	if (vt->flags & KMALLOC_SLUB) {
 		/* 
@@ -4561,34 +4594,20 @@ PG_slab_flag_init(void)
 				fprintf(fp, "PG_head_tail_mask: %lx\n", 
 					vt->PG_head_tail_mask);
 		}
-
-		return;
-	}
-
-	if (enumerator_value("PG_slab", (long *)&flags)) {
-		vt->PG_slab = flags;
-	       	if (CRASHDEBUG(2))
-			fprintf(fp, "PG_slab (enum): %lx\n", vt->PG_slab);
-		return;
-	}
-
-       	if (try_get_symbol_data("vm_area_cachep", sizeof(void *), &vaddr) &&
-            phys_to_page((physaddr_t)VTOP(vaddr), &pageptr) &&
-            readmem(pageptr, KVADDR, buf, SIZE(page),
-            "vm_area_cachep page", RETURN_ON_ERROR|QUIET)) {
-
-        	flags = ULONG(buf + OFFSET(page_flags));
-
-	        if ((bit = ffsl(flags))) {
-	                vt->PG_slab = bit - 1;
-	
-	        	if (CRASHDEBUG(2))
-	                	fprintf(fp,
-	                    "PG_slab bit: vaddr: %lx page: %lx flags: %lx => %ld\n",
-	                        vaddr, pageptr, flags, vt->PG_slab);
-	
+	} else {
+		if (enumerator_value("PG_tail", (long *)&flags))
+			vt->PG_head_tail_mask = (1L << flags);
+		else if (enumerator_value("PG_compound", (long *)&flags) &&
+		    enumerator_value("PG_reclaim", (long *)&flags2)) {
+			vt->PG_head_tail_mask = ((1L << flags) | (1L << flags2));
+	       		if (CRASHDEBUG(2))
+				fprintf(fp, "PG_head_tail_mask: %lx (PG_compound|PG_reclaim)\n", 
+					vt->PG_head_tail_mask);
 		}
 	}
+
+	if (!vt->PG_slab)
+		error(INFO, "cannot determine PG_slab bit value\n");	
 }
 
 /*
@@ -5009,7 +5028,10 @@ dump_mem_map_SPARSEMEM(struct meminfo *m
 					bufferindex += sprintflag("%sreserved");
 				bufferindex += sprintf(outputbuffer+bufferindex, "\n");
 			} else if (THIS_KERNEL_VERSION > LINUX(2,4,9)) {
-				bufferindex += sprintf(outputbuffer+bufferindex, "%lx\n", flags);
+				if (vt->flags & PAGEFLAGS)
+					bufferindex += translate_page_flags(outputbuffer+bufferindex, flags);
+				else
+					bufferindex += sprintf(outputbuffer+bufferindex, "%lx\n", flags);
 			} else {
 	
 		                if ((flags >> v24_PG_locked) & 1)
@@ -5444,7 +5466,10 @@ dump_mem_map(struct meminfo *mi)
 					bufferindex += sprintflag("%sreserved");
 				bufferindex += sprintf(outputbuffer+bufferindex, "\n");
 			} else if (THIS_KERNEL_VERSION > LINUX(2,4,9)) {
-				bufferindex += sprintf(outputbuffer+bufferindex, "%lx\n", flags);
+				if (vt->flags & PAGEFLAGS)
+					bufferindex += translate_page_flags(outputbuffer+bufferindex, flags);
+				else
+					bufferindex += sprintf(outputbuffer+bufferindex, "%lx\n", flags);
 			} else {
 	
 		                if ((flags >> v24_PG_locked) & 1)
@@ -5591,6 +5616,196 @@ fill_mem_map_cache(ulong pp, ulong ppend
         }
 }
 
+static void
+page_flags_init(void)
+{
+	if (!page_flags_init_from_pageflag_names())
+		page_flags_init_from_pageflags_enum();
+
+	PG_reserved_flag_init();
+	PG_slab_flag_init();
+}
+
+static int
+page_flags_init_from_pageflag_names(void)
+{
+	int i, len;
+	char *buffer, *nameptr;
+	char namebuf[BUFSIZE];
+	ulong mask;
+	void *name;
+
+	MEMBER_OFFSET_INIT(trace_print_flags_mask, "trace_print_flags", "mask");
+	MEMBER_OFFSET_INIT(trace_print_flags_name, "trace_print_flags", "name");
+	STRUCT_SIZE_INIT(trace_print_flags, "trace_print_flags");
+
+	if (INVALID_SIZE(trace_print_flags) ||
+	    INVALID_MEMBER(trace_print_flags_mask) || 
+	    INVALID_MEMBER(trace_print_flags_name) ||
+	    !kernel_symbol_exists("pageflag_names") ||
+	    !(len = get_array_length("pageflag_names", NULL, 0)))
+		return FALSE;
+
+	buffer = GETBUF(SIZE(trace_print_flags) * len);
+
+	if (!readmem(symbol_value("pageflag_names"), KVADDR, buffer,
+	    SIZE(trace_print_flags) * len, "pageflag_names array",
+	    RETURN_ON_ERROR)) {
+		FREEBUF(buffer);
+		return FALSE;
+	}
+
+	if (!(vt->pageflags_data = (struct pageflags_data *)
+	    malloc(sizeof(struct pageflags_data) * len))) {
+		error(INFO, "cannot malloc pageflags_data cache\n");
+		FREEBUF(buffer);
+		return FALSE;
+	}
+
+	if (CRASHDEBUG(1))
+		fprintf(fp, "pageflags from pageflag_names: \n");
+
+	for (i = 0; i < len; i++) {
+		mask = ULONG(buffer + (SIZE(trace_print_flags)*i) + 
+			OFFSET(trace_print_flags_mask));		
+		name = VOID_PTR(buffer + (SIZE(trace_print_flags)*i) + 
+			OFFSET(trace_print_flags_name));		
+
+		if ((mask == -1UL) && !name) {   /* Linux 3.5 and earlier */
+			len--;
+			break;
+		}
+
+		if (!read_string((ulong)name, namebuf, BUFSIZE-1)) {
+			error(INFO, "failed to read pageflag_names entry\n",
+				i, name, mask);
+			goto pageflags_fail;
+		}
+
+		if (!(nameptr = (char *)malloc(strlen(namebuf)+1))) {
+			error(INFO, "cannot malloc pageflag_names space\n");
+			goto pageflags_fail;
+		}
+		strcpy(nameptr, namebuf);
+
+		vt->pageflags_data[i].name = nameptr;
+		vt->pageflags_data[i].mask = mask;
+
+		if (CRASHDEBUG(1)) {
+			fprintf(fp, "  %08lx %s\n", 
+				vt->pageflags_data[i].mask,
+				vt->pageflags_data[i].name);
+		}
+	}
+
+	FREEBUF(buffer);
+	vt->nr_pageflags = len;
+	vt->flags |= PAGEFLAGS;
+	return TRUE;
+
+pageflags_fail:
+	FREEBUF(buffer);
+	free(vt->pageflags_data);
+	vt->pageflags_data = NULL;
+	return FALSE;
+}
+
+static int
+page_flags_init_from_pageflags_enum(void)
+{
+	int c;
+	int p, len;
+	char *nameptr;
+	char buf[BUFSIZE];
+	char *arglist[MAXARGS];
+
+	if (!(vt->pageflags_data = (struct pageflags_data *)
+	    malloc(sizeof(struct pageflags_data) * 32))) {
+		error(INFO, "cannot malloc pageflags_data cache\n");
+		return FALSE;
+        }
+
+	p = 0;
+	pc->flags2 |= ALLOW_FP;
+	open_tmpfile();
+
+	if (dump_enumerator_list("pageflags")) {
+		rewind(pc->tmpfile);
+		while (fgets(buf, BUFSIZE, pc->tmpfile)) {
+			if (!strstr(buf, " = "))
+				continue;
+
+			c = parse_line(buf, arglist);
+
+			if (strstr(arglist[0], "__NR_PAGEFLAGS")) {
+				len = atoi(arglist[2]);
+				if (!len || (len > 32))
+					goto enum_fail;
+				vt->nr_pageflags = len;
+				break;
+			}
+
+			if (!(nameptr = (char *)malloc(strlen(arglist[0])))) {
+				error(INFO, "cannot malloc pageflags name space\n");
+				goto enum_fail;
+			}
+			strcpy(nameptr, arglist[0] + strlen("PG_"));
+			vt->pageflags_data[p].name = nameptr;
+			vt->pageflags_data[p].mask = 1 << atoi(arglist[2]); 
+
+			p++;
+		}
+	} else 
+		goto enum_fail;
+
+	close_tmpfile();
+	pc->flags2 &= ~ALLOW_FP;
+
+	if (CRASHDEBUG(1)) {
+		fprintf(fp, "pageflags from enum: \n");
+		for (p = 0; p < vt->nr_pageflags; p++)
+			fprintf(fp, "  %08lx %s\n", 
+				vt->pageflags_data[p].mask,
+				vt->pageflags_data[p].name);
+	}
+
+	vt->flags |= PAGEFLAGS;
+	return TRUE;
+
+enum_fail:
+	close_tmpfile();
+	pc->flags2 &= ~ALLOW_FP;
+
+	for (c = 0; c < p; c++)
+		free(vt->pageflags_data[c].name);
+	free(vt->pageflags_data);
+	vt->pageflags_data = NULL;
+	vt->nr_pageflags = 0;
+
+	return FALSE;
+}
+
+static int
+translate_page_flags(char *buffer, ulong flags)
+{
+	char buf[BUFSIZE];
+	int i, others;
+
+	sprintf(buf, "%lx", flags);
+
+	if (flags) {
+		for (i = others = 0; i < vt->nr_pageflags; i++) {
+			if (flags & vt->pageflags_data[i].mask)
+				sprintf(&buf[strlen(buf)], "%s%s",
+					others++ ? "," : " ",
+					vt->pageflags_data[i].name);
+		}
+	}
+	strcat(buf, "\n");
+	strcpy(buffer, buf);
+
+	return(strlen(buf));
+}
 
 /*
  *  dump_page_hash_table() displays the entries in each page_hash_table.
@@ -7240,7 +7455,8 @@ dump_kmeminfo(void)
 		page_cache_size = nr_file_pages - swapper_space_nrpages -
 			buffer_pages;
 		FREEBUF(swapper_space);
-	}
+	} else
+		page_cache_size = 0;
 
 
         pct = (page_cache_size * 100)/totalram_pages;
@@ -8085,7 +8301,9 @@ vaddr_to_kmem_cache(ulong vaddr, char *b
 		return NULL;
 	}
 
-	if (vt->flags & KMALLOC_SLUB) {
+	if ((vt->flags & KMALLOC_SLUB) ||
+	    ((vt->flags & KMALLOC_COMMON) && 
+	     VALID_MEMBER(page_slab) && VALID_MEMBER(page_first_page))) {
                 readmem(compound_head(page)+OFFSET(page_slab),
                         KVADDR, &cache, sizeof(void *),
                         "page.slab", FAULT_ON_ERROR);
@@ -8136,6 +8354,10 @@ vaddr_to_slab(ulong vaddr)
 
         if (vt->flags & KMALLOC_SLUB)
 		slab = compound_head(page);
+        else if ((vt->flags & KMALLOC_COMMON) && VALID_MEMBER(page_slab_page))
+                readmem(page+OFFSET(page_slab_page),
+                        KVADDR, &slab, sizeof(void *),
+                        "page.slab_page", FAULT_ON_ERROR);
         else if (VALID_MEMBER(page_prev))
                 readmem(page+OFFSET(page_prev),
                         KVADDR, &slab, sizeof(void *),
@@ -8212,7 +8434,7 @@ kmem_cache_init(void)
 		OFFSET(kmem_cache_s_num) : OFFSET(kmem_cache_s_c_num);
 	next_offset = vt->flags & (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2) ?
 		OFFSET(kmem_cache_s_next) : OFFSET(kmem_cache_s_c_nextp);
-        max_cnum = max_limit = max_cpus = cache_count = 0;
+        max_cnum = max_limit = max_cpus = cache_count = tmp2 = 0;
 
 	/*
 	 *  Pre-2.6 versions used the "cache_cache" as the head of the
@@ -8431,6 +8653,43 @@ kmem_cache_downsize(void)
 	FREEBUF(cache_buf);
 }
 
+/*
+ *  Stash a list of presumably-corrupted slab cache addresses.
+ */
+static void
+mark_bad_slab_cache(ulong cache) 
+{
+	size_t sz;
+
+	if (vt->nr_bad_slab_caches) {
+		sz = sizeof(ulong) * (vt->nr_bad_slab_caches + 1);
+		if (!(vt->bad_slab_caches = realloc(vt->bad_slab_caches, sz))) {
+                	error(INFO, "cannot realloc bad_slab_caches array\n");
+			vt->nr_bad_slab_caches = 0;
+			return;
+		}
+	} else {
+		if (!(vt->bad_slab_caches = (ulong *)malloc(sizeof(ulong)))) {
+			error(INFO, "cannot malloc bad_slab_caches array\n");
+			return;
+		}
+	}
+
+	vt->bad_slab_caches[vt->nr_bad_slab_caches++] = cache;
+}
+
+static int
+bad_slab_cache(ulong cache) 
+{
+	int i;
+
+	for (i = 0; i < vt->nr_bad_slab_caches; i++) {
+		if (vt->bad_slab_caches[i] == cache)
+			return TRUE;
+	}
+
+       return FALSE;
+}
 
 /*
  *  Determine the largest cpudata limit for a given cache.
@@ -8526,8 +8785,13 @@ kmem_cache_s_array_nodes:
 	for (i = max_limit = 0; (i < kt->cpus) && cpudata[i]; i++) {
                 if (!readmem(cpudata[i]+OFFSET(array_cache_limit),
                     KVADDR, &limit, sizeof(int),
-                    "array cache limit", RETURN_ON_ERROR))
-			goto bail_out;
+                    "array cache limit", RETURN_ON_ERROR)) {
+			error(INFO, 
+			    "kmem_cache: %lx: invalid array_cache pointer: %lx\n",
+				cache, cpudata[i]);
+			mark_bad_slab_cache(cache);
+			return max_limit;
+		}
 		if (CRASHDEBUG(3))
 			fprintf(fp, "  array limit[%d]: %d\n", i, limit);
                 if (limit > max_limit)
@@ -9232,6 +9496,11 @@ dump_kmem_cache_percpu_v2(struct meminfo
                         goto next_cache;
                 }
 
+		if (bad_slab_cache(si->cache)) {
+                        fprintf(fp, "%lx %-18s [INVALID/CORRUPTED]\n", si->cache, buf);
+                        goto next_cache;
+		}
+
 		si->curname = buf;
 
 	        readmem(si->cache+OFFSET(kmem_cache_s_objsize),
@@ -9264,7 +9533,7 @@ dump_kmem_cache_percpu_v2(struct meminfo
                 	"kmem_cache_s num", FAULT_ON_ERROR);
 		si->c_num = (ulong)tmp_val;
 
-		if( vt->flags & PERCPU_KMALLOC_V2_NODES )
+		if (vt->flags & PERCPU_KMALLOC_V2_NODES)
 			do_slab_chain_percpu_v2_nodes(SLAB_GET_COUNTS, si);
 		else
 			do_slab_chain_percpu_v2(SLAB_GET_COUNTS, si);
@@ -10160,22 +10429,22 @@ do_slab_chain_percpu_v2_nodes(long cmd,
 				if (!slab_chains[s])
 					continue;
 
-	        	if (!specified_slab) {
-	                	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;
+				if (!specified_slab) {
+					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;
 				
@@ -11709,6 +11978,8 @@ dump_vm_table(int verbose)
 		fprintf(fp, "%sVM_EVENT", others++ ? "|" : "");\
 	if (vt->flags & PGCNT_ADJ)
 		fprintf(fp, "%sPGCNT_ADJ", others++ ? "|" : "");\
+	if (vt->flags & PAGEFLAGS)
+		fprintf(fp, "%sPAGEFLAGS", others++ ? "|" : "");\
 	if (vt->flags & SWAPINFO_V1)
 		fprintf(fp, "%sSWAPINFO_V1", others++ ? "|" : "");\
 	if (vt->flags & SWAPINFO_V2)
@@ -11747,10 +12018,15 @@ dump_vm_table(int verbose)
 	fprintf(fp, "   kmem_cache_count: %ld\n", vt->kmem_cache_count);
 	fprintf(fp, " kmem_cache_namelen: %d\n", vt->kmem_cache_namelen);
 	fprintf(fp, "kmem_cache_len_nodes: %ld\n", vt->kmem_cache_len_nodes);
-	fprintf(fp, "        PG_reserved: %lx\n", vt->PG_reserved);
-	fprintf(fp, "            PG_slab: %ld (%lx)\n", vt->PG_slab, 
-		(ulong)1 << vt->PG_slab);
-	fprintf(fp, "  PG_head_tail_mask: %lx\n", vt->PG_head_tail_mask);
+	fprintf(fp, " nr_bad_slab_caches: %d\n", vt->nr_bad_slab_caches);
+	if (!vt->nr_bad_slab_caches)
+		fprintf(fp, "    bad_slab_caches: (unused)\n");
+	else {
+		for (i = 0; i < vt->nr_bad_slab_caches; i++) {
+			fprintf(fp, " bad_slab_caches[%d]: %lx\n", 
+				i, vt->bad_slab_caches[i]);
+		}
+	}
 	fprintf(fp, "        paddr_prlen: %d\n", vt->paddr_prlen);
 	fprintf(fp, "           numnodes: %d\n", vt->numnodes);
 	fprintf(fp, "           nr_zones: %d\n", vt->nr_zones);
@@ -11824,6 +12100,21 @@ dump_vm_table(int verbose)
 	for (i = 0; i < vt->nr_vm_event_items; i++)
 		fprintf(fp, "        [%d] %s\n", i, vt->vm_event_items[i]);
 
+        fprintf(fp, "        PG_reserved: %lx\n", vt->PG_reserved);
+        fprintf(fp, "            PG_slab: %ld (%lx)\n", vt->PG_slab,
+                (ulong)1 << vt->PG_slab);
+        fprintf(fp, "  PG_head_tail_mask: %lx\n", vt->PG_head_tail_mask);
+
+	fprintf(fp, "       nr_pageflags: %d\n", vt->nr_pageflags);
+	fprintf(fp, "     pageflags_data: %s\n",
+		vt->nr_pageflags ? "" : "(not used)");
+	for (i = 0; i < vt->nr_pageflags; i++) {
+		fprintf(fp, "        %s[%d] %08lx: %s\n", 
+			i < 10 ? " " : "", i, 
+			vt->pageflags_data[i].mask,
+			vt->pageflags_data[i].name);
+	}
+
 	dump_vma_cache(VERBOSE);
 }
 
--- crash-7.0.2/filesys.c	2013-10-25 15:28:55.920879569 -0400
+++ crash-7.0.3/filesys.c	2013-10-25 10:09:39.568757187 -0400
@@ -727,8 +727,10 @@ get_proc_version(void)
                 return FALSE;
 
         if (fread(&kt->proc_version, sizeof(char), 
-	    	BUFSIZE-1, version) <= 0) 
+	    	BUFSIZE-1, version) <= 0) {
+		fclose(version);
                 return FALSE;
+	}
         
         fclose(version);
 
--- crash-7.0.2/help.c	2013-10-25 15:28:55.954879567 -0400
+++ crash-7.0.3/help.c	2013-10-24 15:32:58.495826737 -0400
@@ -1083,10 +1083,16 @@ NULL
 char *help_p[] = {
 "p",
 "print the value of an expression",
-"[-x|-d][-u] expression",
+"[-x|-d][-u] [expression | symbol[:cpuspec]]",
 "  This command passes its arguments on to gdb \"print\" command for evaluation.",
 "",
-"    expression   The expression to be evaluated.",
+"    expression  an expression to be evaluated.",
+"        symbol  a kernel symbol.",
+"      :cpuspec  CPU specification for a per-cpu symbol:",
+"                  :             CPU of the currently selected task.",
+"                  :a[ll]        all CPUs.",
+"                  :#[-#][,...]  CPU list(s), e.g. \"1,3,5\", \"1-3\",",
+"                                or \"1,3,5-7,10\".",
 "            -x  override default output format with hexadecimal format.",
 "            -d  override default output format with decimal format.",
 "            -u  the expression evaluates to a user address reference.", 
@@ -1144,6 +1150,39 @@ char *help_p[] = {
 "      swap_address = 0x0, ",
 "      segments = 0x0",
 "    }",
+"",
+"  If a per-cpu symbol is entered as a argument, its data type",
+"  and all of its per-cpu addresses are displayed:",
+" ",
+"    %s> p irq_stat",
+"    PER-CPU DATA TYPE:",
+"      irq_cpustat_t irq_stat;",
+"    PER-CPU ADDRESSES:",
+"      [0]: ffff88021e211540",
+"      [1]: ffff88021e251540",
+"      [2]: ffff88021e291540",
+"      [3]: ffff88021e2d1540",
+" ",
+"  To display the contents a per-cpu symbol for CPU 1, append",
+"  a cpu-specifier:",
+" ",
+"    %s> p irq_stat:1",
+"    per_cpu(irq_stat, 1) = $29 = {",
+"      __softirq_pending = 0, ",
+"      __nmi_count = 209034, ",
+"      apic_timer_irqs = 597509876, ",
+"      irq_spurious_count = 0, ",
+"      icr_read_retry_count = 2, ",
+"      x86_platform_ipis = 0, ",
+"      apic_perf_irqs = 209034, ",
+"      apic_irq_work_irqs = 0, ",
+"      irq_resched_count = 264922233, ",
+"      irq_call_count = 7036692, ",
+"      irq_tlb_count = 4750442, ",
+"      irq_thermal_count = 0, ",
+"      irq_threshold_count = 0",
+"    }",
+" ",
 NULL               
 };
 
@@ -2841,7 +2880,7 @@ char *help_irq[] = {
 "            irq stats of all cpus will be displayed.",
 "   -c cpu   only usable with the -s option, dump the irq stats of the ",
 "            specified cpu[s]; cpu can be specified as \"1,3,5\", \"1-3\",",
-"            or \"1,3,5-7,10\".",
+"            \"1,3,5-7,10\", \"all\", or \"a\" (shortcut for \"all\").",
 "\nEXAMPLES",
 "  Display the relevant data for IRQ 18 from a pre-2.6.37 kernel:\n", 
 "    %s> irq 18",
@@ -4092,8 +4131,8 @@ NULL
 char *help_struct[] = {
 "struct",
 "structure contents",
-"struct_name[.member[,member]][-o][-l offset][-rfuxdp][address | symbol]\n"
-"         [count | -c count]",
+"struct_name[.member[,member]][-o][-l offset][-rfuxdp]\n"
+"         [address | symbol][:cpuspec] [count | -c count]",
 "  This command displays either a structure definition, or a formatted display",
 "  of the contents of a structure at a specified address.  When no address is",
 "  specified, the structure definition is shown along with the structure size.",
@@ -4127,6 +4166,11 @@ char *help_struct[] = {
 "                 to an embedded list_head structure contained within the",
 "                 target data structure, then the \"-l\" option must be used.",
 "         symbol  symbolic reference to the address of a structure.",
+"       :cpuspec  CPU specification for a per-cpu address or symbol:",
+"                   :             CPU of the currently selected task.",
+"                   :a[ll]        all CPUs.",
+"                   :#[-#][,...]  CPU list(s), e.g. \"1,3,5\", \"1-3\",",
+"                                 or \"1,3,5-7,10\".",
 "          count  count of structures to dump from an array of structures;",
 "                 if used, this must be the last argument entered.",
 "       -c count  \"-c\" is only required if \"count\" is not the last argument",
@@ -4363,6 +4407,59 @@ char *help_struct[] = {
 "      [ffff8100145d20b8] struct list_head run_list;",
 "      [ffff8100145d20c8] struct prio_array *array;",
 "    ...",
+" ",
+"  For an example of displaying per-cpu variables, consider the",
+"  struct hd_struct.dkstats member, which is a percpu pointer to",
+"  a disk_stats structure:",
+"",
+"    %s> struct hd_struct.dkstats ",
+"    struct hd_struct {",
+"      [1232] struct disk_stats *dkstats;",
+"    }",
+"",
+" Taking an hd_struct at address ffff8802450e2848, display all",
+" of the per-cpu disk_stats structures that it references:",
+" ",
+"    %s> struct hd_struct.dkstats ffff8802450e2848",
+"      dkstats = 0x60fdb48026c8",
+"    %s> struct disk_stats 0x60fdb48026c8:a",
+"    [0]: ffffe8fefe6026c8",
+"    struct disk_stats {",
+"      sectors = {451376, 80468}, ",
+"      ios = {6041, 971}, ",
+"      merges = {386, 390}, ",
+"      ticks = {194877, 56131}, ",
+"      io_ticks = 12371, ",
+"      time_in_queue = 309163",
+"    }",
+"    [1]: ffffe8fefe8026c8",
+"    struct disk_stats {",
+"      sectors = {0, 0}, ",
+"      ios = {0, 0}, ",
+"      merges = {7, 242}, ",
+"      ticks = {0, 0}, ",
+"      io_ticks = 23, ",
+"      time_in_queue = 581",
+"    }",
+"    [2]: ffffe8fefea026c8",
+"    struct disk_stats {",
+"      sectors = {0, 0}, ",
+"      ios = {0, 0}, ",
+"      merges = {4, 112}, ",
+"      ticks = {0, 0}, ",
+"      io_ticks = 11, ",
+"      time_in_queue = 305",
+"    }",
+"    [3]: ffffe8fefec026c8",
+"    struct disk_stats {",
+"      sectors = {0, 0}, ",
+"      ios = {0, 0}, ",
+"      merges = {5, 54}, ",
+"      ticks = {0, 0}, ",
+"      io_ticks = 17, ",
+"      time_in_queue = 41",
+"    }",
+" ",
 "\nNOTE",
 "  If the structure name does not conflict with any %s command name, the",
 "  \"struct\" command may be dropped.  Accordingly, the examples above could",
@@ -4382,8 +4479,8 @@ NULL
 char *help_union[] = {
 "union",
 "union contents",
-"union_name[.member[,member]] [-o][-l offset][-rfuxdp] [address | symbol]\n"
-"                                     [count | -c count]",
+"union_name[.member[,member]] [-o][-l offset][-rfuxdp]\n"
+"         [address | symbol][:cpuspec] [count | -c count]",
 "  This command displays either a union definition, or a formatted display",
 "  of the contents of a union at a specified address.  When no address is",
 "  specified, the union definition is shown along with the union size.",
@@ -4418,6 +4515,11 @@ char *help_union[] = {
 "                 to an embedded list_head structure contained within the",
 "                 target union structure, then the \"-l\" option must be used.",
 "         symbol  symbolic reference to the address of a union.",
+"       :cpuspec  CPU specification for a per-cpu address or symbol:",
+"                   :             CPU of the currently selected task.",
+"                   :a[ll]        all CPUs.",
+"                   :#[-#][,...]  CPU list(s), e.g. \"1,3,5\", \"1-3\",",
+"                                or \"1,3,5-7,10\".",
 "          count  count of unions to dump from an array of unions; if used,",
 "                 this must be the last argument entered.",
 "       -c count  \"-c\" is only required if \"count\" is not the last argument",
@@ -5433,30 +5535,26 @@ char *help_kmem[] = {
 " ",
 "  Dump the mem_map[] array:\n",
 "    %s> kmem -p",
-"          PAGE       PHYSICAL      MAPPING       INDEX CNT FLAGS",
-"    ffffea0000000000        0                0        0  0 0",
-"    ffffea0000000038     1000                0        0  1 400",
-"    ffffea0000000070     2000                0        0  1 400",
-"    ffffea00000000a8     3000                0        0  1 400",
-"    ffffea00000000e0     4000                0        0  1 400",
-"    ffffea0000000118     5000                0        0  1 400",
-"    ffffea0000000150     6000                0        0  1 400",
-"    ffffea0000000188     7000                0        0  1 80",
-"    ffffea00000001c0     8000                0        0  1 400",
-"    ffffea00000001f8     9000                0        0  1 80",
-"    ffffea0000000230     a000                0        0  1 80",
-"    ffffea0000000268     b000 ffff880012d9bd68     695b  1 2002c",
-"    ffffea00000002a0     c000                0        0  1 80",
-"    ffffea00000002d8     d000 ffff88002a9ee210        9  1 2002c",
-"    ffffea0000000310     e000 ffff880010b265d8      33c  1 2002c",
-"    ffffea0000000348     f000 ffff88001404dd68      2d1  2 868",
-"    ffffea0000000380    10000 ffff88001404dd68      2d6  2 868",
-"    ffffea00000003b8    11000 ffff88001404dd68      2d7  2 868",
-"    ffffea00000003f0    12000 ffff88001404dd68      2d8  2 868",
-"    ffffea0000000428    13000 ffff88001404dd68      2d9  2 868",
-"    ffffea0000000460    14000 ffff88001404dd68      2da  2 868",
-"    ffffea0000000498    15000 ffff88001404dd68      2db  2 868",
-"    ffffea00000004d0    16000 ffff88001404dd68      2dc  2 868",
+"      PAGE    PHYSICAL   MAPPING    INDEX CNT FLAGS",
+"    f5c51200     10000         0         0  1 80 slab",
+"    f5c51220     11000         0         0  1 80 slab",
+"    f5c51240     12000         0         0  1 80 slab",
+"    f5c51260     13000         0         0  1 80 slab",
+"    f5c51280     14000         0         0  1 80 slab",
+"    f5c512a0     15000         0         0  1 80 slab",
+"    f5c512c0     16000         0         0  1 80 slab",
+"    f5c512e0     17000         0         0  1 80 slab",
+"    f5c51300     18000         0         0  1 80 slab",
+"    f5c51320     19000         0         0  1 80 slab",
+"    f5c51340     1a000         0         0  1 80 slab",
+"    f5c51360     1b000         0         0  1 80 slab",
+"    f5c51380     1c000  e6c6a754     13b67  2 868 uptodate,lru,active,private",
+"    f5c513a0     1d000         0         0  1 80 slab",
+"    f5c513c0     1e000         0         0  1 80 slab",
+"    f5c513e0     1f000         0         0  1 80 slab",
+"    f5c51400     20000  e6c6a754     13bbb  2 868 uptodate,lru,active,private",
+"    f5c51420     21000         0         0  1 80 slab",
+"    f5c51440     22000         0         0  1 80 slab",
 "    ...",
 "    ",
 "  Use the commands above with a page pointer or a physical address argument:\n",
@@ -5469,12 +5567,14 @@ char *help_kmem[] = {
 "      2    16k      c02eb01c      ",
 "    c40425b0  (c40425b0 is 1st of 4 pages) ",
 " ",
-"    %s> kmem -p c035de00",
-"      PAGE    PHYSICAL   INODE     OFFSET  CNT FLAGS",
-"    c035de00   50c0000         0    129000  0  uptodate\n",
-"    %s> kmem -p 50c0000",
-"      PAGE    PHYSICAL   INODE     OFFSET  CNT FLAGS",
-"    c035de00   50c0000         0    129000  0  uptodate\n",
+"    %s> kmem -p c25a9c00",
+"      PAGE     PHYSICAL   MAPPING    INDEX CNT FLAGS",
+"    c25a9c00    1fe0000  f429d2e4   21fe3eb  2 800828 uptodate,lru,private",
+" ",
+"    %s> kmem -p 1fe0000",
+"      PAGE     PHYSICAL   MAPPING    INDEX CNT FLAGS",
+"    c25a9c00    1fe0000  f429d2e4   21fe3eb  2 800828 uptodate,lru,private",
+" ",
 "  Display the mapped memory regions allocated by vmalloc():\n",
 "    %s> kmem -v",
 "    VMAP_AREA  VM_STRUCT     ADDRESS RANGE        SIZE",
--- crash-7.0.2/task.c	2013-10-25 15:28:55.949879567 -0400
+++ crash-7.0.3/task.c	2013-10-17 14:42:50.532672513 -0400
@@ -474,7 +474,7 @@ task_init(void)
 		tt->this_task = pid_to_task(active_pid);
 	}
 	else {
-		if (KDUMP_DUMPFILE())
+		if (KDUMP_DUMPFILE() && !(pc->flags2 & QEMU_MEM_DUMP))
 			map_cpus_to_prstatus();
 		else if (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE())
 			map_cpus_to_prstatus_kdump_cmprs();
@@ -4873,10 +4873,10 @@ task_mm(ulong task, int fill)
 char *
 task_cpu(int processor, char *buf, int verbose)
 {
-	if (processor < NO_PROC_ID)
+	if (processor < NR_CPUS)
 		sprintf(buf, "%d", processor);
-	if (processor == NO_PROC_ID)
-		sprintf(buf, verbose ? "NO_PROC_ID" : "-");
+	else
+		sprintf(buf, verbose ? "(unknown)" : "?");
 
         return buf;
 }
--- crash-7.0.2/kernel.c	2013-10-25 15:28:55.958879567 -0400
+++ crash-7.0.3/kernel.c	2013-10-25 10:13:04.143747815 -0400
@@ -5377,7 +5377,6 @@ cmd_irq(void)
         int i, c;
 	int nr_irqs;
 	ulong *cpus;
-	int len;
 	int show_intr, choose_cpu;
 	char buf[10];
 	char arg_buf[BUFSIZE];
@@ -5485,9 +5484,7 @@ cmd_irq(void)
 		error(FATAL, "cannot determine number of IRQs\n");
 
 	if (show_intr) {
-		if ((len = STRUCT_SIZE("cpumask_t")) < 0)
-			len = DIV_ROUND_UP(kt->cpus, BITS_PER_LONG) * sizeof(ulong);
-		cpus = (ulong *)GETBUF(len);
+		cpus = get_cpumask_buf();
 
 		if (choose_cpu) {
 			make_cpumask(arg_buf, cpus, FAULT_ON_ERROR, NULL);
@@ -5648,6 +5645,7 @@ generic_dump_irq(int irq)
 	ulong tmp1, tmp2;
 
 	handler = UNINITIALIZED;
+	action = 0;
 	
 	irq_desc_addr = get_irq_desc_addr(irq);
 	if (!irq_desc_addr && symbol_exists("irq_desc_ptrs")) {
@@ -8398,6 +8396,7 @@ static void add_ikconfig_entry(char *lin
 static int setup_ikconfig(char *config)
 {
 	char *ent, *tokptr;
+	struct ikconfig_list *new;
 
 	ikconfig_all = calloc(1, sizeof(struct ikconfig_list) * IKCONFIG_MAX);
 	if (!ikconfig_all) {
@@ -8424,8 +8423,9 @@ static int setup_ikconfig(char *config)
 		free(ikconfig_all);
 		return 0;
 	}
-	ikconfig_all = realloc(ikconfig_all,
-			   sizeof(struct ikconfig_list) * kt->ikconfig_ents);
+	if ((new = realloc(ikconfig_all,
+	    sizeof(struct ikconfig_list) * kt->ikconfig_ents)))
+		ikconfig_all = new;
 
 	return 1;
 }
--- crash-7.0.2/gdb_interface.c	2013-10-25 15:28:55.936879568 -0400
+++ crash-7.0.3/gdb_interface.c	2013-10-15 15:55:20.440389792 -0400
@@ -357,8 +357,8 @@ gdb_interface(struct gnu_request *req)
 		restart(0);
 
 	if (!req->fp) {
-		req->fp = pc->flags & RUNTIME ? fp : 
-			  CRASHDEBUG(1) ? fp : pc->nullfp;
+		req->fp = ((pc->flags & RUNTIME) || (pc->flags2 & ALLOW_FP)) ? 
+			fp : CRASHDEBUG(1) ? fp : pc->nullfp;
 	}
 
 	pc->cur_req = req;
--- crash-7.0.2/configure.c	2013-10-25 15:28:55.956879567 -0400
+++ crash-7.0.3/configure.c	2013-10-25 10:09:47.567756821 -0400
@@ -790,7 +790,7 @@ make_rh_rpm_package(char *package, int r
 				break;
 			} 
 		}
-		fclose(fp);
+		pclose(fp);
 	
 		if (!cur) {
 			fprintf(stderr, "cannot get version from \"crash -v\"\n");
--- crash-7.0.2/net.c	2013-10-25 15:28:55.923879569 -0400
+++ crash-7.0.3/net.c	2013-10-22 09:42:52.103705675 -0400
@@ -1,8 +1,8 @@
 /* net.c - core analysis suite
  *
  * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
- * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 David Anderson
- * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2002-2013 David Anderson
+ * Copyright (C) 2002-2013 Red Hat, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -231,10 +231,22 @@ net_init(void)
 				} else if ((MEMBER_OFFSET("inet_sock", "sk") == 0) &&
 				    (MEMBER_OFFSET("sock", "__sk_common") == 0)) {
 					MEMBER_OFFSET_INIT(inet_opt_daddr, "sock_common", "skc_daddr");
+					if (INVALID_MEMBER(inet_opt_daddr))
+						ANON_MEMBER_OFFSET_INIT(inet_opt_daddr, "sock_common", 
+							"skc_daddr");
 					MEMBER_OFFSET_INIT(inet_opt_rcv_saddr, "sock_common", "skc_rcv_saddr");
+					if (INVALID_MEMBER(inet_opt_rcv_saddr))
+						ANON_MEMBER_OFFSET_INIT(inet_opt_rcv_saddr, "sock_common",
+							"skc_rcv_saddr");
 					MEMBER_OFFSET_INIT(inet_opt_dport, "inet_sock", "inet_dport");
+					if (INVALID_MEMBER(inet_opt_dport))
+						ANON_MEMBER_OFFSET_INIT(inet_opt_dport, "sock_common", 
+							"skc_dport");
 					MEMBER_OFFSET_INIT(inet_opt_sport, "inet_sock", "inet_sport");
 					MEMBER_OFFSET_INIT(inet_opt_num, "inet_sock", "inet_num");
+					if (INVALID_MEMBER(inet_opt_num))
+						ANON_MEMBER_OFFSET_INIT(inet_opt_num, "sock_common", 
+							"skc_num");
 				}
 			}	
 
--- crash-7.0.2/s390x.c	2013-10-25 15:28:55.928879568 -0400
+++ crash-7.0.3/s390x.c	2013-10-10 14:57:54.080339089 -0400
@@ -590,9 +590,12 @@ static int swap_entry(ulong entry)
 	if (THIS_KERNEL_VERSION < LINUX(2,6,19)) {
 		if ((entry & 0x601ULL) == 0x600ULL)
 			return 1;
-	} else {
+	} if (THIS_KERNEL_VERSION < LINUX(3,12,0)) {
 		if ((entry & 0x403ULL) == 0x403ULL)
 			return 1;
+	} else {
+		if ((entry & 0x603ULL) == 0x402ULL)
+			return 1;
 	}
 	return 0;
 }
--- crash-7.0.2/x86_64.c	2013-10-25 15:28:55.928879568 -0400
+++ crash-7.0.3/x86_64.c	2013-10-17 09:25:14.265545546 -0400
@@ -7251,6 +7251,9 @@ x86_64_get_framesize(struct bt_info *bt,
 		}
 	}
 
+	if ((sp->value >= kt->init_begin) && (sp->value < kt->init_end))
+		return 0;
+
 	framesize = max = 0;
         max_instructions = textaddr - sp->value; 
 	instr = arg = -1;
--- crash-7.0.2/remote.c	2013-10-25 15:28:55.935879568 -0400
+++ crash-7.0.3/remote.c	2013-10-25 10:09:51.680756632 -0400
@@ -1116,8 +1116,10 @@ daemon_proc_version(char *buf)
                 return FALSE;
 
         if (fread(buf, sizeof(char),
-                BUFSIZE-1, pipe) <= 0)
+                BUFSIZE-1, pipe) <= 0) {
+		pclose(pipe);
                 return FALSE;
+	}
 
         pclose(pipe);
 
--- crash-7.0.2/va_server.c	2013-10-25 15:28:55.939879568 -0400
+++ crash-7.0.3/va_server.c	2013-10-25 10:09:58.528756319 -0400
@@ -313,6 +313,7 @@ int read_map(char *crash_file)
 	ret = fseek(vas_file_p, (long)0, SEEK_SET);
 	if(ret == -1) {
 		printf("va_server: unable to fseek, err = %d\n", ferror(vas_file_p));
+		free(disk_hdr);
 		return -1;
 	}
 	items = fread((void *)disk_hdr, 1, Page_Size, vas_file_p);
--- crash-7.0.2/va_server_v1.c	2013-10-25 15:28:55.935879568 -0400
+++ crash-7.0.3/va_server_v1.c	2013-10-25 10:10:02.032756158 -0400
@@ -308,6 +308,7 @@ int read_map_v1(int blk_pos)
 	ret = fseek(vas_file_p, (long)(blk_pos*Page_Size), SEEK_SET);
 	if(ret == -1) {
 		console("va_server: unable to fseek, err = %d\n", ferror(vas_file_p));
+		free(disk_hdr);
 		return -1;
 	}
 	items = fread((void *)disk_hdr, 1, Page_Size, vas_file_p);
--- crash-7.0.2/symbols.c	2013-10-25 15:28:55.956879567 -0400
+++ crash-7.0.3/symbols.c	2013-10-24 15:33:12.359826102 -0400
@@ -72,7 +72,10 @@ struct elf_common;
 static void Elf32_Sym_to_common(Elf32_Sym *, struct elf_common *); 
 static void Elf64_Sym_to_common(Elf64_Sym *, struct elf_common *); 
 static void cmd_datatype_common(ulong);
-static int display_per_cpu_info(struct syment *);
+static void do_datatype_addr(struct datatype_member *, ulong, int,
+			     ulong, char **, int);
+static void process_gdb_output(char *, unsigned, const char *, int);
+static int display_per_cpu_info(struct syment *, int, char *);
 static struct load_module *get_module_percpu_sym_owner(struct syment *);
 static int is_percpu_symbol(struct syment *);
 static void dump_percpu_symbols(struct load_module *);
@@ -116,6 +119,8 @@ static int show_member_offset(FILE *, st
 #define IN_STRUCT      (0x40000)
 #define DATATYPE_QUERY (0x80000)
 #define ANON_MEMBER_QUERY (0x100000)
+#define SHOW_RAW_DATA     (0x200000)
+#define DEREF_POINTERS    (0x400000)
 
 #define INTEGER_TYPE    (UINT8|INT8|UINT16|INT16|UINT32|INT32|UINT64|INT64)
 
@@ -132,6 +137,7 @@ static void dump_datatype_flags(ulong, F
 static long anon_member_offset(char *, char *);
 static int gdb_whatis(char *);
 static void do_datatype_declaration(struct datatype_member *, ulong);
+static int member_to_datatype(char *, struct datatype_member *, ulong);
 
 #define DEBUGINFO_ERROR_MESSAGE1 \
 "the use of a System.map file requires that the accompanying namelist\nargument is a kernel file built with the -g CFLAG.  The namelist argument\nsupplied in this case is a debuginfo file, which must be accompanied by the\nkernel file from which it was derived.\n"
@@ -5704,13 +5710,13 @@ dereference_pointer(ulong addr, struct d
 static void 
 cmd_datatype_common(ulong flags)
 {
-	int i, c;
+	int c;
 	ulong addr, aflag;
+	char *cpuspec;
+	ulong *cpus;
 	struct syment *sp;
-	int rawdata;
-	long len;
 	ulong list_head_offset;
-	int count, pflag;
+	int count;
 	int argc_members;
 	int optind_save;
 	unsigned int radix, restore_radix;
@@ -5721,19 +5727,19 @@ cmd_datatype_common(ulong flags)
 
         dm = &datatype_member;
 	count = 0xdeadbeef;
-	rawdata = 0;
 	aflag = addr = 0;
         list_head_offset = 0;
         argc_members = 0;
 	radix = restore_radix = 0;
 	separator = members = NULL;
-	pflag = 0;
+	cpuspec = NULL;
+	cpus = NULL;
 
         while ((c = getopt(argcnt, args, "pxdhfuc:rvol:")) != EOF) {
                 switch (c)
 		{
 		case 'p':
-			pflag++;
+			flags |= DEREF_POINTERS;
 			break;
 
 		case 'd':
@@ -5756,7 +5762,7 @@ cmd_datatype_common(ulong flags)
 			break;
 
 		case 'r':
-			rawdata = 1;
+			flags |= SHOW_RAW_DATA;
 			break;
 
 		case 'v':
@@ -5816,11 +5822,22 @@ cmd_datatype_common(ulong flags)
 		if (aflag && (count != 0xdeadbeef))
 			error(FATAL, "too many arguments!\n");
 
+		if (!aflag) {
+			cpuspec = strchr(args[optind], ':');
+			if (cpuspec)
+				*cpuspec++ = NULLCHAR;
+		}
+
 		if (clean_arg() && IS_A_NUMBER(args[optind])) { 
 			if (aflag) 
 				count = stol(args[optind], 
 					FAULT_ON_ERROR, NULL);
-			else {
+			else if (cpuspec) {
+				if (pc->curcmd_flags & MEMTYPE_FILEADDR)
+					error(FATAL, "-f option cannot be used with percpu\n");
+				addr = htol(args[optind], FAULT_ON_ERROR, NULL);
+				aflag++;
+			} else {
 				if (pc->curcmd_flags & MEMTYPE_FILEADDR)
 					pc->curcmd_private = stoll(args[optind], 
 						FAULT_ON_ERROR, NULL);
@@ -5835,6 +5852,12 @@ cmd_datatype_common(ulong flags)
 				aflag++;
 			}
 		} else if ((sp = symbol_search(args[optind]))) {
+			if (cpuspec && !is_percpu_symbol(sp)) {
+				error(WARNING,
+				      "%s is not percpu; cpuspec ignored.\n",
+				      sp->name);
+				cpuspec = NULL;
+			}
 	                addr = sp->value;
 			aflag++;
 	        } else {
@@ -5846,6 +5869,14 @@ cmd_datatype_common(ulong flags)
 		}
 	}
 
+	if (cpuspec) {
+		cpus = get_cpumask_buf();
+		if (STREQ(cpuspec, ""))
+			SET_BIT(cpus, CURRENT_CONTEXT()->processor);
+		else
+			make_cpumask(cpuspec, cpus, FAULT_ON_ERROR, NULL);
+	}
+
 	optind = optind_save;
 
 	if (count == 0xdeadbeef)
@@ -5853,7 +5884,7 @@ cmd_datatype_common(ulong flags)
 	else if (!aflag)
 		error(FATAL, "no kernel virtual address argument entered\n");
 
-	if (pflag && !aflag)
+	if ((flags & DEREF_POINTERS) && !aflag)
 		error(FATAL, "-p option requires address argument\n");
 
 	if (list_head_offset)
@@ -5878,6 +5909,15 @@ cmd_datatype_common(ulong flags)
 		DATATYPE_QUERY|ANON_MEMBER_QUERY|RETURN_ON_ERROR) < 1))
 		error(FATAL, "invalid data structure reference: %s\n", structname);
 
+	if (! (flags & (STRUCT_REQUEST|UNION_REQUEST)) ) {
+		flags |= dm->type;
+		if (!(flags & (UNION_REQUEST|STRUCT_REQUEST)))
+			error(FATAL, "invalid argument");
+	} else if ( (flags &(STRUCT_REQUEST|UNION_REQUEST)) != dm->type) {
+		error(FATAL, "data type mismatch: %s is not a %s\n",
+		      dm->name, flags & UNION_REQUEST ? "union" : "struct");
+	}
+
         if ((argc_members > 1) && !aflag) {
                 error(INFO, flags & SHOW_OFFSET ? 
 		    "-o option not valid with multiple member format\n" :
@@ -5891,7 +5931,52 @@ cmd_datatype_common(ulong flags)
 		error(FATAL, 
 		    "-o option not valid with multiple member format\n");
 
-	len = dm->size;
+	set_temporary_radix(radix, &restore_radix);
+
+	/*
+	 *  No address was passed -- dump the structure/member declaration.
+	 */
+	if (!aflag) {
+		if (argc_members &&
+		    !member_to_datatype(memberlist[0], dm,
+					ANON_MEMBER_QUERY))
+			error(FATAL, "invalid data structure reference: %s.%s\n",
+			      dm->name, memberlist[0]);
+		do_datatype_declaration(dm, flags | (dm->flags & TYPEDEF));
+	} else if (cpus) {
+		for (c = 0; c < kt->cpus; c++) {
+			ulong cpuaddr;
+
+			if (!NUM_IN_BITMAP(cpus, c))
+				continue;
+
+			cpuaddr = addr + kt->__per_cpu_offset[c];
+			fprintf(fp, "[%d]: %lx\n", c, cpuaddr);
+			do_datatype_addr(dm, cpuaddr , count,
+					 flags, memberlist, argc_members);
+		}
+	} else
+		do_datatype_addr(dm, addr, count, flags,
+				 memberlist, argc_members);
+
+	restore_current_radix(restore_radix);
+
+freebuf:
+        if (argc_members) {
+                FREEBUF(structname);
+                FREEBUF(members);
+	}
+
+	if (cpus)
+		FREEBUF(cpus);
+}
+
+static void
+do_datatype_addr(struct datatype_member *dm, ulong addr, int count,
+		 ulong flags, char **memberlist, int argc_members)
+{
+	int i, c;
+	long len = dm->size;
 
 	if (count < 0) {
 		addr -= len * abs(count);
@@ -5908,83 +5993,44 @@ cmd_datatype_common(ulong flags)
 		i = 0;
         	do {
                 	if (argc_members) {
-                        	*separator = '.';
-                        	strcpy(separator+1, memberlist[i]);
-			}
-
-			switch (arg_to_datatype(structname, dm,
-				ANON_MEMBER_QUERY|RETURN_ON_ERROR))
-			{
-			case 0: error(FATAL, "invalid data structure reference: %s\n", 
-					structname);
-				break;
-			case 1: break;
-			case 2: if (rawdata)
+				if (!member_to_datatype(memberlist[i], dm,
+							ANON_MEMBER_QUERY))
+					error(FATAL, "invalid data structure reference: %s.%s\n",
+					      dm->name, memberlist[i]);
+				if (flags & SHOW_RAW_DATA)
         				error(FATAL, 
-					    "member-specific output not allowed with -r\n");
-				break;
+					      "member-specific output not allowed with -r\n");
 			}
 
-			if (!(dm->flags & TYPEDEF)) {
-				if (flags &(STRUCT_REQUEST|UNION_REQUEST) ) {
-					if ((flags & (STRUCT_REQUEST|UNION_REQUEST)) != dm->type) 
-						goto freebuf;
-				} else
-					flags |= dm->type;
-			}
-
-			/* 
-	 		 *  No address was passed -- dump the structure/member declaration.
-	 		 */
-			if (!aflag || (aflag && (flags & SHOW_OFFSET))) {
-				if (aflag)
-					dm->vaddr = addr;
-				set_temporary_radix(radix, &restore_radix);
-				do_datatype_declaration(dm, flags | (dm->flags & TYPEDEF));
-				restore_current_radix(restore_radix);
-				goto freebuf;
-			}
-
-			if (!(flags & (UNION_REQUEST|STRUCT_REQUEST)))
-				error(FATAL, "invalid argument");
-
 			/*
-		 	 *  Display data.
+		 	 *  Display member addresses or data
 		 	 */
-			if (rawdata)
+			if (flags & SHOW_OFFSET) {
+				dm->vaddr = addr;
+				do_datatype_declaration(dm, flags | (dm->flags & TYPEDEF));
+			} else if (flags & SHOW_RAW_DATA)
 				raw_data_dump(addr, len, flags & STRUCT_VERBOSE);
-			else if (pflag && !dm->member) {
-				set_temporary_radix(radix, &restore_radix);
+			else if ((flags & DEREF_POINTERS) && !dm->member) {
 				print_struct_with_dereference(addr, dm, flags);
-				restore_current_radix(restore_radix);
                 	} else {
 	                        if (dm->member)
 	                                open_tmpfile();
 	
-				set_temporary_radix(radix, &restore_radix);
-
 				if (flags & UNION_REQUEST)
 					print_union(dm->name, addr);
 				else if (flags & STRUCT_REQUEST)
 					print_struct(dm->name, addr);
 
 				if (dm->member) {
-					if (!(pflag && 
+					if (!((flags & DEREF_POINTERS) &&
 				    	    dereference_pointer(addr, dm, flags)))
 						parse_for_member(dm, PARSE_FOR_DATA);
 					close_tmpfile();
 				}
 
-				restore_current_radix(restore_radix);
                 	}
 		} while (++i < argc_members);
         }
-
-freebuf:
-        if (argc_members) {
-                FREEBUF(structname);
-                FREEBUF(members);
-	}
 }
 
 
@@ -6108,13 +6154,7 @@ arg_to_datatype(char *s, struct datatype
 	if (!both) 
 		return 1;
 
-	dm->member = p1+1;
-
-	if ((dm->member_offset = MEMBER_OFFSET(dm->name, dm->member)) >= 0)
-		return 2;
-
-	if ((flags & ANON_MEMBER_QUERY) &&
-	    ((dm->member_offset = ANON_MEMBER_OFFSET(dm->name, dm->member)) >= 0))
+	if (member_to_datatype(p1 + 1, dm, flags))
 		return 2;
 
 datatype_member_fatal:
@@ -6137,6 +6177,21 @@ datatype_member_fatal:
        	return (error(FATAL, "invalid argument: %s\n", s));
 }
 
+static int
+member_to_datatype(char *s, struct datatype_member *dm, ulong flags)
+{
+	dm->member = s;
+
+	if ((dm->member_offset = MEMBER_OFFSET(dm->name, s)) >= 0)
+		return TRUE;
+
+	if ((flags & ANON_MEMBER_QUERY) &&
+	    ((dm->member_offset = ANON_MEMBER_OFFSET(dm->name, s)) >= 0))
+		return TRUE;
+
+	return FALSE;
+}
+
 /*
  *  debug routine -- not called on purpose by anybody.
  */
@@ -6388,13 +6443,12 @@ cmd_p(void)
 {
         int c;
 	struct syment *sp, *percpu_sp;
-	unsigned radix, restore_radix;
-	int leader, do_load_module_filter, success;
+	unsigned radix;
+	int do_load_module_filter;
 	char buf1[BUFSIZE]; 
-	char buf2[BUFSIZE]; 
-	char *p1;
+	char *cpuspec;
 
-	leader = do_load_module_filter = radix = restore_radix = 0;
+	do_load_module_filter = radix = 0;
 
         while ((c = getopt(argcnt, args, "dhxu")) != EOF) {
                 switch(c)
@@ -6427,33 +6481,57 @@ cmd_p(void)
         if (argerrs || !args[optind])
                 cmd_usage(pc->curcmd, SYNOPSIS);
 
+	cpuspec = strrchr(args[optind], ':');
+	if (cpuspec)
+		*cpuspec++ = NULLCHAR;
+
+	sp = NULL;
 	if ((sp = symbol_search(args[optind])) && !args[optind+1]) {
 		if ((percpu_sp = per_cpu_symbol_search(args[optind])) &&
-		    display_per_cpu_info(percpu_sp))
+		    display_per_cpu_info(percpu_sp, radix, cpuspec))
 			return;
-		sprintf(buf2, "%s = ", args[optind]);
-		leader = strlen(buf2);
 		if (module_symbol(sp->value, NULL, NULL, NULL, *gdb_output_radix))
 			do_load_module_filter = TRUE;
 	} else if ((percpu_sp = per_cpu_symbol_search(args[optind])) &&
-		   display_per_cpu_info(percpu_sp))
+		   display_per_cpu_info(percpu_sp, radix, cpuspec))
 		return;
 	else if (st->flags & LOAD_MODULE_SYMS)
 		do_load_module_filter = TRUE;
 
+	if (cpuspec) {
+		if (sp)
+			error(WARNING, "%s is not percpu; cpuspec ignored.\n",
+			      sp->name);
+		else
+			/* maybe a valid C expression (e.g. ':') */
+			*(cpuspec-1) = ':';
+	}
+
+	process_gdb_output(concat_args(buf1, 0, TRUE), radix,
+			   sp ? sp->name : NULL, do_load_module_filter);
+}
+
+static void
+process_gdb_output(char *gdb_request, unsigned radix,
+		   const char *leader, int do_load_module_filter)
+{
+	unsigned restore_radix;
+	int success;
+	char buf1[BUFSIZE]; 
+	char *p1;
+
 	if (leader || do_load_module_filter)
 		open_tmpfile();
 
 	set_temporary_radix(radix, &restore_radix);
 
-       	success = gdb_pass_through(concat_args(buf1, 0, TRUE), NULL, 
-		GNU_RETURN_ON_ERROR);
+       	success = gdb_pass_through(gdb_request, NULL, GNU_RETURN_ON_ERROR);
 
 	if (success && (leader || do_load_module_filter)) {
 		int firstline;
 
 		if (leader) {
-			fprintf(pc->saved_fp, "%s", buf2);
+			fprintf(pc->saved_fp, "%s = ", leader);
 			fflush(pc->saved_fp);
 		}
 
@@ -6482,8 +6560,41 @@ cmd_p(void)
 	restore_current_radix(restore_radix);
 
 	if (!success) 
-		error(FATAL, "gdb request failed: %s\n",
-			concat_args(buf1, 0, TRUE));
+		error(FATAL, "gdb request failed: %s\n", gdb_request);
+}
+
+/*
+ *  Get the type of an expression using gdb's "whatis" command.
+ *  The returned string is dynamically allocated, and it should
+ *  be passed to FREEBUF() when no longer needed.
+ *  Return NULL if the type cannot be determined.
+ */
+static char *
+expr_type_name(const char *expr)
+{
+	char buf[BUFSIZE], *p;
+
+	open_tmpfile();
+	sprintf(buf, "whatis %s", expr);
+	if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) {
+		close_tmpfile();
+		return NULL;
+	}
+
+	rewind(pc->tmpfile);
+	while (fgets(buf, BUFSIZE, pc->tmpfile) && !STRNEQ(buf, "type = "))
+		;
+	p = feof(pc->tmpfile) ? NULL : buf + strlen("type = ");
+	close_tmpfile();
+
+	if (p) {
+		size_t len = strlen(clean_line(p));
+		/* GDB reports unknown types as <...descriptive text...> */
+		if (p[0] == '<' && p[len-1] == '>')
+			return NULL;
+		return strcpy(GETBUF(len + 1), p);
+	}
+	return NULL;
 }
 
 /*
@@ -6491,30 +6602,73 @@ cmd_p(void)
  *  the addresses of each its per-cpu instances.
  */
 static int
-display_per_cpu_info(struct syment *sp)
+display_per_cpu_info(struct syment *sp, int radix, char *cpuspec)
 {
+	ulong *cpus;
 	int c;
 	ulong addr;
 	char buf[BUFSIZE];
+	char leader[sizeof("&per_cpu(") + strlen(sp->name) +
+		    sizeof(", " STR(UINT_MAX) ")")];
+	char *typename;
+	int do_load_module_filter;
 
 	if (((kt->flags & (SMP|PER_CPU_OFF)) != (SMP|PER_CPU_OFF)) ||
 	    (!is_percpu_symbol(sp)) ||
 	    !((sp->type == 'd') || (sp->type == 'D') || (sp->type == 'V')))
 		return FALSE;
 
-	fprintf(fp, "PER-CPU DATA TYPE:\n  ");
-        sprintf(buf, "whatis %s", sp->name);
-        if (!gdb_pass_through(buf, pc->nullfp, GNU_RETURN_ON_ERROR))
-                fprintf(fp, "[undetermined type] %s;\n", sp->name);
-	else
-        	whatis_variable(sp);
+	if (cpuspec) {
+		cpus = get_cpumask_buf();
+		if (STREQ(cpuspec, ""))
+			SET_BIT(cpus, CURRENT_CONTEXT()->processor);
+		else
+			make_cpumask(cpuspec, cpus, FAULT_ON_ERROR, NULL);
+	} else
+		cpus = NULL;
+
+	typename = expr_type_name(sp->name);
+
+	if (!cpus) {
+		fprintf(fp, "PER-CPU DATA TYPE:\n  ");
+		if (!typename)
+			fprintf(fp, "[undetermined type] %s;\n", sp->name);
+		else
+			whatis_variable(sp);
+
+		fprintf(fp, "PER-CPU ADDRESSES:\n");
+	}
+
+	do_load_module_filter =
+		module_symbol(sp->value, NULL, NULL, NULL, *gdb_output_radix);
 
-	fprintf(fp, "PER-CPU ADDRESSES:\n");
 	for (c = 0; c < kt->cpus; c++) {
+		if (cpus && !NUM_IN_BITMAP(cpus, c))
+			continue;
 		addr = sp->value + kt->__per_cpu_offset[c];
-		fprintf(fp, "  [%d]: %lx\n", c, addr);
+		if (!cpus)
+			fprintf(fp, "  [%d]: %lx\n", c, addr);
+		else if (typename) {
+			snprintf(buf, sizeof buf, "p *(%s*) 0x%lx",
+				 typename, addr);
+			sprintf(leader, "per_cpu(%s, %u)",
+				sp->name, c);
+			process_gdb_output(buf, radix, leader,
+					   do_load_module_filter);
+		} else {
+			snprintf(buf, sizeof buf, "p (void*) 0x%lx", addr);
+			sprintf(leader, "&per_cpu(%s, %u)",
+				sp->name, c);
+			process_gdb_output(buf, radix, leader,
+					   do_load_module_filter);
+		}
 	}
 
+	if (typename)
+		FREEBUF(typename);
+	if (cpus)
+		FREEBUF(cpus);
+
 	return TRUE;
 }
 
@@ -6859,6 +7013,10 @@ dump_datatype_flags(ulong flags, FILE *o
 		fprintf(ofp, "%sDATATYPE_QUERY", others++ ? "|" : "");
 	if (flags & ANON_MEMBER_QUERY)
 		fprintf(ofp, "%sANON_MEMBER_QUERY", others++ ? "|" : "");
+	if (flags & SHOW_RAW_DATA)
+		fprintf(ofp, "%sSHOW_RAW_DATA", others++ ? "|" : "");
+	if (flags & DEREF_POINTERS)
+		fprintf(ofp, "%sDEREF_POINTERS", others++ ? "|" : "");
 	fprintf(ofp, ")\n");
 }
 
@@ -7890,11 +8048,18 @@ dump_offset_table(char *spec, ulong make
                 OFFSET(page_objects));
         fprintf(fp, "                     page_slab: %ld\n",
                 OFFSET(page_slab));
+        fprintf(fp, "                page_slab_page: %ld\n",
+                OFFSET(page_slab_page));
         fprintf(fp, "               page_first_page: %ld\n",
                 OFFSET(page_first_page));
         fprintf(fp, "                 page_freelist: %ld\n",
                 OFFSET(page_freelist));
 
+	fprintf(fp, "        trace_print_flags_mask: %ld\n",
+		OFFSET(trace_print_flags_mask));
+	fprintf(fp, "        trace_print_flags_name: %ld\n",
+		OFFSET(trace_print_flags_name));
+
         fprintf(fp, "    swap_info_struct_swap_file: %ld\n",
 		OFFSET(swap_info_struct_swap_file));
         fprintf(fp, "  swap_info_struct_swap_vfsmnt: %ld\n",
@@ -9021,6 +9186,7 @@ dump_offset_table(char *spec, ulong make
 	fprintf(fp, "\n                    size_table:\n");
 	fprintf(fp, "                          page: %ld\n", SIZE(page));
 	fprintf(fp, "                    page_flags: %ld\n", SIZE(page_flags));
+	fprintf(fp, "             trace_print_flags: %ld\n", SIZE(trace_print_flags));
         fprintf(fp, "              free_area_struct: %ld\n", 
 		SIZE(free_area_struct));
         fprintf(fp, "                     free_area: %ld\n", 
--- crash-7.0.2/diskdump.c	2013-10-25 15:28:55.941879568 -0400
+++ crash-7.0.3/diskdump.c	2013-10-23 09:12:15.913831516 -0400
@@ -40,11 +40,13 @@ struct diskdump_data {
 	struct disk_dump_sub_header	*sub_header;
 	struct kdump_sub_header		*sub_header_kdump;
 
+	unsigned long long	max_mapnr;	/* 64bit max_mapnr */
+
 	size_t	data_offset;
 	int	block_size;
 	int	block_shift;
 	char	*bitmap;
-	int	bitmap_len;
+	off_t	bitmap_len;
 	char	*dumpable_bitmap;
 	int	byte, bit;
 	char	*compressed_page;	/* copy of compressed page data */
@@ -170,9 +172,9 @@ add_diskdump_data(char* name)
 	dd->filename = name;
 
 	if (CRASHDEBUG(1))
-		fprintf(fp, "%s: start_pfn=%lu, end_pfn=%lu\n", name,
-			dd->sub_header_kdump->start_pfn,
-			dd->sub_header_kdump->end_pfn);
+		fprintf(fp, "%s: start_pfn=%llu, end_pfn=%llu\n", name,
+			dd->sub_header_kdump->start_pfn_64,
+			dd->sub_header_kdump->end_pfn_64);
 }
 
 static void 
@@ -199,13 +201,13 @@ get_bit(char *map, int byte, int bit)
 }
 
 static inline int 
-page_is_ram(unsigned int nr)
+page_is_ram(unsigned long nr)
 {
 	return get_bit(dd->bitmap, nr >> 3, nr & 7);
 }
 
 static inline int 
-page_is_dumpable(unsigned int nr)
+page_is_dumpable(unsigned long nr)
 {
 	return dd->dumpable_bitmap[nr>>3] & (1 << (nr & 7));
 }
@@ -214,7 +216,7 @@ static inline int
 dump_is_partial(const struct disk_dump_header *header)
 {
 	return header->bitmap_blocks >=
-	    divideup(divideup(header->max_mapnr, 8), dd->block_size) * 2;
+	    divideup(divideup(dd->max_mapnr, 8), dd->block_size) * 2;
 }
 
 static int 
@@ -321,6 +323,9 @@ x86_process_elf_notes(void *note_ptr, un
  * [40]    unsigned long   size_note;          /  header_version 4 and later  /
  * [44]    off_t           offset_eraseinfo;   /  header_version 5 and later  /
  * [52]    unsigned long   size_eraseinfo;     /  header_version 5 and later  /
+ * [56]    unsigned long long   start_pfn_64;  /  header_version 6 and later  /
+ * [64]    unsigned long long   end_pfn_64;    /  header_version 6 and later  /
+ * [72]    unsigned long long   max_mapnr_64;  /  header_version 6 and later  /
  * };
  * 
  * But when compiled on an ARM processor, each 64-bit "off_t" would be pushed
@@ -337,7 +342,10 @@ x86_process_elf_notes(void *note_ptr, un
  * [40]    off_t           offset_note;        /  header_version 4 and later  /
  * [48]    unsigned long   size_note;          /  header_version 4 and later  /
  * [56]    off_t           offset_eraseinfo;   /  header_version 5 and later  /
- * [62]    unsigned long   size_eraseinfo;     /  header_version 5 and later  /
+ * [64]    unsigned long   size_eraseinfo;     /  header_version 5 and later  /
+ * [72]    unsigned long long   start_pfn_64;  /  header_version 6 and later  /
+ * [80]    unsigned long long   end_pfn_64;    /  header_version 6 and later  /
+ * [88]    unsigned long long   max_mapnr_64;  /  header_version 6 and later  /
  * };
  * 
  */
@@ -357,6 +365,10 @@ struct kdump_sub_header_ARM_target {
 	int 		pad3;	
         off_t           offset_eraseinfo;   /* header_version 5 and later */
         unsigned long   size_eraseinfo;     /* header_version 5 and later */
+	int		pad4;
+	unsigned long long start_pfn_64;    /* header_version 6 and later */
+	unsigned long long end_pfn_64;      /* header_version 6 and later */
+	unsigned long long max_mapnr_64;    /* header_version 6 and later */
 };
 
 static void
@@ -380,6 +392,15 @@ arm_kdump_header_adjust(int header_versi
 		kdsh->offset_eraseinfo = kdsh_ARM_target->offset_eraseinfo;
 		kdsh->size_eraseinfo = kdsh_ARM_target->size_eraseinfo;
 	}
+	if (header_version >= 6) {
+		kdsh->start_pfn_64 = kdsh_ARM_target->start_pfn_64;
+		kdsh->end_pfn_64 = kdsh_ARM_target->end_pfn_64;
+		kdsh->max_mapnr_64 = kdsh_ARM_target->max_mapnr_64;
+	} else {
+		kdsh->start_pfn_64 = kdsh_ARM_target->start_pfn;
+		kdsh->end_pfn_64 = kdsh_ARM_target->end_pfn;
+		kdsh->max_mapnr_64 = dd->max_mapnr;
+	}
 }
 #endif  /* __i386__ && ARM */
 
@@ -390,7 +411,10 @@ read_dump_header(char *file)
 	struct disk_dump_sub_header *sub_header = NULL;
 	struct kdump_sub_header *sub_header_kdump = NULL;
 	size_t size;
-	int bitmap_len;
+	off_t bitmap_len;
+	char *bufptr;
+	size_t len;
+	ssize_t bytes_read;
 	int block_size = (int)sysconf(_SC_PAGESIZE);
 	off_t offset;
 	const off_t failed = (off_t)-1;
@@ -516,6 +540,13 @@ restart:
 			}
 		}
 		dd->sub_header = sub_header;
+
+		/* the 64bit max_mapnr only exists in sub-header of compressed
+		 * kdump file, if it's not a compressed kdump file, we have to
+		 * use the old 32bit max_mapnr in dumpfile header.
+		 * max_mapnr may be truncated here.
+		 */
+		dd->max_mapnr = header->max_mapnr;
 	} else if (KDUMP_CMPRS_VALID()) {
 		if ((sub_header_kdump = malloc(block_size)) == NULL)
 			error(FATAL, "compressed kdump: cannot malloc sub_header_kdump buffer\n");
@@ -540,8 +571,20 @@ restart:
 #if defined(__i386__) && defined(ARM)
 		arm_kdump_header_adjust(header->header_version);
 #endif
+		/* use 64bit max_mapnr in compressed kdump file sub-header */
+		if (header->header_version >= 6)
+			dd->max_mapnr = dd->sub_header_kdump->max_mapnr_64;
+		else {
+			dd->sub_header_kdump->start_pfn_64
+				= dd->sub_header_kdump->start_pfn;
+			dd->sub_header_kdump->end_pfn_64
+				= dd->sub_header_kdump->end_pfn;
+		}
 	}
 
+	if (header->header_version < 6)
+		dd->max_mapnr = header->max_mapnr;
+
 	/* read memory bitmap */
 	bitmap_len = block_size * header->bitmap_blocks;
 	dd->bitmap_len = bitmap_len;
@@ -571,10 +614,18 @@ restart:
 				DISKDUMP_VALID() ? "diskdump" : "compressed kdump");
 			goto err;
 		}
-		if (read(dd->dfd, dd->bitmap, bitmap_len) < bitmap_len) {
-			error(INFO, "%s: cannot read memory bitmap\n",
-				DISKDUMP_VALID() ? "diskdump" : "compressed kdump");
-			goto err;
+		bufptr = dd->bitmap;
+		len = bitmap_len;
+		while (len) {
+			bytes_read = read(dd->dfd, bufptr, len);
+			if (bytes_read  < 0) {
+				error(INFO, "%s: cannot read memory bitmap\n",
+					DISKDUMP_VALID() ? "diskdump"
+					: "compressed kdump");
+				goto err;
+			}
+			len -= bytes_read;
+			bufptr += bytes_read;
 		}
 	}
 
@@ -679,13 +730,13 @@ restart:
 	}
 
 	if (!is_split) {
-		max_sect_len = divideup(header->max_mapnr, BITMAP_SECT_LEN);
+		max_sect_len = divideup(dd->max_mapnr, BITMAP_SECT_LEN);
 		pfn = 0;
 		dd->filename = file;
 	}
 	else {
-		ulong start = sub_header_kdump->start_pfn;
-		ulong end = sub_header_kdump->end_pfn;
+		unsigned long long start = sub_header_kdump->start_pfn_64;
+		unsigned long long end = sub_header_kdump->end_pfn_64;
 		max_sect_len = divideup(end - start + 1, BITMAP_SECT_LEN);
 		pfn = start;
 	}
@@ -727,8 +778,9 @@ pfn_to_pos(ulong pfn)
 	ulong p1, p2;
 
 	if (KDUMP_SPLIT()) {
-		p1 = pfn - dd->sub_header_kdump->start_pfn;
-		p2 = round(p1, BITMAP_SECT_LEN) + dd->sub_header_kdump->start_pfn;
+		p1 = pfn - dd->sub_header_kdump->start_pfn_64;
+		p2 = round(p1, BITMAP_SECT_LEN)
+			+ dd->sub_header_kdump->start_pfn_64;
 	}
 	else {
 		p1 = pfn; 
@@ -1034,12 +1086,12 @@ read_diskdump(int fd, void *bufptr, int
 	if (KDUMP_SPLIT()) {
 		/* Find proper dd */
 		int i;
-		unsigned long start_pfn;
-		unsigned long end_pfn;
+		unsigned long long start_pfn;
+		unsigned long long end_pfn;
 
 		for (i=0; i<num_dumpfiles; i++) {
-			start_pfn = dd_list[i]->sub_header_kdump->start_pfn;
-			end_pfn = dd_list[i]->sub_header_kdump->end_pfn;
+			start_pfn = dd_list[i]->sub_header_kdump->start_pfn_64;
+			end_pfn = dd_list[i]->sub_header_kdump->end_pfn_64;
 			if ((pfn >= start_pfn) && (pfn <= end_pfn))	{
 				dd = dd_list[i];
 				break;
@@ -1058,14 +1110,14 @@ read_diskdump(int fd, void *bufptr, int
 	curpaddr = paddr & ~((physaddr_t)(dd->block_size-1));
 	page_offset = paddr & ((physaddr_t)(dd->block_size-1));
 
-	if ((pfn >= dd->header->max_mapnr) || !page_is_ram(pfn)) {
+	if ((pfn >= dd->max_mapnr) || !page_is_ram(pfn)) {
 		if (CRASHDEBUG(8)) {
 			fprintf(fp, "read_diskdump: SEEK_ERROR: "
 			    "paddr/pfn: %llx/%lx ",
 				(ulonglong)paddr, pfn);
-			if (pfn >= dd->header->max_mapnr)
-				fprintf(fp, "max_mapnr: %x\n",
-					dd->header->max_mapnr);
+			if (pfn >= dd->max_mapnr)
+				fprintf(fp, "max_mapnr: %llx\n",
+					dd->max_mapnr);
 			else
 				fprintf(fp, "!page_is_ram\n");
 		}
@@ -1507,12 +1559,31 @@ __diskdump_memory_dump(FILE *fp)
 	fprintf(fp, "               tv_usec: %lx\n", dh->timestamp.tv_usec);
 	fprintf(fp, "              status: %x (", dh->status);
         others = 0;
-        if (dh->status & DUMP_HEADER_COMPLETED)
-                fprintf(fp, "%sDUMP_HEADER_COMPLETED", others++ ? "|" : "");
-        if (dh->status & DUMP_HEADER_INCOMPLETED)
-                fprintf(fp, "%sDUMP_HEADER_INCOMPLETED", others++ ? "|" : "");
-        if (dh->status & DUMP_HEADER_COMPRESSED)
-                fprintf(fp, "%sDUMP_HEADER_COMPRESSED", others++ ? "|" : "");
+	switch (dd->flags & (DISKDUMP_LOCAL|KDUMP_CMPRS_LOCAL))
+	{
+        case DISKDUMP_LOCAL:
+		if (dh->status == DUMP_HEADER_COMPLETED)
+			fprintf(fp, "%sDUMP_HEADER_COMPLETED", 
+				others++ ? "|" : "");
+		else if (dh->status == DUMP_HEADER_INCOMPLETED)
+			fprintf(fp, "%sDUMP_HEADER_INCOMPLETED", 
+				others++ ? "|" : "");
+		else if (dh->status == DUMP_HEADER_COMPRESSED)
+			fprintf(fp, "%sDUMP_HEADER_COMPRESSED", 
+				others++ ? "|" : "");
+		break;
+	case KDUMP_CMPRS_LOCAL:
+		if (dh->status & DUMP_DH_COMPRESSED_ZLIB)
+			fprintf(fp, "%sDUMP_DH_COMPRESSED_ZLIB", 
+				others++ ? "|" : "");
+		if (dh->status & DUMP_DH_COMPRESSED_LZO)
+			fprintf(fp, "%sDUMP_DH_COMPRESSED_LZO", 
+				others++ ? "|" : "");
+		if (dh->status & DUMP_DH_COMPRESSED_SNAPPY)
+			fprintf(fp, "%sDUMP_DH_COMPRESSED_SNAPPY", 
+				others++ ? "|" : "");
+		break;
+	}
 	fprintf(fp, ")\n");
 	fprintf(fp, "          block_size: %d\n", dh->block_size);
 	fprintf(fp, "        sub_hdr_size: %d\n", dh->sub_hdr_size);
@@ -1662,6 +1733,23 @@ __diskdump_memory_dump(FILE *fp)
 				dump_eraseinfo(fp);
 			}
 		}
+		if (dh->header_version >= 6) {
+			fprintf(fp, "        start_pfn_64: ");
+			if (KDUMP_SPLIT())
+				fprintf(fp, "%lld (0x%llx)\n",
+					kdsh->start_pfn_64, kdsh->start_pfn_64);
+			else
+				fprintf(fp, "(unused)\n");
+			fprintf(fp, "          end_pfn_64: ");
+			if (KDUMP_SPLIT())
+				fprintf(fp, "%lld (0x%llx)\n",
+					kdsh->end_pfn_64, kdsh->end_pfn_64);
+			else
+				fprintf(fp, "(unused)\n");
+
+			fprintf(fp, "        max_mapnr_64: %llu (0x%llx)\n",
+				kdsh->max_mapnr_64, kdsh->max_mapnr_64);
+		}
 		fprintf(fp, "\n");
 	} else
         	fprintf(fp, "(n/a)\n\n");
@@ -1670,7 +1758,8 @@ __diskdump_memory_dump(FILE *fp)
 	fprintf(fp, "        block_size: %d\n", dd->block_size);
 	fprintf(fp, "       block_shift: %d\n", dd->block_shift);
 	fprintf(fp, "            bitmap: %lx\n", (ulong)dd->bitmap);
-	fprintf(fp, "        bitmap_len: %d\n", dd->bitmap_len);
+	fprintf(fp, "        bitmap_len: %lld\n", (ulonglong)dd->bitmap_len);
+	fprintf(fp, "         max_mapnr: %lld (0x%llx)\n", dd->max_mapnr, dd->max_mapnr);
 	fprintf(fp, "   dumpable_bitmap: %lx\n", (ulong)dd->dumpable_bitmap);
 	fprintf(fp, "              byte: %d\n", dd->byte);
 	fprintf(fp, "               bit: %d\n", dd->bit);
--- crash-7.0.2/makedumpfile.c	2013-10-25 15:28:55.951879567 -0400
+++ crash-7.0.3/makedumpfile.c	2013-10-25 10:10:07.615755902 -0400
@@ -59,7 +59,7 @@ store_flat_data_array(char *file, struct
 	unsigned long long	num_allocated = 0;
 	unsigned long long	num_stored    = 0;
 	unsigned long long	size_allocated;
-	struct flat_data	*ptr = NULL, *cur;
+	struct flat_data	*ptr = NULL, *cur, *new;
 	struct makedumpfile_data_header	fdh;
 
 	fd = open(file, O_RDONLY);
@@ -77,12 +77,13 @@ store_flat_data_array(char *file, struct
 			num_allocated += 100;
 			size_allocated = sizeof(struct flat_data)
 					 * num_allocated;
-			ptr = realloc(ptr, size_allocated);
-			if (ptr == NULL) {
+			new = realloc(ptr, size_allocated);
+			if (new == NULL) {
 				error(INFO, 
 				    "unable to realloc flat_data structures\n");
 				break;
 			}
+			ptr = new;
 		}
 		offset_fdh = lseek(fd, 0x0, SEEK_CUR);
 
--- crash-7.0.2/unwind_arm.c	2013-10-25 15:28:55.938879568 -0400
+++ crash-7.0.3/unwind_arm.c	2013-09-06 15:03:40.804904775 -0400
@@ -325,7 +325,8 @@ init_module_unwind_tables(void)
 	hq_open();
 	cnt = do_list(&ld);
 	if (cnt == -1) {
-		error(WARNING, "UNWIND: failed to gather unwind_table list");
+		error(WARNING, "UNWIND: failed to gather unwind_table list\n");
+		hq_close();
 		return FALSE;
 	}
 	table_list = (ulong *)GETBUF(cnt * sizeof(ulong));
--- crash-7.0.2/sadump.c	2013-10-25 15:28:55.941879568 -0400
+++ crash-7.0.3/sadump.c	2013-10-25 10:10:13.104755651 -0400
@@ -18,6 +18,7 @@
 
 #include "defs.h"
 #include "sadump.h"
+#include <arpa/inet.h> /* htonl, htons */
 #include <elf.h>
 
 enum {
@@ -118,7 +119,7 @@ read_dump_header(char *file)
 {
 	struct sadump_part_header *sph = NULL;
 	struct sadump_header *sh = NULL;
-	struct sadump_disk_set_header *sdh = NULL;
+	struct sadump_disk_set_header *new, *sdh = NULL;
 	struct sadump_media_header *smh = NULL;
 	struct sadump_diskset_data *sd_list_len_0 = NULL;
 	size_t block_size = SADUMP_DEFAULT_BLOCK_SIZE;
@@ -127,7 +128,8 @@ read_dump_header(char *file)
 	uint32_t smram_cpu_state_size = 0;
 	ulong bitmap_len, dumpable_bitmap_len;
 	char *bitmap = NULL, *dumpable_bitmap = NULL, *page_buf = NULL;
-	char guid1[33], guid2[33];
+	char guid1[SADUMP_EFI_GUID_TEXT_REPR_LEN+1];
+	char guid2[SADUMP_EFI_GUID_TEXT_REPR_LEN+1];
 
 	sph = malloc(block_size);
 	if (!sph) {
@@ -226,12 +228,13 @@ restart:
 		header_size = header_blocks * block_size;
 
 		if (header_size > block_size) {
-			sdh = realloc(sdh, header_size);
-			if (!sdh) {
+			new = realloc(sdh, header_size);
+			if (!new) {
 				error(INFO, "sadump: cannot re-allocate disk "
 				      "set buffer\n");
 				goto err;
 			}
+			sdh = new;
 		}
 
 		if (!read_device(sdh, header_size, &offset)) {
@@ -468,7 +471,8 @@ add_disk(char *file)
 	struct sadump_part_header *ph;
 	struct sadump_diskset_data *this_disk;
 	int diskid;
-	char guid1[33], guid2[33];
+	char guid1[SADUMP_EFI_GUID_TEXT_REPR_LEN+1];
+	char guid2[SADUMP_EFI_GUID_TEXT_REPR_LEN+1];
 
 	diskid = sd->sd_list_len - 1;
 	this_disk = sd->sd_list[diskid];
@@ -863,7 +867,7 @@ guid_to_str(efi_guid_t *guid, char *buf,
 {
 	snprintf(buf, buflen,
 		 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
-		 guid->data1, guid->data2, guid->data3,
+		 htonl(guid->data1), htons(guid->data2), htons(guid->data3),
 		 guid->data4[0], guid->data4[1], guid->data4[2],
 		 guid->data4[3], guid->data4[4], guid->data4[5],
 		 guid->data4[6], guid->data4[7]);
@@ -905,7 +909,7 @@ int sadump_memory_dump(FILE *fp)
 	struct sadump_header *sh;
 	struct sadump_media_header *smh;
 	int i, others;
-	char guid[33];
+	char guid[SADUMP_EFI_GUID_TEXT_REPR_LEN+1];
 
 	fprintf(fp, "sadump_data: \n");
 	fprintf(fp, "          filename: %s\n", sd->filename);
--- crash-7.0.2/defs.h	2013-10-25 15:28:55.937879568 -0400
+++ crash-7.0.3/defs.h	2013-10-25 11:49:58.544481437 -0400
@@ -59,7 +59,7 @@
 #define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
 #endif
 
-#define BASELEVEL_REVISION  "7.0.2"
+#define BASELEVEL_REVISION  "7.0.3"
 
 #undef TRUE
 #undef FALSE
@@ -503,6 +503,7 @@ struct program_context {
 #define QEMU_MEM_DUMP (0x100ULL)
 #define GET_LOG       (0x200ULL)
 #define VMCOREINFO    (0x400ULL)
+#define ALLOW_FP      (0x800ULL)
 	char *cleanup;
 	char *namelist_orig;
 	char *namelist_debug_orig;
@@ -1876,6 +1877,9 @@ struct offset_table {
 	long task_struct_thread_context_fp;
 	long task_struct_thread_context_sp;
 	long task_struct_thread_context_pc;
+	long page_slab_page;
+	long trace_print_flags_mask;
+	long trace_print_flags_name;
 };
 
 struct size_table {         /* stash of commonly-used sizes */
@@ -2016,6 +2020,7 @@ struct size_table {         /* stash of
 	long hrtimer_clock_base;
 	long hrtimer_base;
 	long tnt;
+	long trace_print_flags;
 };
 
 struct array_table {
@@ -2183,6 +2188,13 @@ struct vm_table {                /* kern
 	int cpu_slab_type;
 	int nr_vm_event_items;
 	char **vm_event_items;
+	int nr_bad_slab_caches;
+	ulong *bad_slab_caches;
+	int nr_pageflags;
+	struct pageflags_data {
+		ulong mask;
+		char *name;
+	} *pageflags_data;
 };
 
 #define NODES                       (0x1)
@@ -2211,6 +2223,7 @@ struct vm_table {                /* kern
 #define NODELISTS_IS_PTR       (0x800000)
 #define KMALLOC_COMMON        (0x1000000)
 #define USE_VMAP_AREA         (0x2000000)
+#define PAGEFLAGS             (0x4000000)
 
 #define IS_FLATMEM()		(vt->flags & FLATMEM)
 #define IS_DISCONTIGMEM()	(vt->flags & DISCONTIGMEM)
@@ -4321,6 +4334,7 @@ int calculate(char *, ulong *, ulonglong
 int endian_mismatch(char *, char, ulong);
 uint16_t swap16(uint16_t, int);
 uint32_t swap32(uint32_t, int);
+ulong *get_cpumask_buf(void);
 int make_cpumask(char *, ulong *, int, int *);
 size_t strlcpy(char *, char *, size_t);
 struct rb_node *rb_first(struct rb_root *);
--- crash-7.0.2/diskdump.h	2013-10-25 15:28:56.133879559 -0400
+++ crash-7.0.3/diskdump.h	2013-10-18 11:11:20.610295600 -0400
@@ -42,7 +42,9 @@ struct disk_dump_header {
 						   header in blocks */
 	unsigned int		bitmap_blocks;	/* Size of Memory bitmap in
 						   block */
-	unsigned int		max_mapnr;	/* = max_mapnr */
+	unsigned int		max_mapnr;	/* = max_mapnr, OBSOLETE!
+						   32bit only, full 64bit
+						   in sub header. */
 	unsigned int		total_ram_blocks;/* Number of blocks should be
 						   written */
 	unsigned int		device_blocks;	/* Number of total blocks in
@@ -61,14 +63,21 @@ struct kdump_sub_header {
 	unsigned long	phys_base;
 	int		dump_level;         /* header_version 1 and later */
 	int		split;              /* header_version 2 and later */
-	unsigned long	start_pfn;          /* header_version 2 and later */
-	unsigned long	end_pfn;            /* header_version 2 and later */
+	unsigned long	start_pfn;          /* header_version 2 and later,
+					       OBSOLETE! 32bit only, full 64bit
+					       in start_pfn_64. */
+	unsigned long	end_pfn;            /* header_version 2 and later,
+					       OBSOLETE! 32bit only, full 64bit
+					       in end_pfn_64. */
 	off_t		offset_vmcoreinfo;  /* header_version 3 and later */
 	unsigned long	size_vmcoreinfo;    /* header_version 3 and later */
 	off_t		offset_note;        /* header_version 4 and later */
 	unsigned long	size_note;          /* header_version 4 and later */
 	off_t		offset_eraseinfo;   /* header_version 5 and later */
 	unsigned long	size_eraseinfo;     /* header_version 5 and later */
+	unsigned long long start_pfn_64;    /* header_version 6 and later */
+	unsigned long long end_pfn_64;      /* header_version 6 and later */
+	unsigned long long max_mapnr_64;    /* header_version 6 and later */
 };
 
 /* page flags */
--- crash-7.0.2/lkcd_vmdump_v1.h	2013-10-25 15:28:55.935879568 -0400
+++ crash-7.0.3/lkcd_vmdump_v1.h	2013-10-24 09:06:51.222888110 -0400
@@ -117,10 +117,12 @@ typedef struct _dump_header_s {
 #ifndef IA64
 #ifndef S390
 #ifndef S390X
+#ifndef ARM64
 	struct pt_regs       dh_regs;
 #endif
 #endif
 #endif
+#endif
 
 	/* the address of the current task */
 	struct task_struct  *dh_current_task;
--- crash-7.0.2/lkcd_vmdump_v2_v3.h	2013-10-25 15:28:55.938879568 -0400
+++ crash-7.0.3/lkcd_vmdump_v2_v3.h	2013-10-24 09:13:13.588870592 -0400
@@ -84,9 +84,11 @@ typedef struct _dump_header_asm_s {
 	/* the dump registers */
 #ifndef S390
 #ifndef S390X
+#ifndef ARM64
 	struct pt_regs       dha_regs;
 #endif
 #endif
+#endif
 
 } dump_header_asm_t;
 
--- crash-7.0.2/sadump.h	2013-10-25 15:28:55.939879568 -0400
+++ crash-7.0.3/sadump.h	2013-09-13 08:48:05.576229221 -0400
@@ -41,6 +41,8 @@ typedef struct {
 	uint8_t data4[8];
 } efi_guid_t;
 
+#define SADUMP_EFI_GUID_TEXT_REPR_LEN 36
+
 struct sadump_part_header {
 #define SADUMP_SIGNATURE1	0x75646173
 #define SADUMP_SIGNATURE2	0x0000706d
--- crash-7.0.2/extensions/snap.c	2013-10-25 15:28:55.943879568 -0400
+++ crash-7.0.3/extensions/snap.c	2013-10-25 10:10:39.188754456 -0400
@@ -416,7 +416,8 @@ generate_elf_header(int type, int fd, ch
 	} else if (machine_type("PPC64")) {
 		e_machine = EM_PPC64;
 		prstatus_len = sizeof(prstatus.ppc64);
-	}
+	} else
+		return NULL;
 
 	/* should be enought for the notes + roundup + two blocks */
 	buffer = (char *)GETBUF(sizeof(Elf64_Ehdr) +
@@ -538,7 +539,7 @@ generate_elf_header(int type, int fd, ch
 			break;
 		}
 
-		l_offset += load[i].p_filesz;
+//		l_offset += load[i].p_filesz;
 		offset += sizeof(Elf64_Phdr);
 		ptr += sizeof(Elf64_Phdr);
 	}
--- crash-7.0.2/extensions/trace.c	2013-10-25 15:28:55.944879568 -0400
+++ crash-7.0.3/extensions/trace.c	2013-10-25 10:10:44.031754234 -0400
@@ -1453,6 +1453,7 @@ static void ftrace_show(int argc, char *
 	if ((file = popen(trace_cmd, "r"))) {
 		ret = fread(buf, 1, sizeof(buf), file);
 		buf[ret] = 0;
+		pclose(file);
 	}
 	if (!strstr(buf, "trace-cmd version")) {
 		if (env_trace_cmd)
--- crash-7.0.3/defs.h.orig
+++ crash-7.0.3/defs.h
@@ -1880,6 +1880,8 @@ struct offset_table {
 	long page_slab_page;
 	long trace_print_flags_mask;
 	long trace_print_flags_name;
+	long task_struct_rss_stat;
+	long task_rss_stat_count;
 };
 
 struct size_table {         /* stash of commonly-used sizes */
--- crash-7.0.3/symbols.c.orig
+++ crash-7.0.3/symbols.c
@@ -7643,6 +7643,10 @@ dump_offset_table(char *spec, ulong make
                 OFFSET(task_struct_tgid));
         fprintf(fp, "         task_struct_namespace: %ld\n",
                 OFFSET(task_struct_namespace));
+        fprintf(fp, "          task_struct_rss_stat: %ld\n",
+                OFFSET(task_struct_rss_stat));
+        fprintf(fp, "           task_rss_stat_count: %ld\n",
+                OFFSET(task_rss_stat_count));
         fprintf(fp, "              task_struct_pids: %ld\n",
                 OFFSET(task_struct_pids));
         fprintf(fp, "          task_struct_last_run: %ld\n",
--- crash-7.0.3/memory.c.orig
+++ crash-7.0.3/memory.c
@@ -4003,6 +4003,7 @@ void
 get_task_mem_usage(ulong task, struct task_mem_usage *tm)
 {
 	struct task_context *tc;
+	long rss = 0;
 
 	BZERO(tm, sizeof(struct task_mem_usage));
 
@@ -4036,22 +4037,65 @@ get_task_mem_usage(ulong task, struct ta
 				filepages = 0;
 				anonpages = 1;
 			}
-			tm->rss += ULONG(tt->mm_struct + 
+			rss += LONG(tt->mm_struct +
 				OFFSET(mm_struct_rss_stat) +
 				OFFSET(mm_rss_stat_count) +
-				(filepages * sizeof(ulong)));
-			tm->rss += ULONG(tt->mm_struct + 
+				(filepages * sizeof(long)));
+			rss += LONG(tt->mm_struct +
 				OFFSET(mm_struct_rss_stat) +
 				OFFSET(mm_rss_stat_count) +
-				(anonpages * sizeof(ulong)));
+				(anonpages * sizeof(long)));
 		}
+
+		/* Check whether SPLIT_RSS_COUNTING is enabled */
+		if (VALID_MEMBER(task_struct_rss_stat)) {
+			int i, sync_rss;
+			ulong tgid;
+			struct task_context *tc1;
+
+			tgid = task_tgid(task);
+
+			tc1 = FIRST_CONTEXT();
+			for (i = 0; i < RUNNING_TASKS(); i++, tc1++) {
+				if (task_tgid(tc1->task) != tgid)
+					continue;
+
+				/* count 0 -> filepages */
+				if (!readmem(tc1->task +
+					OFFSET(task_struct_rss_stat) +
+					OFFSET(task_rss_stat_count), KVADDR,
+					&sync_rss,
+					sizeof(int),
+					"task_struct rss_stat MM_FILEPAGES",
+					RETURN_ON_ERROR))
+						continue;
+
+				rss += sync_rss;
+
+				/* count 1 -> anonpages */
+				if (!readmem(tc1->task +
+					OFFSET(task_struct_rss_stat) +
+					OFFSET(task_rss_stat_count) +
+					sizeof(int),
+					KVADDR, &sync_rss,
+					sizeof(int),
+					"task_struct rss_stat MM_ANONPAGES",
+					RETURN_ON_ERROR))
+						continue;
+
+				rss += sync_rss;
+			}
+		}
+
 		/*  
 		 *  mm_struct._anon_rss and mm_struct._file_rss should exist. 
 		 */
 		if (VALID_MEMBER(mm_struct_anon_rss))
-			tm->rss +=  ULONG(tt->mm_struct + OFFSET(mm_struct_anon_rss));
+			rss +=  LONG(tt->mm_struct + OFFSET(mm_struct_anon_rss));
 		if (VALID_MEMBER(mm_struct_file_rss))
-			tm->rss +=  ULONG(tt->mm_struct + OFFSET(mm_struct_file_rss));
+			rss +=  LONG(tt->mm_struct + OFFSET(mm_struct_file_rss));
+
+		tm->rss = (unsigned long)rss;
 	}
         tm->total_vm = ULONG(tt->mm_struct + OFFSET(mm_struct_total_vm));
         tm->pgd_addr = ULONG(tt->mm_struct + OFFSET(mm_struct_pgd));
--- crash-7.0.3/task.c.orig
+++ crash-7.0.3/task.c
@@ -349,6 +349,11 @@ task_init(void)
 		MEMBER_OFFSET_INIT(task_struct_run_list, "task_struct",
 			"run_list");
 
+	MEMBER_OFFSET_INIT(task_struct_rss_stat, "task_struct",
+		"rss_stat");
+	MEMBER_OFFSET_INIT(task_rss_stat_count, "task_rss_stat",
+		"count");
+
         if ((tt->task_struct = (char *)malloc(SIZE(task_struct))) == NULL)
         	error(FATAL, "cannot malloc task_struct space.");