--- crash-4.0-4.3/main.c 2007-07-20 14:31:23.000000000 -0400 +++ crash-4.0-4.4/main.c 2007-07-18 14:05:18.000000000 -0400 @@ -27,12 +27,12 @@ static void check_xen_hyper(void); static struct option long_options[] = { - {"memory_module", 1, 0, 0}, - {"memory_device", 1, 0, 0}, + {"memory_module", required_argument, 0, 0}, + {"memory_device", required_argument, 0, 0}, {"no_kallsyms", 0, 0, 0}, {"no_modules", 0, 0, 0}, {"no_namelist_gzip", 0, 0, 0}, - {"help", 0, 0, 0}, + {"help", optional_argument, 0, 'h'}, {"data_debug", 0, 0, 0}, {"no_data_debug", 0, 0, 0}, {"no_crashrc", 0, 0, 0}, @@ -40,16 +40,20 @@ {"kmem_cache_delay", 0, 0, 0}, {"readnow", 0, 0, 0}, {"smp", 0, 0, 0}, - {"machdep", 1, 0, 0}, + {"machdep", required_argument, 0, 0}, {"version", 0, 0, 0}, {"buildinfo", 0, 0, 0}, {"shadow_page_tables", 0, 0, 0}, - {"cpus", 1, 0, 0}, + {"cpus", required_argument, 0, 0}, {"no_ikconfig", 0, 0, 0}, {"hyper", 0, 0, 0}, - {"p2m_mfn", 1, 0, 0}, + {"p2m_mfn", required_argument, 0, 0}, {"zero_excluded", 0, 0, 0}, {"no_panic", 0, 0, 0}, + {"more", 0, 0, 0}, + {"less", 0, 0, 0}, + {"CRASHPAGER", 0, 0, 0}, + {"no_scroll", 0, 0, 0}, {0, 0, 0, 0} }; @@ -65,7 +69,7 @@ */ opterr = 0; optind = 0; - while((c = getopt_long(argc, argv, "LgH:h:e:i:sSvc:d:tfp:m:", + while((c = getopt_long(argc, argv, "Lgh::e:i:sSvc:d:tfp:m:", long_options, &option_index)) != -1) { switch (c) { @@ -74,60 +78,55 @@ "memory_module")) pc->memory_module = optarg; - if (STREQ(long_options[option_index].name, + else if (STREQ(long_options[option_index].name, "memory_device")) pc->memory_device = optarg; - if (STREQ(long_options[option_index].name, + else if (STREQ(long_options[option_index].name, "no_kallsyms")) kt->flags |= NO_KALLSYMS; - if (STREQ(long_options[option_index].name, + else if (STREQ(long_options[option_index].name, "no_modules")) kt->flags |= NO_MODULE_ACCESS; - if (STREQ(long_options[option_index].name, + else if (STREQ(long_options[option_index].name, "no_ikconfig")) kt->flags |= NO_IKCONFIG; - if (STREQ(long_options[option_index].name, + else if (STREQ(long_options[option_index].name, "no_namelist_gzip")) pc->flags |= NAMELIST_NO_GZIP; - if (STREQ(long_options[option_index].name, "help")) { - program_usage(LONG_FORM); - clean_exit(0); - } - - if (STREQ(long_options[option_index].name, + else if (STREQ(long_options[option_index].name, "data_debug")) pc->flags |= DATADEBUG; - if (STREQ(long_options[option_index].name, + else if (STREQ(long_options[option_index].name, "no_data_debug")) pc->flags &= ~DATADEBUG; - if (STREQ(long_options[option_index].name, + else if (STREQ(long_options[option_index].name, "no_kmem_cache")) vt->flags |= KMEM_CACHE_UNAVAIL; - if (STREQ(long_options[option_index].name, + else if (STREQ(long_options[option_index].name, "kmem_cache_delay")) vt->flags |= KMEM_CACHE_DELAY; - if (STREQ(long_options[option_index].name, + else if (STREQ(long_options[option_index].name, "readnow")) pc->flags |= READNOW; - if (STREQ(long_options[option_index].name, + else if (STREQ(long_options[option_index].name, "smp")) kt->flags |= SMP; - if (STREQ(long_options[option_index].name, + else if (STREQ(long_options[option_index].name, "machdep")) machdep->cmdline_arg = optarg; - if (STREQ(long_options[option_index].name, + else if (STREQ(long_options[option_index].name, "version")) { pc->flags |= VERSION_QUERY; display_version(); @@ -135,30 +134,60 @@ clean_exit(0); } - if (STREQ(long_options[option_index].name, + else if (STREQ(long_options[option_index].name, "buildinfo")) { dump_build_data(); clean_exit(0); } - if (STREQ(long_options[option_index].name, + else if (STREQ(long_options[option_index].name, "shadow_page_tables")) kt->xen_flags |= SHADOW_PAGE_TABLES; - if (STREQ(long_options[option_index].name, "cpus")) + else if (STREQ(long_options[option_index].name, "cpus")) kt->cpus_override = optarg; - if (STREQ(long_options[option_index].name, "hyper")) + else if (STREQ(long_options[option_index].name, "hyper")) pc->flags |= XEN_HYPER; - if (STREQ(long_options[option_index].name, "p2m_mfn")) + else if (STREQ(long_options[option_index].name, "p2m_mfn")) xen_kdump_p2m_mfn(optarg); - if (STREQ(long_options[option_index].name, "zero_excluded")) + else if (STREQ(long_options[option_index].name, "zero_excluded")) *diskdump_flags |= ZERO_EXCLUDED; - if (STREQ(long_options[option_index].name, "no_panic")) + else if (STREQ(long_options[option_index].name, "no_panic")) tt->flags |= PANIC_TASK_NOT_FOUND; + + else if (STREQ(long_options[option_index].name, "more")) { + if ((pc->scroll_command != SCROLL_NONE) && + file_exists("/bin/more", NULL)) + pc->scroll_command = SCROLL_MORE; + } + + else if (STREQ(long_options[option_index].name, "less")) { + if ((pc->scroll_command != SCROLL_NONE) && + file_exists("/usr/bin/less", NULL)) + pc->scroll_command = SCROLL_LESS; + } + + else if (STREQ(long_options[option_index].name, "CRASHPAGER")) { + if ((pc->scroll_command != SCROLL_NONE) && + CRASHPAGER_valid()) + pc->scroll_command = SCROLL_CRASHPAGER; + } + + else if (STREQ(long_options[option_index].name, "no_scroll")) + pc->flags &= ~SCROLL; + + else if (STREQ(long_options[option_index].name, "no_crashrc")) + pc->flags |= NOCRASHRC; + + else { + error(INFO, "internal error: option %s unhandled\n", + long_options[option_index].name); + program_usage(SHORT_FORM); + } break; case 'f': @@ -169,12 +198,19 @@ pc->flags |= KERNEL_DEBUG_QUERY; break; - case 'H': - cmd_usage(optarg, COMPLETE_HELP); - clean_exit(0); - case 'h': - cmd_usage(optarg, COMPLETE_HELP|PIPE_TO_LESS); + /* note: long_getopt's handling of optional arguments is weak. + * To it, an optional argument must be part of the same argument + * as the flag itself (eg. --help=commands or -hcommands). + * We want to accept "--help commands" or "-h commands". + * So we must do that part ourselves. + */ + if (optarg != NULL) + cmd_usage(optarg, COMPLETE_HELP|PIPE_TO_SCROLL|MUST_HELP); + else if (argv[optind] != NULL && argv[optind][0] != '-') + cmd_usage(argv[optind++], COMPLETE_HELP|PIPE_TO_SCROLL|MUST_HELP); + else + program_usage(LONG_FORM); clean_exit(0); case 'e': @@ -238,13 +274,9 @@ break; default: - if (STREQ(argv[optind-1], "-h")) - program_usage(LONG_FORM); - else { - error(INFO, "invalid option: %s\n", - argv[optind-1]); - program_usage(SHORT_FORM); - } + error(INFO, "invalid option: %s\n", + argv[optind-1]); + program_usage(SHORT_FORM); } } opterr = 1; @@ -745,7 +777,10 @@ * Set up the default scrolling behavior for terminal output. */ if (isatty(fileno(stdout))) { - if (file_exists("/usr/bin/less", NULL)) { + if (CRASHPAGER_valid()) { + pc->flags |= SCROLL; + pc->scroll_command = SCROLL_CRASHPAGER; + } else if (file_exists("/usr/bin/less", NULL)) { pc->flags |= SCROLL; pc->scroll_command = SCROLL_LESS; } else if (file_exists("/bin/more", NULL)) { @@ -1082,10 +1117,22 @@ fprintf(fp, " ifile_offset: %lld\n", (ulonglong)pc->ifile_offset); fprintf(fp, "runtime_ifile_cmd: %s\n", pc->runtime_ifile_cmd ? pc->runtime_ifile_cmd : "(unused)"); - fprintf(fp, " scroll_command: %s\n", - pc->scroll_command == SCROLL_NONE ? "(none)" : - pc->scroll_command == SCROLL_LESS ? - "/usr/bin/less" : "/bin/more"); + fprintf(fp, " scroll_command: "); + switch (pc->scroll_command) + { + case SCROLL_NONE: + fprintf(fp, "SCROLL_NONE\n"); + break; + case SCROLL_LESS: + fprintf(fp, "SCROLL_LESS\n"); + break; + case SCROLL_MORE: + fprintf(fp, "SCROLL_MORE\n"); + break; + case SCROLL_CRASHPAGER: + fprintf(fp, "SCROLL_CRASHPAGER (%s)\n", getenv("CRASHPAGER")); + break; + } buf[0] = NULLCHAR; fprintf(fp, " redirect: %lx ", pc->redirect); @@ -1187,6 +1234,8 @@ fprintf(fp, "%sBAD_INSTRUCTION", others ? "|" : ""); if (pc->curcmd_flags & UD2A_INSTRUCTION) fprintf(fp, "%sUD2A_INSTRUCTION", others ? "|" : ""); + if (pc->curcmd_flags & IRQ_IN_USE) + fprintf(fp, "%sIRQ_IN_USE", 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-4.3/tools.c 2007-07-20 14:31:23.000000000 -0400 +++ crash-4.0-4.4/tools.c 2007-07-17 10:23:57.000000000 -0400 @@ -1845,7 +1845,14 @@ pc->flags |= SCROLL; else if (STREQ(args[optind], "off")) pc->flags &= ~SCROLL; - else if (IS_A_NUMBER(args[optind])) { + else if (STREQ(args[optind], "more")) + pc->scroll_command = SCROLL_MORE; + else if (STREQ(args[optind], "less")) + pc->scroll_command = SCROLL_LESS; + else if (STREQ(args[optind], "CRASHPAGER")) { + if (CRASHPAGER_valid()) + pc->scroll_command = SCROLL_CRASHPAGER; + } else if (IS_A_NUMBER(args[optind])) { value = stol(args[optind], FAULT_ON_ERROR, NULL); if (value) @@ -1856,9 +1863,25 @@ goto invalid_set_command; } - if (runtime) - fprintf(fp, "scroll: %s\n", - pc->flags & SCROLL ? "on" : "off"); + if (runtime) { + fprintf(fp, "scroll: %s ", + pc->flags & SCROLL ? "on" : "off"); + switch (pc->scroll_command) + { + case SCROLL_LESS: + fprintf(fp, "(/usr/bin/less)\n"); + break; + case SCROLL_MORE: + fprintf(fp, "(/bin/more)\n"); + break; + case SCROLL_NONE: + fprintf(fp, "(none)\n"); + break; + case SCROLL_CRASHPAGER: + fprintf(fp, "(CRASHPAGER: %s)\n", getenv("CRASHPAGER")); + break; + } + } return; @@ -2174,7 +2197,23 @@ static void show_options(void) { - fprintf(fp, " scroll: %s\n", pc->flags & SCROLL ? "on" : "off"); + fprintf(fp, " scroll: %s ", + pc->flags & SCROLL ? "on" : "off"); + switch (pc->scroll_command) + { + case SCROLL_LESS: + fprintf(fp, "(/usr/bin/less)\n"); + break; + case SCROLL_MORE: + fprintf(fp, "(/bin/more)\n"); + break; + case SCROLL_NONE: + fprintf(fp, "(none)\n"); + break; + case SCROLL_CRASHPAGER: + fprintf(fp, "(CRASHPAGER: %s)\n", getenv("CRASHPAGER")); + break; + } fprintf(fp, " radix: %d (%s)\n", pc->output_radix, pc->output_radix == 10 ? "decimal" : pc->output_radix == 16 ? "hexadecimal" : "unknown"); --- crash-4.0-4.3/filesys.c 2007-07-20 14:31:23.000000000 -0400 +++ crash-4.0-4.4/filesys.c 2007-07-20 11:11:57.000000000 -0400 @@ -1829,8 +1829,12 @@ if (symbol_exists("height_to_maxindex")) { int tmp; - ARRAY_LENGTH_INIT(tmp, height_to_maxindex, - "height_to_maxindex", NULL, 0); + if (LKCD_KERNTYPES()) + ARRAY_LENGTH_INIT_ALT(tmp, "height_to_maxindex", + "radix_tree_preload.nodes", NULL, 0); + else + ARRAY_LENGTH_INIT(tmp, height_to_maxindex, + "height_to_maxindex", NULL, 0); STRUCT_SIZE_INIT(radix_tree_root, "radix_tree_root"); STRUCT_SIZE_INIT(radix_tree_node, "radix_tree_node"); MEMBER_OFFSET_INIT(radix_tree_root_height, --- crash-4.0-4.3/help.c 2007-07-20 14:31:23.000000000 -0400 +++ crash-4.0-4.4/help.c 2007-07-20 15:17:26.000000000 -0400 @@ -105,34 +105,33 @@ void program_usage(int form) { - int i; - char **p; - FILE *less; + if (form == SHORT_FORM) { + fprintf(fp, program_usage_info[0], pc->program_name); + fprintf(fp, "\nEnter \"%s -h\" for details.\n", + pc->program_name); + clean_exit(1); + } else { + FILE *scroll; + char *scroll_command; + char **p; + + if ((scroll_command = setup_scroll_command()) && + (scroll = popen(scroll_command, "w"))) + fp = scroll; + else + scroll = NULL; - if (form == LONG_FORM) - less = popen("/usr/bin/less", "w"); - else - less = NULL; - - p = program_usage_info; - - if (form == LONG_FORM) { - if (less) - fp = less; - for (i = 0; program_usage_info[i]; i++, p++) { - fprintf(fp, *p, pc->program_name); + for (p = program_usage_info; *p; p++) { + fprintf(fp, *p, pc->program_name); fprintf(fp, "\n"); } - } else { - fprintf(fp, *p, pc->program_name); - fprintf(fp, "\nEnter \"%s -h\" for details.\n", - pc->program_name); - } - fflush(fp); - if (less) - pclose(less); + fflush(fp); + + if (scroll) + pclose(scroll); - clean_exit(1); + clean_exit(0); + } } @@ -397,7 +396,7 @@ if (oflag) dump_offset_table(args[optind], FALSE); else - cmd_usage(args[optind], COMPLETE_HELP); + cmd_usage(args[optind], COMPLETE_HELP|MUST_HELP); optind++; } while (args[optind]); } @@ -659,6 +658,10 @@ " argument is entered, the current value of the %s variable is shown. These", " are the %s variables, acceptable arguments, and purpose:\n", " scroll on | off controls output scrolling.", +" scroll less /usr/bin/less as the output scrolling program.", +" scroll more /bin/more as the output scrolling program.", +" scroll CRASHPAGER use CRASHPAGER environment variable as the", +" output scrolling program.", " radix 10 | 16 sets output radix to 10 or 16.", " refresh on | off controls internal task list refresh.", " print_max number set maximum number of array elements to print.", @@ -704,11 +707,11 @@ " STATE: TASK_RUNNING (PANIC)\n", " Turn off output scrolling:\n", " %s> set scroll off", -" scroll: off", +" scroll: off (/usr/bin/less)", " ", " Show the current state of %s internal variables:\n", " %s> set -v", -" scroll: on", +" scroll: on (/usr/bin/less)", " radix: 10 (decimal)", " refresh: on", " print_max: 256", @@ -2027,7 +2030,7 @@ char *help_irq[] = { "irq", "IRQ data", -"[-d | -b | [index ...]]", +"[[[index ...] | -u] | -d | -b]", " This command collaborates the data in an irq_desc_t, along with its", " associated hw_interrupt_type and irqaction structure data, into a", " consolidated per-IRQ display. Alternatively, the intel interrupt", @@ -2035,6 +2038,7 @@ " If no index value argument(s) nor any options are entered, the IRQ", " data for all IRQs will be displayed.\n", " index a valid IRQ index.", +" -u dump data for in-use IRQs only.", " -d dump the intel interrupt descriptor table.", " -b dump bottom half data.", "\nEXAMPLES", @@ -4902,21 +4906,22 @@ void cmd_usage(char *cmd, int helpflag) { - int i; - int found; - char **p; + char **p, *scroll_command; struct command_table_entry *cp; char buf[BUFSIZE]; - struct alias_data *ad; - FILE *less; + FILE *scroll; + int i; - if (helpflag & PIPE_TO_LESS) { - if ((less = popen("/usr/bin/less", "w")) != NULL) - fp = less; - helpflag &= ~PIPE_TO_LESS; - } else - less = NULL; - + if (helpflag & PIPE_TO_SCROLL) { + if ((scroll_command = setup_scroll_command()) && + (scroll = popen(scroll_command, "w"))) + fp = scroll; + else + scroll = NULL; + } else { + scroll_command = NULL; + scroll = NULL; + } if (STREQ(cmd, "copying")) { display_copying_info(); @@ -4959,46 +4964,50 @@ goto done_usage; } - found = FALSE; -retry: - if ((cp = get_command_table_entry(cmd))) { - if ((p = cp->help_data)) - found = TRUE; - } + /* look up command, possibly through an alias */ + for (;;) { + struct alias_data *ad; + + cp = get_command_table_entry(cmd); + if (cp != NULL) + break; /* found command */ + + /* try for an alias */ + ad = is_alias(cmd); + if (ad == NULL) + break; /* neither command nor alias */ - /* - * Check for alias names or gdb commands. - */ - if (!found) { - if ((ad = is_alias(cmd))) { - cmd = ad->args[0]; - goto retry; - } + cmd = ad->args[0]; + cp = get_command_table_entry(cmd); + } - if (helpflag == SYNOPSIS) { - fprintf(fp, - "No usage data for the \"%s\" command is available.\n", + if (cp == NULL || (p = cp->help_data) == NULL) { + if (helpflag & SYNOPSIS) { + fprintf(fp, + "No usage data for the \"%s\" command" + " is available.\n", cmd); RESTART(); } - if (STREQ(pc->curcmd, "help")) { - if (cp) - fprintf(fp, - "No help data for the \"%s\" command is available.\n", + if (helpflag & MUST_HELP) { + if (cp || !(pc->flags & GDB_INIT)) + fprintf(fp, + "No help data for the \"%s\" command" + " is available.\n", cmd); else if (!gdb_pass_through(concat_args(buf, 0, FALSE), NULL, GNU_RETURN_ON_ERROR)) fprintf(fp, - "No help data for \"%s\" is available.\n", - cmd); + "No help data for \"%s\" is available.\n", + cmd); } goto done_usage; } p++; - if (helpflag == SYNOPSIS) { + if (helpflag & SYNOPSIS) { p++; fprintf(fp, "Usage: %s ", cmd); fprintf(fp, *p, pc->program_name, pc->program_name); @@ -5029,10 +5038,12 @@ done_usage: - if (less) { - fflush(less); - pclose(less); + if (scroll) { + fflush(scroll); + pclose(scroll); } + if (scroll_command) + FREEBUF(scroll_command); } @@ -5180,7 +5191,7 @@ "Copyright (C) 2005, 2006 Fujitsu Limited", "Copyright (C) 2006, 2007 VA Linux Systems Japan K.K.", "Copyright (C) 2005 NEC Corporation", -"Copyright (C) 1999, 2002 Silicon Graphics, Inc.", +"Copyright (C) 1999, 2002, 2007 Silicon Graphics, Inc.", "Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.", "This program is free software, covered by the GNU General Public License,", "and you are welcome to change it and/or distribute copies of it under", --- crash-4.0-4.3/task.c 2007-07-20 14:31:23.000000000 -0400 +++ crash-4.0-4.4/task.c 2007-07-20 11:15:09.000000000 -0400 @@ -323,11 +323,24 @@ tt->refresh_task_table = refresh_pid_hash_task_table; } else { tt->pidhash_addr = symbol_value("pid_hash"); - if (!get_array_length("pid_hash", NULL, sizeof(void *)) && - VALID_STRUCT(pid_link)) - tt->refresh_task_table = refresh_hlist_task_table_v2; - else - tt->refresh_task_table = refresh_hlist_task_table; + if (LKCD_KERNTYPES()) { + if (VALID_STRUCT(pid_link)) + tt->refresh_task_table = + refresh_hlist_task_table_v2; + else + tt->refresh_task_table = + refresh_hlist_task_table; + builtin_array_length("pid_hash", + tt->pidhash_len, NULL); + } else { + if (!get_array_length("pid_hash", NULL, + sizeof(void *)) && VALID_STRUCT(pid_link)) + tt->refresh_task_table = + refresh_hlist_task_table_v2; + else + tt->refresh_task_table = + refresh_hlist_task_table; + } } tt->flags |= PID_HASH; --- crash-4.0-4.3/kernel.c 2007-07-20 14:31:23.000000000 -0400 +++ crash-4.0-4.4/kernel.c 2007-07-20 14:13:33.000000000 -0400 @@ -51,7 +51,6 @@ static int BUG_x86_64(void); - /* * Gather a few kernel basics. */ @@ -62,6 +61,7 @@ char *p1, *p2, buf[BUFSIZE]; struct syment *sp1, *sp2; char *rqstruct; + char *irq_desc_type_name; if (pc->flags & KERNEL_DEBUG_QUERY) return; @@ -165,11 +165,14 @@ verify_version(); if (symbol_exists("__per_cpu_offset")) { - i = get_array_length("__per_cpu_offset", NULL, 0); - get_symbol_data("__per_cpu_offset", + if (LKCD_KERNTYPES()) + i = get_cpus_possible(); + else + i = get_array_length("__per_cpu_offset", NULL, 0); + get_symbol_data("__per_cpu_offset", sizeof(long)*(i <= NR_CPUS ? i : NR_CPUS), - &kt->__per_cpu_offset[0]); - kt->flags |= PER_CPU_OFF; + &kt->__per_cpu_offset[0]); + kt->flags |= PER_CPU_OFF; } if (STRUCT_EXISTS("runqueue")) rqstruct = "runqueue"; @@ -278,13 +281,19 @@ STRUCT_SIZE_INIT(hlist_head, "hlist_head"); STRUCT_SIZE_INIT(hlist_node, "hlist_node"); - MEMBER_OFFSET_INIT(irq_desc_t_status, "irq_desc_t", "status"); - if (MEMBER_EXISTS("irq_desc_t", "handler")) - MEMBER_OFFSET_INIT(irq_desc_t_handler, "irq_desc_t", "handler"); + if (STRUCT_EXISTS("irq_desc_t")) + irq_desc_type_name = "irq_desc_t"; else - MEMBER_OFFSET_INIT(irq_desc_t_chip, "irq_desc_t", "chip"); - MEMBER_OFFSET_INIT(irq_desc_t_action, "irq_desc_t", "action"); - MEMBER_OFFSET_INIT(irq_desc_t_depth, "irq_desc_t", "depth"); + irq_desc_type_name = "irq_desc"; + + STRUCT_SIZE_INIT(irq_desc_t, irq_desc_type_name); + MEMBER_OFFSET_INIT(irq_desc_t_status, irq_desc_type_name, "status"); + if (MEMBER_EXISTS(irq_desc_type_name, "handler")) + MEMBER_OFFSET_INIT(irq_desc_t_handler, irq_desc_type_name, "handler"); + else + MEMBER_OFFSET_INIT(irq_desc_t_chip, irq_desc_type_name, "chip"); + MEMBER_OFFSET_INIT(irq_desc_t_action, irq_desc_type_name, "action"); + MEMBER_OFFSET_INIT(irq_desc_t_depth, irq_desc_type_name, "depth"); if (STRUCT_EXISTS("hw_interrupt_type")) { MEMBER_OFFSET_INIT(hw_interrupt_type_typename, "hw_interrupt_type", "typename"); @@ -346,8 +355,6 @@ MEMBER_OFFSET_INIT(irqaction_dev_id, "irqaction", "dev_id"); MEMBER_OFFSET_INIT(irqaction_next, "irqaction", "next"); - STRUCT_SIZE_INIT(irq_desc_t, "irq_desc_t"); - STRUCT_SIZE_INIT(irq_cpustat_t, "irq_cpustat_t"); MEMBER_OFFSET_INIT(irq_cpustat_t___softirq_active, "irq_cpustat_t", "__softirq_active"); @@ -717,6 +724,10 @@ if (pc->flags & KERNEL_DEBUG_QUERY) return; + /* the kerntypes may not match in terms of gcc version or SMP */ + if (LKCD_KERNTYPES()) + return; + if (!strlen(kt->utsname.version)) return; @@ -3852,7 +3863,7 @@ if (machine_type("S390") || machine_type("S390X")) command_not_supported(); - while ((c = getopt(argcnt, args, "db")) != EOF) { + while ((c = getopt(argcnt, args, "dbu")) != EOF) { switch(c) { case 'd': @@ -3882,6 +3893,17 @@ kt->display_bh(); return; + case 'u': + pc->curcmd_flags |= IRQ_IN_USE; + if (kernel_symbol_exists("no_irq_chip")) + pc->curcmd_private = (ulonglong)symbol_value("no_irq_chip"); + else if (kernel_symbol_exists("no_irq_type")) + pc->curcmd_private = (ulonglong)symbol_value("no_irq_type"); + else + error(WARNING, + "irq: -u option ignored: \"no_irq_chip\" or \"no_irq_type\" symbols do not exist\n"); + break; + default: argerrs++; break; @@ -3900,6 +3922,8 @@ return; } + pc->curcmd_flags &= ~IRQ_IN_USE; + while (args[optind]) { i = dtoi(args[optind], FAULT_ON_ERROR, NULL); if (i >= nr_irqs) @@ -3953,6 +3977,9 @@ readmem(irq_desc_addr + OFFSET(irq_desc_t_depth), KVADDR, &depth, sizeof(int), "irq_desc entry", FAULT_ON_ERROR); + if (!action && (handler == (ulong)pc->curcmd_private)) + return; + fprintf(fp, " IRQ: %d\n", irq); fprintf(fp, " STATUS: %x %s", status, status ? "(" : ""); others = 0; @@ -5489,6 +5516,43 @@ } /* + * For kernels containing at least the cpu_possible_map, used + * to determine the cpu count (of online and offline cpus). + */ +int +get_cpus_possible() +{ + int i, len, possible; + struct gnu_request req; + char *buf; + ulong *maskptr; + + if (!symbol_exists("cpu_possible_map")) + return 0; + + len = get_symbol_type("cpu_possible_map", NULL, &req) == + TYPE_CODE_UNDEF ? sizeof(ulong) : req.length; + buf = GETBUF(len); + + possible = 0; + + if (readmem(symbol_value("cpu_possible_map"), KVADDR, buf, len, + "cpu_possible_map", RETURN_ON_ERROR)) { + + maskptr = (ulong *)buf; + for (i = 0; i < (len/sizeof(ulong)); i++, maskptr++) + possible += count_bits_long(*maskptr); + + FREEBUF(buf); + if (CRASHDEBUG(1)) + error(INFO, "get_cpus_possible: possible: %d\n", + possible); + } + + return possible; +} + +/* * Xen machine-address to pseudo-physical-page translator. */ ulonglong --- crash-4.0-4.3/x86_64.c 2007-07-20 14:31:23.000000000 -0400 +++ crash-4.0-4.4/x86_64.c 2007-07-20 11:36:13.000000000 -0400 @@ -266,11 +266,15 @@ if ((machdep->machspec->irqstack = (char *) malloc(machdep->machspec->stkinfo.isize)) == NULL) error(FATAL, "cannot malloc irqstack space."); - if (symbol_exists("irq_desc")) - ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc, - "irq_desc", NULL, 0); - else - machdep->nr_irqs = 224; /* NR_IRQS (at least) */ + if (symbol_exists("irq_desc")) { + if (LKCD_KERNTYPES()) + ARRAY_LENGTH_INIT_ALT(machdep->nr_irqs, + "irq_desc", "kernel_stat.irqs", NULL, 0); + else + ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc, + "irq_desc", NULL, 0); + } else + machdep->nr_irqs = 224; /* NR_IRQS (at least) */ machdep->vmalloc_start = x86_64_vmalloc_start; machdep->dump_irq = x86_64_dump_irq; if (!machdep->hz) { @@ -521,14 +525,22 @@ cpu_pda_buf = GETBUF(SIZE(x8664_pda)); - if (symbol_exists("_cpu_pda")) { - if (!(nr_pda = get_array_length("_cpu_pda", NULL, 0))) - nr_pda = NR_CPUS; - _cpu_pda = TRUE; + if (LKCD_KERNTYPES()) { + if (symbol_exists("_cpu_pda")) + _cpu_pda = TRUE; + else + _cpu_pda = FALSE; + nr_pda = get_cpus_possible(); } else { - if (!(nr_pda = get_array_length("cpu_pda", NULL, 0))) - nr_pda = NR_CPUS; - _cpu_pda = FALSE; + if (symbol_exists("_cpu_pda")) { + if (!(nr_pda = get_array_length("_cpu_pda", NULL, 0))) + nr_pda = NR_CPUS; + _cpu_pda = TRUE; + } else { + if (!(nr_pda = get_array_length("cpu_pda", NULL, 0))) + nr_pda = NR_CPUS; + _cpu_pda = FALSE; + } } for (i = cpus = 0; i < nr_pda; i++) { @@ -566,8 +578,8 @@ i, level4_pgt, data_offset); } - - if ((i = get_array_length("boot_cpu_stack", NULL, 0))) { + if (!LKCD_KERNTYPES() && + (i = get_array_length("boot_cpu_stack", NULL, 0))) { istacksize = i; } else if ((sp = symbol_search("boot_cpu_stack")) && (nsp = next_symbol(NULL, sp))) { @@ -3656,7 +3668,7 @@ return(generic_dump_irq(irq)); } - error(FATAL, "ia64_dump_irq: irq_desc[] does not exist?\n"); + error(FATAL, "x86_64_dump_irq: irq_desc[] does not exist?\n"); } /* @@ -3827,14 +3839,22 @@ cpu_pda_buf = GETBUF(SIZE(x8664_pda)); - if (symbol_exists("_cpu_pda")) { - if (!(nr_pda = get_array_length("_cpu_pda", NULL, 0))) - nr_pda = NR_CPUS; - _cpu_pda = TRUE; + if (LKCD_KERNTYPES()) { + if (symbol_exists("_cpu_pda")) + _cpu_pda = TRUE; + else + _cpu_pda = FALSE; + nr_pda = get_cpus_possible(); } else { - if (!(nr_pda = get_array_length("cpu_pda", NULL, 0))) - nr_pda = NR_CPUS; - _cpu_pda = FALSE; + if (symbol_exists("_cpu_pda")) { + if (!(nr_pda = get_array_length("_cpu_pda", NULL, 0))) + nr_pda = NR_CPUS; + _cpu_pda = TRUE; + } else { + if (!(nr_pda = get_array_length("cpu_pda", NULL, 0))) + nr_pda = NR_CPUS; + _cpu_pda = FALSE; + } } for (i = cpus = 0; i < nr_pda; i++) { if (_cpu_pda) { --- crash-4.0-4.3/symbols.c 2007-07-20 14:31:23.000000000 -0400 +++ crash-4.0-4.4/symbols.c 2007-07-20 11:36:57.000000000 -0400 @@ -71,6 +71,8 @@ #define MODULE_SECTIONS (void *)(2) #define VERIFY_SECTIONS (void *)(3) +#define EV_DWARFEXTRACT 101010101 + #define PARSE_FOR_DATA (1) #define PARSE_FOR_DECLARATION (2) static void parse_for_member(struct datatype_member *, ulong); @@ -144,6 +146,12 @@ if (!bfd_check_format_matches(st->bfd, bfd_object, &matching)) error(FATAL, "cannot determine object file format: %s\n", pc->namelist); + /* + * Check whether the namelist is a kerntypes file built by + * dwarfextract, which places a magic number in e_version. + */ + if (file_elf_version(pc->namelist) == EV_DWARFEXTRACT) + pc->flags |= KERNTYPES; if (pc->flags & SYSMAP) { bfd_map_over_sections(st->bfd, section_header_info, @@ -158,13 +166,16 @@ } store_sysmap_symbols(); return; - } + } else if (LKCD_KERNTYPES()) + error(FATAL, "%s: use of kerntypes requires a system map\n", + pc->namelist); /* * Pull a bait-and-switch on st->bfd if we've got a separate - * .gnu_debuglink file that matches the CRC. + * .gnu_debuglink file that matches the CRC. Not done for kerntypes. */ - if (!(bfd_get_file_flags(st->bfd) & HAS_SYMS)) { + if (!(LKCD_KERNTYPES()) && + !(bfd_get_file_flags(st->bfd) & HAS_SYMS)) { if (!check_gnu_debuglink(st->bfd)) no_debugging_data(FATAL); } @@ -3806,6 +3817,7 @@ dm->size = size; dm->member_size = member_size; dm->member_typecode = member_typecode; + dm->member_offset = offset; if (req->is_typedef) { dm->flags |= TYPEDEF; } @@ -5338,7 +5350,8 @@ if ((retval = builtin_array_length(s, 0, two_dim))) return retval; - if (symbol_search(s)) { + /* symbol_search cannot be done with just kernel type information */ + if (!(LKCD_KERNTYPES()) && symbol_search(s)) { if (!two_dim) { req = &gnu_request; if ((get_symbol_type(copy, NULL, req) == @@ -5448,6 +5461,23 @@ } /* + * Get and store the size of a "known" array. + * A wrapper for get_array_length(), for cases in which + * the name of the result to be stored is different from the + * structure.member to be evaluated. + */ +int +get_array_length_alt(char *name, char *s, int *two_dim, long entry_size) +{ + int retval; + + retval = get_array_length(s, two_dim, entry_size); + if (retval) + retval = builtin_array_length(name, retval, two_dim); + return retval; +} + +/* * Designed for use by non-debug kernels, but used by all. */ int @@ -5502,6 +5532,8 @@ lenptr = &array_table.prio_array_queue; else if (STREQ(s, "height_to_maxindex")) lenptr = &array_table.height_to_maxindex; + else if (STREQ(s, "pid_hash")) + lenptr = &array_table.pid_hash; else if (STREQ(s, "free_area")) { lenptr = &array_table.free_area; if (two_dim) @@ -6819,6 +6851,8 @@ get_array_length("prio_array.queue", NULL, SIZE(list_head))); fprintf(fp, " height_to_maxindex: %d\n", ARRAY_LENGTH(height_to_maxindex)); + fprintf(fp, " pid_hash: %d\n", + ARRAY_LENGTH(pid_hash)); if (spec) { int in_size_table, in_array_table, arrays, offsets, sizes; --- crash-4.0-4.3/cmdline.c 2007-07-20 14:31:23.000000000 -0400 +++ crash-4.0-4.4/cmdline.c 2007-07-18 14:41:55.000000000 -0400 @@ -306,6 +306,106 @@ } /* + * Pager arguments. + */ + +static char *less_argv[5] = { + "/usr/bin/less", + "-E", + "-X", + "-Ps -- MORE -- forward\\: , or j backward\\: b or k quit\\: q", + NULL +}; + +static char *more_argv[2] = { + "/bin/more", + NULL +}; + +static char **CRASHPAGER_argv = NULL; + +int +CRASHPAGER_valid(void) +{ + int i, c; + char *env, *CRASHPAGER_buf; + char *arglist[MAXARGS]; + + if (CRASHPAGER_argv) + return TRUE; + + if (!(env = getenv("CRASHPAGER"))) + return FALSE; + + if (strstr(env, "|") || strstr(env, "<") || strstr(env, ">")) { + error(INFO, + "CRASHPAGER ignored: contains invalid character: \"%s\"\n", + env); + return FALSE; + } + + if ((CRASHPAGER_buf = (char *)malloc(strlen(env)+1)) == NULL) + return FALSE; + + strcpy(CRASHPAGER_buf, env); + + if (!(c = parse_line(CRASHPAGER_buf, arglist)) || + !file_exists(arglist[0], NULL) || access(arglist[0], X_OK) || + !(CRASHPAGER_argv = (char **)malloc(sizeof(char *) * (c+1)))) { + free(CRASHPAGER_buf); + if (strlen(env)) + error(INFO, + "CRASHPAGER ignored: \"%s\"\n", env); + return FALSE; + } + + for (i = 0; i < c; i++) + CRASHPAGER_argv[i] = arglist[i]; + CRASHPAGER_argv[i] = NULL; + + return TRUE; +} + +/* + * Set up a command string buffer for error/help output. + */ +char * +setup_scroll_command(void) +{ + char *buf; + long i, len; + + if (!(pc->flags & SCROLL)) + return NULL; + + switch (pc->scroll_command) + { + case SCROLL_LESS: + buf = GETBUF(strlen(less_argv[0])+1); + strcpy(buf, less_argv[0]); + break; + case SCROLL_MORE: + buf = GETBUF(strlen(more_argv[0])+1); + strcpy(buf, more_argv[0]); + break; + case SCROLL_CRASHPAGER: + for (i = len = 0; CRASHPAGER_argv[i]; i++) + len += strlen(CRASHPAGER_argv[i])+1; + + buf = GETBUF(len); + + for (i = 0; CRASHPAGER_argv[i]; i++) { + sprintf(&buf[strlen(buf)], "%s%s", + i ? " " : "", + CRASHPAGER_argv[i]); + } + break; + } + + return buf; +} + +/* * Parse the command line for pipe or redirect characters: * * 1. if a "|" character is found, popen() what comes after it, and @@ -497,10 +597,13 @@ switch (pc->scroll_command) { case SCROLL_LESS: - strcpy(pc->pipe_command, "/usr/bin/less"); + strcpy(pc->pipe_command, less_argv[0]); break; case SCROLL_MORE: - strcpy(pc->pipe_command, "/bin/more"); + strcpy(pc->pipe_command, more_argv[0]); + break; + case SCROLL_CRASHPAGER: + strcpy(pc->pipe_command, CRASHPAGER_argv[0]); break; } @@ -880,7 +983,7 @@ pc->stdpipe = NULL; if (pc->stdpipe_pid && PID_ALIVE(pc->stdpipe_pid)) { while (!waitpid(pc->stdpipe_pid, &waitstatus, WNOHANG)) - ; + stall(1000); } pc->stdpipe_pid = 0; } @@ -890,12 +993,16 @@ console("wait for redirect %d->%d to finish...\n", pc->pipe_shell_pid, pc->pipe_pid); if (pc->pipe_pid) - while (PID_ALIVE(pc->pipe_pid)) + while (PID_ALIVE(pc->pipe_pid)) { waitpid(pc->pipe_pid, &waitstatus, WNOHANG); + stall(1000); + } if (pc->pipe_shell_pid) - while (PID_ALIVE(pc->pipe_shell_pid)) + while (PID_ALIVE(pc->pipe_shell_pid)) { waitpid(pc->pipe_shell_pid, &waitstatus, WNOHANG); + stall(1000); + } pc->pipe_pid = 0; } if (pc->ifile_pipe) { @@ -907,12 +1014,16 @@ (FROM_INPUT_FILE|REDIRECT_TO_PIPE|REDIRECT_PID_KNOWN))) { console("wait for redirect %d->%d to finish...\n", pc->pipe_shell_pid, pc->pipe_pid); - while (PID_ALIVE(pc->pipe_pid)) + while (PID_ALIVE(pc->pipe_pid)) { waitpid(pc->pipe_pid, &waitstatus, WNOHANG); + stall(1000); + } if (pc->pipe_shell_pid) - while (PID_ALIVE(pc->pipe_shell_pid)) + while (PID_ALIVE(pc->pipe_shell_pid)) { waitpid(pc->pipe_shell_pid, &waitstatus, WNOHANG); + stall(1000); + } if (pc->redirect & (REDIRECT_MULTI_PIPE)) wait_for_children(ALL_CHILDREN); } @@ -1915,19 +2026,6 @@ * Set up the standard output pipe using whichever was selected during init. */ -static char *less_argv[5] = { - "/usr/bin/less", - "-E", - "-X", - "-Ps -- MORE -- forward\\: , or j backward\\: b or k quit\\: q", - NULL -}; - -static char *more_argv[2] = { - "/bin/more", - NULL -}; - static int setup_stdpipe(void) { @@ -1963,6 +2061,9 @@ case SCROLL_MORE: strcpy(pc->pipe_command, more_argv[0]); break; + case SCROLL_CRASHPAGER: + strcpy(pc->pipe_command, CRASHPAGER_argv[0]); + break; } if (CRASHDEBUG(2)) @@ -1991,10 +2092,16 @@ path = more_argv[0]; execv(path, more_argv); break; + + case SCROLL_CRASHPAGER: + path = CRASHPAGER_argv[0]; + execv(path, CRASHPAGER_argv); + break; } - perror("child execv failed"); - return(clean_exit(1)); + perror(path); + fprintf(stderr, "execv of scroll command failed\n"); + exit(1); } } @@ -2025,5 +2132,6 @@ fprintf(fp, "wait_for_children: reaped %d\n", pid); break; } + stall(1000); } } --- crash-4.0-4.3/netdump.c 2007-07-20 14:31:23.000000000 -0400 +++ crash-4.0-4.4/netdump.c 2007-07-20 11:50:42.000000000 -0400 @@ -275,6 +275,51 @@ } /* + * Return the e_version number of an ELF file + * (or -1 if its not readable ELF file) + */ +int +file_elf_version(char *file) +{ + int fd, size; + Elf32_Ehdr *elf32; + Elf64_Ehdr *elf64; + char header[MIN_NETDUMP_ELF_HEADER_SIZE]; + char buf[BUFSIZE]; + + if ((fd = open(file, O_RDONLY)) < 0) { + sprintf(buf, "%s: open", file); + perror(buf); + return -1; + } + + size = MIN_NETDUMP_ELF_HEADER_SIZE; + if (read(fd, header, size) != size) { + sprintf(buf, "%s: read", file); + perror(buf); + close(fd); + return -1; + } + close(fd); + + elf32 = (Elf32_Ehdr *)&header[0]; + elf64 = (Elf64_Ehdr *)&header[0]; + + 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)) { + return (elf32->e_version); + } else if (STRNEQ(elf64->e_ident, ELFMAG) && + (elf64->e_ident[EI_CLASS] == ELFCLASS64) && + (elf64->e_ident[EI_VERSION] == EV_CURRENT)) { + return (elf64->e_version); + } + + return -1; +} + +/* * Perform any post-dumpfile determination stuff here. */ int --- crash-4.0-4.3/defs.h 2007-07-20 14:31:23.000000000 -0400 +++ crash-4.0-4.4/defs.h 2007-07-20 14:13:38.000000000 -0400 @@ -178,6 +178,7 @@ #define XEN_CORE (0x100000000000000ULL) #define PLEASE_WAIT (0x200000000000000ULL) #define IFILE_ERROR (0x400000000000000ULL) +#define KERNTYPES (0x800000000000000ULL) #define ACTIVE() (pc->flags & LIVE_SYSTEM) #define DUMPFILE() (!(pc->flags & LIVE_SYSTEM)) @@ -196,6 +197,7 @@ #define XEN_HYPER_MODE() (pc->flags & XEN_HYPER) #define SYSRQ_TASK(X) ((pc->flags & SYSRQ) && is_task_active(X)) #define XEN_CORE_DUMPFILE() (pc->flags & XEN_CORE) +#define LKCD_KERNTYPES() (pc->flags & KERNTYPES) #define NETDUMP_LOCAL (0x1) /* netdump_data flags */ #define NETDUMP_REMOTE (0x2) @@ -347,6 +349,7 @@ #define SCROLL_NONE 0 #define SCROLL_LESS 1 #define SCROLL_MORE 2 +#define SCROLL_CRASHPAGER 3 ulong redirect; /* per-cmd origin and output flags */ pid_t stdpipe_pid; /* per-cmd standard output pipe's pid */ pid_t pipe_pid; /* per-cmd output pipe's pid */ @@ -366,6 +369,7 @@ #define HEADER_PRINTED (0x40) #define BAD_INSTRUCTION (0x80) #define UD2A_INSTRUCTION (0x100) +#define IRQ_IN_USE (0x200) ulonglong curcmd_private; /* general purpose per-command info */ int cur_gdb_cmd; /* current gdb command */ int last_gdb_cmd; /* previously-executed gdb command */ @@ -1503,6 +1507,7 @@ int free_area_DIMENSION; int prio_array_queue; int height_to_maxindex; + int pid_hash; }; /* @@ -1541,6 +1546,7 @@ #define MEMBER_OFFSET_INIT(X, Y, Z) (ASSIGN_OFFSET(X) = MEMBER_OFFSET(Y, Z)) #define STRUCT_SIZE_INIT(X, Y) (ASSIGN_SIZE(X) = STRUCT_SIZE(Y)) #define ARRAY_LENGTH_INIT(A, B, C, D, E) ((A) = get_array_length(C, D, E)) +#define ARRAY_LENGTH_INIT_ALT(A, B, C, D, E) ((A) = get_array_length_alt(B, C, D, E)) #define MEMBER_SIZE_INIT(X, Y, Z) (ASSIGN_SIZE(X) = MEMBER_SIZE(Y, Z)) /* @@ -2627,9 +2633,10 @@ #define MINSPACE (-100) -#define SYNOPSIS (0x1) -#define COMPLETE_HELP (0x2) -#define PIPE_TO_LESS (0x4) +#define SYNOPSIS (0x1) +#define COMPLETE_HELP (0x2) +#define PIPE_TO_SCROLL (0x4) +#define MUST_HELP (0x8) #define LEFT_JUSTIFY (1) #define RIGHT_JUSTIFY (2) @@ -3027,6 +3034,8 @@ int interruptible(void); int received_SIGINT(void); void debug_redirect(char *); +int CRASHPAGER_valid(void); +char *setup_scroll_command(void); /* * tools.c @@ -3180,9 +3189,11 @@ void dump_struct_table(ulong); void dump_offset_table(char *, ulong); int is_elf_file(char *); +int file_elf_version(char *); int is_system_map(char *); int select_namelist(char *); int get_array_length(char *, int *, long); +int get_array_length_alt(char *, char *, int *, long); int builtin_array_length(char *, int, int *); char *get_line_number(ulong, char *, int); char *get_build_directory(char *); @@ -3483,6 +3494,7 @@ void clear_machdep_cache(void); struct stack_hook *gather_text_list(struct bt_info *); int get_cpus_online(void); +int get_cpus_possible(void); void print_stack_text_syms(struct bt_info *, ulong, ulong); void back_trace(struct bt_info *); #define BT_RAW (0x1ULL) --- crash-4.0-4.3/Makefile 2007-07-20 15:20:16.000000000 -0400 +++ crash-4.0-4.4/Makefile 2007-07-20 15:20:14.000000000 -0400 @@ -446,7 +446,7 @@ show_files: @if [ -f ${PROGRAM} ]; then \ - ./${PROGRAM} --no_crashrc -h README > README; fi + ./${PROGRAM} --no_scroll --no_crashrc -h README > README; echo $?; fi @echo ${SOURCE_FILES} Makefile ${GDB_FILES} ${GDB_PATCH_FILES} COPYING README \ .rh_rpm_package crash.8 ${EXTENSION_SOURCE_FILES} @@ -459,7 +459,7 @@ do_tar: @if [ -f ${PROGRAM} ]; then \ - ./${PROGRAM} --no_crashrc -h README > README; fi + ./${PROGRAM} --no_scroll --no_crashrc -h README > README; fi tar cvzf ${PROGRAM}.tar.gz ${TAR_FILES} ${GDB_FILES} ${GDB_PATCH_FILES} @echo; ls -l ${PROGRAM}.tar.gz @@ -498,7 +498,7 @@ @tar cf - ${SOURCE_FILES} Makefile ${GDB_FILES} ${GDB_PATCH_FILES} COPYING \ .rh_rpm_package crash.8 ${EXTENSION_SOURCE_FILES} | (cd ./RELDIR/${PROGRAM}-${RELEASE}; tar xf -) @cp ${GDB}.tar.gz ./RELDIR/${PROGRAM}-${RELEASE} - @./${PROGRAM} --no_crashrc -h README > ./RELDIR/${PROGRAM}-${RELEASE}/README + @./${PROGRAM} --no_scroll --no_crashrc -h README > ./RELDIR/${PROGRAM}-${RELEASE}/README @(cd ./RELDIR; find . -exec chown root {} ";") @(cd ./RELDIR; find . -exec chgrp root {} ";") @(cd ./RELDIR; find . -exec touch {} ";") --- crash-4.0-4.3/crash.8 2007-07-20 14:31:23.000000000 -0400 +++ crash-4.0-4.4/crash.8 2007-07-13 16:57:38.000000000 -0400 @@ -5,7 +5,7 @@ .TH CRASH 8 .SH NAME crash \- Analyze Linux crash data or a live system -.SH SYNAPSIS +.SH SYNOPSIS .B crash [ .B -h @@ -42,9 +42,13 @@ is a tool for interactively analyzing the state of the Linux system while it is running, or after a kernel crash has occurred and a core dump has been created by the Red Hat -.I netdump -facility. It is loosely based on the SVR4 UNIX crash -command, but has been signficantly enhanced +.I netdump, +.I diskdump, +.I kdump, +or +.I xendump +facilities. It is loosely based on the SVR4 UNIX crash +command, but has been significantly enhanced by completely merging it with the .I gdb debugger. The marriage of the two effectively combines the @@ -207,15 +211,15 @@ .I dis disassembles memory, either entire kernel functions, from a location for a specified number of instructions, or from the start of a -fuction up to a specified memory location. +function up to a specified memory location. .TP .I eval evalues an expression or numeric type and displays the result -in hexidecimal, decimal, octal and binary. +in hexadecimal, decimal, octal and binary. .TP .I exit causes -.I crash +.B crash to exit. .TP .I extend @@ -230,7 +234,7 @@ in the system. .TP .I fuser -displays the tasks using the specifed file or socket. +displays the tasks using the specified file or socket. .TP .I gdb passes its argument to the underlying @@ -274,7 +278,7 @@ display various network related data. .TP .I p -passes its argumnts to the +passes its arguments to the .I gdb "print" command for evaluation and display. .TP @@ -361,11 +365,85 @@ .I wr modifies the contents of memory. When writing to memory on a live system, this command should obviously be used with great care. +.SH FILES +.TP +.I .crashrc +Initialization commands. The file can be located in the user's +.B HOME +directory and/or the current directory. Commands found in the +.I .crashrc +file in the +.B HOME +directory are executed before those in the current directory's +.I .crashrc +file. +.SH ENVIRONMENT +.TP +.B EDITOR +Command input is read using +.BR readline(3). +If +.B EDITOR +is set to +.I emacs +or +.I vi +then suitable keybindings are used. If +.B EDITOR +is not set, then +.I vi +is used. This can be overridden by +.B set vi +or +.B set emacs +commands located in a +.IR .crashrc +file, or by entering +.B -e emacs +on the +.B crash +command line. +.TP +.B CRASHPAGER +If +.B CRASHPAGER +is set, its value is used as the name of the program to which command output will be sent. +If not, then command output is sent to +.B /usr/bin/less -E -X +by default. +.SH NOTES +.PP +If +.B crash +does not work, look for a newer version: kernel evolution frequently makes +.B crash +updates necessary. +.PP +The command +.B set scroll off +will cause output to be sent directly to +the terminal rather than through a paging program. This is useful, +for example, if you are running +.B crash +in a window of +.BR emacs . .SH AUTHOR Dave Anderson wrote -.B Crash +.B crash .TP Jay Fenlason wrote this man page. .SH "SEE ALSO" -netdump(8) -gdb(1) +.PP +The +.I help +command within +.B crash +provides more complete and accurate documentation than this man page. +.PP +.I http://people.redhat.com/anderson +- the home page of the +.B crash +utility. +.PP +.BR netdump (8), +.BR gdb (1)