--- 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.");