--- crash-4.0-3.21/main.c 2007-03-23 14:13:27.000000000 -0500 +++ crash-4.0-3.22/main.c 2007-04-03 13:38:43.000000000 -0400 @@ -48,6 +48,7 @@ {"no_ikconfig", 0, 0, 0}, {"hyper", 0, 0, 0}, {"p2m_mfn", 1, 0, 0}, + {"zero_excluded", 0, 0, 0}, {0, 0, 0, 0} }; @@ -152,6 +153,9 @@ if (STREQ(long_options[option_index].name, "p2m_mfn")) xen_kdump_p2m_mfn(optarg); + if (STREQ(long_options[option_index].name, "zero_excluded")) + *diskdump_flags |= ZERO_EXCLUDED; + break; case 'f': @@ -720,6 +724,7 @@ pc->redhat_debug_loc = DEFAULT_REDHAT_DEBUG_LOCATION; pc->cmdgencur = 0; pc->cmd_table = linux_command_table; + kt->BUG_bytes = -1; /* * Get gdb version before initializing it since this might be one @@ -1152,6 +1157,10 @@ fprintf(fp, "%sMEMTYPE_FILEADDR", others ? "|" : ""); if (pc->curcmd_flags & HEADER_PRINTED) fprintf(fp, "%sHEADER_PRINTED", others ? "|" : ""); + if (pc->curcmd_flags & BAD_INSTRUCTION) + fprintf(fp, "%sBAD_INSTRUCTION", others ? "|" : ""); + if (pc->curcmd_flags & UD2A_INSTRUCTION) + fprintf(fp, "%sUD2A_INSTRUCTION", others ? "|" : ""); fprintf(fp, ")\n"); fprintf(fp, " curcmd_private: %llx\n", pc->curcmd_private); fprintf(fp, " sigint_cnt: %d\n", pc->sigint_cnt); --- crash-4.0-3.21/tools.c 2007-03-23 14:13:27.000000000 -0500 +++ crash-4.0-3.22/tools.c 2007-03-23 15:13:37.000000000 -0500 @@ -2097,6 +2097,31 @@ pc->flags |= DATADEBUG; return; + } else if (STREQ(args[optind], "zero_excluded")) { + + if (args[optind+1]) { + optind++; + if (STREQ(args[optind], "on")) + *diskdump_flags |= ZERO_EXCLUDED; + else if (STREQ(args[optind], "off")) + *diskdump_flags &= ~ZERO_EXCLUDED; + else if (IS_A_NUMBER(args[optind])) { + value = stol(args[optind], + FAULT_ON_ERROR, NULL); + if (value) + *diskdump_flags |= ZERO_EXCLUDED; + else + *diskdump_flags &= ~ZERO_EXCLUDED; + } else + goto invalid_set_command; + } + + if (runtime) + fprintf(fp, "zero_excluded: %s\n", + *diskdump_flags & ZERO_EXCLUDED ? + "on" : "off"); + return; + } else if (runtime) { ulong pid, task; @@ -2165,6 +2190,7 @@ fprintf(fp, " namelist: %s\n", pc->namelist); fprintf(fp, " dumpfile: %s\n", pc->dumpfile); fprintf(fp, " unwind: %s\n", kt->flags & DWARF_UNWIND ? "on" : "off"); + fprintf(fp, " zero_excluded: %s\n", *diskdump_flags & ZERO_EXCLUDED ? "on" : "off"); } --- crash-4.0-3.21/memory.c 2007-03-23 14:13:27.000000000 -0500 +++ crash-4.0-3.22/memory.c 2007-03-29 08:59:13.000000000 -0500 @@ -1523,6 +1523,7 @@ #define SEEK_ERRMSG "seek error: %s address: %llx type: \"%s\"\n" #define READ_ERRMSG "read error: %s address: %llx type: \"%s\"\n" #define WRITE_ERRMSG "write error: %s address: %llx type: \"%s\"\n" +#define PAGE_EXCLUDED_ERRMSG "page excluded: %s address: %llx type: \"%s\"\n" int readmem(ulonglong addr, int memtype, void *buffer, long size, @@ -1643,6 +1644,11 @@ error(INFO, READ_ERRMSG, memtype_string(memtype, 0), addr, type); goto readmem_error; + case PAGE_EXCLUDED: + if (PRINT_ERROR_MESSAGE) + error(INFO, PAGE_EXCLUDED_ERRMSG, memtype_string(memtype, 0), addr, type); + goto readmem_error; + default: break; } --- crash-4.0-3.21/help.c 2007-03-23 14:13:27.000000000 -0500 +++ crash-4.0-3.22/help.c 2007-04-03 14:28:30.000000000 -0400 @@ -669,6 +669,8 @@ " edit vi | emacs set line editing mode (from .%src file only).", " namelist filename name of kernel (from .%src file only).", " dumpfile filename name of core dumpfile (from .%src file only).", +" zero_excluded on | off controls whether excluded pages from a dumpfile", +" should return zero-filled memory.", " ", " Internal variables may be set in four manners:\n", " 1. entering the set command in $HOME/.%src.", @@ -714,6 +716,7 @@ " edit: vi", " namelist: vmlinux", " dumpfile: vmcore", +" zero_excluded: off", " ", " Show the current context:\n", " %s> set", @@ -1228,7 +1231,7 @@ " fails or the -t option starts too high in the process stack).", " -l show file and line number of each stack trace text location.", " -e search the stack for possible kernel and user mode exception frames.", -" -E search the IRQ stacks (x86, x86_64 and PPC64), and the exception", +" -E search the IRQ stacks (x86, x86_64 and ppc64), and the exception", " stacks (x86_64) for possible exception frames; all other arguments", " will be ignored since this is not a context-sensitive operation.", " -f display all stack data contained in a frame; this option can be", @@ -4268,7 +4271,7 @@ char *help_dis[] = { "dis", "disassemble", -"[-r][-l][-u] [address | symbol | (expression)] [count]", +"[-r][-l][-u][-b [num]] [address | symbol | (expression)] [count]", " This command disassembles source code instructions starting (or ending) at", " a text address that may be expressed by value, symbol or expression:\n", " -r (reverse) displays all instructions from the start of the ", @@ -4278,8 +4281,11 @@ " -u address is a user virtual address in the current context;", " otherwise the address is assumed to be a kernel virtual address.", " If this option is used, then -r and -l are ignored.", +" -b [num] modify the pre-calculated number of encoded bytes to skip after", +" a kernel BUG (\"ud2a\") instruction; with no argument, displays", +" the current number of bytes being skipped. (x86 and x86_64 only)", " address starting hexadecimal text address.", -" symbol symbol of starting text address. On PPC64, the symbol", +" symbol symbol of starting text address. On ppc64, the symbol", " preceded by '.' is used.", " (expression) expression evaluating to a starting text address.", " count the number of instructions to be disassembled (default is 1).", --- crash-4.0-3.21/kernel.c 2007-03-23 14:13:27.000000000 -0500 +++ crash-4.0-3.22/kernel.c 2007-04-09 13:50:38.000000000 -0400 @@ -46,6 +46,10 @@ static ulong __xen_m2p(ulonglong, ulong); static int search_mapping_page(ulong, ulong *, ulong *, ulong *); static void read_in_kernel_config_err(int, char *); +static void BUG_bytes_init(void); +static int BUG_x86(void); +static int BUG_x86_64(void); + /* @@ -457,6 +461,8 @@ if (!(kt->flags & DWARF_UNWIND)) kt->flags |= NO_DWARF_UNWIND; + + BUG_bytes_init(); } /* @@ -837,7 +843,7 @@ { int c; int do_load_module_filter, do_machdep_filter, reverse; - int unfiltered, user_mode, count_entered; + int unfiltered, user_mode, count_entered, bug_bytes_entered; ulong curaddr; ulong revtarget; ulong count; @@ -851,7 +857,16 @@ char buf4[BUFSIZE]; char buf5[BUFSIZE]; - reverse = count_entered = FALSE; + if ((argcnt == 2) && STREQ(args[1], "-b")) { + fprintf(fp, "encoded bytes being skipped after ud2a: "); + if (kt->BUG_bytes < 0) + fprintf(fp, "undetermined\n"); + else + fprintf(fp, "%d\n", kt->BUG_bytes); + return; + } + + reverse = count_entered = bug_bytes_entered = FALSE; sp = NULL; unfiltered = user_mode = do_machdep_filter = do_load_module_filter = 0; @@ -860,7 +875,7 @@ req->flags |= GNU_FROM_TTY_OFF|GNU_RETURN_ON_ERROR; req->count = 1; - while ((c = getopt(argcnt, args, "ulrx")) != EOF) { + while ((c = getopt(argcnt, args, "ulrxb:B:")) != EOF) { switch(c) { case 'x': @@ -883,6 +898,12 @@ BZERO(buf4, BUFSIZE); break; + case 'B': + case 'b': + kt->BUG_bytes = atoi(optarg); + bug_bytes_entered = TRUE; + break; + default: argerrs++; break; @@ -1059,7 +1080,9 @@ close_tmpfile(); } } - else cmd_usage(pc->curcmd, SYNOPSIS); + else if (bug_bytes_entered) + return; + else cmd_usage(pc->curcmd, SYNOPSIS); if (!reverse) { FREEBUF(req->buf); @@ -1150,6 +1173,185 @@ FREEBUF(req); } +/* + * x86 and x86_64 kernels may have file/line-number encoding + * asm()'d in just after the "ud2a" instruction, which confuses + * the disassembler and the x86 backtracer. Determine the + * number of bytes to skip. + */ +static void +BUG_bytes_init(void) +{ + if (machine_type("X86")) + kt->BUG_bytes = BUG_x86(); + else if (machine_type("X86_64")) + kt->BUG_bytes = BUG_x86_64(); +} + +static int +BUG_x86(void) +{ + struct syment *sp, *spn; + char buf1[BUFSIZE]; + char buf2[BUFSIZE]; + char *arglist[MAXARGS]; + ulong vaddr, fileptr; + int found; + + /* + * Prior to 2.4.19, a call to do_BUG() preceded + * the standalone ud2a instruction. + */ + if (THIS_KERNEL_VERSION < LINUX(2,4,19)) + return 0; + + /* + * 2.6.20 introduced __bug_table support for i386, + * but even if CONFIG_DEBUG_BUGVERBOSE is not configured, + * the ud2a stands alone. + */ + if (THIS_KERNEL_VERSION >= LINUX(2,6,20)) + return 0; + + /* + * For previous kernel versions, it may depend upon + * whether CONFIG_DEBUG_BUGVERBOSE was configured: + * + * #ifdef CONFIG_DEBUG_BUGVERBOSE + * #define BUG() \ + * __asm__ __volatile__( "ud2\n" \ + * "\t.word %c0\n" \ + * "\t.long %c1\n" \ + * : : "i" (__LINE__), "i" (__FILE__)) + * #else + * #define BUG() __asm__ __volatile__("ud2\n") + * #endif + * + * But that's not necessarily true, since there are + * pre-2.6.11 versions that force it like so: + * + * #if 1 /- Set to zero for a slightly smaller kernel -/ + * #define BUG() \ + * __asm__ __volatile__( "ud2\n" \ + * "\t.word %c0\n" \ + * "\t.long %c1\n" \ + * : : "i" (__LINE__), "i" (__FILE__)) + * #else + * #define BUG() __asm__ __volatile__("ud2\n") + * #endif + */ + + /* + * This works if in-kernel config data is available. + */ + if ((THIS_KERNEL_VERSION >= LINUX(2,6,11)) && + (kt->flags & BUGVERBOSE_OFF)) + return 0; + + /* + * At this point, it's a pretty safe bet that it's configured, + * but to be sure, disassemble a known BUG() caller and + * verify that the encoding is there. + */ + +#define X86_BUG_BYTES (6) /* sizeof(short) + sizeof(pointer) */ + + if (!(sp = symbol_search("do_exit")) || + !(spn = next_symbol(NULL, sp))) + return X86_BUG_BYTES; + + sprintf(buf1, "x/%ldi 0x%lx", spn->value - sp->value, sp->value); + + found = FALSE; + open_tmpfile(); + gdb_pass_through(buf1, pc->tmpfile, GNU_RETURN_ON_ERROR); + rewind(pc->tmpfile); + while (fgets(buf2, BUFSIZE, pc->tmpfile)) { + if (parse_line(buf2, arglist) < 3) + continue; + + if ((vaddr = htol(arglist[0], RETURN_ON_ERROR, NULL)) >= spn->value) + continue; + + if (STREQ(arglist[2], "ud2a")) { + found = TRUE; + break; + } + } + close_tmpfile(); + + if (!found || !readmem(vaddr+4, KVADDR, &fileptr, sizeof(ulong), + "BUG filename pointer", RETURN_ON_ERROR|QUIET)) + return X86_BUG_BYTES; + + if (!IS_KVADDR(fileptr)) { + if (CRASHDEBUG(1)) + fprintf(fp, + "no filename pointer: kt->BUG_bytes: 0\n"); + return 0; + } + + if (!read_string(fileptr, buf1, BUFSIZE-1)) + error(WARNING, + "cannot read BUG (ud2a) encoded filename address: %lx\n", + fileptr); + else if (CRASHDEBUG(1)) + fprintf(fp, "BUG bytes filename encoding: [%s]\n", buf1); + + return X86_BUG_BYTES; +} + +static int +BUG_x86_64(void) +{ + /* + * 2.6.20 introduced __bug_table support for x86_64, + * but even if CONFIG_DEBUG_BUGVERBOSE is not configured, + * the ud2a stands alone. + */ + if (THIS_KERNEL_VERSION >= LINUX(2,6,20)) + return 0; + + /* + * The original bug_frame structure looks like this, which + * causes the disassembler to go off into the weeds: + * + * struct bug_frame { + * unsigned char ud2[2]; + * char *filename; + * unsigned short line; + * } + * + * In 2.6.13, fake push and ret instructions were encoded + * into the frame so that the disassembly would at least + * "work", although the two fake instructions show nonsensical + * arguments: + * + * struct bug_frame { + * unsigned char ud2[2]; + * unsigned char push; + * signed int filename; + * unsigned char ret; + * unsigned short line; + * } + */ + + if (STRUCT_EXISTS("bug_frame")) + return (int)(STRUCT_SIZE("bug_frame") - 2); + + return 0; +} + + +/* + * Callback from gdb disassembly code. + */ +int +kernel_BUG_encoding_bytes(void) +{ + return kt->BUG_bytes; +} + #ifdef NOT_USED /* * To avoid premature stoppage/extension of a dis that includes @@ -3113,6 +3315,9 @@ if (NETDUMP_DUMPFILE() && is_partial_netdump()) fprintf(fp, " [PARTIAL DUMP]"); + if (DISKDUMP_DUMPFILE() && is_partial_diskdump()) + fprintf(fp, " [PARTIAL DUMP]"); + fprintf(fp, "\n"); } @@ -3514,6 +3719,8 @@ fprintf(fp, "%sDWARF_UNWIND_EH_FRAME", others++ ? "|" : ""); if (kt->flags & DWARF_UNWIND_MODULES) fprintf(fp, "%sDWARF_UNWIND_MODULES", others++ ? "|" : ""); + if (kt->flags & BUGVERBOSE_OFF) + fprintf(fp, "%sBUGVERBOSE_OFF", others++ ? "|" : ""); fprintf(fp, ")\n"); fprintf(fp, " stext: %lx\n", kt->stext); fprintf(fp, " etext: %lx\n", kt->etext); @@ -3554,6 +3761,7 @@ kt->kernel_version[1], kt->kernel_version[2]); fprintf(fp, " gcc_version: %d.%d.%d\n", kt->gcc_version[0], kt->gcc_version[1], kt->gcc_version[2]); + fprintf(fp, " BUG_bytes: %d\n", kt->BUG_bytes); fprintf(fp, " runq_siblings: %d\n", kt->runq_siblings); fprintf(fp, " __rq_idx[NR_CPUS]: "); nr_cpus = kt->kernel_NR_CPUS ? kt->kernel_NR_CPUS : NR_CPUS; @@ -5513,6 +5721,7 @@ "CONFIG_NR_CPUS", "CONFIG_PGTABLE_4", "CONFIG_HZ", + "CONFIG_DEBUG_BUGVERBOSE", NULL, }; @@ -5646,9 +5855,13 @@ while (whitespace(*ln)) ln++; - /* skip comments */ - if (*ln == '#') + /* skip comments -- except when looking for "not set" */ + if (*ln == '#') { + if (strstr(ln, "CONFIG_DEBUG_BUGVERBOSE") && + strstr(ln, "not set")) + kt->flags |= BUGVERBOSE_OFF; continue; + } /* Find '=' */ if ((head = strchr(ln, '=')) != NULL) { --- crash-4.0-3.21/x86.c 2007-03-23 14:13:27.000000000 -0500 +++ crash-4.0-3.22/x86.c 2007-04-04 14:29:35.000000000 -0400 @@ -3760,7 +3760,11 @@ !strstr(buf2, "+")) sprintf(p1, buf1); } - } + } + else if (STREQ(argv[2], "ud2a")) + pc->curcmd_flags |= UD2A_INSTRUCTION; + else if (STREQ(argv[2], "(bad)")) + pc->curcmd_flags |= BAD_INSTRUCTION; if (CRASHDEBUG(1)) console(" %s", inbuf); --- crash-4.0-3.21/ppc.c 2007-03-23 14:13:27.000000000 -0500 +++ crash-4.0-3.22/ppc.c 2007-03-19 12:55:31.000000000 -0500 @@ -301,8 +301,8 @@ if (machdep->flags & CPU_BOOKE) page_table = page_middle + (BTOP(vaddr) & (PTRS_PER_PTE - 1)); else - page_table = ((page_middle & machdep->pagemask) + machdep->kvbase) + - (BTOP(vaddr) & (PTRS_PER_PTE-1)); + page_table = (ulong *)(((pgd_pte & (ulong)machdep->pagemask) + machdep->kvbase) + + ((ulong)BTOP(vaddr) & (PTRS_PER_PTE-1))); if (verbose) fprintf(fp, " PMD: %lx => %lx\n",(ulong)page_middle, @@ -389,8 +389,8 @@ if (machdep->flags & CPU_BOOKE) page_table = page_middle + (BTOP(kvaddr) & (PTRS_PER_PTE - 1)); else - page_table = ((page_middle & machdep->pagemask) + machdep->kvbase) + - (BTOP(kvaddr) & (PTRS_PER_PTE-1)); + page_table = (ulong *)(((pgd_pte & (ulong)machdep->pagemask) + machdep->kvbase) + + ((ulong)BTOP(kvaddr) & (PTRS_PER_PTE-1))); if (verbose) fprintf(fp, " PMD: %lx => %lx\n", (ulong)page_middle, --- crash-4.0-3.21/x86_64.c 2007-03-23 14:13:27.000000000 -0500 +++ crash-4.0-3.22/x86_64.c 2007-03-21 11:01:19.000000000 -0500 @@ -4250,6 +4250,21 @@ 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); + } } /* --- crash-4.0-3.21/cmdline.c 2007-03-23 14:13:27.000000000 -0500 +++ crash-4.0-3.22/cmdline.c 2007-04-03 14:01:38.000000000 -0400 @@ -928,6 +928,11 @@ pc->pipe_pid = 0; pc->pipe_shell_pid = 0; pc->sbrk = sbrk(0); + if ((pc->curcmd_flags & (UD2A_INSTRUCTION|BAD_INSTRUCTION)) == + (UD2A_INSTRUCTION|BAD_INSTRUCTION)) + error(WARNING, "A (bad) instruction was noted in last disassembly.\n" + " Use \"dis -b [number]\" to set/restore the number of\n" + " encoded bytes to skip after a ud2a (BUG) instruction.\n"); pc->curcmd_flags = 0; pc->curcmd_private = 0; --- crash-4.0-3.21/lkcd_x86_trace.c 2007-03-23 14:13:27.000000000 -0500 +++ crash-4.0-3.22/lkcd_x86_trace.c 2007-04-05 16:02:46.000000000 -0400 @@ -5153,6 +5153,8 @@ } else { codeptr++; } + if (STREQ(op->name, "ud2a")) + codeptr += kt->BUG_bytes; } else { opcode = *codeptr; op = &op_386[*codeptr]; --- crash-4.0-3.21/netdump.c 2007-03-23 14:13:27.000000000 -0500 +++ crash-4.0-3.22/netdump.c 2007-04-09 16:14:00.000000000 -0400 @@ -672,6 +672,42 @@ if (nd->flags & PARTIAL_DUMP) netdump_print("%sPARTIAL_DUMP", others++ ? "|" : ""); netdump_print(")\n"); + if ((pc->flags & RUNTIME) && symbol_exists("dump_level")) { + int dump_level; + if (readmem(symbol_value("dump_level"), KVADDR, &dump_level, + sizeof(dump_level), "dump_level", QUIET|RETURN_ON_ERROR)) { + netdump_print(" dump_level: %d (0x%x) %s", + dump_level, dump_level, + dump_level > 0 ? "(" : ""); + +#define DUMP_EXCLUDE_CACHE 0x00000001 /* Exclude LRU & SwapCache pages*/ +#define DUMP_EXCLUDE_CLEAN 0x00000002 /* Exclude all-zero pages */ +#define DUMP_EXCLUDE_FREE 0x00000004 /* Exclude free pages */ +#define DUMP_EXCLUDE_ANON 0x00000008 /* Exclude Anon pages */ +#define DUMP_SAVE_PRIVATE 0x00000010 /* Save private pages */ + + others = 0; + if (dump_level & DUMP_EXCLUDE_CACHE) + netdump_print("%sDUMP_EXCLUDE_CACHE", + others++ ? "|" : ""); + if (dump_level & DUMP_EXCLUDE_CLEAN) + netdump_print("%sDUMP_EXCLUDE_CLEAN", + others++ ? "|" : ""); + if (dump_level & DUMP_EXCLUDE_FREE) + netdump_print("%sDUMP_EXCLUDE_FREE", + others++ ? "|" : ""); + if (dump_level & DUMP_EXCLUDE_ANON) + netdump_print("%sDUMP_EXCLUDE_ANON", + others++ ? "|" : ""); + if (dump_level & DUMP_SAVE_PRIVATE) + netdump_print("%sDUMP_SAVE_PRIVATE", + others++ ? "|" : ""); + netdump_print("%s\n", dump_level > 0 ? ")" : ""); + } else + netdump_print(" dump_level: (unknown)\n"); + } else if (!(pc->flags & RUNTIME) && symbol_exists("dump_level")) + netdump_print(" dump_level: (undetermined)\n"); + netdump_print(" ndfd: %d\n", nd->ndfd); netdump_print(" ofp: %lx\n", nd->ofp); netdump_print(" header_size: %d\n", nd->header_size); --- crash-4.0-3.21/diskdump.c 2007-03-23 14:13:27.000000000 -0500 +++ crash-4.0-3.22/diskdump.c 2007-04-10 10:20:29.000000000 -0400 @@ -58,10 +58,14 @@ ulong evictions; /* total evictions done */ ulong cached_reads; ulong *valid_pages; + ulong accesses; }; static struct diskdump_data diskdump_data = { 0 }; static struct diskdump_data *dd = &diskdump_data; +static int get_dump_level(void); + +ulong *diskdump_flags = &diskdump_data.flags; static inline int get_bit(char *map, int byte, int bit) { @@ -134,6 +138,8 @@ } else if (!memcmp(header->signature, KDUMP_SIGNATURE, sizeof(header->signature))) { dd->flags |= KDUMP_CMPRS_LOCAL; + if (header->header_version >= 1) + dd->flags |= ERROR_EXCLUDED; } else { if (CRASHDEBUG(1)) error(INFO, "diskdump: dump does not have panic dump header\n"); @@ -292,6 +298,9 @@ if ((dd->compressed_page = (char *)malloc(dd->block_size)) == NULL) error(FATAL, "diskdump: cannot malloc compressed page space\n"); + if (CRASHDEBUG(1)) + diskdump_memory_dump(fp); + return TRUE; } @@ -332,6 +341,8 @@ int i; struct page_cache_hdr *pgc; + dd->accesses++; + for (i = 0; i < DISKDUMP_CACHED_PAGES; i++) { pgc = &dd->page_cache_hdr[i]; @@ -452,6 +463,9 @@ if ((pfn >= dd->header->max_mapnr) || !page_is_ram(pfn)) return SEEK_ERROR; if (!page_is_dumpable(pfn)) { + if ((dd->flags & (ZERO_EXCLUDED|ERROR_EXCLUDED)) == + ERROR_EXCLUDED) + return PAGE_EXCLUDED; memset(bufptr, 0, cnt); return cnt; } @@ -566,6 +580,197 @@ int diskdump_memory_dump(FILE *fp) { + int i, others, dump_level; + struct disk_dump_header *dh; + struct disk_dump_sub_header *dsh; + struct kdump_sub_header *kdsh; + ulong *tasks; + + fprintf(fp, "diskdump_data: \n"); + fprintf(fp, " flags: %lx (", dd->flags); + others = 0; + if (dd->flags & DISKDUMP_LOCAL) + fprintf(fp, "%sDISKDUMP_LOCAL", others++ ? "|" : ""); + if (dd->flags & KDUMP_CMPRS_LOCAL) + fprintf(fp, "%sKDUMP_CMPRS_LOCAL", others++ ? "|" : ""); + if (dd->flags & ERROR_EXCLUDED) + fprintf(fp, "%sERROR_EXCLUDED", others++ ? "|" : ""); + if (dd->flags & ZERO_EXCLUDED) + fprintf(fp, "%sZERO_EXCLUDED", others++ ? "|" : ""); + fprintf(fp, ")\n"); + fprintf(fp, " dfd: %d\n", dd->dfd); + fprintf(fp, " ofp: %lx\n", (ulong)dd->ofp); + fprintf(fp, " machine_type: %d ", dd->machine_type); + switch (dd->machine_type) + { + case EM_386: + fprintf(fp, "(EM_386)\n"); break; + case EM_X86_64: + fprintf(fp, "(EM_X86_64)\n"); break; + case EM_IA_64: + fprintf(fp, "(EM_IA_64)\n"); break; + case EM_PPC64: + fprintf(fp, "(EM_PPC64)\n"); break; + default: + fprintf(fp, "(unknown)\n"); break; + } + + fprintf(fp, "\n header: %lx\n", (ulong)dd->header); + dh = dd->header; + fprintf(fp, " signature: \""); + for (i = 0; i < SIG_LEN; i++) + if (dh->signature[i]) + fprintf(fp, "%c", dh->signature[i]); + fprintf(fp, "\"\n"); + fprintf(fp, " header_version: %d\n", dh->header_version); + fprintf(fp, " utsname:\n"); + fprintf(fp, " sysname: %s\n", dh->utsname.sysname); + fprintf(fp, " nodename: %s\n", dh->utsname.nodename); + fprintf(fp, " release: %s\n", dh->utsname.release); + fprintf(fp, " version: %s\n", dh->utsname.version); + fprintf(fp, " machine: %s\n", dh->utsname.machine); + fprintf(fp, " domainname: %s\n", dh->utsname.domainname); + fprintf(fp, " timestamp:\n"); + fprintf(fp, " tv_sec: %lx\n", dh->timestamp.tv_sec); + fprintf(fp, " tv_usec: %lx\n", dh->timestamp.tv_usec); + fprintf(fp, " status: %x (", dh->status); + others = 0; + if (dh->status & DUMP_HEADER_COMPLETED) + fprintf(fp, "%sDUMP_HEADER_COMPLETED", others++ ? "|" : ""); + if (dh->status & DUMP_HEADER_INCOMPLETED) + fprintf(fp, "%sDUMP_HEADER_INCOMPLETED", others++ ? "|" : ""); + if (dh->status & DUMP_HEADER_COMPRESSED) + fprintf(fp, "%sDUMP_HEADER_COMPRESSED", others++ ? "|" : ""); + fprintf(fp, ")\n"); + fprintf(fp, " block_size: %d\n", dh->block_size); + fprintf(fp, " sub_hdr_size: %d\n", dh->sub_hdr_size); + fprintf(fp, " bitmap_blocks: %u\n", dh->bitmap_blocks); + fprintf(fp, " max_mapnr: %u\n", dh->max_mapnr); + fprintf(fp, " total_ram_blocks: %u\n", dh->total_ram_blocks); + fprintf(fp, " device_blocks: %u\n", dh->device_blocks); + fprintf(fp, " written_blocks: %u\n", dh->written_blocks); + fprintf(fp, " current_cpu: %u\n", dh->current_cpu); + fprintf(fp, " nr_cpus: %d\n", dh->nr_cpus); + tasks = (ulong *)&dh->tasks[0]; + fprintf(fp, " tasks[nr_cpus]: %lx\n", *tasks); + for (tasks++, i = 1; i < dh->nr_cpus; i++) { + fprintf(fp, " %lx\n", *tasks); + tasks++; + } + fprintf(fp, "\n"); + fprintf(fp, " sub_header: %lx ", (ulong)dd->sub_header); + if ((dsh = dd->sub_header)) { + fprintf(fp, "\n elf_regs: %lx\n", + (ulong)&dsh->elf_regs); + fprintf(fp, " dump_level: "); + if ((pc->flags & RUNTIME) && + ((dump_level = get_dump_level()) >= 0)) { + fprintf(fp, "%d (0x%x) %s", dump_level, dump_level, + dump_level ? "(" : ""); + +#define DUMP_EXCLUDE_CACHE 0x00000001 /* Exclude LRU & SwapCache pages*/ +#define DUMP_EXCLUDE_CLEAN 0x00000002 /* Exclude all-zero pages */ +#define DUMP_EXCLUDE_FREE 0x00000004 /* Exclude free pages */ +#define DUMP_EXCLUDE_ANON 0x00000008 /* Exclude Anon pages */ +#define DUMP_SAVE_PRIVATE 0x00000010 /* Save private pages */ + + others = 0; + if (dump_level & DUMP_EXCLUDE_CACHE) + fprintf(fp, "%sDUMP_EXCLUDE_CACHE", + others++ ? "|" : ""); + if (dump_level & DUMP_EXCLUDE_CLEAN) + fprintf(fp, "%sDUMP_EXCLUDE_CLEAN", + others++ ? "|" : ""); + if (dump_level & DUMP_EXCLUDE_FREE) + fprintf(fp, "%sDUMP_EXCLUDE_FREE", + others++ ? "|" : ""); + if (dump_level & DUMP_EXCLUDE_ANON) + fprintf(fp, "%sDUMP_EXCLUDE_ANON", + others++ ? "|" : ""); + if (dump_level & DUMP_SAVE_PRIVATE) + fprintf(fp, "%sDUMP_SAVE_PRIVATE", + others++ ? "|" : ""); + fprintf(fp, "%s\n\n", dump_level ? ")" : ""); + } else + fprintf(fp, "%s\n\n", pc->flags & RUNTIME ? + "(unknown)" : "(undetermined)"); + + } else + fprintf(fp, "(n/a)\n\n"); + + fprintf(fp, " sub_header_kdump: %lx ", (ulong)dd->sub_header_kdump); + if ((kdsh = dd->sub_header_kdump)) { + fprintf(fp, "\n phys_base: %lx\n", + (ulong)kdsh->phys_base); + fprintf(fp, " dump_level: "); + if ((dump_level = get_dump_level()) >= 0) { + fprintf(fp, "%d (0x%x) %s", dump_level, dump_level, + dump_level ? "(" : ""); + +#define DL_EXCLUDE_ZERO (0x001) /* Exclude Pages filled with Zeros */ +#define DL_EXCLUDE_CACHE (0x002) /* Exclude Cache Pages without Private Pages */ +#define DL_EXCLUDE_CACHE_PRI (0x004) /* Exclude Cache Pages with Private Pages */ +#define DL_EXCLUDE_USER_DATA (0x008) /* Exclude UserProcessData Pages */ +#define DL_EXCLUDE_FREE (0x010) /* Exclude Free Pages */ + + if (dump_level & DL_EXCLUDE_ZERO) + fprintf(fp, "%sDUMP_EXCLUDE_ZERO", + others++ ? "|" : ""); + if (dump_level & DL_EXCLUDE_CACHE) + fprintf(fp, "%sDUMP_EXCLUDE_CACHE", + others++ ? "|" : ""); + if (dump_level & DL_EXCLUDE_CACHE_PRI) + fprintf(fp, "%sDUMP_EXCLUDE_CACHE_PRI", + others++ ? "|" : ""); + if (dump_level & DL_EXCLUDE_USER_DATA) + fprintf(fp, "%sDUMP_EXCLUDE_USER_DATA", + others++ ? "|" : ""); + if (dump_level & DL_EXCLUDE_FREE) + fprintf(fp, "%sDUMP_EXCLUDE_FREE", + others++ ? "|" : ""); + others = 0; + + fprintf(fp, "%s\n\n", dump_level ? ")" : ""); + } else + fprintf(fp, "(unknown)\n\n"); + } else + fprintf(fp, "(n/a)\n\n"); + + fprintf(fp, " data_offset: %lx\n", (ulong)dd->data_offset); + fprintf(fp, " block_size: %d\n", dd->block_size); + fprintf(fp, " block_shift: %d\n", dd->block_shift); + fprintf(fp, " bitmap: %lx\n", (ulong)dd->bitmap); + fprintf(fp, " bitmap_len: %d\n", dd->bitmap_len); + fprintf(fp, " dumpable_bitmap: %lx\n", (ulong)dd->dumpable_bitmap); + fprintf(fp, " byte: %d\n", dd->byte); + fprintf(fp, " bit: %d\n", dd->bit); + fprintf(fp, " compressed_page: %lx\n", (ulong)dd->compressed_page); + fprintf(fp, " curbufptr: %lx\n\n", (ulong)dd->curbufptr); + + for (i = 0; i < DISKDUMP_CACHED_PAGES; i++) { + fprintf(fp, "%spage_cache_hdr[%d]:\n", i < 10 ? " " : "", i); + fprintf(fp, " pg_flags: %x (", dd->page_cache_hdr[i].pg_flags); + others = 0; + if (dd->page_cache_hdr[i].pg_flags & PAGE_VALID) + fprintf(fp, "%sPAGE_VALID", others++ ? "|" : ""); + fprintf(fp, ")\n"); + fprintf(fp, " pg_addr: %llx\n", (ulonglong)dd->page_cache_hdr[i].pg_addr); + fprintf(fp, " pg_bufptr: %lx\n", (ulong)dd->page_cache_hdr[i].pg_bufptr); + fprintf(fp, " pg_hit_count: %ld\n", dd->page_cache_hdr[i].pg_hit_count); + } + + fprintf(fp, "\n page_cache_buf: %lx\n", (ulong)dd->page_cache_buf); + fprintf(fp, " evict_index: %d\n", dd->evict_index); + fprintf(fp, " evictions: %ld\n", dd->evictions); + fprintf(fp, " accesses: %ld\n", dd->accesses); + fprintf(fp, " cached_reads: %ld ", dd->cached_reads); + if (dd->accesses) + fprintf(fp, "(%ld%%)\n", + dd->cached_reads * 100 / dd->accesses); + else + fprintf(fp, "\n"); + fprintf(fp, " valid_pages: %lx\n", (ulong)dd->valid_pages); + return 0; } @@ -577,3 +782,36 @@ { return 0; } + +/* + * Versions of disk_dump that support it contain the "dump_level" symbol. + * Version 1 and later compressed kdump dumpfiles contain the dump level + * in an additional field of the sub_header_kdump structure. + */ +static int +get_dump_level(void) +{ + int dump_level; + + if (DISKDUMP_VALID()) { + if (symbol_exists("dump_level") && + readmem(symbol_value("dump_level"), KVADDR, &dump_level, + sizeof(dump_level), "dump_level", QUIET|RETURN_ON_ERROR)) + return dump_level; + } else if (KDUMP_CMPRS_VALID()) { + if (dd->header->header_version >= 1) + return dd->sub_header_kdump->dump_level; + } + + return -1; +} + +/* + * Used by the "sys" command to display [PARTIAL DUMP] + * after the dumpfile name. + */ +int +is_partial_diskdump(void) +{ + return (get_dump_level() > 0 ? TRUE : FALSE); +} --- crash-4.0-3.21/defs.h 2007-03-23 14:13:27.000000000 -0500 +++ crash-4.0-3.22/defs.h 2007-04-09 13:49:52.000000000 -0400 @@ -211,6 +211,8 @@ #define DISKDUMP_LOCAL (0x1) #define KDUMP_CMPRS_LOCAL (0x2) +#define ERROR_EXCLUDED (0x4) +#define ZERO_EXCLUDED (0x8) #define DISKDUMP_VALID() (dd->flags & DISKDUMP_LOCAL) #define KDUMP_CMPRS_VALID() (dd->flags & KDUMP_CMPRS_LOCAL) @@ -234,6 +236,7 @@ #define SEEK_ERROR (-1) #define READ_ERROR (-2) #define WRITE_ERROR (-3) +#define PAGE_EXCLUDED (-4) #define RESTART() (longjmp(pc->main_loop_env, 1)) #define RESUME_FOREACH() (longjmp(pc->foreach_loop_env, 1)) @@ -360,6 +363,8 @@ #define MEMTYPE_UVADDR (0x10) #define MEMTYPE_FILEADDR (0x20) #define HEADER_PRINTED (0x40) +#define BAD_INSTRUCTION (0x80) +#define UD2A_INSTRUCTION (0x100) ulonglong curcmd_private; /* general purpose per-command info */ int cur_gdb_cmd; /* current gdb command */ int last_gdb_cmd; /* previously-executed gdb command */ @@ -446,6 +451,7 @@ #define DWARF_UNWIND_EH_FRAME (0x400000) #define DWARF_UNWIND_CAPABLE (DWARF_UNWIND_MEMORY|DWARF_UNWIND_EH_FRAME) #define DWARF_UNWIND_MODULES (0x800000) +#define BUGVERBOSE_OFF (0x1000000) #define GCC_VERSION_DEPRECATED (GCC_3_2|GCC_3_2_3|GCC_2_96|GCC_3_3_2|GCC_3_3_3) @@ -486,6 +492,7 @@ long __cpu_idx[NR_CPUS]; long __per_cpu_offset[NR_CPUS]; ulong cpu_flags[NR_CPUS]; + int BUG_bytes; #define NMI 0x1 ulong xen_flags; #define WRITABLE_PAGE_TABLES (0x1) @@ -3453,6 +3460,7 @@ int is_system_call(char *, ulong); void generic_dump_irq(int); int generic_dis_filter(ulong, char *); +int kernel_BUG_encoding_bytes(void); void display_sys_stats(void); char *get_uptime(char *, ulonglong *); void clone_bt_info(struct bt_info *, struct bt_info *, struct task_context *); @@ -3949,6 +3957,8 @@ FILE *set_diskdump_fp(FILE *); void get_diskdump_regs(struct bt_info *, ulong *, ulong *); int diskdump_phys_base(unsigned long *); +ulong *diskdump_flags; +int is_partial_diskdump(void); /* * xendump.c @@ -4316,7 +4326,6 @@ extern int prettyprint_structs; extern int prettyprint_arrays; extern int repeat_count_threshold; -extern int repeat_count_threshold; extern unsigned int print_max; /* --- crash-4.0-3.21/diskdump.h 2007-03-23 14:13:27.000000000 -0500 +++ crash-4.0-3.22/diskdump.h 2007-04-09 12:15:02.000000000 -0400 @@ -56,6 +56,7 @@ struct kdump_sub_header { unsigned long phys_base; + int dump_level; /* header_version 1 and later */ }; /* page flags */ --- crash-4.0-3.21/gdb-6.1.patch 2007-03-23 14:13:27.000000000 -0500 +++ crash-4.0-3.22/gdb-6.1.patch 2007-04-03 11:43:05.000000000 -0400 @@ -72,3 +72,16 @@ augmentation++; } +--- gdb-6.1/opcodes/i386-dis.c.orig ++++ gdb-6.1/opcodes/i386-dis.c +@@ -2092,6 +2092,10 @@ print_insn (bfd_vma pc, disassemble_info + dp = &dis386_twobyte[*++codep]; + need_modrm = twobyte_has_modrm[*codep]; + uses_SSE_prefix = twobyte_uses_SSE_prefix[*codep]; ++ if (dp->name && strcmp(dp->name, "ud2a") == 0) { ++ extern int kernel_BUG_encoding_bytes(void); ++ codep += kernel_BUG_encoding_bytes(); ++ } + } + else + {