crash/main.c
Dave Anderson 045c00ac34 Added recognition of the new DUMP_DH_COMPRESSED_INCOMPLETE flag in
the header of compressed kdumps, and the new DUMP_ELF_INCOMPLETE flag
in the header of ELF kdumps.  If the makedumpfile(8) facility fails
to complete the creation of compressed or ELF kdump vmcore files
due to ENOSPC or other error, it will mark the vmcore as incomplete.
If either flag is set, the crash utility will issue a warning that
the dumpfile is known to be incomplete during initialization, just
prior to the system banner display.  When reads are attempted on
missing data, a read error will be returned.  As an alternative,
zero-filled data will be returned if the "--zero_excluded" command
line flag is used, or the "zero_excluded" runtime variable is set
to "on".  In either case, the read errors or zero-filled memory
may cause the crash session to fail entirely, cause commands to
fail, or may result in other unpredictable runtime behavior.
(anderson@redhat.com, zhouwj-fnst@cn.fujitsu.com)
2014-10-30 10:42:38 -04:00

1876 lines
58 KiB
C

/* main.c - core analysis suite
*
* Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
* Copyright (C) 2002-2014 David Anderson
* Copyright (C) 2002-2014 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},
{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"))
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")) {
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 {
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':
pc->flags |= 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);
}
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_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 {
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 (!(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();
}
}
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->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->flags & MEMSRC_LOCAL)
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)
fprintf(fp, "%sQEMU_MEM_DUMP", 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++ ? "|" : "");
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 ? "|" : "");
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);
}
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
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
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))
pc->flags2 |= FLAT;
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);
}