The dump_mem_map() function displays basic data about each entry in the mem_map[] array, or if an address is specified, just the mem_map[] entry for that address. This patch introduces the -m option to be used with 'kmem -p' exclusively. When used with -p, a comma-separated list of one or more struct page members may be specified to generate a custom, formatted display. For example: crash> kmem -p -m mapping,index,_mapcount.counter,_count.counter ffffea0000000000 0x0 0 0 0 ffffea0000000040 0x0 0 -1 1 ffffea0000000080 0x0 0 -1 1 ffffea00000000c0 0x0 0 -1 1 ffffea0000000100 0x0 0 -1 1 ffffea0000000140 0x0 0 -1 1 ffffea0000000180 0x0 0 -1 1 ffffea00000001c0 0x0 0 -1 1 ffffea0000000200 0x0 0 -1 1 ffffea0000000240 0x0 0 -1 1 ... Signed-off-by: Aaron Tomlin <atomlin@xxxxxxxxxx> --- help.c | 19 +- memory.c | 1074 ++++++++++++++++++++++++++++++++++++-------------------------- 2 files changed, 649 insertions(+), 444 deletions(-) diff --git a/help.c b/help.c index b2f4d21..76b640a 100644 --- a/help.c +++ b/help.c @@ -5530,7 +5530,7 @@ char *help_kmem[] = { "kmem", "kernel memory", "[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n|-z|-o|-h] [slab] [[-P] address]\n" -" [-g [flags]] [-I slab[,slab]]", +" [-g [flags]] [-I slab[,slab]] [-m member[,member]]", " This command displays information about the use of kernel memory.\n", " -f displays the contents of the system free memory headers.", " also verifies that the page count equals nr_free_pages.", @@ -5565,6 +5565,9 @@ char *help_kmem[] = { " all slab cache names and addresses are listed.", " -I slab when used with -s or -S, one or more slab cache names in a", " comma-separated list may be specified as slab caches to ignore.", +" -m member when used with -p, a comma-separated list of one or more", +" struct page members may be specified to generate a custom", +" formatted display.", " -P declares that the following address argument is a physical address.", " address when used without any flag, the address can be a kernel virtual,", " or physical address; a search is made through the symbol table,", @@ -5717,6 +5720,20 @@ char *help_kmem[] = { " f5c51440 22000 0 0 1 80 slab", " ...", " ", +" Dump the mem_map[] array but select desired fields:\n", +" %s> kmem -p -m mapping,index,_mapcount.counter", +" ffffea0000000000 0x0 0 0", +" ffffea0000000040 0x0 0 -1", +" ffffea0000000080 0x0 0 -1", +" ffffea00000000c0 0x0 0 -1", +" ffffea0000000100 0x0 0 -1", +" ffffea0000000140 0x0 0 -1", +" ffffea0000000180 0x0 0 -1", +" ffffea00000001c0 0x0 0 -1", +" ffffea0000000200 0x0 0 -1", +" ffffea0000000240 0x0 0 -1", +" ...", +" ", " Use the commands above with a page pointer or a physical address argument:\n", " %s> kmem -f c40425b0", " NODE ", diff --git a/memory.c b/memory.c index aacf929..d4114c2 100644 --- a/memory.c +++ b/memory.c @@ -55,6 +55,7 @@ struct meminfo { /* general purpose memory information structure */ ulong found; ulong retval; char *ignore; + char *include; int errors; int calls; int cpu; @@ -4425,7 +4426,7 @@ cmd_kmem(void) BZERO(&meminfo, sizeof(struct meminfo)); BZERO(&value[0], sizeof(ulonglong)*MAXARGS); - while ((c = getopt(argcnt, args, "gI:sSFfpvczCinl:L:PVoh")) != EOF) { + while ((c = getopt(argcnt, args, "gI:sSFfm:pvczCinl:L:PVoh")) != EOF) { switch(c) { case 'V': @@ -4480,6 +4481,10 @@ cmd_kmem(void) pflag = 1; break; + case 'm': + meminfo.include = optarg; + break; + case 'I': meminfo.ignore = optarg; break; @@ -4948,7 +4953,7 @@ PG_slab_flag_init(void) static void dump_mem_map_SPARSEMEM(struct meminfo *mi) { - ulong i; + ulong i, j; long total_pages; int others, page_not_mapped, phys_not_mapped, page_mapping; ulong pp, ppend; @@ -4967,7 +4972,11 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) char buf4[BUFSIZE]; char *page_cache; char *pcache; - ulong section, section_nr, nr_mem_sections, section_size; + char *members = NULL; + char *memberlist[MAXARGS]; + struct struct_member_data *member_data[MAXARGS]; + int nr_members, populated; + ulong tmpvalue, section, section_nr, nr_mem_sections, section_size; long buffersize; char *outputbuffer; int bufferindex; @@ -4980,66 +4989,81 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) char style3[100]; char style4[100]; - sprintf((char *)&style1, "%%lx%s%%%dllx%s%%%dlx%s%%8lx %%2d%s", - space(MINSPACE), - (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), - space(MINSPACE), - VADDR_PRLEN, - space(MINSPACE), - space(MINSPACE)); - sprintf((char *)&style2, "%%-%dlx%s%%%dllx%s%s%s%s %2s ", - VADDR_PRLEN, - space(MINSPACE), - (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), - space(MINSPACE), - mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, " "), - space(MINSPACE), - mkstring(buf4, 8, CENTER|RJUST, " "), - " "); - sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s %%2d ", - VADDR_PRLEN, - space(MINSPACE), - (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), - space(MINSPACE), - mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "-------"), - space(MINSPACE), - mkstring(buf4, 8, CENTER|RJUST, "-----")); - sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%%dlx%s%%8lx %%2d ", - VADDR_PRLEN, - space(MINSPACE), - (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), - space(MINSPACE), - VADDR_PRLEN, - space(MINSPACE)); + nr_members = mapping = index = 0; + reserved = shared = slabs = buffers = inode = offset = 0; + pg_spec = phys_spec = print_hdr = FALSE; v22 = VALID_MEMBER(page_inode); /* page.inode vs. page.mapping */ - if (v22) { - sprintf(hdr, "%s%s%s%s%s%s%s%sCNT FLAGS\n", - mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), - space(MINSPACE), - mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), - RJUST, "PHYSICAL"), - space(MINSPACE), - mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "INODE"), - space(MINSPACE), - mkstring(buf4, 8, CENTER|LJUST, "OFFSET"), - space(MINSPACE-1)); - } else { - sprintf(hdr, "%s%s%s%s%s%s%sCNT FLAGS\n", - mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), - space(MINSPACE), - mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), - RJUST, "PHYSICAL"), - space(MINSPACE), - mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "MAPPING"), - space(MINSPACE), - mkstring(buf4, 8, CENTER|RJUST, "INDEX")); - } + if (!mi->include) { + sprintf((char *)&style1, "%%lx%s%%%dllx%s%%%dlx%s%%8lx %%2d%s", + space(MINSPACE), + (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), + space(MINSPACE), + VADDR_PRLEN, + space(MINSPACE), + space(MINSPACE)); + sprintf((char *)&style2, "%%-%dlx%s%%%dllx%s%s%s%s %2s ", + VADDR_PRLEN, + space(MINSPACE), + (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), + space(MINSPACE), + mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, " "), + space(MINSPACE), + mkstring(buf4, 8, CENTER|RJUST, " "), + " "); + sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s %%2d ", + VADDR_PRLEN, + space(MINSPACE), + (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), + space(MINSPACE), + mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "-------"), + space(MINSPACE), + mkstring(buf4, 8, CENTER|RJUST, "-----")); + sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%%dlx%s%%8lx %%2d ", + VADDR_PRLEN, + space(MINSPACE), + (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), + space(MINSPACE), + VADDR_PRLEN, + space(MINSPACE)); + + if (v22) { + sprintf(hdr, "%s%s%s%s%s%s%s%sCNT FLAGS\n", + mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), + space(MINSPACE), + mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), + RJUST, "PHYSICAL"), + space(MINSPACE), + mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "INODE"), + space(MINSPACE), + mkstring(buf4, 8, CENTER|LJUST, "OFFSET"), + space(MINSPACE-1)); + } else { + sprintf(hdr, "%s%s%s%s%s%s%sCNT FLAGS\n", + mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), + space(MINSPACE), + mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), + RJUST, "PHYSICAL"), + space(MINSPACE), + mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "MAPPING"), + space(MINSPACE), + mkstring(buf4, 8, CENTER|RJUST, "INDEX")); + } + } else { + if (count_chars(mi->include, ',') > MAXARGS) + error(FATAL, "too many members in comma-separated list!\n"); - mapping = index = 0; - reserved = shared = slabs = buffers = inode = offset = 0; - pg_spec = phys_spec = print_hdr = FALSE; + if ((LASTCHAR(mi->include) == ',') || (LASTCHAR(mi->include) == '.')) + error(FATAL, "invalid format: %s\n", mi->include); + + members = GETBUF(strlen(mi->include)+1); + strcpy(members, mi->include); + replace_string(members, ",", ' '); + nr_members = parse_line(members, memberlist); + populated = FALSE; + + } switch (mi->flags) { @@ -5065,7 +5089,8 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) error(FATAL, "dump_mem_map: no memtype specified\n"); break; } - print_hdr = TRUE; + if (!mi->include) + print_hdr = TRUE; break; case GET_ALL: @@ -5092,7 +5117,8 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) break; default: - print_hdr = TRUE; + if (!mi->include) + print_hdr = TRUE; break; } @@ -5188,187 +5214,251 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) if (!done && (pg_spec || phys_spec)) continue; - - flags = ULONG(pcache + OFFSET(page_flags)); - if (SIZE(page_flags) == 4) - flags &= 0xffffffff; - count = UINT(pcache + OFFSET(page_count)); - switch (mi->flags) - { - case GET_ALL: - case GET_BUFFERS_PAGES: - if (VALID_MEMBER(page_buffers)) { - tmp = ULONG(pcache + - OFFSET(page_buffers)); - if (tmp) - buffers++; - } else if (THIS_KERNEL_VERSION >= LINUX(2,6,0)) { - if ((flags >> v26_PG_private) & 1) - buffers++; - } else - error(FATAL, - "cannot determine whether pages have buffers\n"); + if (mi->include) { + if (!populated) { - if (mi->flags != GET_ALL) - continue; + j = 0; + do { + if (!(member_data[j] = malloc(sizeof(struct struct_member_data)))) { + error(WARNING, "cannot malloc member_data space.\n"); + nr_members = j += 1; + goto failed_member_data; + } - /* FALLTHROUGH */ + member_data[j]->structure = "page"; + member_data[j]->member = memberlist[j]; + if (!(fill_struct_member_data(member_data[j]))) { + error(WARNING, "Failed to populate member_data: " + "%s.%s does not exist.\n", + member_data[j]->structure, member_data[j]->member); + nr_members = j += 1; + goto failed_member_data; + } - case GET_SLAB_PAGES: - if (v22) { - if ((flags >> v22_PG_Slab) & 1) - slabs++; - } else if (vt->PG_slab) { - if ((flags >> vt->PG_slab) & 1) - slabs++; - } else { - if ((flags >> v24_PG_slab) & 1) - slabs++; + } while (++j < nr_members); + populated = TRUE; } - if (mi->flags != GET_ALL) - continue; - /* FALLTHROUGH */ - case GET_SHARED_PAGES: - case GET_TOTALRAM_PAGES: - if (vt->PG_reserved) - PG_reserved_flag = vt->PG_reserved; - else - PG_reserved_flag = v22 ? - 1 << v22_PG_reserved : - 1 << v24_PG_reserved; + bufferindex += sprintf(outputbuffer + bufferindex, + "%lx\t", pp); - if (flags & PG_reserved_flag) { - reserved++; - } else { - if ((int)count > - (vt->flags & PGCNT_ADJ ? 0 : 1)) - shared++; - } - continue; - } - page_mapping = VALID_MEMBER(page_mapping); - - if (v22) { - inode = ULONG(pcache + OFFSET(page_inode)); - offset = ULONG(pcache + OFFSET(page_offset)); - } else if (page_mapping) { - mapping = ULONG(pcache + - OFFSET(page_mapping)); - index = ULONG(pcache + OFFSET(page_index)); - } - - page_not_mapped = phys_not_mapped = FALSE; + j = 0; + do { + switch (member_data[j]->type) + { + case TYPE_CODE_PTR: + readmem(pp + member_data[j]->offset, KVADDR, &tmpvalue, + member_data[j]->length, "tmpvalue", FAULT_ON_ERROR); + bufferindex += sprintf(outputbuffer + bufferindex, "0x%lx\t", + tmpvalue); + break; + case TYPE_CODE_INT: + readmem(pp + member_data[j]->offset, KVADDR, &tmpvalue, + member_data[j]->length, "tmpvalue", FAULT_ON_ERROR); + if (member_data[j]->unsigned_type || + member_data[j]->length == sizeof(ulonglong)) + bufferindex += sprintf(outputbuffer + bufferindex, + "%lu\t", tmpvalue); + else + bufferindex += sprintf(outputbuffer + bufferindex, + "%d\t", (int)tmpvalue); + break; + default: + error(WARNING, "invalid data structure reference %s.%s\n", + member_data[j]->structure, member_data[j]->member); + nr_members = j += 1; + goto failed_member_data; + break; + } + } while (++j < nr_members); + + bufferindex += sprintf(outputbuffer+bufferindex, "\n"); - if (v22) { - bufferindex += sprintf(outputbuffer+bufferindex, - (char *)&style1, pp, phys, inode, - offset, count); } else { - if ((vt->flags & V_MEM_MAP)) { - if (!machdep->verify_paddr(phys)) - phys_not_mapped = TRUE; - if (!kvtop(NULL, pp, NULL, 0)) - page_not_mapped = TRUE; + + flags = ULONG(pcache + OFFSET(page_flags)); + if (SIZE(page_flags) == 4) + flags &= 0xffffffff; + count = UINT(pcache + OFFSET(page_count)); + + switch (mi->flags) + { + case GET_ALL: + case GET_BUFFERS_PAGES: + if (VALID_MEMBER(page_buffers)) { + tmp = ULONG(pcache + + OFFSET(page_buffers)); + if (tmp) + buffers++; + } else if (THIS_KERNEL_VERSION >= LINUX(2,6,0)) { + if ((flags >> v26_PG_private) & 1) + buffers++; + } else + error(FATAL, + "cannot determine whether pages have buffers\n"); + + if (mi->flags != GET_ALL) + continue; + + /* FALLTHROUGH */ + + case GET_SLAB_PAGES: + if (v22) { + if ((flags >> v22_PG_Slab) & 1) + slabs++; + } else if (vt->PG_slab) { + if ((flags >> vt->PG_slab) & 1) + slabs++; + } else { + if ((flags >> v24_PG_slab) & 1) + slabs++; + } + if (mi->flags != GET_ALL) + continue; + + /* FALLTHROUGH */ + + case GET_SHARED_PAGES: + case GET_TOTALRAM_PAGES: + if (vt->PG_reserved) + PG_reserved_flag = vt->PG_reserved; + else + PG_reserved_flag = v22 ? + 1 << v22_PG_reserved : + 1 << v24_PG_reserved; + + if (flags & PG_reserved_flag) { + reserved++; + } else { + if ((int)count > + (vt->flags & PGCNT_ADJ ? 0 : 1)) + shared++; + } + continue; } - if (page_not_mapped) - bufferindex += sprintf(outputbuffer+bufferindex, - (char *)&style2, pp, phys); - else if (!page_mapping) - bufferindex += sprintf(outputbuffer+bufferindex, - (char *)&style3, pp, phys, count); - else + page_mapping = VALID_MEMBER(page_mapping); + + if (v22) { + inode = ULONG(pcache + OFFSET(page_inode)); + offset = ULONG(pcache + OFFSET(page_offset)); + } else if (page_mapping) { + mapping = ULONG(pcache + + OFFSET(page_mapping)); + index = ULONG(pcache + OFFSET(page_index)); + } + + page_not_mapped = phys_not_mapped = FALSE; + + if (v22) { bufferindex += sprintf(outputbuffer+bufferindex, - (char *)&style4, pp, phys, - mapping, index, count); - } - - others = 0; - + (char *)&style1, pp, phys, inode, + offset, count); + } else { + if ((vt->flags & V_MEM_MAP)) { + if (!machdep->verify_paddr(phys)) + phys_not_mapped = TRUE; + if (!kvtop(NULL, pp, NULL, 0)) + page_not_mapped = TRUE; + } + if (page_not_mapped) + bufferindex += sprintf(outputbuffer+bufferindex, + (char *)&style2, pp, phys); + else if (!page_mapping) + bufferindex += sprintf(outputbuffer+bufferindex, + (char *)&style3, pp, phys, count); + else + bufferindex += sprintf(outputbuffer+bufferindex, + (char *)&style4, pp, phys, + mapping, index, count); + } + + others = 0; + #define sprintflag(X) sprintf(outputbuffer + bufferindex, X, others++ ? "," : "") - if (v22) { - if ((flags >> v22_PG_DMA) & 1) - bufferindex += sprintflag("%sDMA"); - if ((flags >> v22_PG_locked) & 1) - bufferindex += sprintflag("%slocked"); - if ((flags >> v22_PG_error) & 1) - bufferindex += sprintflag("%serror"); - if ((flags >> v22_PG_referenced) & 1) - bufferindex += sprintflag("%sreferenced"); - if ((flags >> v22_PG_dirty) & 1) - bufferindex += sprintflag("%sdirty"); - if ((flags >> v22_PG_uptodate) & 1) - bufferindex += sprintflag("%suptodate"); - if ((flags >> v22_PG_free_after) & 1) - bufferindex += sprintflag("%sfree_after"); - if ((flags >> v22_PG_decr_after) & 1) - bufferindex += sprintflag("%sdecr_after"); - if ((flags >> v22_PG_swap_unlock_after) & 1) - bufferindex += sprintflag("%sswap_unlock_after"); - if ((flags >> v22_PG_Slab) & 1) - bufferindex += sprintflag("%sslab"); - if ((flags >> v22_PG_swap_cache) & 1) - bufferindex += sprintflag("%sswap_cache"); - if ((flags >> v22_PG_skip) & 1) - bufferindex += sprintflag("%sskip"); - if ((flags >> v22_PG_reserved) & 1) - bufferindex += sprintflag("%sreserved"); - bufferindex += sprintf(outputbuffer+bufferindex, "\n"); - } else if (THIS_KERNEL_VERSION > LINUX(2,4,9)) { - 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) - bufferindex += sprintflag("%slocked"); - if ((flags >> v24_PG_error) & 1) - bufferindex += sprintflag("%serror"); - if ((flags >> v24_PG_referenced) & 1) - bufferindex += sprintflag("%sreferenced"); - if ((flags >> v24_PG_uptodate) & 1) - bufferindex += sprintflag("%suptodate"); - if ((flags >> v24_PG_dirty) & 1) - bufferindex += sprintflag("%sdirty"); - if ((flags >> v24_PG_decr_after) & 1) - bufferindex += sprintflag("%sdecr_after"); - if ((flags >> v24_PG_active) & 1) - bufferindex += sprintflag("%sactive"); - if ((flags >> v24_PG_inactive_dirty) & 1) - bufferindex += sprintflag("%sinactive_dirty"); - if ((flags >> v24_PG_slab) & 1) - bufferindex += sprintflag("%sslab"); - if ((flags >> v24_PG_swap_cache) & 1) - bufferindex += sprintflag("%sswap_cache"); - if ((flags >> v24_PG_skip) & 1) - bufferindex += sprintflag("%sskip"); - if ((flags >> v24_PG_inactive_clean) & 1) - bufferindex += sprintflag("%sinactive_clean"); - if ((flags >> v24_PG_highmem) & 1) - bufferindex += sprintflag("%shighmem"); - if ((flags >> v24_PG_checked) & 1) - bufferindex += sprintflag("%schecked"); - if ((flags >> v24_PG_bigpage) & 1) - bufferindex += sprintflag("%sbigpage"); - if ((flags >> v24_PG_arch_1) & 1) - bufferindex += sprintflag("%sarch_1"); - if ((flags >> v24_PG_reserved) & 1) - bufferindex += sprintflag("%sreserved"); - if (phys_not_mapped) - bufferindex += sprintflag("%s[NOT MAPPED]"); - - bufferindex += sprintf(outputbuffer+bufferindex, "\n"); + if (v22) { + if ((flags >> v22_PG_DMA) & 1) + bufferindex += sprintflag("%sDMA"); + if ((flags >> v22_PG_locked) & 1) + bufferindex += sprintflag("%slocked"); + if ((flags >> v22_PG_error) & 1) + bufferindex += sprintflag("%serror"); + if ((flags >> v22_PG_referenced) & 1) + bufferindex += sprintflag("%sreferenced"); + if ((flags >> v22_PG_dirty) & 1) + bufferindex += sprintflag("%sdirty"); + if ((flags >> v22_PG_uptodate) & 1) + bufferindex += sprintflag("%suptodate"); + if ((flags >> v22_PG_free_after) & 1) + bufferindex += sprintflag("%sfree_after"); + if ((flags >> v22_PG_decr_after) & 1) + bufferindex += sprintflag("%sdecr_after"); + if ((flags >> v22_PG_swap_unlock_after) & 1) + bufferindex += sprintflag("%sswap_unlock_after"); + if ((flags >> v22_PG_Slab) & 1) + bufferindex += sprintflag("%sslab"); + if ((flags >> v22_PG_swap_cache) & 1) + bufferindex += sprintflag("%sswap_cache"); + if ((flags >> v22_PG_skip) & 1) + bufferindex += sprintflag("%sskip"); + if ((flags >> v22_PG_reserved) & 1) + bufferindex += sprintflag("%sreserved"); + bufferindex += sprintf(outputbuffer+bufferindex, "\n"); + } else if (THIS_KERNEL_VERSION > LINUX(2,4,9)) { + 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) + bufferindex += sprintflag("%slocked"); + if ((flags >> v24_PG_error) & 1) + bufferindex += sprintflag("%serror"); + if ((flags >> v24_PG_referenced) & 1) + bufferindex += sprintflag("%sreferenced"); + if ((flags >> v24_PG_uptodate) & 1) + bufferindex += sprintflag("%suptodate"); + if ((flags >> v24_PG_dirty) & 1) + bufferindex += sprintflag("%sdirty"); + if ((flags >> v24_PG_decr_after) & 1) + bufferindex += sprintflag("%sdecr_after"); + if ((flags >> v24_PG_active) & 1) + bufferindex += sprintflag("%sactive"); + if ((flags >> v24_PG_inactive_dirty) & 1) + bufferindex += sprintflag("%sinactive_dirty"); + if ((flags >> v24_PG_slab) & 1) + bufferindex += sprintflag("%sslab"); + if ((flags >> v24_PG_swap_cache) & 1) + bufferindex += sprintflag("%sswap_cache"); + if ((flags >> v24_PG_skip) & 1) + bufferindex += sprintflag("%sskip"); + if ((flags >> v24_PG_inactive_clean) & 1) + bufferindex += sprintflag("%sinactive_clean"); + if ((flags >> v24_PG_highmem) & 1) + bufferindex += sprintflag("%shighmem"); + if ((flags >> v24_PG_checked) & 1) + bufferindex += sprintflag("%schecked"); + if ((flags >> v24_PG_bigpage) & 1) + bufferindex += sprintflag("%sbigpage"); + if ((flags >> v24_PG_arch_1) & 1) + bufferindex += sprintflag("%sarch_1"); + if ((flags >> v24_PG_reserved) & 1) + bufferindex += sprintflag("%sreserved"); + if (phys_not_mapped) + bufferindex += sprintflag("%s[NOT MAPPED]"); + + bufferindex += sprintf(outputbuffer+bufferindex, "\n"); + } } if (bufferindex > buffersize) { fprintf(fp, "%s", outputbuffer); bufferindex = 0; } - + if (done) break; } @@ -5413,12 +5503,18 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) FREEBUF(outputbuffer); FREEBUF(page_cache); +failed_member_data: + if (mi->include) { + FREEBUF(members); + for (i = 0; i < nr_members; i++) + free(member_data[i]); + } } static void dump_mem_map(struct meminfo *mi) { - long i, n; + ulong i, n, j; long total_pages; int others, page_not_mapped, phys_not_mapped, page_mapping; ulong pp, ppend; @@ -5439,6 +5535,11 @@ dump_mem_map(struct meminfo *mi) char buf4[BUFSIZE]; char *page_cache; char *pcache; + char *members = NULL; + char *memberlist[MAXARGS]; + struct struct_member_data *member_data[MAXARGS]; + int nr_members, populated; + ulong tmpvalue; long buffersize; char *outputbuffer; int bufferindex; @@ -5456,67 +5557,82 @@ dump_mem_map(struct meminfo *mi) return; } - sprintf((char *)&style1, "%%lx%s%%%dllx%s%%%dlx%s%%8lx %%2d%s", - space(MINSPACE), - (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), - space(MINSPACE), - VADDR_PRLEN, - space(MINSPACE), - space(MINSPACE)); - sprintf((char *)&style2, "%%-%dlx%s%%%dllx%s%s%s%s %2s ", - VADDR_PRLEN, - space(MINSPACE), - (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), - space(MINSPACE), - mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, " "), - space(MINSPACE), - mkstring(buf4, 8, CENTER|RJUST, " "), - " "); - sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s %%2d ", - VADDR_PRLEN, - space(MINSPACE), - (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), - space(MINSPACE), - mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "-------"), - space(MINSPACE), - mkstring(buf4, 8, CENTER|RJUST, "-----")); - sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%%dlx%s%%8lx %%2d ", - VADDR_PRLEN, - space(MINSPACE), - (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), - space(MINSPACE), - VADDR_PRLEN, - space(MINSPACE)); + nr_members = mapping = index = 0; + reserved = shared = slabs = buffers = inode = offset = 0; + pg_spec = phys_spec = print_hdr = FALSE; v22 = VALID_MEMBER(page_inode); /* page.inode vs. page.mapping */ - if (v22) { - sprintf(hdr, "%s%s%s%s%s%s%s%sCNT FLAGS\n", - mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), - space(MINSPACE), - mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), - RJUST, "PHYSICAL"), - space(MINSPACE), - mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "INODE"), - space(MINSPACE), - mkstring(buf4, 8, CENTER|LJUST, "OFFSET"), - space(MINSPACE-1)); - } else { - sprintf(hdr, "%s%s%s%s%s%s%sCNT FLAGS\n", - mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), - space(MINSPACE), - mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), - RJUST, "PHYSICAL"), - space(MINSPACE), - mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "MAPPING"), - space(MINSPACE), - mkstring(buf4, 8, CENTER|RJUST, "INDEX")); - } + if (!mi->include) { + sprintf((char *)&style1, "%%lx%s%%%dllx%s%%%dlx%s%%8lx %%2d%s", + space(MINSPACE), + (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), + space(MINSPACE), + VADDR_PRLEN, + space(MINSPACE), + space(MINSPACE)); + sprintf((char *)&style2, "%%-%dlx%s%%%dllx%s%s%s%s %2s ", + VADDR_PRLEN, + space(MINSPACE), + (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), + space(MINSPACE), + mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, " "), + space(MINSPACE), + mkstring(buf4, 8, CENTER|RJUST, " "), + " "); + sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s %%2d ", + VADDR_PRLEN, + space(MINSPACE), + (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), + space(MINSPACE), + mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "-------"), + space(MINSPACE), + mkstring(buf4, 8, CENTER|RJUST, "-----")); + sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%%dlx%s%%8lx %%2d ", + VADDR_PRLEN, + space(MINSPACE), + (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), + space(MINSPACE), + VADDR_PRLEN, + space(MINSPACE)); + + if (v22) { + sprintf(hdr, "%s%s%s%s%s%s%s%sCNT FLAGS\n", + mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), + space(MINSPACE), + mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), + RJUST, "PHYSICAL"), + space(MINSPACE), + mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "INODE"), + space(MINSPACE), + mkstring(buf4, 8, CENTER|LJUST, "OFFSET"), + space(MINSPACE-1)); + } else { + sprintf(hdr, "%s%s%s%s%s%s%sCNT FLAGS\n", + mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), + space(MINSPACE), + mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), + RJUST, "PHYSICAL"), + space(MINSPACE), + mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "MAPPING"), + space(MINSPACE), + mkstring(buf4, 8, CENTER|RJUST, "INDEX")); + } + } else { + if (count_chars(mi->include, ',') > MAXARGS) + error(FATAL, "too many members in comma-separated list!\n"); + + if ((LASTCHAR(mi->include) == ',') || (LASTCHAR(mi->include) == '.')) + error(FATAL, "invalid format: %s\n", mi->include); + + members = GETBUF(strlen(mi->include)+1); + strcpy(members, mi->include); + replace_string(members, ",", ' '); + nr_members = parse_line(members, memberlist); + populated = FALSE; + + } - mapping = index = 0; - reserved = shared = slabs = buffers = inode = offset = 0; - pg_spec = phys_spec = print_hdr = FALSE; - switch (mi->flags) { case ADDRESS_SPECIFIED: @@ -5541,7 +5657,8 @@ dump_mem_map(struct meminfo *mi) error(FATAL, "dump_mem_map: no memtype specified\n"); break; } - print_hdr = TRUE; + if (!mi->include) + print_hdr = TRUE; break; case GET_ALL: @@ -5568,7 +5685,8 @@ dump_mem_map(struct meminfo *mi) break; default: - print_hdr = TRUE; + if (!mi->include) + print_hdr = TRUE; break; } @@ -5625,181 +5743,245 @@ dump_mem_map(struct meminfo *mi) if (!done && (pg_spec || phys_spec)) continue; - - flags = ULONG(pcache + OFFSET(page_flags)); - if (SIZE(page_flags) == 4) - flags &= 0xffffffff; - count = UINT(pcache + OFFSET(page_count)); - switch (mi->flags) - { - case GET_ALL: - case GET_BUFFERS_PAGES: - if (VALID_MEMBER(page_buffers)) { - tmp = ULONG(pcache + - OFFSET(page_buffers)); - if (tmp) - buffers++; - } else if (THIS_KERNEL_VERSION >= LINUX(2,6,0)) { - if ((flags >> v26_PG_private) & 1) - buffers++; - } else - error(FATAL, - "cannot determine whether pages have buffers\n"); + if (mi->include) { + if (!populated) { - if (mi->flags != GET_ALL) - continue; + j = 0; + do { + if (!(member_data[j] = malloc(sizeof(struct struct_member_data)))) { + error(WARNING, "cannot malloc member_data space.\n"); + nr_members = j += 1; + goto failed_member_data; + } - /* FALLTHROUGH */ + member_data[j]->structure = "page"; + member_data[j]->member = memberlist[j]; + if (!(fill_struct_member_data(member_data[j]))) { + error(WARNING, "Failed to populate member_data: " + "%s.%s does not exist.\n", + member_data[j]->structure, member_data[j]->member); + nr_members = j += 1; + goto failed_member_data; + } - case GET_SLAB_PAGES: - if (v22) { - if ((flags >> v22_PG_Slab) & 1) - slabs++; - } else if (vt->PG_slab) { - if ((flags >> vt->PG_slab) & 1) - slabs++; - } else { - if ((flags >> v24_PG_slab) & 1) - slabs++; + } while (++j < nr_members); + populated = TRUE; } - if (mi->flags != GET_ALL) - continue; - /* FALLTHROUGH */ - case GET_SHARED_PAGES: - case GET_TOTALRAM_PAGES: - if (vt->PG_reserved) - PG_reserved_flag = vt->PG_reserved; - else - PG_reserved_flag = v22 ? - 1 << v22_PG_reserved : - 1 << v24_PG_reserved; + bufferindex += sprintf(outputbuffer + bufferindex, + "%lx\t", pp); - if (flags & PG_reserved_flag) { - reserved++; - } else { - if ((int)count > - (vt->flags & PGCNT_ADJ ? 0 : 1)) - shared++; - } - continue; - } - - page_mapping = VALID_MEMBER(page_mapping); - - if (v22) { - inode = ULONG(pcache + OFFSET(page_inode)); - offset = ULONG(pcache + OFFSET(page_offset)); - } else if (page_mapping) { - mapping = ULONG(pcache + - OFFSET(page_mapping)); - index = ULONG(pcache + OFFSET(page_index)); - } - - page_not_mapped = phys_not_mapped = FALSE; + j = 0; + do { + switch (member_data[j]->type) + { + case TYPE_CODE_PTR: + readmem(pp + member_data[j]->offset, KVADDR, &tmpvalue, + member_data[j]->length, "tmpvalue", FAULT_ON_ERROR); + bufferindex += sprintf(outputbuffer + bufferindex, "0x%lx\t", + tmpvalue); + break; + case TYPE_CODE_INT: + readmem(pp + member_data[j]->offset, KVADDR, &tmpvalue, + member_data[j]->length, "tmpvalue", FAULT_ON_ERROR); + if (member_data[j]->unsigned_type || + member_data[j]->length == sizeof(ulonglong)) + bufferindex += sprintf(outputbuffer + bufferindex, + "%lu\t", tmpvalue); + else + bufferindex += sprintf(outputbuffer + bufferindex, + "%d\t", (int)tmpvalue); + break; + default: + error(WARNING, "invalid data structure reference %s.%s\n", + member_data[j]->structure, member_data[j]->member); + nr_members = j += 1; + goto failed_member_data; + break; + } + } while (++j < nr_members); + + bufferindex += sprintf(outputbuffer+bufferindex, "\n"); - if (v22) { - bufferindex += sprintf(outputbuffer+bufferindex, - (char *)&style1, pp, phys, inode, - offset, count); } else { - if ((vt->flags & V_MEM_MAP)) { - if (!machdep->verify_paddr(phys)) - phys_not_mapped = TRUE; - if (!kvtop(NULL, pp, NULL, 0)) - page_not_mapped = TRUE; + + flags = ULONG(pcache + OFFSET(page_flags)); + if (SIZE(page_flags) == 4) + flags &= 0xffffffff; + count = UINT(pcache + OFFSET(page_count)); + + switch (mi->flags) + { + case GET_ALL: + case GET_BUFFERS_PAGES: + if (VALID_MEMBER(page_buffers)) { + tmp = ULONG(pcache + + OFFSET(page_buffers)); + if (tmp) + buffers++; + } else if (THIS_KERNEL_VERSION >= LINUX(2,6,0)) { + if ((flags >> v26_PG_private) & 1) + buffers++; + } else + error(FATAL, + "cannot determine whether pages have buffers\n"); + + if (mi->flags != GET_ALL) + continue; + + /* FALLTHROUGH */ + + case GET_SLAB_PAGES: + if (v22) { + if ((flags >> v22_PG_Slab) & 1) + slabs++; + } else if (vt->PG_slab) { + if ((flags >> vt->PG_slab) & 1) + slabs++; + } else { + if ((flags >> v24_PG_slab) & 1) + slabs++; + } + if (mi->flags != GET_ALL) + continue; + + /* FALLTHROUGH */ + + case GET_SHARED_PAGES: + case GET_TOTALRAM_PAGES: + if (vt->PG_reserved) + PG_reserved_flag = vt->PG_reserved; + else + PG_reserved_flag = v22 ? + 1 << v22_PG_reserved : + 1 << v24_PG_reserved; + + if (flags & PG_reserved_flag) { + reserved++; + } else { + if ((int)count > + (vt->flags & PGCNT_ADJ ? 0 : 1)) + shared++; + } + continue; } - if (page_not_mapped) - bufferindex += sprintf(outputbuffer+bufferindex, - (char *)&style2, pp, phys); - else if (!page_mapping) - bufferindex += sprintf(outputbuffer+bufferindex, - (char *)&style3, pp, phys, count); - else + + page_mapping = VALID_MEMBER(page_mapping); + + if (v22) { + inode = ULONG(pcache + OFFSET(page_inode)); + offset = ULONG(pcache + OFFSET(page_offset)); + } else if (page_mapping) { + mapping = ULONG(pcache + + OFFSET(page_mapping)); + index = ULONG(pcache + OFFSET(page_index)); + } + + page_not_mapped = phys_not_mapped = FALSE; + + if (v22) { bufferindex += sprintf(outputbuffer+bufferindex, - (char *)&style4, pp, phys, - mapping, index, count); - } - - others = 0; - + (char *)&style1, pp, phys, inode, + offset, count); + } else { + if ((vt->flags & V_MEM_MAP)) { + if (!machdep->verify_paddr(phys)) + phys_not_mapped = TRUE; + if (!kvtop(NULL, pp, NULL, 0)) + page_not_mapped = TRUE; + } + if (page_not_mapped) + bufferindex += sprintf(outputbuffer+bufferindex, + (char *)&style2, pp, phys); + else if (!page_mapping) + bufferindex += sprintf(outputbuffer+bufferindex, + (char *)&style3, pp, phys, count); + else + bufferindex += sprintf(outputbuffer+bufferindex, + (char *)&style4, pp, phys, + mapping, index, count); + } + + others = 0; + #define sprintflag(X) sprintf(outputbuffer + bufferindex, X, others++ ? "," : "") - if (v22) { - if ((flags >> v22_PG_DMA) & 1) - bufferindex += sprintflag("%sDMA"); - if ((flags >> v22_PG_locked) & 1) - bufferindex += sprintflag("%slocked"); - if ((flags >> v22_PG_error) & 1) - bufferindex += sprintflag("%serror"); - if ((flags >> v22_PG_referenced) & 1) - bufferindex += sprintflag("%sreferenced"); - if ((flags >> v22_PG_dirty) & 1) - bufferindex += sprintflag("%sdirty"); - if ((flags >> v22_PG_uptodate) & 1) - bufferindex += sprintflag("%suptodate"); - if ((flags >> v22_PG_free_after) & 1) - bufferindex += sprintflag("%sfree_after"); - if ((flags >> v22_PG_decr_after) & 1) - bufferindex += sprintflag("%sdecr_after"); - if ((flags >> v22_PG_swap_unlock_after) & 1) - bufferindex += sprintflag("%sswap_unlock_after"); - if ((flags >> v22_PG_Slab) & 1) - bufferindex += sprintflag("%sslab"); - if ((flags >> v22_PG_swap_cache) & 1) - bufferindex += sprintflag("%sswap_cache"); - if ((flags >> v22_PG_skip) & 1) - bufferindex += sprintflag("%sskip"); - if ((flags >> v22_PG_reserved) & 1) - bufferindex += sprintflag("%sreserved"); - bufferindex += sprintf(outputbuffer+bufferindex, "\n"); - } else if (THIS_KERNEL_VERSION > LINUX(2,4,9)) { - 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) - bufferindex += sprintflag("%slocked"); - if ((flags >> v24_PG_error) & 1) - bufferindex += sprintflag("%serror"); - if ((flags >> v24_PG_referenced) & 1) - bufferindex += sprintflag("%sreferenced"); - if ((flags >> v24_PG_uptodate) & 1) - bufferindex += sprintflag("%suptodate"); - if ((flags >> v24_PG_dirty) & 1) - bufferindex += sprintflag("%sdirty"); - if ((flags >> v24_PG_decr_after) & 1) - bufferindex += sprintflag("%sdecr_after"); - if ((flags >> v24_PG_active) & 1) - bufferindex += sprintflag("%sactive"); - if ((flags >> v24_PG_inactive_dirty) & 1) - bufferindex += sprintflag("%sinactive_dirty"); - if ((flags >> v24_PG_slab) & 1) - bufferindex += sprintflag("%sslab"); - if ((flags >> v24_PG_swap_cache) & 1) - bufferindex += sprintflag("%sswap_cache"); - if ((flags >> v24_PG_skip) & 1) - bufferindex += sprintflag("%sskip"); - if ((flags >> v24_PG_inactive_clean) & 1) - bufferindex += sprintflag("%sinactive_clean"); - if ((flags >> v24_PG_highmem) & 1) - bufferindex += sprintflag("%shighmem"); - if ((flags >> v24_PG_checked) & 1) - bufferindex += sprintflag("%schecked"); - if ((flags >> v24_PG_bigpage) & 1) - bufferindex += sprintflag("%sbigpage"); - if ((flags >> v24_PG_arch_1) & 1) - bufferindex += sprintflag("%sarch_1"); - if ((flags >> v24_PG_reserved) & 1) - bufferindex += sprintflag("%sreserved"); - if (phys_not_mapped) - bufferindex += sprintflag("%s[NOT MAPPED]"); - - bufferindex += sprintf(outputbuffer+bufferindex, "\n"); + if (v22) { + if ((flags >> v22_PG_DMA) & 1) + bufferindex += sprintflag("%sDMA"); + if ((flags >> v22_PG_locked) & 1) + bufferindex += sprintflag("%slocked"); + if ((flags >> v22_PG_error) & 1) + bufferindex += sprintflag("%serror"); + if ((flags >> v22_PG_referenced) & 1) + bufferindex += sprintflag("%sreferenced"); + if ((flags >> v22_PG_dirty) & 1) + bufferindex += sprintflag("%sdirty"); + if ((flags >> v22_PG_uptodate) & 1) + bufferindex += sprintflag("%suptodate"); + if ((flags >> v22_PG_free_after) & 1) + bufferindex += sprintflag("%sfree_after"); + if ((flags >> v22_PG_decr_after) & 1) + bufferindex += sprintflag("%sdecr_after"); + if ((flags >> v22_PG_swap_unlock_after) & 1) + bufferindex += sprintflag("%sswap_unlock_after"); + if ((flags >> v22_PG_Slab) & 1) + bufferindex += sprintflag("%sslab"); + if ((flags >> v22_PG_swap_cache) & 1) + bufferindex += sprintflag("%sswap_cache"); + if ((flags >> v22_PG_skip) & 1) + bufferindex += sprintflag("%sskip"); + if ((flags >> v22_PG_reserved) & 1) + bufferindex += sprintflag("%sreserved"); + bufferindex += sprintf(outputbuffer+bufferindex, "\n"); + } else if (THIS_KERNEL_VERSION > LINUX(2,4,9)) { + 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) + bufferindex += sprintflag("%slocked"); + if ((flags >> v24_PG_error) & 1) + bufferindex += sprintflag("%serror"); + if ((flags >> v24_PG_referenced) & 1) + bufferindex += sprintflag("%sreferenced"); + if ((flags >> v24_PG_uptodate) & 1) + bufferindex += sprintflag("%suptodate"); + if ((flags >> v24_PG_dirty) & 1) + bufferindex += sprintflag("%sdirty"); + if ((flags >> v24_PG_decr_after) & 1) + bufferindex += sprintflag("%sdecr_after"); + if ((flags >> v24_PG_active) & 1) + bufferindex += sprintflag("%sactive"); + if ((flags >> v24_PG_inactive_dirty) & 1) + bufferindex += sprintflag("%sinactive_dirty"); + if ((flags >> v24_PG_slab) & 1) + bufferindex += sprintflag("%sslab"); + if ((flags >> v24_PG_swap_cache) & 1) + bufferindex += sprintflag("%sswap_cache"); + if ((flags >> v24_PG_skip) & 1) + bufferindex += sprintflag("%sskip"); + if ((flags >> v24_PG_inactive_clean) & 1) + bufferindex += sprintflag("%sinactive_clean"); + if ((flags >> v24_PG_highmem) & 1) + bufferindex += sprintflag("%shighmem"); + if ((flags >> v24_PG_checked) & 1) + bufferindex += sprintflag("%schecked"); + if ((flags >> v24_PG_bigpage) & 1) + bufferindex += sprintflag("%sbigpage"); + if ((flags >> v24_PG_arch_1) & 1) + bufferindex += sprintflag("%sarch_1"); + if ((flags >> v24_PG_reserved) & 1) + bufferindex += sprintflag("%sreserved"); + if (phys_not_mapped) + bufferindex += sprintflag("%s[NOT MAPPED]"); + + bufferindex += sprintf(outputbuffer+bufferindex, "\n"); + } } if (bufferindex > buffersize) { @@ -5851,6 +6033,12 @@ dump_mem_map(struct meminfo *mi) FREEBUF(outputbuffer); FREEBUF(page_cache); +failed_member_data: + if (mi->include) { + FREEBUF(members); + for (i = 0; i < nr_members; i++) + free(member_data[i]); + } } /* -- 1.9.3 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility