crash/main.c

1979 lines
61 KiB
C

/* main.c - core analysis suite
*
* Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
* Copyright (C) 2002-2019 David Anderson
* Copyright (C) 2002-2019 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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 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},
{"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},
{"offline", required_argument, 0, 0},
{"src", required_argument, 0, 0},
{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:",
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") &&
!machine_type("ARM64") && !machine_type("X86") &&
!machine_type("S390X"))
error(INFO, "--kaslr not valid "
"with this 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;
st->_stext_vmlinux = UNINITIALIZED;
}
} else if (STREQ(long_options[option_index].name, "reloc")) {
if (!calculate(optarg, &kt->relocate, NULL, 0)) {
error(INFO, "invalid --reloc argument: %s\n",
optarg);
program_usage(SHORT_FORM);
}
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;
}
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);
}
}
else if (STREQ(long_options[option_index].name, "src"))
kt->source_tree = optarg;
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;
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;
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;
}
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]))
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;
} else if (is_vmware_guestdump(argv[optind])) {
if (pc->flags & MEMORY_SOURCES) {
error(INFO,
"too many dumpfile arguments\n");
program_usage(SHORT_FORM);
}
pc->flags |= VMWARE_VMSS;
pc->flags2 |= VMWARE_VMSS_GUESTDUMP;
pc->dumpfile = argv[optind];
pc->readmem = read_vmware_vmss;
pc->writemem = write_vmware_vmss;
} 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",
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");
}
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);
}
if (!(pc->flags & GDB_INIT)) {
gdb_session_init();
machdep_init(POST_RELOC);
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();
}
}
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;
if (!set_error("default")) {
fprintf(stderr, "crash: cannot malloc error() path string\n");
clean_exit(1);
}
/*
* 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->flags2 |= REDZONE;
pc->confd = -2;
pc->machine_type = MACHINE_TYPE;
if (file_readable("/dev/mem")) { /* defaults until argv[] is parsed */
pc->readmem = read_dev_mem;
pc->writemem = write_dev_mem;
} else if (file_exists("/proc/kcore", NULL)) {
pc->readmem = read_proc_kcore;
pc->writemem = write_proc_kcore;
}
pc->read_vmcoreinfo = no_vmcoreinfo;
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;
machdep->is_page_ptr = generic_is_page_ptr;
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->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 & VMWARE_VMSS)
sprintf(&buf[strlen(buf)],
"%sVMWARE_VMSS", 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++ ? "|" : "");
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++ ? "|" : "");
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++ ? "|" : "");
if (pc->flags2 & MEMSRC_LOCAL)
fprintf(fp, "%sMEMSRC_LOCAL", others++ ? "|" : "");
if (pc->flags2 & REDZONE)
fprintf(fp, "%sREDZONE", others++ ? "|" : "");
if (pc->flags2 & VMWARE_VMSS_GUESTDUMP)
fprintf(fp, "%sVMWARE_VMSS_GUESTDUMP", others++ ? "|" : "");
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 ? "|" : "");
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, " 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);
fprintf(fp, " error_fp: %lx\n", (ulong)pc->error_fp);
fprintf(fp, " error_path: %s\n", pc->error_path);
}
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");
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");
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();
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)) {
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);
}
char *
no_vmcoreinfo(const char *unused)
{
return NULL;
}