mirror of https://github.com/crash-utility/crash
1979 lines
61 KiB
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;
|
|
}
|