--- crash-4.0-4.12/main.c 2008-01-11 14:37:30.000000000 -0500 +++ crash-4.0-4.13/main.c 2008-01-04 09:42:08.000000000 -0500 @@ -1,8 +1,8 @@ /* main.c - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson - * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 David Anderson + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 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 @@ -55,6 +55,7 @@ {"CRASHPAGER", 0, 0, 0}, {"no_scroll", 0, 0, 0}, {"reloc", required_argument, 0, 0}, + {"active", 0, 0, 0}, {0, 0, 0, 0} }; @@ -184,6 +185,9 @@ else if (STREQ(long_options[option_index].name, "no_crashrc")) pc->flags |= NOCRASHRC; + else if (STREQ(long_options[option_index].name, "active")) + tt->flags |= ACTIVE_ONLY; + else if (STREQ(long_options[option_index].name, "reloc")) { if (!calculate(optarg, &kt->relocate, NULL, 0)) { error(INFO, "invalid --reloc argument: %s\n", @@ -319,7 +323,7 @@ } else if (!is_readable(argv[optind])) program_usage(SHORT_FORM); - if (is_elf_file(argv[optind])) { + if (is_kernel(argv[optind])) { if (pc->namelist || pc->server_namelist) { if (!select_namelist(argv[optind])) { error(INFO, --- crash-4.0-4.12/tools.c 2008-01-11 14:37:30.000000000 -0500 +++ crash-4.0-4.13/tools.c 2008-01-04 09:42:08.000000000 -0500 @@ -1,8 +1,8 @@ /* tools.c - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson - * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 David Anderson + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 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 @@ -4523,6 +4523,23 @@ return STREQ(MACHINE_TYPE, type); } +int +machine_type_mismatch(char *file, char *e_machine, char *alt, ulong query) +{ + if (machine_type(e_machine) || machine_type(alt)) + return FALSE; + + if (query == KDUMP_LOCAL) /* already printed by NETDUMP_LOCAL */ + return TRUE; + + error(WARNING, "machine type mismatch:\n"); + + fprintf(fp, " crash utility: %s\n", MACHINE_TYPE); + fprintf(fp, " %s: %s%s%s\n\n", file, e_machine, + alt ? " or " : "", alt ? alt : ""); + + return TRUE; +} void command_not_supported() { @@ -4581,3 +4598,65 @@ return ((c2 == '\0') && (c1 == '/') && (*p1 == '\0')) ? 0 : c1 - c2; } + +#include + +/* + * Check the byte-order of an ELF file vs. the host byte order. + */ +int +endian_mismatch(char *file, char dumpfile_endian, ulong query) +{ + char *endian; + + switch (dumpfile_endian) + { + case ELFDATA2LSB: + if (__BYTE_ORDER == __LITTLE_ENDIAN) + return FALSE; + endian = "big-endian"; + break; + case ELFDATA2MSB: + if (__BYTE_ORDER == __BIG_ENDIAN) + return FALSE; + endian = "little-endian"; + break; + default: + endian = "unknown"; + break; + } + + if (query == KDUMP_LOCAL) /* already printed by NETDUMP_LOCAL */ + return TRUE; + + error(WARNING, "endian mismatch:\n"); + + fprintf(fp, " crash utility: %s\n", + (__BYTE_ORDER == __LITTLE_ENDIAN) ? + "little-endian" : "big-endian"); + fprintf(fp, " %s: %s\n\n", file, endian); + + return TRUE; +} + +uint16_t +swap16(uint16_t val, int swap) +{ + if (swap) + return (((val & 0x00ff) << 8) | + ((val & 0xff00) >> 8)); + else + return val; +} + +uint32_t +swap32(uint32_t val, int swap) +{ + if (swap) + return (((val & 0x000000ffU) << 24) | + ((val & 0x0000ff00U) << 8) | + ((val & 0x00ff0000U) >> 8) | + ((val & 0xff000000U) >> 24)); + else + return val; +} --- crash-4.0-4.12/memory.c 2008-01-11 14:37:30.000000000 -0500 +++ crash-4.0-4.13/memory.c 2008-01-11 11:58:54.000000000 -0500 @@ -141,6 +141,7 @@ static char *vma_file_offset(ulong, ulong, char *); static ssize_t read_dev_kmem(ulong, char *, long); static void dump_memory_nodes(int); +static void dump_zone_stats(void); #define MEMORY_NODES_DUMP (0) #define MEMORY_NODES_INITIALIZE (1) static void node_table_init(void); @@ -164,7 +165,10 @@ static int next_online_node(int); static ulong next_online_pgdat(int); static int vm_stat_init(void); -static int dump_vm_stat(char *, long *); +static int vm_event_state_init(void); +static int dump_vm_stat(char *, long *, ulong); +static int dump_vm_event_state(void); +static int dump_page_states(void); static int generic_read_dumpfile(ulonglong, void *, long, char *, ulong); static int generic_write_dumpfile(ulonglong, void *, long, char *, ulong); static int page_to_nid(ulong); @@ -233,11 +237,8 @@ MEMBER_OFFSET_INIT(mm_struct_rss, "mm_struct", "rss"); if (!VALID_MEMBER(mm_struct_rss)) MEMBER_OFFSET_INIT(mm_struct_rss, "mm_struct", "_rss"); - if (!VALID_MEMBER(mm_struct_rss)) - MEMBER_OFFSET_INIT(mm_struct_rss, "mm_struct", "_file_rss"); - MEMBER_OFFSET_INIT(mm_struct_anon_rss, "mm_struct", "anon_rss"); - if (!VALID_MEMBER(mm_struct_anon_rss)) - MEMBER_OFFSET_INIT(mm_struct_anon_rss, "mm_struct", "_anon_rss"); + MEMBER_OFFSET_INIT(mm_struct_anon_rss, "mm_struct", "_anon_rss"); + MEMBER_OFFSET_INIT(mm_struct_file_rss, "mm_struct", "_file_rss"); MEMBER_OFFSET_INIT(mm_struct_total_vm, "mm_struct", "total_vm"); MEMBER_OFFSET_INIT(mm_struct_start_code, "mm_struct", "start_code"); MEMBER_OFFSET_INIT(vm_area_struct_vm_mm, "vm_area_struct", "vm_mm"); @@ -755,12 +756,23 @@ "zone", "zone_start_pfn"); MEMBER_OFFSET_INIT(zone_spanned_pages, "zone", "spanned_pages"); + MEMBER_OFFSET_INIT(zone_present_pages, + "zone", "present_pages"); MEMBER_OFFSET_INIT(zone_pages_min, "zone", "pages_min"); MEMBER_OFFSET_INIT(zone_pages_low, "zone", "pages_low"); MEMBER_OFFSET_INIT(zone_pages_high, "zone", "pages_high"); + MEMBER_OFFSET_INIT(zone_nr_active, + "zone", "nr_active"); + MEMBER_OFFSET_INIT(zone_nr_inactive, + "zone", "nr_inactive"); + MEMBER_OFFSET_INIT(zone_all_unreclaimable, + "zone", "all_unreclaimable"); + MEMBER_OFFSET_INIT(zone_flags, "zone", "flags"); + MEMBER_OFFSET_INIT(zone_pages_scanned, "zone", + "pages_scanned"); ARRAY_LENGTH_INIT(vt->nr_free_areas, zone_free_area, "zone.free_area", NULL, SIZE(free_area)); vt->dump_free_pages = dump_free_pages_zones_v2; @@ -3329,9 +3341,20 @@ if (!task_mm(task, TRUE)) return; - tm->rss = ULONG(tt->mm_struct + OFFSET(mm_struct_rss)); - if (VALID_MEMBER(mm_struct_anon_rss)) - tm->rss += ULONG(tt->mm_struct + OFFSET(mm_struct_anon_rss)); + if (VALID_MEMBER(mm_struct_rss)) + /* + * mm_struct.rss or mm_struct._rss exist. + */ + tm->rss = ULONG(tt->mm_struct + OFFSET(mm_struct_rss)); + else { + /* + * 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)); + if (VALID_MEMBER(mm_struct_file_rss)) + tm->rss += ULONG(tt->mm_struct + OFFSET(mm_struct_file_rss)); + } tm->total_vm = ULONG(tt->mm_struct + OFFSET(mm_struct_total_vm)); tm->pgd_addr = ULONG(tt->mm_struct + OFFSET(mm_struct_pgd)); @@ -3403,7 +3426,7 @@ { int i; int c; - int sflag, Sflag, pflag, fflag, Fflag, vflag; + int sflag, Sflag, pflag, fflag, Fflag, vflag, zflag; int nflag, cflag, Cflag, iflag, lflag, Lflag, Pflag, Vflag; struct meminfo meminfo; ulonglong value[MAXARGS]; @@ -3412,12 +3435,12 @@ int spec_addr; spec_addr = 0; - sflag = Sflag = pflag = fflag = Fflag = Pflag = 0; + sflag = Sflag = pflag = fflag = Fflag = Pflag = zflag = 0; vflag = Cflag = cflag = iflag = nflag = lflag = Lflag = Vflag = 0; BZERO(&meminfo, sizeof(struct meminfo)); BZERO(&value[0], sizeof(ulonglong)*MAXARGS); - while ((c = getopt(argcnt, args, "I:sSFfpvcCinl:L:PV")) != EOF) { + while ((c = getopt(argcnt, args, "I:sSFfpvczCinl:L:PV")) != EOF) { switch(c) { case 'V': @@ -3428,6 +3451,10 @@ nflag = 1; break; + case 'z': + zflag = 1; + break; + case 'i': iflag = 1; break; @@ -3635,7 +3662,7 @@ /* * no value arguments allowed! */ - if (nflag || iflag || Fflag || Cflag || Lflag || Vflag) { + if (zflag || nflag || iflag || Fflag || Cflag || Lflag || Vflag) { error(INFO, "no address arguments allowed with this option\n"); cmd_usage(pc->curcmd, SYNOPSIS); @@ -3704,6 +3731,9 @@ if (nflag == 1) dump_memory_nodes(MEMORY_NODES_DUMP); + if (zflag == 1) + dump_zone_stats(); + if (lflag == 1) { dump_page_lists(&meminfo); } @@ -3713,10 +3743,13 @@ dump_page_lists(&meminfo); } - if (Vflag == 1) - dump_vm_stat(NULL, NULL); + if (Vflag == 1) { + dump_vm_stat(NULL, NULL, 0); + dump_page_states(); + dump_vm_event_state(); + } - if (!(sflag + Sflag + pflag + fflag + Fflag + vflag + Vflag + + if (!(sflag + Sflag + pflag + fflag + Fflag + vflag + Vflag + zflag + cflag + Cflag + iflag + nflag + lflag + Lflag + meminfo.calls)) cmd_usage(pc->curcmd, SYNOPSIS); @@ -6345,11 +6378,11 @@ * If vm_stat array exists, override page search info. */ if (vm_stat_init()) { - if (dump_vm_stat("NR_SLAB", &nr_slab)) + if (dump_vm_stat("NR_SLAB", &nr_slab, 0)) get_slabs = nr_slab; - else if (dump_vm_stat("NR_SLAB_RECLAIMABLE", &nr_slab)) { + else if (dump_vm_stat("NR_SLAB_RECLAIMABLE", &nr_slab, 0)) { get_slabs = nr_slab; - if (dump_vm_stat("NR_SLAB_UNRECLAIMABLE", &nr_slab)) + if (dump_vm_stat("NR_SLAB_UNRECLAIMABLE", &nr_slab, 0)) get_slabs += nr_slab; } } @@ -6434,7 +6467,7 @@ get_symbol_data("nr_pagecache", sizeof(int), &tmp); page_cache_size = (long)tmp; page_cache_size -= subtract_buffer_pages; - } else if (dump_vm_stat("NR_FILE_PAGES", &nr_file_pages)) { + } else if (dump_vm_stat("NR_FILE_PAGES", &nr_file_pages, 0)) { char *swapper_space = GETBUF(SIZE(address_space)); if (!readmem(symbol_value("swapper_space"), KVADDR, swapper_space, @@ -10537,6 +10570,8 @@ fprintf(fp, "%sKMALLOC_SLUB", others++ ? "|" : "");\ if (vt->flags & CONFIG_NUMA) fprintf(fp, "%sCONFIG_NUMA", others++ ? "|" : "");\ + if (vt->flags & VM_EVENT) + fprintf(fp, "%sVM_EVENT", others++ ? "|" : "");\ fprintf(fp, ")\n"); if (vt->kernel_pgd[0] == vt->kernel_pgd[1]) @@ -10638,6 +10673,12 @@ for (i = 0; i < vt->nr_vm_stat_items; i++) fprintf(fp, " [%d] %s\n", i, vt->vm_stat_items[i]); + fprintf(fp, " nr_vm_event_items: %d\n", vt->nr_vm_event_items); + fprintf(fp, " vm_event_items: %s", (vt->flags & VM_EVENT) ? + "\n" : "(not used)\n"); + for (i = 0; i < vt->nr_vm_event_items; i++) + fprintf(fp, " [%d] %s\n", i, vt->vm_event_items[i]); + dump_vma_cache(VERBOSE); } @@ -11947,6 +11988,145 @@ dump_mem_sections(); } +static void +dump_zone_stats(void) +{ + int i, n; + ulong pgdat, node_zones; + char *zonebuf; + char buf1[BUFSIZE]; + int ivalue; + ulong value1; + ulong value2; + ulong value3; + ulong value4; + ulong value5; + ulong value6; + + pgdat = vt->node_table[0].pgdat; + zonebuf = GETBUF(SIZE_OPTION(zone_struct, zone)); + vm_stat_init(); + + for (n = 0; pgdat; n++) { + node_zones = pgdat + OFFSET(pglist_data_node_zones); + + for (i = 0; i < vt->nr_zones; i++) { + + if (!readmem(node_zones, KVADDR, zonebuf, + SIZE_OPTION(zone_struct, zone), + "zone buffer", FAULT_ON_ERROR)) + break; + + value1 = ULONG(zonebuf + + OFFSET_OPTION(zone_struct_name, zone_name)); + + if (!read_string(value1, buf1, BUFSIZE-1)) + sprintf(buf1, "(unknown) "); + + if (VALID_MEMBER(zone_struct_size)) + value1 = value6 = ULONG(zonebuf + + OFFSET(zone_struct_size)); + else if (VALID_MEMBER(zone_struct_memsize)) { + value1 = value6 = ULONG(zonebuf + + OFFSET(zone_struct_memsize)); + } else if (VALID_MEMBER(zone_spanned_pages)) { + value1 = ULONG(zonebuf + + OFFSET(zone_spanned_pages)); + value6 = ULONG(zonebuf + + OFFSET(zone_present_pages)); + } else error(FATAL, + "zone struct has unknown size field\n"); + + value2 = ULONG(zonebuf + OFFSET_OPTION(zone_pages_min, + zone_struct_pages_min)); + value3 = ULONG(zonebuf + OFFSET_OPTION(zone_pages_low, + zone_struct_pages_low)); + value4 = ULONG(zonebuf + OFFSET_OPTION(zone_pages_high, + zone_struct_pages_high)); + value5 = ULONG(zonebuf + OFFSET_OPTION(zone_free_pages, + zone_struct_free_pages)); + + fprintf(fp, + "NODE: %d ZONE: %d ADDR: %lx NAME: \"%s\"\n", + n, i, node_zones, buf1); + + if (!value1) { + fprintf(fp, " [unpopulated]\n"); + goto next_zone; + } + fprintf(fp, " SIZE: %ld", value1); + if (value6 < value1) + fprintf(fp, " PRESENT: %ld", value6); + fprintf(fp, " MIN/LOW/HIGH: %ld/%ld/%ld", + value2, value3, value4); + + if (VALID_MEMBER(zone_vm_stat)) + dump_vm_stat("NR_FREE_PAGES", (long *)&value5, + node_zones + OFFSET(zone_vm_stat)); + + if (VALID_MEMBER(zone_nr_active) && + VALID_MEMBER(zone_nr_inactive)) { + value1 = ULONG(zonebuf + + OFFSET(zone_nr_active)); + value2 = ULONG(zonebuf + + OFFSET(zone_nr_inactive)); + fprintf(fp, + "\n NR_ACTIVE: %ld NR_INACTIVE: %ld FREE: %ld\n", + value1, value2, value5); + if (VALID_MEMBER(zone_vm_stat)) { + fprintf(fp, " VM_STAT:\n"); + dump_vm_stat(NULL, NULL, node_zones + + OFFSET(zone_vm_stat)); + } + } else if (VALID_MEMBER(zone_vm_stat) && + dump_vm_stat("NR_ACTIVE", (long *)&value1, + node_zones + OFFSET(zone_vm_stat)) && + dump_vm_stat("NR_INACTIVE", (long *)&value2, + node_zones + OFFSET(zone_vm_stat))) { + fprintf(fp, "\n VM_STAT:\n"); + dump_vm_stat(NULL, NULL, node_zones + + OFFSET(zone_vm_stat)); + } else { + fprintf(fp, " FREE: %ld\n", value5); + goto next_zone; + } + + if (VALID_MEMBER(zone_all_unreclaimable)) { + ivalue = UINT(zonebuf + + OFFSET(zone_all_unreclaimable)); + fprintf(fp, " ALL_UNRECLAIMABLE: %s ", + ivalue ? "yes" : "no"); + } else if (VALID_MEMBER(zone_flags) && + enumerator_value("ZONE_ALL_UNRECLAIMABLE", + (long *)&value1)) { + value2 = ULONG(zonebuf + OFFSET(zone_flags)); + value3 = value2 & (1 << value1); + fprintf(fp, " ALL_UNRECLAIMABLE: %s ", + value3 ? "yes" : "no"); + } + + if (VALID_MEMBER(zone_pages_scanned)) { + value1 = ULONG(zonebuf + + OFFSET(zone_pages_scanned)); + fprintf(fp, "PAGES_SCANNED: %ld ", value1); + } + fprintf(fp, "\n"); + +next_zone: + fprintf(fp, "\n"); + node_zones += SIZE_OPTION(zone_struct, zone); + } + + if ((n+1) < vt->numnodes) + pgdat = vt->node_table[n+1].pgdat; + else + pgdat = 0; + } + + FREEBUF(zonebuf); + +} + /* * Gather essential information regarding each memory node. */ @@ -12767,7 +12947,7 @@ (sizeof(void *) * vt->nr_vm_stat_items); if (!(vt->vm_stat_items = (char **)malloc(total))) { close_tmpfile(); - error(FATAL, "cannot malloc vm_area_struct cache\n"); + error(FATAL, "cannot malloc vm_stat_items cache\n"); } start = (char *)&vt->vm_stat_items[vt->nr_vm_stat_items]; @@ -12796,33 +12976,39 @@ /* * Either dump all vm_stat entries, or return the value of - * the specified vm_stat item. + * the specified vm_stat item. Use the global counter unless + * a zone-specific address is passed. */ static int -dump_vm_stat(char *item, long *retval) +dump_vm_stat(char *item, long *retval, ulong zone) { char *buf; ulong *vp; + ulong location; int i; if (!vm_stat_init()) { if (!item) - error(FATAL, - "vm_stat not available in this kernel\n"); + if (CRASHDEBUG(1)) + error(INFO, + "vm_stat not available in this kernel\n"); return FALSE; } buf = GETBUF(sizeof(ulong) * vt->nr_vm_stat_items); - readmem(symbol_value("vm_stat"), KVADDR, buf, + location = zone ? zone : symbol_value("vm_stat"); + + readmem(location, KVADDR, buf, sizeof(ulong) * vt->nr_vm_stat_items, "vm_stat", FAULT_ON_ERROR); - if (!item) { + if (!zone) + fprintf(fp, " VM_STAT:\n"); vp = (ulong *)buf; for (i = 0; i < vt->nr_vm_stat_items; i++) - fprintf(fp, "%21s: %ld\n", vt->vm_stat_items[i], vp[i]); + fprintf(fp, "%23s: %ld\n", vt->vm_stat_items[i], vp[i]); return TRUE; } @@ -12838,6 +13024,232 @@ } /* + * Dump the cumulative totals of the per_cpu__page_states counters. + */ +int +dump_page_states(void) +{ + struct syment *sp; + ulong addr, value; + int i, c, fd, len, instance, members; + char buf[BUFSIZE]; + char *arglist[MAXARGS]; + struct entry { + char *name; + ulong value; + } *entry_list; + struct stat stat; + char *namebuf, *nameptr; + + if (!(sp = symbol_search("per_cpu__page_states"))) { + if (CRASHDEBUG(1)) + error(INFO, "per_cpu__page_states" + "not available in this kernel\n"); + return FALSE; + } + + instance = members = len = 0; + + sprintf(buf, "ptype struct page_state"); + + open_tmpfile(); + if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) { + close_tmpfile(); + return FALSE; + } + + fflush(pc->tmpfile); + fd = fileno(pc->tmpfile); + fstat(fd, &stat); + namebuf = GETBUF(stat.st_size); + nameptr = namebuf; + + rewind(pc->tmpfile); + while (fgets(buf, BUFSIZE, pc->tmpfile)) { + if (strstr(buf, "struct page_state") || + strstr(buf, "}")) + continue; + members++; + } + + entry_list = (struct entry *) + GETBUF(sizeof(struct entry) * members); + + rewind(pc->tmpfile); + i = 0; + while (fgets(buf, BUFSIZE, pc->tmpfile)) { + if (strstr(buf, "struct page_state") || + strstr(buf, "}")) + continue; + strip_ending_char(strip_linefeeds(buf), ';'); + c = parse_line(buf, arglist); + strcpy(nameptr, arglist[c-1]); + entry_list[i].name = nameptr; + if (strlen(nameptr) > len) + len = strlen(nameptr); + nameptr += strlen(nameptr)+2; + i++; + } + close_tmpfile(); + + open_tmpfile(); + + for (c = 0; c < kt->cpus; c++) { + addr = sp->value + kt->__per_cpu_offset[c]; + dump_struct("page_state", addr, RADIX(16)); + } + + i = 0; + rewind(pc->tmpfile); + while (fgets(buf, BUFSIZE, pc->tmpfile)) { + if (strstr(buf, "struct page_state")) { + instance++; + i = 0; + continue; + } + if (strstr(buf, "}")) + continue; + strip_linefeeds(buf); + extract_hex(buf, &value, ',', TRUE); + entry_list[i].value += value; + i++; + } + + close_tmpfile(); + + fprintf(fp, " PAGE_STATES:\n"); + for (i = 0; i < members; i++) { + sprintf(buf, "%s", entry_list[i].name); + fprintf(fp, "%s", mkstring(buf, len+2, RJUST, 0)); + fprintf(fp, ": %ld\n", entry_list[i].value); + } + + FREEBUF(namebuf); + FREEBUF(entry_list); + + return TRUE; +} + + +/* + * Dump the cumulative totals of the per_cpu__vm_event_state + * counters. + */ +static int +dump_vm_event_state(void) +{ + int i, c; + struct syment *sp; + ulong addr; + ulong *events, *cumulative; + + if (!vm_event_state_init()) + return FALSE; + + events = (ulong *)GETBUF((sizeof(ulong) * vt->nr_vm_event_items) * 2); + cumulative = &events[vt->nr_vm_event_items]; + + sp = symbol_search("per_cpu__vm_event_states"); + + for (c = 0; c < kt->cpus; c++) { + addr = sp->value + kt->__per_cpu_offset[c]; + if (CRASHDEBUG(1)) { + fprintf(fp, "[%d]: %lx\n", c, addr); + dump_struct("vm_event_state", addr, RADIX(16)); + } + readmem(addr, KVADDR, events, + sizeof(ulong) * vt->nr_vm_event_items, + "vm_event_states buffer", FAULT_ON_ERROR); + for (i = 0; i < vt->nr_vm_event_items; i++) + cumulative[i] += events[i]; + } + + fprintf(fp, "\n VM_EVENT_STATES:\n"); + for (i = 0; i < vt->nr_vm_event_items; i++) + fprintf(fp, "%23s: %ld\n", vt->vm_event_items[i], cumulative[i]); + + FREEBUF(events); + + return TRUE; +} + +static int +vm_event_state_init(void) +{ + int i, c, stringlen, total; + long count; + struct gnu_request *req; + char *arglist[MAXARGS]; + char buf[BUFSIZE]; + char *start; + + if (vt->flags & VM_EVENT) + return TRUE; + + if ((vt->nr_vm_event_items == -1) || + !symbol_exists("per_cpu__vm_event_states")) + goto bailout; + + if (!enumerator_value("NR_VM_EVENT_ITEMS", &count)) + return FALSE; + + vt->nr_vm_event_items = count; + + open_tmpfile(); + req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request)); + req->command = GNU_GET_DATATYPE; + req->name = "vm_event_item"; + req->flags = GNU_PRINT_ENUMERATORS; + gdb_interface(req); + FREEBUF(req); + + stringlen = 1; + + rewind(pc->tmpfile); + while (fgets(buf, BUFSIZE, pc->tmpfile)) { + if (strstr(buf, "{") || strstr(buf, "}")) + continue; + clean_line(buf); + c = parse_line(buf, arglist); + if (STREQ(arglist[0], "NR_VM_EVENT_ITEMS")) + break; + else + stringlen += strlen(arglist[0]); + } + + total = stringlen + vt->nr_vm_event_items + + (sizeof(void *) * vt->nr_vm_event_items); + if (!(vt->vm_event_items = (char **)malloc(total))) { + close_tmpfile(); + error(FATAL, "cannot malloc vm_event_items cache\n"); + } + + start = (char *)&vt->vm_event_items[vt->nr_vm_event_items]; + + rewind(pc->tmpfile); + while (fgets(buf, BUFSIZE, pc->tmpfile)) { + if (strstr(buf, "{") || strstr(buf, "}")) + continue; + c = parse_line(buf, arglist); + i = atoi(arglist[2]); + if (i < vt->nr_vm_event_items) { + vt->vm_event_items[i] = start; + strcpy(start, arglist[0]); + start += strlen(arglist[0]) + 1; + } + } + close_tmpfile(); + + vt->flags |= VM_EVENT; + return TRUE; + +bailout: + vt->nr_vm_event_items = -1; + return FALSE; +} + + +/* * Support for slub.c slab cache. */ static void --- crash-4.0-4.12/help.c 2008-01-11 14:37:30.000000000 -0500 +++ crash-4.0-4.13/help.c 2008-01-04 11:54:24.000000000 -0500 @@ -1,8 +1,8 @@ /* help.c - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson - * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 David Anderson + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 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 @@ -3861,7 +3861,7 @@ char *help_kmem[] = { "kmem", "kernel memory", -"[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n] [-[l|L][a|i]] [slab] [[-P] address]", +"[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n|-z] [-[l|L][a|i]] [slab] [[-P] address]", " 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.", @@ -3878,8 +3878,11 @@ " address of each kmem_cache_node, its count of full and partial", " slabs, and a list of all tracked slabs.", " -v displays the vmlist entries.", -" -V displays the kernel vm_stat table.", +" -V displays the kernel vm_stat table if it exists, the cumulative", +" page_states counter values if they exist, and/or the cumulative", +" vm_event_states counter values if they exist.", " -n display memory node data (if supported).", +" -z displays per-zone memory statistics.", " -la walks through the active_list and verifies nr_active_pages.", " -li walks through the inactive_list and verifies nr_inactive_pages.", " -La same as -la, but also dumps each page in the active_list.", @@ -5198,7 +5201,7 @@ static char *version_info[] = { -"Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc.", +"Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc.", "Copyright (C) 2004, 2005, 2006 IBM Corporation", "Copyright (C) 1999-2006 Hewlett-Packard Co", "Copyright (C) 2005, 2006 Fujitsu Limited", --- crash-4.0-4.12/task.c 2008-01-11 14:37:30.000000000 -0500 +++ crash-4.0-4.13/task.c 2008-01-07 11:00:21.000000000 -0500 @@ -29,6 +29,7 @@ static void refresh_hlist_task_table(void); static void refresh_hlist_task_table_v2(void); static void refresh_hlist_task_table_v3(void); +static void refresh_active_task_table(void); static struct task_context *store_context(struct task_context *, ulong, char *); static void refresh_context(ulong, ulong); static void parent_list(ulong); @@ -409,6 +410,10 @@ irqstacks_init(); get_active_set(); + + if (tt->flags & ACTIVE_ONLY) + tt->refresh_task_table = refresh_active_task_table; + tt->refresh_task_table(); if (tt->flags & TASK_REFRESH_OFF) @@ -1971,6 +1976,125 @@ tt->retries = MAX(tt->retries, retries); } +static void +refresh_active_task_table(void) +{ + int i; + char *tp; + int cnt; + struct task_context *tc; + ulong curtask; + ulong curpid; + ulong retries; + ulong *tlp; + + if (DUMPFILE() && (tt->flags & TASK_INIT_DONE)) /* impossible */ + return; + + if (DUMPFILE()) { + please_wait("gathering task table data"); + if (!symbol_exists("panic_threads")) + tt->flags |= POPULATE_PANIC; + } + + if (ACTIVE() && !(tt->flags & TASK_REFRESH)) + return; + + get_active_set(); + /* + * The current task's task_context entry may change, + * or the task may not even exist anymore. + */ + if (ACTIVE() && (tt->flags & TASK_INIT_DONE)) { + curtask = CURRENT_TASK(); + curpid = CURRENT_PID(); + } + +retry_active: + + if (!hq_open()) { + error(INFO, "cannot hash task_struct entries\n"); + if (!(tt->flags & TASK_INIT_DONE)) + clean_exit(1); + error(INFO, "using stale task_structs\n"); + return; + } + + /* + * Get the active tasks. + */ + cnt = 0; + for (i = 0; i < kt->cpus; i++) { + if (hq_enter(tt->active_set[i])) + cnt++; + else + error(WARNING, "%sduplicate active tasks?\n", + DUMPFILE() ? "\n" : ""); + } + + BZERO(tt->task_local, tt->max_tasks * sizeof(void *)); + cnt = retrieve_list((ulong *)tt->task_local, cnt); + + hq_close(); + + clear_task_cache(); + + for (i = 0, tlp = (ulong *)tt->task_local, + tt->running_tasks = 0, tc = tt->context_array; + i < tt->max_tasks; i++, tlp++) { + if (!(*tlp)) + continue; + + if (!IS_TASK_ADDR(*tlp)) { + error(WARNING, + "%sinvalid task address found in task list: %lx\n", + DUMPFILE() ? "\n" : "", *tlp); + if (DUMPFILE()) + continue; + retries++; + goto retry_active; + } + + if (task_exists(*tlp)) { + error(WARNING, + "%sduplicate task address found in task list: %lx\n", + DUMPFILE() ? "\n" : "", *tlp); + if (DUMPFILE()) + continue; + retries++; + goto retry_active; + } + + if (!(tp = fill_task_struct(*tlp))) { + if (DUMPFILE()) + continue; + retries++; + goto retry_active; + } + + if (store_context(tc, *tlp, tp)) { + tc++; + tt->running_tasks++; + } else if (DUMPFILE()) + error(WARNING, "corrupt/invalid active task: %lx\n", + *tlp); + } + + if (!tt->running_tasks) { + if (DUMPFILE()) + error(FATAL, "cannot determine any active tasks!\n"); + retries++; + goto retry_active; + } + + please_wait_done(); + + if (ACTIVE() && (tt->flags & TASK_INIT_DONE)) + refresh_context(curtask, curpid); + + tt->retries = MAX(tt->retries, retries); +} + /* * Fill a task_context structure with the data from a task. If a NULL * task_context pointer is passed in, use the next available one. @@ -1994,6 +2118,8 @@ do_verify = 2; else if (tt->refresh_task_table == refresh_hlist_task_table_v3) do_verify = 2; + else if (tt->refresh_task_table == refresh_active_task_table) + do_verify = 2; else do_verify = 0; @@ -3952,6 +4078,10 @@ cnt++ ? "" : "\n", tc->comm); break; } + + if (!(pc->flags & RUNTIME) && (tt->flags & ACTIVE_ONLY)) + error(WARNING, + "\nonly the active tasks on each cpu are being tracked\n"); } @@ -5413,6 +5543,8 @@ fprintf(fp, "refresh_hlist_task_table_v2()\n"); else if (tt->refresh_task_table == refresh_hlist_task_table_v3) fprintf(fp, "refresh_hlist_task_table_v3()\n"); + else if (tt->refresh_task_table == refresh_active_task_table) + fprintf(fp, "refresh_active_task_table()\n"); else fprintf(fp, "%lx\n", (ulong)tt->refresh_task_table); @@ -5461,6 +5593,9 @@ if (tt->flags & NO_TIMESPEC) sprintf(&buf[strlen(buf)], "%sNO_TIMESPEC", others++ ? "|" : ""); + if (tt->flags & ACTIVE_ONLY) + sprintf(&buf[strlen(buf)], + "%sACTIVE_ONLY", others++ ? "|" : ""); sprintf(&buf[strlen(buf)], ")"); if (strlen(buf) > 54) --- crash-4.0-4.12/x86.c 2008-01-11 14:37:30.000000000 -0500 +++ crash-4.0-4.13/x86.c 2008-01-04 09:42:08.000000000 -0500 @@ -1009,22 +1009,22 @@ static ulong x86_get_stackbase_hyper(ulong); static ulong x86_get_stacktop_hyper(ulong); -static int INT_EFRAME_SS = 14; -static int INT_EFRAME_ESP = 13; -static int INT_EFRAME_EFLAGS = 12; /* CS lcall7 */ -static int INT_EFRAME_CS = 11; /* EIP lcall7 */ -static int INT_EFRAME_EIP = 10; /* EFLAGS lcall7 */ -static int INT_EFRAME_ERR = 9; -static int INT_EFRAME_ES = 8; -static int INT_EFRAME_DS = 7; -static int INT_EFRAME_EAX = 6; -static int INT_EFRAME_EBP = 5; -static int INT_EFRAME_EDI = 4; -static int INT_EFRAME_ESI = 3; -static int INT_EFRAME_EDX = 2; -static int INT_EFRAME_ECX = 1; -static int INT_EFRAME_EBX = 0; -static int INT_EFRAME_GS = -1; +int INT_EFRAME_SS = 14; +int INT_EFRAME_ESP = 13; +int INT_EFRAME_EFLAGS = 12; /* CS lcall7 */ +int INT_EFRAME_CS = 11; /* EIP lcall7 */ +int INT_EFRAME_EIP = 10; /* EFLAGS lcall7 */ +int INT_EFRAME_ERR = 9; +int INT_EFRAME_ES = 8; +int INT_EFRAME_DS = 7; +int INT_EFRAME_EAX = 6; +int INT_EFRAME_EBP = 5; +int INT_EFRAME_EDI = 4; +int INT_EFRAME_ESI = 3; +int INT_EFRAME_EDX = 2; +int INT_EFRAME_ECX = 1; +int INT_EFRAME_EBX = 0; +int INT_EFRAME_GS = -1; #define MAX_USER_EFRAME_SIZE (16) #define KERNEL_EFRAME_SIZE (INT_EFRAME_EFLAGS+1) --- crash-4.0-4.12/x86_64.c 2008-01-11 14:37:30.000000000 -0500 +++ crash-4.0-4.13/x86_64.c 2008-01-04 09:42:08.000000000 -0500 @@ -4339,126 +4339,6 @@ #include "netdump.h" /* - * Determine the physical address base for relocatable kernels. - */ -static void -x86_64_calc_phys_base(void) -{ - int i; - FILE *iomem; - char buf[BUFSIZE]; - char *p1; - ulong phys_base, text_start, kernel_code_start; - int errflag; - struct vmcore_data *vd; - Elf64_Phdr *phdr; - - if (machdep->flags & PHYS_BASE) /* --machdep override */ - return; - - machdep->machspec->phys_base = 0; /* default/traditional */ - - if (!kernel_symbol_exists("phys_base")) - return; - - if (!symbol_exists("_text")) - return; - else - text_start = symbol_value("_text"); - - if (ACTIVE()) { - if ((iomem = fopen("/proc/iomem", "r")) == NULL) - return; - - errflag = 1; - while (fgets(buf, BUFSIZE, iomem)) { - if (strstr(buf, ": Kernel code")) { - clean_line(buf); - errflag = 0; - break; - } - } - fclose(iomem); - - if (errflag) - return; - - if (!(p1 = strstr(buf, "-"))) - return; - else - *p1 = NULLCHAR; - - errflag = 0; - kernel_code_start = htol(buf, RETURN_ON_ERROR|QUIET, &errflag); - if (errflag) - return; - - machdep->machspec->phys_base = kernel_code_start - - (text_start - __START_KERNEL_map); - - if (CRASHDEBUG(1)) { - fprintf(fp, "_text: %lx ", text_start); - fprintf(fp, "Kernel code: %lx -> ", kernel_code_start); - fprintf(fp, "phys_base: %lx\n\n", - machdep->machspec->phys_base); - } - - return; - } - - /* - * Get relocation value from whatever dumpfile format is being used. - */ - - if (DISKDUMP_DUMPFILE()) { - if (diskdump_phys_base(&phys_base)) { - machdep->machspec->phys_base = phys_base; - if (CRASHDEBUG(1)) - fprintf(fp, "compressed kdump: phys_base: %lx\n", - phys_base); - } - return; - } - - if ((vd = get_kdump_vmcore_data())) { - for (i = 0; i < vd->num_pt_load_segments; i++) { - phdr = vd->load64 + i; - if ((phdr->p_vaddr >= __START_KERNEL_map) && - !(IS_VMALLOC_ADDR(phdr->p_vaddr))) { - - machdep->machspec->phys_base = phdr->p_paddr - - (phdr->p_vaddr & ~(__START_KERNEL_map)); - - if (CRASHDEBUG(1)) { - fprintf(fp, "p_vaddr: %lx p_paddr: %lx -> ", - phdr->p_vaddr, phdr->p_paddr); - fprintf(fp, "phys_base: %lx\n\n", - machdep->machspec->phys_base); - } - break; - } - } - - return; - } - - if (XENDUMP_DUMPFILE() && (text_start == __START_KERNEL_map)) { - /* - * Xen kernels are not relocable (yet) and don't have the - * "phys_base" entry point, so this must be a xendump of a - * fully-virtualized relocatable kernel. No clues exist in - * the xendump header, so hardwire phys_base to 2MB and hope - * for the best. - */ - machdep->machspec->phys_base = 0x200000; - if (CRASHDEBUG(1)) - fprintf(fp, - "default relocatable default phys_base: %lx\n", - machdep->machspec->phys_base); - } -} - -/* * From the xen vmcore, create an index of mfns for each page that makes * up the dom0 kernel's complete phys_to_machine_mapping[max_pfn] array. */ @@ -4718,6 +4598,154 @@ #include "xendump.h" /* + * Determine the physical address base for relocatable kernels. + */ +static void +x86_64_calc_phys_base(void) +{ + int i; + FILE *iomem; + char buf[BUFSIZE]; + char *p1; + ulong phys_base, text_start, kernel_code_start; + int errflag; + struct vmcore_data *vd; + static struct xendump_data *xd; + Elf64_Phdr *phdr; + + if (machdep->flags & PHYS_BASE) /* --machdep override */ + return; + + machdep->machspec->phys_base = 0; /* default/traditional */ + + if (!kernel_symbol_exists("phys_base")) + return; + + if (!symbol_exists("_text")) + return; + else + text_start = symbol_value("_text"); + + if (ACTIVE()) { + if ((iomem = fopen("/proc/iomem", "r")) == NULL) + return; + + errflag = 1; + while (fgets(buf, BUFSIZE, iomem)) { + if (strstr(buf, ": Kernel code")) { + clean_line(buf); + errflag = 0; + break; + } + } + fclose(iomem); + + if (errflag) + return; + + if (!(p1 = strstr(buf, "-"))) + return; + else + *p1 = NULLCHAR; + + errflag = 0; + kernel_code_start = htol(buf, RETURN_ON_ERROR|QUIET, &errflag); + if (errflag) + return; + + machdep->machspec->phys_base = kernel_code_start - + (text_start - __START_KERNEL_map); + + if (CRASHDEBUG(1)) { + fprintf(fp, "_text: %lx ", text_start); + fprintf(fp, "Kernel code: %lx -> ", kernel_code_start); + fprintf(fp, "phys_base: %lx\n\n", + machdep->machspec->phys_base); + } + + return; + } + + /* + * Get relocation value from whatever dumpfile format is being used. + */ + + if (DISKDUMP_DUMPFILE()) { + if (diskdump_phys_base(&phys_base)) { + machdep->machspec->phys_base = phys_base; + if (CRASHDEBUG(1)) + fprintf(fp, "compressed kdump: phys_base: %lx\n", + phys_base); + } + return; + } + + if ((vd = get_kdump_vmcore_data())) { + for (i = 0; i < vd->num_pt_load_segments; i++) { + phdr = vd->load64 + i; + if ((phdr->p_vaddr >= __START_KERNEL_map) && + !(IS_VMALLOC_ADDR(phdr->p_vaddr))) { + + machdep->machspec->phys_base = phdr->p_paddr - + (phdr->p_vaddr & ~(__START_KERNEL_map)); + + if (CRASHDEBUG(1)) { + fprintf(fp, "p_vaddr: %lx p_paddr: %lx -> ", + phdr->p_vaddr, phdr->p_paddr); + fprintf(fp, "phys_base: %lx\n\n", + machdep->machspec->phys_base); + } + break; + } + } + + return; + } + + if ((xd = get_xendump_data())) { + if (text_start == __START_KERNEL_map) { + /* + * Xen kernels are not relocable (yet) and don't have + * the "phys_base" entry point, so this is most likely + * a xendump of a fully-virtualized relocatable kernel. + * No clues exist in the xendump header, so hardwire + * phys_base to 2MB and hope for the best. + */ + machdep->machspec->phys_base = 0x200000; + if (CRASHDEBUG(1)) + fprintf(fp, + "default relocatable phys_base: %lx\n", + machdep->machspec->phys_base); + + } else if (text_start > __START_KERNEL_map) { + switch (xd->flags & (XC_CORE_ELF|XC_CORE_NO_P2M)) + { + /* + * If this is a new ELF-style xendump with no + * p2m information, then it also must be a + * fully-virtualized relocatable kernel. Again, + * the xendump header is useless, and we don't + * have /proc/iomem, so presume that the kernel + * code starts at 2MB. + */ + case (XC_CORE_ELF|XC_CORE_NO_P2M): + machdep->machspec->phys_base = 0x200000 - + (text_start - __START_KERNEL_map); + if (CRASHDEBUG(1)) + fprintf(fp, "default relocatable " + "phys_base: %lx\n", + machdep->machspec->phys_base); + break; + + default: + break; + } + } + } +} + + +/* * Create an index of mfns for each page that makes up the * kernel's complete phys_to_machine_mapping[max_pfn] array. */ --- crash-4.0-4.12/symbols.c 2008-01-11 14:37:30.000000000 -0500 +++ crash-4.0-4.13/symbols.c 2008-01-04 09:42:08.000000000 -0500 @@ -1,8 +1,8 @@ /* symbols.c - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson - * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 David Anderson + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 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 @@ -2497,6 +2497,96 @@ } /* + * Verify a vmlinux file, issuing a warning for processor and endianness + * mismatches. + */ +int +is_kernel(char *file) +{ + int fd, swap; + char eheader[BUFSIZE]; + Elf32_Ehdr *elf32; + Elf64_Ehdr *elf64; + + if ((fd = open(file, O_RDONLY)) < 0) { + error(INFO, "%s: %s\n", file, strerror(errno)); + return FALSE; + } + if (read(fd, eheader, BUFSIZE) != BUFSIZE) { + /* error(INFO, "%s: %s\n", file, strerror(errno)); */ + close(fd); + return FALSE; + } + close(fd); + + if (!STRNEQ(eheader, ELFMAG) || eheader[EI_VERSION] != EV_CURRENT) + return FALSE; + + elf32 = (Elf32_Ehdr *)&eheader[0]; + elf64 = (Elf64_Ehdr *)&eheader[0]; + + swap = (((eheader[EI_DATA] == ELFDATA2LSB) && + (__BYTE_ORDER == __BIG_ENDIAN)) || + ((eheader[EI_DATA] == ELFDATA2MSB) && + (__BYTE_ORDER == __LITTLE_ENDIAN))); + + if ((elf32->e_ident[EI_CLASS] == ELFCLASS32) && + (swap16(elf32->e_type, swap) == ET_EXEC) && + (swap32(elf32->e_version, swap) == EV_CURRENT)) { + switch (swap16(elf32->e_machine, swap)) + { + case EM_386: + if (machine_type_mismatch(file, "X86", NULL, 0)) + goto bailout; + break; + + default: + if (machine_type_mismatch(file, "(unknown)", NULL, 0)) + goto bailout; + } + + if (endian_mismatch(file, elf32->e_ident[EI_DATA], 0)) + goto bailout; + + } else if ((elf64->e_ident[EI_CLASS] == ELFCLASS64) && + (swap16(elf64->e_type, swap) == ET_EXEC) && + (swap32(elf64->e_version, swap) == EV_CURRENT)) { + switch (swap16(elf64->e_machine, swap)) + { + case EM_IA_64: + if (machine_type_mismatch(file, "IA64", NULL, 0)) + goto bailout; + break; + + case EM_PPC64: + if (machine_type_mismatch(file, "PPC64", NULL, 0)) + goto bailout; + break; + + case EM_X86_64: + if (machine_type_mismatch(file, "X86_64", NULL, 0)) + goto bailout; + break; + + case EM_386: + if (machine_type_mismatch(file, "X86", NULL, 0)) + goto bailout; + break; + + default: + if (machine_type_mismatch(file, "(unknown)", NULL, 0)) + goto bailout; + } + + if (endian_mismatch(file, elf64->e_ident[EI_DATA], 0)) + goto bailout; + } + +bailout: + return(is_bfd_format(file)); +} + +/* * Given a choice between two namelists, pick the one for gdb to use. * For now, just check get their stats and check their sizes; the larger * one presumably has debug data. @@ -6017,6 +6107,8 @@ OFFSET(mm_struct_rss)); fprintf(fp, " mm_struct_anon_rss: %ld\n", OFFSET(mm_struct_anon_rss)); + fprintf(fp, " mm_struct_file_rss: %ld\n", + OFFSET(mm_struct_file_rss)); fprintf(fp, " mm_struct_total_vm: %ld\n", OFFSET(mm_struct_total_vm)); fprintf(fp, " mm_struct_start_code: %ld\n", @@ -6689,6 +6781,8 @@ OFFSET(zone_name)); fprintf(fp, " zone_spanned_pages: %ld\n", OFFSET(zone_spanned_pages)); + fprintf(fp, " zone_present_pages: %ld\n", + OFFSET(zone_present_pages)); fprintf(fp, " zone_zone_start_pfn: %ld\n", OFFSET(zone_zone_start_pfn)); fprintf(fp, " zone_pages_min: %ld\n", @@ -6699,6 +6793,16 @@ OFFSET(zone_pages_high)); fprintf(fp, " zone_vm_stat: %ld\n", OFFSET(zone_vm_stat)); + fprintf(fp, " zone_nr_active: %ld\n", + OFFSET(zone_nr_active)); + fprintf(fp, " zone_nr_inactive: %ld\n", + OFFSET(zone_nr_inactive)); + fprintf(fp, " zone_all_unreclaimable: %ld\n", + OFFSET(zone_all_unreclaimable)); + fprintf(fp, " zone_flags: %ld\n", + OFFSET(zone_flags)); + fprintf(fp, " zone_pages_scanned: %ld\n", + OFFSET(zone_pages_scanned)); fprintf(fp, " neighbour_next: %ld\n", OFFSET(neighbour_next)); --- crash-4.0-4.12/lkcd_x86_trace.c 2008-01-11 14:37:30.000000000 -0500 +++ crash-4.0-4.13/lkcd_x86_trace.c 2008-01-04 09:42:08.000000000 -0500 @@ -54,10 +54,9 @@ static int find_trace(kaddr_t, kaddr_t, kaddr_t, kaddr_t, trace_t *, int); static void dump_stack_frame(trace_t *, sframe_t *, FILE *); static void print_trace(trace_t *, int, FILE *); -struct pt_regs; -static int eframe_type(struct pt_regs *); +static int eframe_type(uaddr_t *); char *funcname_display(char *); -static void print_eframe(FILE *, struct pt_regs *); +static void print_eframe(FILE *, uaddr_t *); static void trace_banner(FILE *); static void print_kaddr(kaddr_t, FILE *, int); int do_text_list(kaddr_t, int, FILE *); @@ -1122,7 +1121,6 @@ return(0); } -#include #ifndef REDHAT #include #endif @@ -1148,34 +1146,34 @@ * Check if the exception frame is of kernel or user type * Is checking only DS and CS values sufficient ? */ -int eframe_type(struct pt_regs *regs) + +int eframe_type(uaddr_t *int_eframe) { - if (((regs->xcs & 0xffff) == __KERNEL_CS) && - ((regs->xds & 0xffff) == __KERNEL_DS)) + ushort xcs, xds; + + xcs = (ushort)(int_eframe[INT_EFRAME_CS] & 0xffff); + xds = (ushort)(int_eframe[INT_EFRAME_DS] & 0xffff); + + if ((xcs == __KERNEL_CS) && (xds == __KERNEL_DS)) return KERNEL_EFRAME; #ifdef REDHAT - else if (((regs->xcs & 0xffff) == 0x60) && - ((regs->xds & 0xffff) == 0x68)) + else if ((xcs == 0x60) && (xds == 0x68)) + return KERNEL_EFRAME; + else if ((xcs == 0x60) && (xds == 0x7b)) return KERNEL_EFRAME; - else if (((regs->xcs & 0xffff) == 0x60) && - ((regs->xds & 0xffff) == 0x7b)) - return KERNEL_EFRAME; - else if (XEN() && ((regs->xcs & 0xffff) == 0x61) && - ((regs->xds & 0xffff) == 0x7b)) + else if (XEN() && (xcs == 0x61) && (xds == 0x7b)) return KERNEL_EFRAME; #endif - else if (((regs->xcs & 0xffff) == __USER_CS) && - ((regs->xds & 0xffff) == __USER_DS)) + else if ((xcs == __USER_CS) && (xds == __USER_DS)) return USER_EFRAME; #ifdef REDHAT - else if (((regs->xcs & 0xffff) == 0x73) && - ((regs->xds & 0xffff) == 0x7b)) + else if ((xcs == 0x73) && (xds == 0x7b)) return USER_EFRAME; #endif return -1; } -void print_eframe(FILE *ofp, struct pt_regs *regs) +void print_eframe(FILE *ofp, uaddr_t *regs) { int type = eframe_type(regs); @@ -1350,7 +1348,7 @@ int flag; int interrupted_system_call = FALSE; struct bt_info *bt = trace->bt; - struct pt_regs *pt; + uaddr_t *pt; #endif sbp = trace->stack[curstkidx].ptr; sbase = trace->stack[curstkidx].addr; @@ -1624,14 +1622,14 @@ asp = (uaddr_t*)((uaddr_t)sbp + (STACK_SIZE - (saddr - sp))); curframe = alloc_sframe(trace, flags); - ra = ((struct pt_regs *)asp)->eip; - frame_type = eframe_type((struct pt_regs*)asp); + ra = asp[INT_EFRAME_EIP]; + frame_type = eframe_type(asp); UPDATE_FRAME(func_name, pc, ra, sp, bp, asp, 0, 0, (bp - sp + 4), EX_FRAME); /* prepare for next kernel frame, if present */ if (frame_type == KERNEL_EFRAME) { - pc = ((struct pt_regs *)asp)->eip; + pc = asp[INT_EFRAME_EIP]; sp = curframe->fp+4; #ifdef REDHAT bp = sp + get_framesize(pc, bt); @@ -1650,20 +1648,20 @@ sp = curframe->fp + 4; asp = (uaddr_t*)((uaddr_t)sbp + (STACK_SIZE - (saddr - sp))); - frame_type = eframe_type((struct pt_regs*)asp); + frame_type = eframe_type(asp); if (frame_type == KERNEL_EFRAME) bp = curframe->fp+(KERNEL_EFRAME_SZ-1)*4; else bp = curframe->fp+(USER_EFRAME_SZ-1)*4; curframe = alloc_sframe(trace, flags); - ra = ((struct pt_regs *)asp)->eip; + ra = asp[INT_EFRAME_EIP]; UPDATE_FRAME(func_name, pc, ra, sp, bp + 4, asp, 0, 0, curframe->fp - curframe->sp+4, EX_FRAME); /* prepare for next kernel frame, if present */ if (frame_type == KERNEL_EFRAME) { sp = curframe->fp + 4; - pc = ((struct pt_regs *)asp)->eip; + pc = asp[INT_EFRAME_EIP]; #ifdef REDHAT bp = sp + get_framesize(pc, bt); #else @@ -1711,7 +1709,7 @@ */ if ((bt->flags & BT_XEN_STOP_THIS_CPU) && bt->tc->mm_struct && STREQ(kl_funcname(curframe->pc), "hypervisor_callback")) { - pt = (struct pt_regs *)(curframe->asp+1); + pt = curframe->asp+1; if (eframe_type(pt) == USER_EFRAME) { if (program_context.debug >= 1) /* pc above */ error(INFO, @@ -1803,7 +1801,7 @@ #ifdef REDHAT kaddr_t fp = 0; kaddr_t last_fp, last_pc, next_fp, next_pc; - struct pt_regs *pt; + uaddr_t *pt; struct bt_info *bt; bt = trace->bt; @@ -1864,7 +1862,7 @@ fprintf(ofp, " [0x%x]\n", frmp->pc); #endif if (frmp->flag & EX_FRAME) { - pt = (struct pt_regs *)frmp->asp; + pt = frmp->asp; if (CRASHDEBUG(1)) fprintf(ofp, " EXCEPTION FRAME: %lx\n", @@ -2259,7 +2257,7 @@ (sp && (bt->ref->hexval == sp->value))) bt->ref->cmdflags |= BT_REF_FOUND; if (frmp->flag & EX_FRAME) { - type = eframe_type((struct pt_regs *)frmp->asp); + type = eframe_type(frmp->asp); x86_dump_eframe_common(bt, (ulong *)frmp->asp, (type == KERNEL_EFRAME)); } --- crash-4.0-4.12/netdump.c 2008-01-11 14:37:30.000000000 -0500 +++ crash-4.0-4.13/netdump.c 2008-01-04 09:42:08.000000000 -0500 @@ -1,7 +1,7 @@ /* netdump.c * - * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson - * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 David Anderson + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc. All rights reserved. * * This software may be freely redistributed under the terms of the * GNU General Public License. @@ -44,13 +44,12 @@ int is_netdump(char *file, ulong source_query) { - int i; - int fd; + int i, fd, swap; Elf32_Ehdr *elf32; Elf32_Phdr *load32; Elf64_Ehdr *elf64; Elf64_Phdr *load64; - char header[MIN_NETDUMP_ELF_HEADER_SIZE]; + char eheader[MIN_NETDUMP_ELF_HEADER_SIZE]; char buf[BUFSIZE]; size_t size, len, tot; Elf32_Off offset32; @@ -67,7 +66,7 @@ } size = MIN_NETDUMP_ELF_HEADER_SIZE; - if (read(fd, header, size) != size) { + if (read(fd, eheader, size) != size) { sprintf(buf, "%s: read", file); perror(buf); goto bailout; @@ -80,8 +79,8 @@ } tmp_flags = 0; - elf32 = (Elf32_Ehdr *)&header[0]; - elf64 = (Elf64_Ehdr *)&header[0]; + elf32 = (Elf32_Ehdr *)&eheader[0]; + elf64 = (Elf64_Ehdr *)&eheader[0]; /* * Verify the ELF header, and determine the dumpfile format. @@ -98,24 +97,39 @@ * If either kdump difference is seen, presume kdump -- this * is obviously subject to change. */ - if (STRNEQ(elf32->e_ident, ELFMAG) && - (elf32->e_ident[EI_CLASS] == ELFCLASS32) && - (elf32->e_ident[EI_DATA] == ELFDATA2LSB) && - (elf32->e_ident[EI_VERSION] == EV_CURRENT) && - (elf32->e_type == ET_CORE) && - (elf32->e_version == EV_CURRENT) && - (elf32->e_phnum >= 2)) { - switch (elf32->e_machine) + + if (!STRNEQ(eheader, ELFMAG) || eheader[EI_VERSION] != EV_CURRENT) + goto bailout; + + swap = (((eheader[EI_DATA] == ELFDATA2LSB) && + (__BYTE_ORDER == __BIG_ENDIAN)) || + ((eheader[EI_DATA] == ELFDATA2MSB) && + (__BYTE_ORDER == __LITTLE_ENDIAN))); + + if ((elf32->e_ident[EI_CLASS] == ELFCLASS32) && + (swap16(elf32->e_type, swap) == ET_CORE) && + (swap32(elf32->e_version, swap) == EV_CURRENT) && + (swap16(elf32->e_phnum, swap) >= 2)) { + switch (swap16(elf32->e_machine, swap)) { case EM_386: - if (machine_type("X86")) - break; + if (machine_type_mismatch(file, "X86", NULL, + source_query)) + goto bailout; + break; + default: - goto bailout; + if (machine_type_mismatch(file, "(unknown)", NULL, + source_query)) + goto bailout; } + if (endian_mismatch(file, elf32->e_ident[EI_DATA], + source_query)) + goto bailout; + load32 = (Elf32_Phdr *) - &header[sizeof(Elf32_Ehdr)+sizeof(Elf32_Phdr)]; + &eheader[sizeof(Elf32_Ehdr)+sizeof(Elf32_Phdr)]; size = (size_t)load32->p_offset; if ((load32->p_offset & (MIN_PAGE_SIZE-1)) && @@ -123,56 +137,63 @@ tmp_flags |= KDUMP_ELF32; else tmp_flags |= NETDUMP_ELF32; - } else if (STRNEQ(elf64->e_ident, ELFMAG) && - (elf64->e_ident[EI_CLASS] == ELFCLASS64) && - (elf64->e_ident[EI_VERSION] == EV_CURRENT) && - (elf64->e_type == ET_CORE) && - (elf64->e_version == EV_CURRENT) && - (elf64->e_phnum >= 2)) { - switch (elf64->e_machine) + } else if ((elf64->e_ident[EI_CLASS] == ELFCLASS64) && + (swap16(elf64->e_type, swap) == ET_CORE) && + (swap32(elf64->e_version, swap) == EV_CURRENT) && + (swap16(elf64->e_phnum, swap) >= 2)) { + switch (swap16(elf64->e_machine, swap)) { case EM_IA_64: - if ((elf64->e_ident[EI_DATA] == ELFDATA2LSB) && - machine_type("IA64")) - break; - else + if (machine_type_mismatch(file, "IA64", NULL, + source_query)) goto bailout; + break; case EM_PPC64: - if ((elf64->e_ident[EI_DATA] == ELFDATA2MSB) && - machine_type("PPC64")) - break; - else + if (machine_type_mismatch(file, "PPC64", NULL, + source_query)) goto bailout; + break; case EM_X86_64: - if ((elf64->e_ident[EI_DATA] == ELFDATA2LSB) && - machine_type("X86_64")) - break; - else + if (machine_type_mismatch(file, "X86_64", NULL, + source_query)) goto bailout; + break; case EM_386: - if ((elf64->e_ident[EI_DATA] == ELFDATA2LSB) && - machine_type("X86")) - break; - else + if (machine_type_mismatch(file, "X86", NULL, + source_query)) goto bailout; + break; default: - goto bailout; + if (machine_type_mismatch(file, "(unknown)", NULL, + source_query)) + goto bailout; } + if (endian_mismatch(file, elf64->e_ident[EI_DATA], + source_query)) + goto bailout; + load64 = (Elf64_Phdr *) - &header[sizeof(Elf64_Ehdr)+sizeof(Elf64_Phdr)]; + &eheader[sizeof(Elf64_Ehdr)+sizeof(Elf64_Phdr)]; size = (size_t)load64->p_offset; if ((load64->p_offset & (MIN_PAGE_SIZE-1)) && (load64->p_align == 0)) tmp_flags |= KDUMP_ELF64; else tmp_flags |= NETDUMP_ELF64; - } else + } else { + if (CRASHDEBUG(2)) + error(INFO, "%s: not a %s ELF dumpfile\n", + file, source_query == NETDUMP_LOCAL ? + "netdump" : "kdump"); + + goto bailout; + } switch (DUMPFILE_FORMAT(tmp_flags)) { @@ -1335,22 +1356,22 @@ netdump_print("(?)\n"); } - netdump_print(" p_offset: %ld (%lx)\n", prog->p_offset, + netdump_print(" p_offset: %lld (%llx)\n", prog->p_offset, prog->p_offset); if (store_pt_load_data) pls->file_offset = prog->p_offset; - netdump_print(" p_vaddr: %lx\n", prog->p_vaddr); - netdump_print(" p_paddr: %lx\n", prog->p_paddr); + netdump_print(" p_vaddr: %llx\n", prog->p_vaddr); + netdump_print(" p_paddr: %llx\n", prog->p_paddr); if (store_pt_load_data) pls->phys_start = prog->p_paddr; - netdump_print(" p_filesz: %lu (%lx)\n", prog->p_filesz, + netdump_print(" p_filesz: %llu (%llx)\n", prog->p_filesz, prog->p_filesz); if (store_pt_load_data) { pls->phys_end = pls->phys_start + prog->p_filesz; pls->zero_fill = (prog->p_filesz == prog->p_memsz) ? 0 : pls->phys_start + prog->p_memsz; } - netdump_print(" p_memsz: %lu (%lx)\n", prog->p_memsz, + netdump_print(" p_memsz: %llu (%llx)\n", prog->p_memsz, prog->p_memsz); netdump_print(" p_flags: %lx (", prog->p_flags); others = 0; @@ -1361,7 +1382,7 @@ if (prog->p_flags & PF_R) netdump_print("%sPF_R", others++ ? "|" : ""); netdump_print(")\n"); - netdump_print(" p_align: %ld\n", prog->p_align); + netdump_print(" p_align: %lld\n", prog->p_align); } /* @@ -1377,14 +1398,14 @@ char buf[BUFSIZE]; char *ptr; ulong *uptr; - int xen_core; + int xen_core, vmcoreinfo; note = (Elf32_Nhdr *)((char *)nd->elf32 + offset); netdump_print("Elf32_Nhdr:\n"); netdump_print(" n_namesz: %ld ", note->n_namesz); BZERO(buf, BUFSIZE); - xen_core = FALSE; + xen_core = vmcoreinfo = FALSE; ptr = (char *)note + sizeof(Elf32_Nhdr); BCOPY(ptr, buf, note->n_namesz); netdump_print("(\"%s\")\n", buf); @@ -1446,12 +1467,15 @@ #endif default: xen_core = STRNEQ(buf, "XEN CORE") || STRNEQ(buf, "Xen"); + vmcoreinfo = STRNEQ(buf, "VMCOREINFO"); if (xen_core) { netdump_print("(unknown Xen n_type)\n"); if (store) error(WARNING, "unknown Xen n_type: %lx\n\n", note->n_type); - } else + } else if (vmcoreinfo) + netdump_print("(unused)\n"); + else netdump_print("(?)\n"); break; @@ -1521,14 +1545,25 @@ if (xen_core) uptr = (ulong *)roundup((ulong)uptr, 4); - for (i = lf = 0; i < note->n_descsz/sizeof(ulong); i++) { - if (((i%4)==0)) { - netdump_print("%s ", - i ? "\n" : ""); - lf++; - } else - lf = 0; - netdump_print("%08lx ", *uptr++); + if (vmcoreinfo) { + netdump_print(" "); + ptr += note->n_namesz + 1; + for (i = 0; i < note->n_descsz; i++, ptr++) { + netdump_print("%c", *ptr); + if (*ptr == '\n') + netdump_print(" "); + } + lf = 0; + } else { + for (i = lf = 0; i < note->n_descsz/sizeof(ulong); i++) { + if (((i%4)==0)) { + netdump_print("%s ", + i ? "\n" : ""); + lf++; + } else + lf = 0; + netdump_print("%08lx ", *uptr++); + } } if (!lf || (note->n_type == NT_TASKSTRUCT) || (note->n_type == NT_DISKDUMP) || xen_core) @@ -1553,7 +1588,7 @@ ulonglong *uptr; int *iptr; ulong *up; - int xen_core; + int xen_core, vmcoreinfo; note = (Elf64_Nhdr *)((char *)nd->elf64 + offset); @@ -1561,7 +1596,7 @@ netdump_print(" n_namesz: %ld ", note->n_namesz); BZERO(buf, BUFSIZE); ptr = (char *)note + sizeof(Elf64_Nhdr); - xen_core = FALSE; + xen_core = vmcoreinfo = FALSE; BCOPY(ptr, buf, note->n_namesz); netdump_print("(\"%s\")\n", buf); @@ -1635,12 +1670,15 @@ #endif default: xen_core = STRNEQ(buf, "XEN CORE") || STRNEQ(buf, "Xen"); + vmcoreinfo = STRNEQ(buf, "VMCOREINFO"); if (xen_core) { netdump_print("(unknown Xen n_type)\n"); if (store) error(WARNING, "unknown Xen n_type: %lx\n\n", note->n_type); - } else + } else if (vmcoreinfo) + netdump_print("(unused)\n"); + else netdump_print("(?)\n"); break; @@ -1721,6 +1759,15 @@ lf = 0; netdump_print("%08lx ", *iptr++); } + } else if (vmcoreinfo) { + netdump_print(" "); + ptr += note->n_namesz + 1; + for (i = 0; i < note->n_descsz; i++, ptr++) { + netdump_print("%c", *ptr); + if (*ptr == '\n') + netdump_print(" "); + } + lf = 0; } else { for (i = lf = 0; i < note->n_descsz/sizeof(ulonglong); i++) { if (((i%2)==0)) { --- crash-4.0-4.12/diskdump.c 2008-01-11 14:37:30.000000000 -0500 +++ crash-4.0-4.13/diskdump.c 2008-01-04 09:42:08.000000000 -0500 @@ -7,8 +7,8 @@ * netdump dumpfiles, the facilities in netdump.c are used. For * compressed dumpfiles, the facilities in this file are used. * - * Copyright (C) 2004, 2005, 2006 David Anderson - * Copyright (C) 2004, 2005, 2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008 David Anderson + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (C) 2005 FUJITSU LIMITED * Copyright (C) 2005 NEC Corporation * @@ -94,14 +94,14 @@ fd = open(file, O_RDONLY); if (fd < 0) { - error(INFO, "diskdump: unable to open dump file %s", file); + error(INFO, "diskdump / compressed kdump: unable to open dump file %s", file); return FALSE; } dd->dfd = fd; return TRUE; } -static int read_dump_header(void) +static int read_dump_header(char *file) { struct disk_dump_header *header = NULL; struct disk_dump_sub_header *sub_header = NULL; @@ -117,17 +117,17 @@ return FALSE; if ((header = malloc(block_size)) == NULL) - error(FATAL, "diskdump: cannot malloc block_size buffer\n"); + error(FATAL, "diskdump / compressed kdump: cannot malloc block_size buffer\n"); if (lseek(dd->dfd, 0, SEEK_SET) == failed) { if (CRASHDEBUG(1)) - error(INFO, "diskdump: cannot lseek dump header\n"); + error(INFO, "diskdump / compressed kdump: cannot lseek dump header\n"); goto err; } if (read(dd->dfd, header, block_size) < block_size) { if (CRASHDEBUG(1)) - error(INFO, "diskdump: cannot read dump header\n"); + error(INFO, "diskdump / compressed kdump: cannot read dump header\n"); goto err; } @@ -142,13 +142,33 @@ dd->flags |= ERROR_EXCLUDED; } else { if (CRASHDEBUG(1)) - error(INFO, "diskdump: dump does not have panic dump header\n"); + error(INFO, + "diskdump / compressed kdump: dump does not have panic dump header\n"); goto err; } + if (CRASHDEBUG(1)) + fprintf(fp, "%s: header->utsname.machine: %s\n", + DISKDUMP_VALID() ? "diskdump" : "compressed kdump", + header->utsname.machine); + + if (STRNEQ(header->utsname.machine, "i686") && + machine_type_mismatch(file, "X86", NULL, 0)) + goto err; + else if (STRNEQ(header->utsname.machine, "x86_64") && + machine_type_mismatch(file, "X86_64", NULL, 0)) + goto err; + else if (STRNEQ(header->utsname.machine, "ia64") && + machine_type_mismatch(file, "IA64", NULL, 0)) + goto err; + else if (STRNEQ(header->utsname.machine, "ppc64") && + machine_type_mismatch(file, "PPC64", NULL, 0)) + goto err; + if (header->block_size != block_size) { - error(INFO, "diskdump: block size in the dump header does not match" - " with system page size\n"); + error(INFO, "%s: block size in the dump header does not match" + " with system page size\n", + DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); goto err; } dd->block_size = block_size; @@ -156,14 +176,18 @@ if (sizeof(*header) + sizeof(void *) * header->nr_cpus > block_size || header->nr_cpus <= 0) { - error(INFO, "diskdump: invalid nr_cpus value: %d\n", header->nr_cpus); + error(INFO, "%s: invalid nr_cpus value: %d\n", + DISKDUMP_VALID() ? "diskdump" : "compressed kdump", + header->nr_cpus); goto err; } /* read sub header */ offset = (off_t)block_size; if (lseek(dd->dfd, offset, SEEK_SET) == failed) { - error(INFO, "diskdump: cannot lseek dump sub header\n"); + error(INFO, "%s: cannot lseek dump sub header\n", + DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); + goto err; } @@ -179,11 +203,11 @@ dd->sub_header = sub_header; } else if (KDUMP_CMPRS_VALID()) { if ((sub_header_kdump = malloc(block_size)) == NULL) - error(FATAL, "diskdump: cannot malloc sub_header_kdump buffer\n"); + error(FATAL, "compressed kdump: cannot malloc sub_header_kdump buffer\n"); if (read(dd->dfd, sub_header_kdump, block_size) < block_size) { - error(INFO, "diskdump: cannot read dump sub header\n"); + error(INFO, "compressed kdump: cannot read dump sub header\n"); goto err; } dd->sub_header_kdump = sub_header_kdump; @@ -195,15 +219,20 @@ offset = (off_t)block_size * (1 + header->sub_hdr_size); if (lseek(dd->dfd, offset, SEEK_SET) == failed) { - error(INFO, "diskdump: cannot lseek memory bitmap\n"); + error(INFO, "%s: cannot lseek memory bitmap\n", + DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); + goto err; } if ((dd->bitmap = malloc(bitmap_len)) == NULL) - error(FATAL, "diskdump: cannot malloc bitmap buffer\n"); + error(FATAL, "%s: cannot malloc bitmap buffer\n", + DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); + dd->dumpable_bitmap = calloc(bitmap_len, 1); if (read(dd->dfd, dd->bitmap, bitmap_len) < bitmap_len) { - error(INFO, "diskdump: cannot read memory bitmap\n"); + error(INFO, "%s: cannot read memory bitmap\n", + DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); goto err; } @@ -228,7 +257,9 @@ else if (machine_type("PPC64")) dd->machine_type = EM_PPC64; else { - error(INFO, "diskdump: unsupported machine type: %s\n", MACHINE_TYPE); + error(INFO, "%s: unsupported machine type: %s\n", + DISKDUMP_VALID() ? "diskdump" : "compressed kdump", + MACHINE_TYPE); goto err; } @@ -284,19 +315,21 @@ { int sz, i; - if (!open_dump_file(file) || !read_dump_header()) + if (!open_dump_file(file) || !read_dump_header(file)) return FALSE; sz = dd->block_size * (DISKDUMP_CACHED_PAGES); if ((dd->page_cache_buf = malloc(sz)) == NULL) - error(FATAL, "diskdump: cannot malloc compressed page_cache_buf\n"); + error(FATAL, "%s: cannot malloc compressed page_cache_buf\n", + DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); for (i = 0; i < DISKDUMP_CACHED_PAGES; i++) dd->page_cache_hdr[i].pg_bufptr = &dd->page_cache_buf[i * dd->block_size]; if ((dd->compressed_page = (char *)malloc(dd->block_size)) == NULL) - error(FATAL, "diskdump: cannot malloc compressed page space\n"); + error(FATAL, "%s: cannot malloc compressed page space\n", + DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); if (CRASHDEBUG(1)) diskdump_memory_dump(fp); @@ -433,7 +466,9 @@ (unsigned char *)dd->compressed_page, pd.size); if ((ret != Z_OK) || (retlen != block_size)) { - error(INFO, "diskdump: uncompress failed: %d\n", ret); + error(INFO, "%s: uncompress failed: %d\n", + DISKDUMP_VALID() ? "diskdump" : "compressed kdump", + ret); return READ_ERROR; } } else @@ -541,7 +576,10 @@ break; default: - error(FATAL, "diskdump: unsupported machine type: %s\n", MACHINE_TYPE); + error(FATAL, "%s: unsupported machine type: %s\n", + DISKDUMP_VALID() ? "diskdump" : "compressed kdump", + MACHINE_TYPE); + } } --- crash-4.0-4.12/xendump.c 2008-01-11 14:37:30.000000000 -0500 +++ crash-4.0-4.13/xendump.c 2008-01-04 09:42:08.000000000 -0500 @@ -1,8 +1,8 @@ /* * xendump.c * - * Copyright (C) 2006, 2007 David Anderson - * Copyright (C) 2006, 2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008 David Anderson + * Copyright (C) 2006, 2007, 2008 Red Hat, Inc. All rights reserved. * * This software may be freely redistributed under the terms of the * GNU General Public License. @@ -19,7 +19,7 @@ static struct xendump_data *xd = &xendump_data; static int xc_save_verify(char *); -static int xc_core_verify(char *); +static int xc_core_verify(char *, char *); static int xc_save_read(void *, int, ulong, physaddr_t); static int xc_core_read(void *, int, ulong, physaddr_t); static int xc_core_mfns(ulong, FILE *); @@ -35,7 +35,7 @@ static void xendump_print(char *fmt, ...); -static int xc_core_elf_verify(char *); +static int xc_core_elf_verify(char *, char *); static void xc_core_elf_dump(void); static char *xc_core_elf_mfn_to_page(ulong, char *); static int xc_core_elf_mfn_to_page_index(ulong); @@ -80,7 +80,7 @@ else xd->page_size = machdep->pagesize; - verified = xc_save_verify(buf) || xc_core_verify(buf); + verified = xc_save_verify(buf) || xc_core_verify(file, buf); if (!verified) close(xd->xfd); @@ -93,13 +93,13 @@ * library function in libxc/xc_core.c. */ static int -xc_core_verify(char *buf) +xc_core_verify(char *file, char *buf) { struct xc_core_header *xcp; xcp = (struct xc_core_header *)buf; - if (xc_core_elf_verify(buf)) + if (xc_core_elf_verify(file, buf)) return TRUE; if ((xcp->xch_magic != XC_CORE_MAGIC) && @@ -1974,33 +1974,49 @@ * Support for xc_core ELF dumpfile format. */ static int -xc_core_elf_verify(char *buf) +xc_core_elf_verify(char *file, char *buf) { int i; Elf32_Ehdr *elf32; Elf64_Ehdr *elf64; Elf32_Off offset32; Elf64_Off offset64; + char *eheader; + int swap; + + eheader = buf; + + if (!STRNEQ(eheader, ELFMAG) || eheader[EI_VERSION] != EV_CURRENT) + goto bailout; + + swap = (((eheader[EI_DATA] == ELFDATA2LSB) && + (__BYTE_ORDER == __BIG_ENDIAN)) || + ((eheader[EI_DATA] == ELFDATA2MSB) && + (__BYTE_ORDER == __LITTLE_ENDIAN))); elf32 = (Elf32_Ehdr *)buf; elf64 = (Elf64_Ehdr *)buf; - if (STRNEQ(elf32->e_ident, ELFMAG) && - (elf32->e_ident[EI_CLASS] == ELFCLASS32) && - (elf32->e_ident[EI_DATA] == ELFDATA2LSB) && - (elf32->e_ident[EI_VERSION] == EV_CURRENT) && - (elf32->e_type == ET_CORE) && - (elf32->e_version == EV_CURRENT) && - (elf32->e_shnum > 0)) { - switch (elf32->e_machine) + if ((elf32->e_ident[EI_CLASS] == ELFCLASS32) && + (swap16(elf32->e_type, swap) == ET_CORE) && + (swap32(elf32->e_version, swap) == EV_CURRENT) && + (swap16(elf32->e_shnum, swap) > 0)) { + switch (swap16(elf32->e_machine, swap)) { case EM_386: - if (machine_type("X86")) - break; + if (machine_type_mismatch(file, "X86", NULL, 0)) + goto bailout; + break; + default: - goto bailout; + if (machine_type_mismatch(file, "(unknown)", NULL, 0)) + goto bailout; + break; } + if (endian_mismatch(file, elf32->e_ident[EI_DATA], 0)) + goto bailout; + xd->xc_core.elf_class = ELFCLASS32; if ((xd->xc_core.elf32 = (Elf32_Ehdr *)malloc(sizeof(Elf32_Ehdr))) == NULL) { fprintf(stderr, "cannot malloc ELF header buffer\n"); @@ -2008,39 +2024,35 @@ } BCOPY(buf, xd->xc_core.elf32, sizeof(Elf32_Ehdr)); - } else if (STRNEQ(elf64->e_ident, ELFMAG) && - (elf64->e_ident[EI_CLASS] == ELFCLASS64) && - (elf64->e_ident[EI_VERSION] == EV_CURRENT) && - (elf64->e_type == ET_CORE) && - (elf64->e_version == EV_CURRENT) && - (elf64->e_shnum > 0)) { - switch (elf64->e_machine) + } else if ((elf64->e_ident[EI_CLASS] == ELFCLASS64) && + (swap16(elf64->e_type, swap) == ET_CORE) && + (swap32(elf64->e_version, swap) == EV_CURRENT) && + (swap16(elf64->e_shnum, swap) > 0)) { + switch (swap16(elf64->e_machine, swap)) { case EM_IA_64: - if ((elf64->e_ident[EI_DATA] == ELFDATA2LSB) && - machine_type("IA64")) - break; - else + if (machine_type_mismatch(file, "IA64", NULL, 0)) goto bailout; + break; case EM_X86_64: - if ((elf64->e_ident[EI_DATA] == ELFDATA2LSB) && - (machine_type("X86_64") || machine_type("X86"))) - break; - else + if (machine_type_mismatch(file, "X86_64", "X86", 0)) goto bailout; + break; case EM_386: - if ((elf64->e_ident[EI_DATA] == ELFDATA2LSB) && - machine_type("X86")) - break; - else + if (machine_type_mismatch(file, "X86", NULL, 0)) goto bailout; + break; default: - goto bailout; + if (machine_type_mismatch(file, "(unknown)", NULL, 0)) + goto bailout; } + if (endian_mismatch(file, elf64->e_ident[EI_DATA], 0)) + goto bailout; + xd->xc_core.elf_class = ELFCLASS64; if ((xd->xc_core.elf64 = (Elf64_Ehdr *)malloc(sizeof(Elf64_Ehdr))) == NULL) { fprintf(stderr, "cannot malloc ELF header buffer\n"); @@ -2050,7 +2062,7 @@ } else { if (CRASHDEBUG(1)) - error(INFO, "xc_core_elf_verify: not a xen ELF core file\n"); + error(INFO, "%s: not a xen ELF core file\n", file); goto bailout; } @@ -2829,3 +2841,8 @@ } } +struct xendump_data * +get_xendump_data(void) +{ + return (XENDUMP_VALID() ? xd : NULL); +} --- crash-4.0-4.12/defs.h 2008-01-11 14:37:30.000000000 -0500 +++ crash-4.0-4.13/defs.h 2008-01-11 11:51:01.000000000 -0500 @@ -1,8 +1,8 @@ /* defs.h - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson - * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 David Anderson + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (C) 2002 Silicon Graphics, Inc. * * This program is free software; you can redistribute it and/or modify @@ -625,6 +625,7 @@ #define IRQSTACKS (0x800) #define TIMESPEC (0x1000) #define NO_TIMESPEC (0x2000) +#define ACTIVE_ONLY (0x4000) #define TASK_SLUSH (20) @@ -1010,6 +1011,7 @@ long mm_struct_pgd; long mm_struct_rss; long mm_struct_anon_rss; + long mm_struct_file_rss; long mm_struct_total_vm; long mm_struct_start_code; long mm_struct_arg_start; @@ -1429,6 +1431,12 @@ long kmem_cache_cpu_freelist; long kmem_cache_cpu_page; long kmem_cache_cpu_node; + long zone_nr_active; + long zone_nr_inactive; + long zone_all_unreclaimable; + long zone_present_pages; + long zone_flags; + long zone_pages_scanned; }; struct size_table { /* stash of commonly-used sizes */ @@ -1694,6 +1702,8 @@ int nr_vm_stat_items; char **vm_stat_items; int cpu_slab_type; + int nr_vm_event_items; + char **vm_event_items; }; #define NODES (0x1) @@ -1714,6 +1724,7 @@ #define VM_STAT (0x8000) #define KMALLOC_SLUB (0x10000) #define CONFIG_NUMA (0x20000) +#define VM_EVENT (0x40000) #define IS_FLATMEM() (vt->flags & FLATMEM) #define IS_DISCONTIGMEM() (vt->flags & DISCONTIGMEM) @@ -1994,7 +2005,7 @@ #define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) #define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) #define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) -#define KVBASE_MASK (0x7fffff) +#define KVBASE_MASK (0x1ffffff) #define PGDIR_SHIFT_2LEVEL (22) #define PTRS_PER_PTE_2LEVEL (1024) @@ -3199,13 +3210,16 @@ int clean_arg(void); int empty_list(ulong); int machine_type(char *); +int machine_type_mismatch(char *, char *, char *, ulong); void command_not_supported(void); void option_not_supported(int); void please_wait(char *); void please_wait_done(void); int pathcmp(char *, char *); int calculate(char *, ulong *, ulonglong *, ulong); - +int endian_mismatch(char *, char, ulong); +uint16_t swap16(uint16_t, int); +uint32_t swap32(uint32_t, int); /* * symbols.c @@ -3260,6 +3274,7 @@ void dump_struct_table(ulong); void dump_offset_table(char *, ulong); int is_elf_file(char *); +int is_kernel(char *); int file_elf_version(char *); int is_system_map(char *); int select_namelist(char *); @@ -4091,6 +4106,7 @@ int xc_core_mfn_to_page_index(ulong); void xendump_panic_hook(char *); int read_xendump_hyper(int, void *, int, ulong, physaddr_t); +struct xendump_data *get_xendump_data(void); /* * net.c --- crash-4.0-4.12/lkcd_x86_trace.h 2008-01-11 14:37:30.000000000 -0500 +++ crash-4.0-4.13/lkcd_x86_trace.h 2008-01-04 09:42:08.000000000 -0500 @@ -35,6 +35,25 @@ typedef uint32_t kaddr_t; +extern int INT_EFRAME_SS; +extern int INT_EFRAME_ESP; +extern int INT_EFRAME_EFLAGS; +extern int INT_EFRAME_CS; +extern int INT_EFRAME_EIP; +extern int INT_EFRAME_ERR; +extern int INT_EFRAME_ES; +extern int INT_EFRAME_DS; +extern int INT_EFRAME_EAX; +extern int INT_EFRAME_EBP; +extern int INT_EFRAME_EDI; +extern int INT_EFRAME_ESI; +extern int INT_EFRAME_EDX; +extern int INT_EFRAME_ECX; +extern int INT_EFRAME_EBX; +extern int INT_EFRAME_GS; + +extern ulong int_eframe[]; + #endif /* REDHAT */