crash/main.c

1945 lines
60 KiB
C
Raw Normal View History

2014-01-28 21:46:11 +00:00
/* main.c - core analysis suite
*
* Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
* Copyright (C) 2002-2016 David Anderson
* Copyright (C) 2002-2016 Red Hat, Inc. All rights reserved.
2014-01-28 21:46:11 +00:00
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "defs.h"
#include "xen_hyper_defs.h"
#include <curses.h>
#include <getopt.h>
#include <sys/prctl.h>
static void setup_environment(int, char **);
static int is_external_command(void);
static int is_builtin_command(void);
static int is_input_file(void);
static void check_xen_hyper(void);
static void show_untrusted_files(void);
static void get_osrelease(char *);
static void get_log(char *);
static char *no_vmcoreinfo(const char *);
2014-01-28 21:46:11 +00:00
static struct option long_options[] = {
{"memory_module", required_argument, 0, 0},
{"memory_device", required_argument, 0, 0},
{"no_kallsyms", 0, 0, 0},
{"no_modules", 0, 0, 0},
{"help", optional_argument, 0, 'h'},
{"no_data_debug", 0, 0, 0},
{"no_crashrc", 0, 0, 0},
{"no_kmem_cache", 0, 0, 0},
{"kmem_cache_delay", 0, 0, 0},
{"readnow", 0, 0, 0},
{"smp", 0, 0, 0},
{"machdep", required_argument, 0, 0},
{"version", 0, 0, 0},
{"buildinfo", 0, 0, 0},
{"cpus", required_argument, 0, 0},
{"no_ikconfig", 0, 0, 0},
{"hyper", 0, 0, 0},
{"p2m_mfn", required_argument, 0, 0},
{"xen_phys_start", 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},
{"reloc", required_argument, 0, 0},
{"kaslr", required_argument, 0, 0},
2014-01-28 21:46:11 +00:00
{"active", 0, 0, 0},
{"minimal", 0, 0, 0},
{"mod", required_argument, 0, 0},
{"kvmhost", required_argument, 0, 0},
{"kvmio", required_argument, 0, 0},
{"no_elf_notes", 0, 0, 0},
{"osrelease", required_argument, 0, 0},
{"log", required_argument, 0, 0},
{"hex", 0, 0, 0},
{"dec", 0, 0, 0},
{"no_strip", 0, 0, 0},
{"hash", required_argument, 0, 0},
Implement a new "offline" internal crash variable that can be set to either "show" (the default) or "hide". When set to "hide", certain command output associated with offline cpus will be hidden from view, and the output will indicate that the cpu is "[OFFLINE]". The new variable can be set during invocation on the crash command line via the option "--offline [show|hide]". During runtime, or in a .crashrc or other crash input file, the variable can be set by entering "set offline [show|hide]". The commands or options that are affected when the variable is set to "hide" are as follows: o On X86_64 machines, the "bt -E" option will not search exception stacks associated with offline cpus. o On X86_64 machines, the "mach" command will append "[OFFLINE]" to the addresses of IRQ and exception stacks associated with offline cpus. o On X86_64 machines, the "mach -c" command will not display the cpuinfo_x86 data structure associated with offline cpus. o The "help -r" option has been fixed so as to not attempt to display register sets of offline cpus from ELF kdump vmcores, compressed kdump vmcores, and ELF kdump clones created by "virsh dump --memory-only". o The "bt -c" option will not accept an offline cpu number. o The "set -c" option will not accept an offline cpu number. o The "irq -s" option will not display statistics associated with offline cpus. o The "timer" command will not display hrtimer data associated with offline cpus. o The "timer -r" option will not display hrtimer data associated with offline cpus. o The "ptov" command will append "[OFFLINE]" when translating a per-cpu address offset to a virtal address of an offline cpu. o The "kmem -o" option will append "[OFFLINE]" to the base per-cpu virtual address of an offline cpu. o The "kmem -S" option in CONFIG_SLUB kernels will not display per-cpu data associated with offline cpus. o When a per-cpu address reference is passed to the "struct" command, the data structure will not be displayed for offline cpus. o When a per-cpu symbol and cpu reference is passed to the "p" command, the data will not be displayed for offline cpus. o When the "ps -[l|m]" option is passed the optional "-C [cpus]" option, the tasks queued on offline cpus are not shown. o The "runq" command and the "runq [-t/-m/-g/-d]" options will not display runqueue data for offline cpus. o The "ps" command will replace the ">" active task indicator to a "-" for offline cpus. The initial system information banner and the "sys" command will display the total number of cpus as before, but will append the count of offline cpus. Lastly, a fix has been made for the initialization time determination of the maximum number of per-cpu objects queued in a CONFIG_SLAB kmem_cache so as to continue checking all cpus higher than the first offline cpu. These changes in behavior are not dependent upon the setting of the crash "offline" variable. (qiaonuohan@cn.fujitsu.com)
2014-10-06 19:32:37 +00:00
{"offline", required_argument, 0, 0},
{"src", required_argument, 0, 0},
2014-01-28 21:46:11 +00:00
{0, 0, 0, 0}
};
int
main(int argc, char **argv)
{
int i, c, option_index;
char *tmpname;
setup_environment(argc, argv);
/*
* Get and verify command line options.
*/
opterr = 0;
optind = 0;
while((c = getopt_long(argc, argv, "Lkgh::e:i:sSvc:d:tfp:m:xo:",
2014-01-28 21:46:11 +00:00
long_options, &option_index)) != -1) {
switch (c)
{
case 0:
if (STREQ(long_options[option_index].name,
"memory_module"))
pc->memory_module = optarg;
else if (STREQ(long_options[option_index].name,
"memory_device"))
pc->memory_device = optarg;
else if (STREQ(long_options[option_index].name,
"no_kallsyms"))
kt->flags |= NO_KALLSYMS;
else if (STREQ(long_options[option_index].name,
"no_modules"))
kt->flags |= NO_MODULE_ACCESS;
else if (STREQ(long_options[option_index].name,
"no_ikconfig"))
kt->flags |= NO_IKCONFIG;
else if (STREQ(long_options[option_index].name,
"no_data_debug"))
pc->flags &= ~DATADEBUG;
else if (STREQ(long_options[option_index].name,
"no_kmem_cache"))
vt->flags |= KMEM_CACHE_UNAVAIL;
else if (STREQ(long_options[option_index].name,
"kmem_cache_delay"))
vt->flags |= KMEM_CACHE_DELAY;
else if (STREQ(long_options[option_index].name,
"readnow"))
pc->flags |= READNOW;
else if (STREQ(long_options[option_index].name,
"smp"))
kt->flags |= SMP;
else if (STREQ(long_options[option_index].name,
"machdep")) {
for (i = 0; i < MAX_MACHDEP_ARGS; i++) {
if (machdep->cmdline_args[i])
continue;
machdep->cmdline_args[i] = optarg;
break;
}
if (i == MAX_MACHDEP_ARGS)
error(INFO, "option ignored: %s\n",
optarg);
}
else if (STREQ(long_options[option_index].name,
"version")) {
pc->flags |= VERSION_QUERY;
display_version();
display_gdb_banner();
clean_exit(0);
}
else if (STREQ(long_options[option_index].name,
"buildinfo")) {
dump_build_data();
clean_exit(0);
}
else if (STREQ(long_options[option_index].name, "cpus"))
kt->cpus_override = optarg;
else if (STREQ(long_options[option_index].name, "hyper"))
pc->flags |= XEN_HYPER;
else if (STREQ(long_options[option_index].name, "p2m_mfn"))
xen_kdump_p2m_mfn(optarg);
else if (STREQ(long_options[option_index].name, "xen_phys_start"))
set_xen_phys_start(optarg);
else if (STREQ(long_options[option_index].name, "zero_excluded"))
*diskdump_flags |= ZERO_EXCLUDED;
else if (STREQ(long_options[option_index].name, "no_elf_notes")) {
if (machine_type("X86") || machine_type("X86_64"))
*diskdump_flags |= NO_ELF_NOTES;
else
error(INFO,
"--no_elf_notes is only applicable to "
"the X86 and X86_64 architectures.\n");
}
else if (STREQ(long_options[option_index].name, "no_panic"))
tt->flags |= PANIC_TASK_NOT_FOUND;
else if (STREQ(long_options[option_index].name, "no_strip"))
st->flags |= NO_STRIP;
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 if (STREQ(long_options[option_index].name, "active"))
tt->flags |= ACTIVE_ONLY;
else if (STREQ(long_options[option_index].name, "mod"))
kt->module_tree = optarg;
else if (STREQ(long_options[option_index].name, "hash")) {
if (!calculate(optarg, &pc->nr_hash_queues, NULL, 0)) {
error(INFO, "invalid --hash argument: %s\n",
optarg);
}
} else if (STREQ(long_options[option_index].name, "kaslr")) {
if (!machine_type("X86_64"))
error(INFO, "--kaslr only valid "
"with X86_64 machine type.\n");
else if (STREQ(optarg, "auto"))
kt->flags2 |= (RELOC_AUTO|KASLR);
else {
if (!calculate(optarg, &kt->relocate,
NULL, 0)) {
error(INFO,
"invalid --kaslr argument: %s\n",
optarg);
program_usage(SHORT_FORM);
}
kt->relocate *= -1;
kt->flags |= RELOC_SET;
kt->flags2 |= KASLR;
}
} else if (STREQ(long_options[option_index].name, "reloc")) {
2014-01-28 21:46:11 +00:00
if (!calculate(optarg, &kt->relocate, NULL, 0)) {
error(INFO, "invalid --reloc argument: %s\n",
optarg);
program_usage(SHORT_FORM);
}
2014-01-28 21:46:11 +00:00
kt->flags |= RELOC_SET;
}
else if (STREQ(long_options[option_index].name, "minimal"))
pc->flags |= MINIMAL_MODE;
else if (STREQ(long_options[option_index].name, "kvmhost"))
set_kvmhost_type(optarg);
else if (STREQ(long_options[option_index].name, "kvmio"))
set_kvm_iohole(optarg);
else if (STREQ(long_options[option_index].name, "osrelease")) {
pc->flags2 |= GET_OSRELEASE;
get_osrelease(optarg);
}
else if (STREQ(long_options[option_index].name, "log")) {
pc->flags2 |= GET_LOG;
get_log(optarg);
}
else if (STREQ(long_options[option_index].name, "hex")) {
pc->flags2 |= RADIX_OVERRIDE;
pc->output_radix = 16;
}
else if (STREQ(long_options[option_index].name, "dec")) {
pc->flags2 |= RADIX_OVERRIDE;
pc->output_radix = 10;
}
Implement a new "offline" internal crash variable that can be set to either "show" (the default) or "hide". When set to "hide", certain command output associated with offline cpus will be hidden from view, and the output will indicate that the cpu is "[OFFLINE]". The new variable can be set during invocation on the crash command line via the option "--offline [show|hide]". During runtime, or in a .crashrc or other crash input file, the variable can be set by entering "set offline [show|hide]". The commands or options that are affected when the variable is set to "hide" are as follows: o On X86_64 machines, the "bt -E" option will not search exception stacks associated with offline cpus. o On X86_64 machines, the "mach" command will append "[OFFLINE]" to the addresses of IRQ and exception stacks associated with offline cpus. o On X86_64 machines, the "mach -c" command will not display the cpuinfo_x86 data structure associated with offline cpus. o The "help -r" option has been fixed so as to not attempt to display register sets of offline cpus from ELF kdump vmcores, compressed kdump vmcores, and ELF kdump clones created by "virsh dump --memory-only". o The "bt -c" option will not accept an offline cpu number. o The "set -c" option will not accept an offline cpu number. o The "irq -s" option will not display statistics associated with offline cpus. o The "timer" command will not display hrtimer data associated with offline cpus. o The "timer -r" option will not display hrtimer data associated with offline cpus. o The "ptov" command will append "[OFFLINE]" when translating a per-cpu address offset to a virtal address of an offline cpu. o The "kmem -o" option will append "[OFFLINE]" to the base per-cpu virtual address of an offline cpu. o The "kmem -S" option in CONFIG_SLUB kernels will not display per-cpu data associated with offline cpus. o When a per-cpu address reference is passed to the "struct" command, the data structure will not be displayed for offline cpus. o When a per-cpu symbol and cpu reference is passed to the "p" command, the data will not be displayed for offline cpus. o When the "ps -[l|m]" option is passed the optional "-C [cpus]" option, the tasks queued on offline cpus are not shown. o The "runq" command and the "runq [-t/-m/-g/-d]" options will not display runqueue data for offline cpus. o The "ps" command will replace the ">" active task indicator to a "-" for offline cpus. The initial system information banner and the "sys" command will display the total number of cpus as before, but will append the count of offline cpus. Lastly, a fix has been made for the initialization time determination of the maximum number of per-cpu objects queued in a CONFIG_SLAB kmem_cache so as to continue checking all cpus higher than the first offline cpu. These changes in behavior are not dependent upon the setting of the crash "offline" variable. (qiaonuohan@cn.fujitsu.com)
2014-10-06 19:32:37 +00:00
else if (STREQ(long_options[option_index].name, "offline")) {
if (STREQ(optarg, "show"))
pc->flags2 &= ~OFFLINE_HIDE;
else if (STREQ(optarg, "hide"))
pc->flags2 |= OFFLINE_HIDE;
else {
error(INFO, "invalid --offline argument: %s\n", optarg);
program_usage(SHORT_FORM);
}
}
2014-01-28 21:46:11 +00:00
else if (STREQ(long_options[option_index].name, "src"))
kt->source_tree = optarg;
2014-01-28 21:46:11 +00:00
else {
error(INFO, "internal error: option %s unhandled\n",
long_options[option_index].name);
program_usage(SHORT_FORM);
}
break;
case 'f':
st->flags |= FORCE_DEBUGINFO;
break;
case 'g':
pc->flags |= KERNEL_DEBUG_QUERY;
break;
case 'h':
/* 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 'k':
pc->flags |= KERNTYPES;
break;
case 'e':
if (STREQ(optarg, "vi"))
pc->editing_mode = "vi";
else if (STREQ(optarg, "emacs"))
pc->editing_mode = "emacs";
else
fprintf(fp, "invalid edit mode: %s\n", optarg);
break;
case 't':
kt->flags2 |= GET_TIMESTAMP;
2014-01-28 21:46:11 +00:00
break;
case 'i':
pc->input_file = optarg;
pc->flags |= CMDLINE_IFILE;
break;
case 'v':
pc->flags |= VERSION_QUERY;
display_version();
display_gdb_banner();
clean_exit(0);
case 's':
pc->flags |= SILENT;
pc->flags &= ~SCROLL;
// pc->scroll_command = SCROLL_NONE; (why?)
break;
case 'L':
if (mlockall(MCL_CURRENT|MCL_FUTURE) == -1)
perror("mlockall");
break;
case 'S':
if (is_system_map("/boot/System.map")) {
pc->system_map = "/boot/System.map";
pc->flags |= (SYSMAP|SYSMAP_ARG);
}
break;
case 'c':
create_console_device(optarg);
break;
case 'd':
pc->debug = atol(optarg);
set_lkcd_debug(pc->debug);
set_vas_debug(pc->debug);
break;
case 'p':
force_page_size(optarg);
break;
case 'm':
for (i = 0; i < MAX_MACHDEP_ARGS; i++) {
if (machdep->cmdline_args[i])
continue;
machdep->cmdline_args[i] = optarg;
break;
}
if (i == MAX_MACHDEP_ARGS)
error(INFO, "option ignored: %s\n",
optarg);
break;
case 'x':
pc->flags |= PRELOAD_EXTENSIONS;
break;
case 'o':
ramdump_elf_output_file(optarg);
break;
2014-01-28 21:46:11 +00:00
default:
error(INFO, "invalid option: %s\n",
argv[optind-1]);
program_usage(SHORT_FORM);
}
}
opterr = 1;
display_version();
/*
* Take the kernel and dumpfile arguments in either order.
*/
while (argv[optind]) {
if (is_ramdump(argv[optind])) {
if (pc->flags & MEMORY_SOURCES) {
error(INFO,
"too many dumpfile arguments\n");
program_usage(SHORT_FORM);
}
if (ACTIVE()) {
pc->flags |= LIVE_RAMDUMP;
pc->readmem = read_ramdump;
pc->writemem = NULL;
optind++;
continue;
}
pc->dumpfile = ramdump_to_elf();
if (is_kdump(pc->dumpfile, KDUMP_LOCAL)) {
pc->flags |= KDUMP;
if (is_ramdump_image())
pc->readmem = read_ramdump;
else
pc->readmem = read_kdump;
pc->writemem = NULL;
} else {
error(INFO, "malformed ELF file: %s\n",
pc->dumpfile);
program_usage(SHORT_FORM);
}
optind++;
continue;
}
2014-01-28 21:46:11 +00:00
if (is_remote_daemon(argv[optind])) {
if (pc->flags & DUMPFILE_TYPES) {
error(INFO,
"too many dumpfile/memory arguments\n");
program_usage(SHORT_FORM);
}
pc->flags2 |= REMOTE_DAEMON;
optind++;
continue;
}
if (STREQ(argv[optind], "/dev/crash")) {
pc->memory_device = argv[optind];
optind++;
continue;
}
if (!file_exists(argv[optind], NULL)) {
error(INFO, "%s: %s\n", argv[optind], strerror(ENOENT));
program_usage(SHORT_FORM);
} else if (is_directory(argv[optind])) {
error(INFO, "%s: not a supported file format\n",
argv[optind]);
program_usage(SHORT_FORM);
} else if (!is_readable(argv[optind]))
2014-01-28 21:46:11 +00:00
program_usage(SHORT_FORM);
if (is_kernel(argv[optind])) {
if (pc->namelist || pc->server_namelist) {
if (!select_namelist(argv[optind])) {
error(INFO,
"too many namelist arguments\n");
program_usage(SHORT_FORM);
}
} else
pc->namelist = argv[optind];
} else if (is_compressed_kernel(argv[optind], &tmpname)) {
if (pc->namelist) {
if (!select_namelist(tmpname)) {
error(INFO,
"too many namelist arguments\n");
program_usage(SHORT_FORM);
}
if (pc->namelist_debug == tmpname) {
pc->namelist_debug_orig = argv[optind];
} else {
pc->namelist_debug_orig = pc->namelist_orig;
pc->namelist_orig = argv[optind];
}
} else {
pc->namelist = tmpname;
pc->namelist_orig = argv[optind];
}
pc->cleanup = NULL;
} else if (!(pc->flags & KERNEL_DEBUG_QUERY)) {
if (is_flattened_format(argv[optind]))
pc->flags2 |= FLAT;
if (STREQ(argv[optind], "/dev/mem")) {
if (pc->flags & MEMORY_SOURCES) {
error(INFO,
"too many dumpfile arguments\n");
program_usage(SHORT_FORM);
}
pc->flags |= DEVMEM;
pc->dumpfile = NULL;
pc->readmem = read_dev_mem;
pc->writemem = write_dev_mem;
pc->live_memsrc = argv[optind];
} else if (is_proc_kcore(argv[optind], KCORE_LOCAL)) {
if (pc->flags & MEMORY_SOURCES) {
error(INFO,
"too many dumpfile arguments\n");
program_usage(SHORT_FORM);
}
pc->flags |= PROC_KCORE;
pc->dumpfile = NULL;
pc->readmem = read_proc_kcore;
pc->writemem = write_proc_kcore;
pc->live_memsrc = argv[optind];
} else if (is_netdump(argv[optind], NETDUMP_LOCAL)) {
if (pc->flags & MEMORY_SOURCES) {
error(INFO,
"too many dumpfile arguments\n");
program_usage(SHORT_FORM);
}
pc->flags |= NETDUMP;
pc->dumpfile = argv[optind];
if (is_sadump_xen()) {
pc->readmem = read_kdump;
pc->writemem = write_kdump;
} else {
pc->readmem = read_netdump;
pc->writemem = write_netdump;
}
} else if (is_kdump(argv[optind], KDUMP_LOCAL)) {
if (pc->flags & MEMORY_SOURCES) {
error(INFO,
"too many dumpfile arguments\n");
program_usage(SHORT_FORM);
}
pc->flags |= KDUMP;
pc->dumpfile = argv[optind];
pc->readmem = read_kdump;
pc->writemem = write_kdump;
} else if (is_kvmdump(argv[optind])) {
if (pc->flags & MEMORY_SOURCES) {
error(INFO,
"too many dumpfile arguments\n");
program_usage(SHORT_FORM);
}
pc->flags |= KVMDUMP;
pc->dumpfile = argv[optind];
pc->readmem = read_kvmdump;
pc->writemem = write_kvmdump;
} else if (is_kvmdump_mapfile(argv[optind])) {
if (pc->kvmdump_mapfile) {
error(INFO,
"too many KVM map file arguments\n");
program_usage(SHORT_FORM);
}
pc->kvmdump_mapfile = argv[optind];
} else if (is_xendump(argv[optind])) {
if (pc->flags & MEMORY_SOURCES) {
error(INFO,
"too many dumpfile arguments\n");
program_usage(SHORT_FORM);
}
pc->flags |= XENDUMP;
pc->dumpfile = argv[optind];
pc->readmem = read_xendump;
pc->writemem = write_xendump;
} else if (is_system_map(argv[optind])) {
pc->system_map = argv[optind];
pc->flags |= (SYSMAP|SYSMAP_ARG);
} else if (is_diskdump(argv[optind])) {
if ((pc->flags & MEMORY_SOURCES) &&
(!dumpfile_is_split())) {
error(INFO,
"too many dumpfile arguments\n");
program_usage(SHORT_FORM);
}
pc->flags |= DISKDUMP;
pc->dumpfile = argv[optind];
pc->readmem = read_diskdump;
pc->writemem = write_diskdump;
} else if (is_lkcd_compressed_dump(argv[optind])) {
if (pc->flags & MEMORY_SOURCES) {
error(INFO,
"too many dumpfile arguments\n");
program_usage(SHORT_FORM);
}
pc->flags |= LKCD;
pc->dumpfile = argv[optind];
pc->readmem = read_lkcd_dumpfile;
pc->writemem = write_lkcd_dumpfile;
} else if (is_mclx_compressed_dump(argv[optind])) {
if (pc->flags & MEMORY_SOURCES) {
error(INFO,
"too many dumpfile arguments\n");
program_usage(SHORT_FORM);
}
pc->flags |= MCLXCD;
pc->dumpfile = argv[optind];
pc->readmem = read_mclx_dumpfile;
pc->writemem = write_mclx_dumpfile;
} else if (is_s390_dump(argv[optind])) {
if (pc->flags & MEMORY_SOURCES) {
error(INFO,
"too many dumpfile arguments\n");
program_usage(SHORT_FORM);
}
pc->flags |= S390D;
pc->dumpfile = argv[optind];
pc->readmem = read_s390_dumpfile;
pc->writemem = write_s390_dumpfile;
} else if (is_sadump(argv[optind])) {
if ((pc->flags & MEMORY_SOURCES) &&
!sadump_is_diskset()) {
error(INFO,
"too many dumpfile arguments\n");
program_usage(SHORT_FORM);
}
pc->flags |= SADUMP;
pc->dumpfile = argv[optind];
pc->readmem = read_sadump;
pc->writemem = write_sadump;
} else if (is_vmware_vmss(argv[optind])) {
if (pc->flags & MEMORY_SOURCES) {
error(INFO,
"too many dumpfile arguments\n");
program_usage(SHORT_FORM);
}
pc->flags |= VMWARE_VMSS;
pc->dumpfile = argv[optind];
pc->readmem = read_vmware_vmss;
pc->writemem = write_vmware_vmss;
2014-01-28 21:46:11 +00:00
} else {
error(INFO,
"%s: not a supported file format\n",
argv[optind]);
program_usage(SHORT_FORM);
}
}
optind++;
}
check_xen_hyper();
if (setjmp(pc->main_loop_env))
clean_exit(1);
/*
* Initialize various subsystems.
*/
fd_init();
buf_init();
cmdline_init();
mem_init();
hq_init();
machdep_init(PRE_SYMTAB);
symtab_init();
paravirt_init();
machdep_init(PRE_GDB);
datatype_init();
/*
* gdb_main_loop() modifies "command_loop_hook" to point to the
* main_loop() function below, and then calls gdb's main() function.
* After gdb initializes itself, it calls back to main_loop().
*/
gdb_main_loop(argc, argv);
clean_exit(0);
exit(0);
}
/*
* This routine is called from above, but also will be re-entered
* as part of gdb's SIGINT handling. Since GDB_INIT and RUNTIME
* will be set on re-entrancy, the initialization routines won't
* be called. This can be avoided by always making gdb ignore SIGINT.
*/
void
main_loop(void)
{
if (pc->flags2 & ERASEINFO_DATA)
error(WARNING, "\n%s:\n "
"Kernel data has been erased from this dumpfile. This may "
"cause\n the crash session to fail entirely, may "
"cause commands to fail,\n or may result in "
"unpredictable\n runtime behavior.\n",
pc->dumpfile);
if (pc->flags2 & INCOMPLETE_DUMP) {
error(WARNING, "\n%s:\n "
"This dumpfile is incomplete. This may cause the crash session"
"\n to fail entirely, may cause commands to fail, or may"
" result in\n unpredictable runtime behavior.\n",
2014-01-28 21:46:11 +00:00
pc->dumpfile);
if (!(*diskdump_flags & ZERO_EXCLUDED))
fprintf(fp,
" NOTE: This dumpfile may be analyzed with the --zero_excluded command\n"
" line option, in which case any read requests from missing pages\n"
" will return zero-filled memory.\n");
}
2014-01-28 21:46:11 +00:00
if (pc->flags2 & EXCLUDED_VMEMMAP) {
error(WARNING, "\n%s:\n "
"This dumpfile is incomplete because the page structures associated\n"
" with excluded pages may also be excluded. This may cause the crash\n"
" session to fail entirely, may cause commands to fail (most notably\n"
" the \"kmem\" command), or may result in unpredictable runtime behavior.\n",
pc->dumpfile);
}
2014-01-28 21:46:11 +00:00
if (!(pc->flags & GDB_INIT)) {
gdb_session_init();
show_untrusted_files();
kdump_backup_region_init();
if (XEN_HYPER_MODE()) {
#ifdef XEN_HYPERVISOR_ARCH
machdep_init(POST_GDB);
xen_hyper_init();
machdep_init(POST_INIT);
#else
error(FATAL, XEN_HYPERVISOR_NOT_SUPPORTED);
#endif
} else if (!(pc->flags & MINIMAL_MODE)) {
read_in_kernel_config(IKCFG_INIT);
kernel_init();
machdep_init(POST_GDB);
vm_init();
machdep_init(POST_VM);
module_init();
help_init();
task_init();
vfs_init();
net_init();
dev_init();
machdep_init(POST_INIT);
}
} else
SIGACTION(SIGINT, restart, &pc->sigaction, NULL);
/*
* Display system statistics and current context.
*/
if (!(pc->flags & SILENT) && !(pc->flags & RUNTIME)) {
if (XEN_HYPER_MODE()) {
#ifdef XEN_HYPERVISOR_ARCH
xen_hyper_display_sys_stats();
xen_hyper_show_vcpu_context(XEN_HYPER_VCPU_LAST_CONTEXT());
fprintf(fp, "\n");
#else
error(FATAL, XEN_HYPERVISOR_NOT_SUPPORTED);
#endif
} else if (!(pc->flags & MINIMAL_MODE)) {
display_sys_stats();
show_context(CURRENT_CONTEXT());
fprintf(fp, "\n");
}
}
if (pc->flags & MINIMAL_MODE)
error(NOTE,
"minimal mode commands: log, dis, rd, sym, eval, set, extend and exit\n\n");
pc->flags |= RUNTIME;
if (pc->flags & PRELOAD_EXTENSIONS)
preload_extensions();
/*
* Return here if a non-recoverable error occurs
* during command execution.
*/
if (setjmp(pc->main_loop_env)) {
;
}
/*
* process_command_line() reads, parses and stores input command lines
* in the global args[] array. exec_command() figures out what to
* do with the parsed line.
*/
while (TRUE) {
process_command_line();
exec_command();
}
}
/*
* Most of the time args[0] simply contains the name string of a command
* found in the global command_table[]. Special consideration is done for
* dealing with input files, "known" external commands, and built-in commands.
* If none of the above apply, the args[0] string is checked against the
* known list of structure, union and typedef names, and if found, passed
* on to cmd_struct(), cmd_union() or cmd_whatis().
*/
void
exec_command(void)
{
struct command_table_entry *ct;
struct args_input_file args_ifile;
if (args[0] && (args[0][0] == '\\') && args[0][1]) {
shift_string_left(args[0], 1);
shift_string_left(pc->orig_line, 1);
pc->curcmd_flags |= NO_MODIFY;
}
reattempt:
if (!args[0])
return;
optind = argerrs = 0;
if ((ct = get_command_table_entry(args[0]))) {
if (ct->flags & REFRESH_TASK_TABLE) {
if (XEN_HYPER_MODE()) {
#ifdef XEN_HYPERVISOR_ARCH
xen_hyper_refresh_domain_context_space();
xen_hyper_refresh_vcpu_context_space();
#else
error(FATAL, XEN_HYPERVISOR_NOT_SUPPORTED);
#endif
} else if (!(pc->flags & MINIMAL_MODE)) {
tt->refresh_task_table();
sort_context_array();
sort_tgid_array();
2014-01-28 21:46:11 +00:00
}
}
if (!STREQ(pc->curcmd, pc->program_name))
pc->lastcmd = pc->curcmd;
pc->curcmd = ct->name;
pc->cmdgencur++;
if (is_args_input_file(ct, &args_ifile))
exec_args_input_file(ct, &args_ifile);
else
(*ct->func)();
pc->lastcmd = pc->curcmd;
pc->curcmd = pc->program_name;
return;
}
if (is_input_file())
return;
if (is_external_command())
return;
if (is_builtin_command())
return;
if (is_datatype_command())
goto reattempt;
if (STRNEQ(args[0], "#") || STRNEQ(args[0], "//"))
return;
if (!(pc->flags & MINIMAL_MODE) &&
is_gdb_command(TRUE, FAULT_ON_ERROR))
goto reattempt;
if (REMOTE() && remote_execute())
return;
pc->curcmd = pc->program_name;
if (pc->flags & MINIMAL_MODE)
error(INFO,
"%s: command not available in minimal mode\n"
"NOTE: minimal mode commands: log, dis, rd, sym, eval, set, extend and exit\n",
args[0]);
else
error(INFO, "command not found: %s\n", args[0]);
if (pc->curcmd_flags & REPEAT)
pc->curcmd_flags &= ~REPEAT;
}
/*
* Find the command_table structure associated with a command name.
*/
struct command_table_entry *
get_command_table_entry(char *name)
{
int i;
struct command_table_entry *cp;
struct extension_table *ext;
if (pc->flags2 & GDB_CMD_MODE) {
if (STREQ(name, "crash")) {
if (argcnt == 1)
error(FATAL,
"a crash command must follow "
"the \"crash\" directive\n");
for (i = 1; i <= argcnt; i++)
args[i-1] = args[i];
argcnt--;
name = args[0];
} else
name = "gdb";
}
for (cp = pc->cmd_table; cp->name; cp++) {
if (STREQ(cp->name, name)) {
if (!(pc->flags & MINIMAL_MODE) || (cp->flags & MINIMAL))
return cp;
else
return NULL;
}
}
for (ext = extension_table; ext; ext = ext->next) {
for (cp = ext->command_table; cp->name; cp++) {
if (STREQ(cp->name, name)) {
if (!(pc->flags & MINIMAL_MODE) || (cp->flags & MINIMAL))
return cp;
else
return NULL;
}
}
}
return NULL;
}
static int
is_input_file(void)
{
if (STREQ(args[0], "<")) {
exec_input_file();
return TRUE;
}
return FALSE;
}
static int
is_builtin_command(void)
{
int i;
struct remote_file remote_file, *rfp;
/*
* cmd_test() is used strictly for debugging -- but not advertised
* in the help menu.
*/
if (STREQ(args[0], "test")) {
pc->curcmd = "test";
cmd_test();
return TRUE;
}
if (STREQ(args[0], "save")) {
pc->curcmd = "save";
rfp = &remote_file;
BZERO(rfp, sizeof(struct remote_file));
rfp->flags |= REMOTE_VERBOSE;
for (i = 1; i < argcnt; i++) {
rfp->filename = args[i];
get_remote_file(rfp);
}
return TRUE;
}
return FALSE;
}
/*
* Pure laziness -- to avoid having to type the exclamation point at the
* beginning of the line.
*/
static int
is_external_command(void)
{
int i;
char *cmd;
char command[BUFSIZE];
cmd = args[0];
if (STREQ(cmd, "vi") ||
STREQ(cmd, "pwd") ||
STREQ(cmd, "grep") ||
STREQ(cmd, "cat") ||
STREQ(cmd, "more") ||
STREQ(cmd, "less") ||
STREQ(cmd, "echo") ||
STREQ(cmd, "ls")) {
sprintf(command, "%s", cmd);
for (i = 1; i < argcnt; i++) {
strcat(command, " ");
if (strstr(args[i], " ")) {
strcat(command, "\"");
strcat(command, args[i]);
strcat(command, "\"");
}
else
strcat(command, args[i]);
}
if (system(command) == -1)
perror(command);
return TRUE;
}
return FALSE;
}
void
cmd_quit(void)
{
if (REMOTE())
remote_exit();
clean_exit(0);
}
void
cmd_mach(void)
{
machdep->cmd_mach();
}
static void
setup_environment(int argc, char **argv)
{
int i;
char *p1;
char buf[BUFSIZE];
char homerc[BUFSIZE];
char localrc[BUFSIZE];
FILE *afp;
char *program;
program = argv[0];
/*
* Program output typically goes via "fprintf(fp, ...)", but the
* contents of fp are modified on the fly to handle redirection
* to pipes or output files.
*/
fp = stdout;
/*
* Start populating the program_context structure. It's used so
* frequently that "pc" has been declared globally to point to the
* "program_context" structure.
*/
pc->program_name = (char *)basename(program);
pc->program_path = program;
pc->program_version = build_version;
pc->program_pid = (ulong)getpid();
pc->curcmd = pc->program_name;
pc->flags = (HASH|SCROLL);
pc->flags |= DATADEBUG; /* default until unnecessary */
pc->confd = -2;
pc->machine_type = MACHINE_TYPE;
pc->readmem = read_dev_mem; /* defaults until argv[] is parsed */
pc->writemem = write_dev_mem;
pc->read_vmcoreinfo = no_vmcoreinfo;
2014-01-28 21:46:11 +00:00
pc->memory_module = NULL;
pc->memory_device = MEMORY_DRIVER_DEVICE;
machdep->bits = sizeof(long) * 8;
machdep->verify_paddr = generic_verify_paddr;
machdep->get_kvaddr_ranges = generic_get_kvaddr_ranges;
pc->redhat_debug_loc = DEFAULT_REDHAT_DEBUG_LOCATION;
pc->cmdgencur = 0;
pc->cmd_table = linux_command_table;
kt->BUG_bytes = -1;
kt->flags |= PRE_KERNEL_INIT;
/*
* Set up to perform a clean_exit() upon parent death.
*/
SIGACTION(SIGUSR2, restart, &pc->sigaction, NULL);
prctl(PR_SET_PDEATHSIG, SIGUSR2);
/*
* Get gdb version before initializing it since this might be one
* of the short-hand commands that need it without running gdb.
*/
get_gdb_version();
/*
* Set up the default scrolling behavior for terminal output.
*/
if (isatty(fileno(stdout))) {
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)) {
pc->flags |= SCROLL;
pc->scroll_command = SCROLL_MORE;
} else {
pc->scroll_command = SCROLL_NONE;
pc->flags &= ~SCROLL;
}
}
/*
* Setup the readline command line editing mode based upon the
* following order:
*
* (1) EDITOR environment variable
* (2) overridden by any .crashrc entry: "set vi" or "set emacs"
* (3) RL_VI_MODE if not set anywhere else
*/
pc->flags |= READLINE;
pc->editing_mode = "no_mode";
if ((p1 = getenv("EDITOR"))) {
if (strstr(p1, "vi"))
pc->editing_mode = "vi";
if (strstr(p1, "emacs"))
pc->editing_mode = "emacs";
}
/*
* Resolve $HOME .rc file first, then the one in the local directory.
* Note that only "set" and "alias" commands are done at this time.
*/
for (i = 1; i < argc; i++)
if (STREQ(argv[i], "--no_crashrc"))
pc->flags |= NOCRASHRC;
alias_init(NULL);
if ((p1 = getenv("HOME"))) {
if ((pc->home = (char *)malloc(strlen(p1)+1)) == NULL) {
error(INFO, "home directory malloc: %s\n",
strerror(errno));
pc->home = "(unknown)";
} else
strcpy(pc->home, p1);
sprintf(homerc, "%s/.%src", pc->home, pc->program_name);
if (!(pc->flags & NOCRASHRC) && file_exists(homerc, NULL)) {
if ((afp = fopen(homerc, "r")) == NULL)
error(INFO, "cannot open %s: %s\n",
homerc, strerror(errno));
else if (untrusted_file(afp, homerc))
fclose(afp);
else {
while (fgets(buf, BUFSIZE, afp))
resolve_rc_cmd(buf, ALIAS_RCHOME);
fclose(afp);
}
}
}
sprintf(localrc, ".%src", pc->program_name);
if (!same_file(homerc, localrc) &&
!(pc->flags & NOCRASHRC) && file_exists(localrc, NULL)) {
if ((afp = fopen(localrc, "r")) == NULL)
error(INFO, "cannot open %s: %s\n",
localrc, strerror(errno));
else if (untrusted_file(afp, localrc))
fclose(afp);
else {
while (fgets(buf, BUFSIZE, afp))
resolve_rc_cmd(buf, ALIAS_RCLOCAL);
fclose(afp);
}
}
if (STREQ(pc->editing_mode, "no_mode"))
pc->editing_mode = "vi";
machdep_init(SETUP_ENV);
}
/*
* "help -p" output
*/
void
dump_program_context(void)
{
int i;
int others = 0;
char *p1;
char buf[BUFSIZE];
char buf2[BUFSIZE];
fprintf(fp, " program_name: %s\n", pc->program_name);
fprintf(fp, " program_path: %s\n", pc->program_path);
fprintf(fp, " program_version: %s\n", pc->program_version);
fprintf(fp, " gdb_version: %s\n", pc->gdb_version);
fprintf(fp, " program_pid: %ld\n", pc->program_pid);
fprintf(fp, " prompt: \"%s\"\n", pc->prompt);
fprintf(fp, " flags: %llx ", pc->flags);
if (pc->flags)
sprintf(buf, "(");
if (pc->flags & RUNTIME)
sprintf(&buf[strlen(buf)], "%sRUNTIME", others++ ? "|" : "");
if (pc->flags & LIVE_SYSTEM)
sprintf(&buf[strlen(buf)], "%sLIVE_SYSTEM",
others++ ? "|" : "");
if (pc->flags & TTY)
sprintf(&buf[strlen(buf)], "%sTTY", others++ ? "|" : "");
if (pc->flags & IN_FOREACH)
sprintf(&buf[strlen(buf)], "%sIN_FOREACH", others++ ? "|" : "");
if (pc->flags & MFD_RDWR)
sprintf(&buf[strlen(buf)], "%sMFD_RDWR", others++ ? "|" : "");
if (pc->flags & KVMDUMP)
sprintf(&buf[strlen(buf)], "%sKVMDUMP", others++ ? "|" : "");
if (pc->flags & SILENT)
sprintf(&buf[strlen(buf)], "%sSILENT", others++ ? "|" : "");
if (pc->flags & HASH)
sprintf(&buf[strlen(buf)], "%sHASH", others++ ? "|" : "");
if (pc->flags & SCROLL)
sprintf(&buf[strlen(buf)], "%sSCROLL", others++ ? "|" : "");
if (pc->flags & NO_CONSOLE)
sprintf(&buf[strlen(buf)], "%sNO_CONSOLE", others++ ? "|" : "");
if (pc->flags & MCLXCD)
sprintf(&buf[strlen(buf)], "%sMCLXCD", others++ ? "|" : "");
if (pc->flags & RUNTIME_IFILE)
sprintf(&buf[strlen(buf)], "%sRUNTIME_IFILE",
others++ ? "|" : "");
if (pc->flags & CMDLINE_IFILE)
sprintf(&buf[strlen(buf)], "%sCMDLINE_IFILE",
others++ ? "|" : "");
if (pc->flags & DROP_CORE)
sprintf(&buf[strlen(buf)], "%sDROP_CORE", others++ ? "|" : "");
if (pc->flags & LKCD)
sprintf(&buf[strlen(buf)], "%sLKCD", others++ ? "|" : "");
if (pc->flags & GDB_INIT)
sprintf(&buf[strlen(buf)], "%sGDB_INIT", others++ ? "|" : "");
if (pc->flags & IN_GDB)
sprintf(&buf[strlen(buf)], "%sIN_GDB", others++ ? "|" : "");
if (pc->flags & RCHOME_IFILE)
sprintf(&buf[strlen(buf)], "%sRCHOME_IFILE",
others++ ? "|" : "");
if (pc->flags & RCLOCAL_IFILE)
sprintf(&buf[strlen(buf)], "%sRCLOCAL_IFILE",
others++ ? "|" : "");
if (pc->flags & READLINE)
sprintf(&buf[strlen(buf)], "%sREADLINE", others++ ? "|" : "");
if (pc->flags & _SIGINT_)
sprintf(&buf[strlen(buf)],
"%s_SIGINT_", others++ ? "|" : "");
if (pc->flags & IN_RESTART)
sprintf(&buf[strlen(buf)], "%sIN_RESTART", others++ ? "|" : "");
if (pc->flags & KERNEL_DEBUG_QUERY)
sprintf(&buf[strlen(buf)],
"%sKERNEL_DEBUG_QUERY", others++ ? "|" : "");
if (pc->flags & DEVMEM)
sprintf(&buf[strlen(buf)],
"%sDEVMEM", others++ ? "|" : "");
if (pc->flags & MEMMOD)
sprintf(&buf[strlen(buf)],
"%sMEMMOD", others++ ? "|" : "");
if (pc->flags & MODPRELOAD)
sprintf(&buf[strlen(buf)],
"%sMODPRELOAD", others++ ? "|" : "");
if (pc->flags & REM_LIVE_SYSTEM)
sprintf(&buf[strlen(buf)],
"%sREM_LIVE_SYSTEM", others++ ? "|" : "");
if (pc->flags2 & MEMSRC_LOCAL)
2014-01-28 21:46:11 +00:00
sprintf(&buf[strlen(buf)],
"%sMEMSRC_LOCAL", others++ ? "|" : "");
if (pc->flags & NAMELIST_LOCAL)
sprintf(&buf[strlen(buf)],
"%sNAMELIST_LOCAL", others++ ? "|" : "");
if (pc->flags & DUMPFILE_SAVED)
sprintf(&buf[strlen(buf)],
"%sDUMPFILE_SAVED", others++ ? "|" : "");
if (pc->flags & NAMELIST_SAVED)
sprintf(&buf[strlen(buf)],
"%sNAMELIST_SAVED", others++ ? "|" : "");
if (pc->flags & UNLINK_NAMELIST)
sprintf(&buf[strlen(buf)],
"%sUNLINK_NAMELIST", others++ ? "|" : "");
if (pc->flags & NAMELIST_UNLINKED)
sprintf(&buf[strlen(buf)],
"%sNAMELIST_UNLINKED", others++ ? "|" : "");
if (pc->flags & REM_MCLXCD)
sprintf(&buf[strlen(buf)],
"%sREM_MCLXCD", others++ ? "|" : "");
if (pc->flags & REM_LKCD)
sprintf(&buf[strlen(buf)],
"%sREM_LKCD", others++ ? "|" : "");
if (pc->flags & NAMELIST_NO_GZIP)
sprintf(&buf[strlen(buf)],
"%sNAMELIST_NO_GZIP", others++ ? "|" : "");
if (pc->flags & UNLINK_MODULES)
sprintf(&buf[strlen(buf)],
"%sUNLINK_MODULES", others++ ? "|" : "");
if (pc->flags & S390D)
sprintf(&buf[strlen(buf)],
"%sS390D", others++ ? "|" : "");
if (pc->flags & REM_S390D)
sprintf(&buf[strlen(buf)],
"%sREM_S390D", others++ ? "|" : "");
if (pc->flags & NETDUMP)
sprintf(&buf[strlen(buf)],
"%sNETDUMP", others++ ? "|" : "");
if (pc->flags & XENDUMP)
sprintf(&buf[strlen(buf)],
"%sXENDUMP", others++ ? "|" : "");
if (pc->flags & KDUMP)
sprintf(&buf[strlen(buf)],
"%sKDUMP", others++ ? "|" : "");
if (pc->flags & SADUMP)
sprintf(&buf[strlen(buf)],
"%sSADUMP", others++ ? "|" : "");
if (pc->flags & SYSRQ)
sprintf(&buf[strlen(buf)],
"%sSYSRQ", others++ ? "|" : "");
if (pc->flags & REM_NETDUMP)
sprintf(&buf[strlen(buf)],
"%sREM_NETDUMP", others++ ? "|" : "");
if (pc->flags & DISKDUMP)
sprintf(&buf[strlen(buf)],
"%sDISKDUMP", others++ ? "|" : "");
if (pc->flags & SYSMAP)
sprintf(&buf[strlen(buf)],
"%sSYSMAP", others++ ? "|" : "");
if (pc->flags & SYSMAP_ARG)
sprintf(&buf[strlen(buf)],
"%sSYSMAP_ARG", others++ ? "|" : "");
if (pc->flags & DATADEBUG)
sprintf(&buf[strlen(buf)],
"%sDATADEBUG", others++ ? "|" : "");
if (pc->flags & FINDKERNEL)
sprintf(&buf[strlen(buf)],
"%sFINDKERNEL", others++ ? "|" : "");
if (pc->flags & VERSION_QUERY)
sprintf(&buf[strlen(buf)],
"%sVERSION_QUERY", others++ ? "|" : "");
if (pc->flags & READNOW)
sprintf(&buf[strlen(buf)],
"%sREADNOW", others++ ? "|" : "");
if (pc->flags & NOCRASHRC)
sprintf(&buf[strlen(buf)],
"%sNOCRASHRC", others++ ? "|" : "");
if (pc->flags & INIT_IFILE)
sprintf(&buf[strlen(buf)],
"%sINIT_IFILE", others++ ? "|" : "");
if (pc->flags & XEN_HYPER)
sprintf(&buf[strlen(buf)],
"%sXEN_HYPER", others++ ? "|" : "");
if (pc->flags & XEN_CORE)
sprintf(&buf[strlen(buf)],
"%sXEN_CORE", others++ ? "|" : "");
if (pc->flags & PLEASE_WAIT)
sprintf(&buf[strlen(buf)],
"%sPLEASE_WAIT", others++ ? "|" : "");
if (pc->flags & IFILE_ERROR)
sprintf(&buf[strlen(buf)],
"%sIFILE_ERROR", others++ ? "|" : "");
if (pc->flags & MINIMAL_MODE)
sprintf(&buf[strlen(buf)],
"%sMINIMAL_MODE", others++ ? "|" : "");
if (pc->flags & CRASHBUILTIN)
sprintf(&buf[strlen(buf)],
"%sCRASHBUILTIN", others++ ? "|" : "");
if (pc->flags & PRELOAD_EXTENSIONS)
sprintf(&buf[strlen(buf)],
"%sPRELOAD_EXTENSIONS", others++ ? "|" : "");
if (pc->flags & PROC_KCORE)
sprintf(&buf[strlen(buf)],
"%sPROC_KCORE", others++ ? "|" : "");
if (pc->flags)
strcat(buf, ")");
if (strlen(buf)) {
if (strlen(buf) > 46) {
sprintf(buf2, "\n%s\n",
mkstring(buf, 80, CENTER|LJUST, NULL));
if (strlen(buf2) <= 82)
fprintf(fp, "%s", buf2);
else {
for (i = strlen(buf2)-1; i; i--) {
if ((buf2[i] == '|') && (i < 80))
break;
}
strcpy(buf, buf2);
buf[i+1] = NULLCHAR;
fprintf(fp, "%s\n %s", buf, &buf2[i+1]);
}
}
else
fprintf(fp, "%s\n", buf);
}
others = 0;
fprintf(fp, " flags2: %llx (", pc->flags2);
if (pc->flags2 & FLAT)
fprintf(fp, "%sFLAT", others++ ? "|" : "");
if (pc->flags2 & ELF_NOTES)
fprintf(fp, "%sELF_NOTES", others++ ? "|" : "");
if (pc->flags2 & GET_OSRELEASE)
fprintf(fp, "%sGET_OSRELEASE", others++ ? "|" : "");
if (pc->flags2 & REMOTE_DAEMON)
fprintf(fp, "%sREMOTE_DAEMON", others++ ? "|" : "");
if (pc->flags2 & LIVE_DUMP)
fprintf(fp, "%sLIVE_DUMP", others++ ? "|" : "");
if (pc->flags2 & RADIX_OVERRIDE)
fprintf(fp, "%sRADIX_OVERRIDE", others++ ? "|" : "");
if (pc->flags2 & QEMU_MEM_DUMP_ELF)
fprintf(fp, "%sQEMU_MEM_DUMP_ELF", others++ ? "|" : "");
if (pc->flags2 & QEMU_MEM_DUMP_COMPRESSED)
fprintf(fp, "%sQEMU_MEM_DUMP_COMPRESSED", others++ ? "|" : "");
2014-01-28 21:46:11 +00:00
if (pc->flags2 & GET_LOG)
fprintf(fp, "%sGET_LOG", others++ ? "|" : "");
if (pc->flags2 & VMCOREINFO)
fprintf(fp, "%sVMCOREINFO", others++ ? "|" : "");
if (pc->flags2 & ALLOW_FP)
fprintf(fp, "%sALLOW_FP", others++ ? "|" : "");
if (pc->flags2 & RAMDUMP)
fprintf(fp, "%sRAMDUMP", others++ ? "|" : "");
Implement a new "offline" internal crash variable that can be set to either "show" (the default) or "hide". When set to "hide", certain command output associated with offline cpus will be hidden from view, and the output will indicate that the cpu is "[OFFLINE]". The new variable can be set during invocation on the crash command line via the option "--offline [show|hide]". During runtime, or in a .crashrc or other crash input file, the variable can be set by entering "set offline [show|hide]". The commands or options that are affected when the variable is set to "hide" are as follows: o On X86_64 machines, the "bt -E" option will not search exception stacks associated with offline cpus. o On X86_64 machines, the "mach" command will append "[OFFLINE]" to the addresses of IRQ and exception stacks associated with offline cpus. o On X86_64 machines, the "mach -c" command will not display the cpuinfo_x86 data structure associated with offline cpus. o The "help -r" option has been fixed so as to not attempt to display register sets of offline cpus from ELF kdump vmcores, compressed kdump vmcores, and ELF kdump clones created by "virsh dump --memory-only". o The "bt -c" option will not accept an offline cpu number. o The "set -c" option will not accept an offline cpu number. o The "irq -s" option will not display statistics associated with offline cpus. o The "timer" command will not display hrtimer data associated with offline cpus. o The "timer -r" option will not display hrtimer data associated with offline cpus. o The "ptov" command will append "[OFFLINE]" when translating a per-cpu address offset to a virtal address of an offline cpu. o The "kmem -o" option will append "[OFFLINE]" to the base per-cpu virtual address of an offline cpu. o The "kmem -S" option in CONFIG_SLUB kernels will not display per-cpu data associated with offline cpus. o When a per-cpu address reference is passed to the "struct" command, the data structure will not be displayed for offline cpus. o When a per-cpu symbol and cpu reference is passed to the "p" command, the data will not be displayed for offline cpus. o When the "ps -[l|m]" option is passed the optional "-C [cpus]" option, the tasks queued on offline cpus are not shown. o The "runq" command and the "runq [-t/-m/-g/-d]" options will not display runqueue data for offline cpus. o The "ps" command will replace the ">" active task indicator to a "-" for offline cpus. The initial system information banner and the "sys" command will display the total number of cpus as before, but will append the count of offline cpus. Lastly, a fix has been made for the initialization time determination of the maximum number of per-cpu objects queued in a CONFIG_SLAB kmem_cache so as to continue checking all cpus higher than the first offline cpu. These changes in behavior are not dependent upon the setting of the crash "offline" variable. (qiaonuohan@cn.fujitsu.com)
2014-10-06 19:32:37 +00:00
if (pc->flags2 & OFFLINE_HIDE)
fprintf(fp, "%sOFFLINE_HIDE", others++ ? "|" : "");
if (pc->flags2 & INCOMPLETE_DUMP)
fprintf(fp, "%sINCOMPLETE_DUMP", others++ ? "|" : "");
if (pc->flags2 & SNAP)
fprintf(fp, "%sSNAP", others++ ? "|" : "");
if (pc->flags2 & EXCLUDED_VMEMMAP)
fprintf(fp, "%sEXCLUDED_VMEMMAP", others++ ? "|" : "");
2014-01-28 21:46:11 +00:00
fprintf(fp, ")\n");
fprintf(fp, " namelist: %s\n", pc->namelist);
fprintf(fp, " dumpfile: %s\n", pc->dumpfile);
fprintf(fp, " live_memsrc: %s\n", pc->live_memsrc);
fprintf(fp, " system_map: %s\n", pc->system_map);
fprintf(fp, " namelist_debug: %s\n", pc->namelist_debug);
fprintf(fp, " debuginfo_file: %s\n", pc->debuginfo_file);
fprintf(fp, " namelist_orig: %s\n", pc->namelist_orig);
fprintf(fp, "namelist_dbg_orig: %s\n", pc->namelist_debug_orig);
fprintf(fp, " kvmdump_mapfile: %s\n", pc->kvmdump_mapfile);
fprintf(fp, " memory_module: %s\n", pc->memory_module);
fprintf(fp, " memory_device: %s\n", pc->memory_device);
fprintf(fp, " machine_type: %s\n", pc->machine_type);
fprintf(fp, " editing_mode: %s\n", pc->editing_mode);
fprintf(fp, " nfd: %d\n", pc->nfd);
fprintf(fp, " mfd: %d\n", pc->mfd);
fprintf(fp, " kfd: %d\n", pc->kfd);
fprintf(fp, " dfd: %d\n", pc->dfd);
fprintf(fp, " confd: %d\n", pc->confd);
fprintf(fp, " home: %s\n", pc->home);
fprintf(fp, " command_line: ");
if (STRNEQ(pc->command_line, args[0]))
fprintf(fp, "%s\n", concat_args(buf, 0, FALSE));
else
fprintf(fp, "%s\n", pc->command_line);
fprintf(fp, " orig_line: %s\n", pc->orig_line);
fprintf(fp, " eoc_index: %d\n", pc->eoc_index);
fprintf(fp, " readline: %lx\n", (ulong)pc->readline);
fprintf(fp, " my_tty: %s\n", pc->my_tty);
fprintf(fp, " debug: %ld\n", pc->debug);
fprintf(fp, " debug_save: %ld\n", pc->debug_save);
fprintf(fp, " console: %s\n", pc->console);
fprintf(fp, " redhat_debug_loc: %s\n", pc->redhat_debug_loc);
fprintf(fp, " pipefd[2]: %d,%d\n", pc->pipefd[0], pc->pipefd[1]);
fprintf(fp, " nullfp: %lx\n", (ulong)pc->nullfp);
fprintf(fp, " stdpipe: %lx\n", (ulong)pc->stdpipe);
fprintf(fp, " pipe: %lx\n", (ulong)pc->pipe);
fprintf(fp, " ifile: %lx\n", (ulong)pc->ifile);
fprintf(fp, " ofile: %lx\n", (ulong)pc->ofile);
fprintf(fp, " ifile_pipe: %lx\n", (ulong)pc->ifile_pipe);
fprintf(fp, " ifile_ofile: %lx\n", (ulong)pc->ifile_ofile);
fprintf(fp, " args_ifile: %lx\n", (ulong)pc->args_ifile);
fprintf(fp, " input_file: %s\n", pc->input_file);
fprintf(fp, "ifile_in_progress: %lx (", pc->ifile_in_progress);
others = 0;
if (pc->ifile_in_progress & RCHOME_IFILE)
fprintf(fp, "%sRCHOME_IFILE", others++ ? "|" : "");
if (pc->ifile_in_progress & RCLOCAL_IFILE)
fprintf(fp, "%sRCLOCAL_IFILE", others++ ? "|" : "");
if (pc->ifile_in_progress & CMDLINE_IFILE)
fprintf(fp, "%sCMDLINE_IFILE", others++ ? "|" : "");
if (pc->ifile_in_progress & RUNTIME_IFILE)
fprintf(fp, "%sRUNTIME_IFILE", others++ ? "|" : "");
fprintf(fp, ")\n");
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: ");
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);
if (pc->redirect)
sprintf(buf, "(");
others = 0;
if (pc->redirect & FROM_COMMAND_LINE)
sprintf(&buf[strlen(buf)],
"%sFROM_COMMAND_LINE", others++ ? "|" : "");
if (pc->redirect & FROM_INPUT_FILE)
sprintf(&buf[strlen(buf)],
"%sFROM_INPUT_FILE", others++ ? "|" : "");
if (pc->redirect & REDIRECT_NOT_DONE)
sprintf(&buf[strlen(buf)],
"%sREDIRECT_NOT_DONE", others++ ? "|" : "");
if (pc->redirect & REDIRECT_TO_PIPE)
sprintf(&buf[strlen(buf)],
"%sREDIRECT_TO_PIPE", others++ ? "|" : "");
if (pc->redirect & REDIRECT_TO_STDPIPE)
sprintf(&buf[strlen(buf)],
"%sREDIRECT_TO_STDPIPE", others++ ? "|" : "");
if (pc->redirect & REDIRECT_TO_FILE)
sprintf(&buf[strlen(buf)],
"%sREDIRECT_TO_FILE", others++ ? "|" : "");
if (pc->redirect & REDIRECT_FAILURE)
sprintf(&buf[strlen(buf)],
"%sREDIRECT_FAILURE", others++ ? "|" : "");
if (pc->redirect & REDIRECT_SHELL_ESCAPE)
sprintf(&buf[strlen(buf)],
"%sREDIRECT_SHELL_ESCAPE", others++ ? "|" : "");
if (pc->redirect & REDIRECT_SHELL_COMMAND)
sprintf(&buf[strlen(buf)],
"%sREDIRECT_SHELL_COMMAND", others++ ? "|" : "");
if (pc->redirect & REDIRECT_PID_KNOWN)
sprintf(&buf[strlen(buf)],
"%sREDIRECT_PID_KNOWN", others++ ? "|" : "");
if (pc->redirect & REDIRECT_MULTI_PIPE)
sprintf(&buf[strlen(buf)],
"%sREDIRECT_MULTI_PIPE", others++ ? "|" : "");
if (pc->redirect)
strcat(buf, ")");
if (strlen(buf)) {
if (strlen(buf) > 54)
fprintf(fp, "\n%s\n",
mkstring(buf, 80, CENTER|LJUST, NULL));
else
fprintf(fp, "%s\n", buf);
}
if (!pc->redirect)
fprintf(fp, "\n");
fprintf(fp, " stdpipe_pid: %d\n", pc->stdpipe_pid);
fprintf(fp, " pipe_pid: %d\n", pc->pipe_pid);
fprintf(fp, " pipe_shell_pid: %d\n", pc->pipe_shell_pid);
fprintf(fp, " pipe_command: %s\n", pc->pipe_command);
if (pc->symfile && pc->symfile2) {
fprintf(fp, " symfile: %lx (%ld)\n",
(ulong)pc->symfile, (ulong)ftell(pc->symfile));
fprintf(fp, " symfile2: %lx (%ld)\n",
(ulong)pc->symfile2, (ulong)ftell(pc->symfile2));
} else {
fprintf(fp, " symfile: %lx \n", (ulong)pc->symfile);
fprintf(fp, " symfile2: %lx \n", (ulong)pc->symfile2);
}
fprintf(fp, " tmpfile: %lx\n", (ulong)pc->tmpfile);
fprintf(fp, " saved_fp: %lx\n", (ulong)pc->saved_fp);
fprintf(fp, " tmp_fp: %lx\n", (ulong)pc->tmp_fp);
fprintf(fp, " tmpfile2: %lx\n", (ulong)pc->tmpfile2);
fprintf(fp, " cmd_table: %s\n", XEN_HYPER_MODE() ?
"xen_hyper_command_table" : "linux_command_table");
fprintf(fp, " curcmd: %s\n", pc->curcmd);
fprintf(fp, " lastcmd: %s\n", pc->lastcmd);
fprintf(fp, " cur_gdb_cmd: %d %s\n", pc->cur_gdb_cmd,
gdb_command_string(pc->cur_gdb_cmd, buf, FALSE));
fprintf(fp, " last_gdb_cmd: %d %s\n", pc->last_gdb_cmd,
gdb_command_string(pc->last_gdb_cmd, buf, FALSE));
fprintf(fp, " cur_req: %lx\n", (ulong)pc->cur_req);
fprintf(fp, " cmdgencur: %ld\n", pc->cmdgencur);
fprintf(fp, " curcmd_flags: %lx (", pc->curcmd_flags);
others = 0;
if (pc->curcmd_flags & XEN_MACHINE_ADDR)
fprintf(fp, "%sXEN_MACHINE_ADDR", others ? "|" : "");
if (pc->curcmd_flags & REPEAT)
fprintf(fp, "%sREPEAT", others ? "|" : "");
if (pc->curcmd_flags & IDLE_TASK_SHOWN)
fprintf(fp, "%sIDLE_TASK_SHOWN", others ? "|" : "");
if (pc->curcmd_flags & TASK_SPECIFIED)
fprintf(fp, "%sTASK_SPECIFIED", others ? "|" : "");
if (pc->curcmd_flags & MEMTYPE_UVADDR)
fprintf(fp, "%sMEMTYPE_UVADDR", others ? "|" : "");
if (pc->curcmd_flags & MEMTYPE_FILEADDR)
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 ? "|" : "");
if (pc->curcmd_flags & IRQ_IN_USE)
fprintf(fp, "%sIRQ_IN_USE", others ? "|" : "");
if (pc->curcmd_flags & IGNORE_ERRORS)
fprintf(fp, "%sIGNORE_ERRORS", others ? "|" : "");
if (pc->curcmd_flags & FROM_RCFILE)
fprintf(fp, "%sFROM_RCFILE", others ? "|" : "");
if (pc->curcmd_flags & MEMTYPE_KVADDR)
fprintf(fp, "%sMEMTYPE_KVADDR", others ? "|" : "");
if (pc->curcmd_flags & NO_MODIFY)
fprintf(fp, "%sNO_MODIFY", others ? "|" : "");
if (pc->curcmd_flags & MOD_SECTIONS)
fprintf(fp, "%sMOD_SECTIONS", others ? "|" : "");
if (pc->curcmd_flags & MOD_READNOW)
fprintf(fp, "%sMOD_READNOW", others ? "|" : "");
if (pc->curcmd_flags & MM_STRUCT_FORCE)
fprintf(fp, "%sMM_STRUCT_FORCE", others ? "|" : "");
if (pc->curcmd_flags & CPUMASK)
fprintf(fp, "%sCPUMASK", others ? "|" : "");
if (pc->curcmd_flags & PARTIAL_READ_OK)
fprintf(fp, "%sPARTIAL_READ_OK", others ? "|" : "");
2014-01-28 21:46:11 +00:00
fprintf(fp, ")\n");
fprintf(fp, " curcmd_private: %llx\n", pc->curcmd_private);
fprintf(fp, " cmd_cleanup: %lx\n", (ulong)pc->cmd_cleanup);
fprintf(fp, " cmd_cleanup_arg: %lx\n", (ulong)pc->cmd_cleanup_arg);
fprintf(fp, " sigint_cnt: %d\n", pc->sigint_cnt);
fprintf(fp, " sigaction: %lx\n", (ulong)&pc->sigaction);
fprintf(fp, " gdb_sigaction: %lx\n", (ulong)&pc->gdb_sigaction);
fprintf(fp, " main_loop_env: %lx\n", (ulong)&pc->main_loop_env);
fprintf(fp, " foreach_loop_env: %lx\n", (ulong)&pc->foreach_loop_env);
fprintf(fp, "gdb_interface_env: %lx\n", (ulong)&pc->gdb_interface_env);
fprintf(fp, " termios_orig: %lx\n", (ulong)&pc->termios_orig);
fprintf(fp, " termios_raw: %lx\n", (ulong)&pc->termios_raw);
fprintf(fp, " ncmds: %d\n", pc->ncmds);
fprintf(fp, " cmdlist: %lx\n", (ulong)pc->cmdlist);
fprintf(fp, " cmdlistsz: %d\n", pc->cmdlistsz);
fprintf(fp, " output_radix: %d (%s)\n", pc->output_radix,
pc->output_radix == 16 ?
"hex" : ((pc->output_radix == 10) ? "decimal" : "???"));
fprintf(fp, " server: %s\n", pc->server);
fprintf(fp, " server_pid: %ld\n", pc->server_pid);
fprintf(fp, " port: %d\n", pc->port);
fprintf(fp, " sockfd: %d\n", pc->sockfd);
fprintf(fp, " server_memsrc: %s\n", pc->server_memsrc);
fprintf(fp, " server_namelist: %s\n", pc->server_namelist);
fprintf(fp, " rmfd: %d\n", pc->rmfd);
fprintf(fp, " rkfd: %d\n", pc->rkfd);
fprintf(fp, " rcvbufsize: %ld\n", pc->rcvbufsize);
fprintf(fp, " readmem: ");
if ((p1 = readmem_function_name()))
fprintf(fp, "%s()\n", p1);
else
fprintf(fp, "%lx\n", (ulong)pc->readmem);
fprintf(fp, " writemem: ");
if ((p1 = writemem_function_name()))
fprintf(fp, "%s()\n", p1);
else
fprintf(fp, "%lx\n", (ulong)pc->writemem);
fprintf(fp, " dumpfile memory: %d\n",
dumpfile_memory(DUMPFILE_MEM_USED));
fprintf(fp, " curext: %lx\n", (ulong)pc->curext);
fprintf(fp, " sbrk: %lx\n", (ulong)pc->sbrk);
fprintf(fp, " cleanup: %s\n", pc->cleanup);
fprintf(fp, " scope: %lx %s\n", pc->scope,
pc->scope ? "" : "(not set)");
fprintf(fp, " nr_hash_queues: %ld\n", pc->nr_hash_queues);
fprintf(fp, " read_vmcoreinfo: %lx\n", (ulong)pc->read_vmcoreinfo);
2014-01-28 21:46:11 +00:00
}
char *
readmem_function_name(void)
{
if (pc->readmem == read_dev_mem)
return("read_dev_mem");
else if (pc->readmem == read_mclx_dumpfile)
return("read_mclx_dumpfile");
else if (pc->readmem == read_lkcd_dumpfile)
return("read_lkcd_dumpfile");
else if (pc->readmem == read_daemon)
return("read_daemon");
else if (pc->readmem == read_netdump)
return("read_netdump");
else if (pc->readmem == read_xendump)
return("read_xendump");
else if (pc->readmem == read_kdump)
return("read_kdump");
else if (pc->readmem == read_memory_device)
return("read_memory_device");
else if (pc->readmem == read_xendump_hyper)
return("read_xendump_hyper");
else if (pc->readmem == read_diskdump)
return("read_diskdump");
else if (pc->readmem == read_proc_kcore)
return("read_proc_kcore");
else if (pc->readmem == read_sadump)
return("read_sadump");
else if (pc->readmem == read_s390_dumpfile)
return("read_s390_dumpfile");
else if (pc->readmem == read_ramdump)
return("read_ramdump");
else if (pc->readmem == read_vmware_vmss)
return("read_vmware_vmss");
2014-01-28 21:46:11 +00:00
else
return NULL;
}
char *
writemem_function_name(void)
{
if (pc->writemem == write_dev_mem)
return("write_dev_mem");
else if (pc->writemem == write_mclx_dumpfile)
return("write_mclx_dumpfile");
else if (pc->writemem == write_lkcd_dumpfile)
return("write_lkcd_dumpfile");
else if (pc->writemem == write_daemon)
return("write_daemon");
else if (pc->writemem == write_netdump)
return("write_netdump");
else if (pc->writemem == write_xendump)
return("write_xendump");
else if (pc->writemem == write_kdump)
return("write_kdump");
else if (pc->writemem == write_memory_device)
return("write_memory_device");
// else if (pc->writemem == write_xendump_hyper)
// return("write_xendump_hyper");
else if (pc->writemem == write_diskdump)
return("write_diskdump");
else if (pc->writemem == write_proc_kcore)
return("write_proc_kcore");
else if (pc->writemem == write_sadump)
return("write_sadump");
else if (pc->writemem == write_s390_dumpfile)
return("write_s390_dumpfile");
else if (pc->writemem == write_vmware_vmss)
return("write_vmware_vmss");
2014-01-28 21:46:11 +00:00
else
return NULL;
}
/*
* "help -B" output
*/
void
dump_build_data(void)
{
fprintf(fp, " build_command: %s\n", build_command);
fprintf(fp, " build_data: %s\n", build_data);
fprintf(fp, " build_target: %s\n", build_target);
fprintf(fp, " build_version: %s\n", build_version);
fprintf(fp, "compiler version: %s\n", compiler_version);
}
/*
* Perform any cleanup activity here.
*/
int
clean_exit(int status)
{
if (pc->flags & MEMMOD)
cleanup_memory_driver();
if ((pc->namelist_orig) && file_exists(pc->namelist, NULL))
unlink(pc->namelist);
if ((pc->namelist_debug_orig) && file_exists(pc->namelist_debug, NULL))
unlink(pc->namelist_debug);
if (pc->cleanup && file_exists(pc->cleanup, NULL))
unlink(pc->cleanup);
ramdump_cleanup();
2014-01-28 21:46:11 +00:00
exit(status);
}
/*
* Check whether this session is for xen hypervisor analysis.
*/
static void
check_xen_hyper(void)
{
if (!pc->namelist)
return;
if (!XEN_HYPER_MODE()) {
if (STRNEQ(basename(pc->namelist), "xen-syms"))
pc->flags |= XEN_HYPER;
else
return;
}
#ifdef XEN_HYPERVISOR_ARCH
pc->cmd_table = xen_hyper_command_table;
if (pc->flags & XENDUMP)
pc->readmem = read_xendump_hyper;
#else
error(FATAL, XEN_HYPERVISOR_NOT_SUPPORTED);
#endif
}
/*
* Reject untrusted .crashrc, $HOME/.crashrc,
* .gdbinit, and $HOME/.gdbinit files.
*/
static char *untrusted_file_list[4] = { 0 };
int
untrusted_file(FILE *filep, char *filename)
{
struct stat sbuf;
int i;
if (filep && (fstat(fileno(filep), &sbuf) == 0) &&
(sbuf.st_uid == getuid()) && !(sbuf.st_mode & S_IWOTH))
return FALSE;
for (i = 0; i < 4; i++) {
if (!untrusted_file_list[i]) {
untrusted_file_list[i] = strdup(filename);
break;
}
}
return TRUE;
}
static void
show_untrusted_files(void)
{
int i, cnt;
for (i = cnt = 0; i < 4; i++) {
if (untrusted_file_list[i]) {
error(WARNING, "not using untrusted file: \"%s\"\n",
untrusted_file_list[i]);
free(untrusted_file_list[i]);
cnt++;
}
}
if (cnt)
fprintf(fp, "\n");
}
/*
* If GET_OSRELEASE is still set, the OS release has been
* found and displayed.
*/
static void
get_osrelease(char *dumpfile)
{
int retval = 1;
if (is_flattened_format(dumpfile)) {
if (pc->flags2 & GET_OSRELEASE)
retval = 0;
} else if (is_diskdump(dumpfile)) {
2014-01-28 21:46:11 +00:00
if (pc->flags2 & GET_OSRELEASE)
retval = 0;
} else if (is_kdump(dumpfile, KDUMP_LOCAL)) {
if (pc->flags2 & GET_OSRELEASE)
retval = 0;
}
if (retval)
fprintf(fp, "unknown\n");
clean_exit(retval);
}
static void
get_log(char *dumpfile)
{
int retval = 1;
if (is_flattened_format(dumpfile))
pc->flags2 |= FLAT;
if (is_diskdump(dumpfile)) {
if (pc->flags2 & GET_LOG)
retval = 0;
} else if (is_kdump(dumpfile, KDUMP_LOCAL)) {
if (pc->flags2 & GET_LOG)
retval = 0;
}
if (retval)
fprintf(fp, "%s: no VMCOREINFO data\n", dumpfile);
clean_exit(retval);
}
static char *
no_vmcoreinfo(const char *unused)
{
return NULL;
}