mirror of
https://github.com/crash-utility/crash
synced 2024-12-14 21:24:29 +00:00
045c00ac34
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)
1876 lines
58 KiB
C
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);
|
|
}
|