From babf924841509ad8df91103a6efc735d68f40a95 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 29 Aug 2007 19:10:12 +0000 Subject: [PATCH] - Updated crash.patch to match upstream version 4.0-4.6. --- crash.patch | 29633 ++++++++++++++++++++++++++++++++++++++++++++++---- crash.spec | 7 +- 2 files changed, 27565 insertions(+), 2075 deletions(-) diff --git a/crash.patch b/crash.patch index a4892ec..5923be3 100644 --- a/crash.patch +++ b/crash.patch @@ -1,6 +1,6 @@ ---- crash/extensions/Makefile.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/extensions/Makefile 2005-11-08 11:39:26.000000000 -0500 -@@ -0,0 +1,41 @@ +--- crash/extensions/Makefile.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/extensions/Makefile 2007-05-29 10:16:56.000000000 -0400 +@@ -0,0 +1,43 @@ +# +# Makefile for building crash shared object extensions +# @@ -37,12 +37,14 @@ + ln -s ../defs.h; fi + +echo.so: ../defs.h echo.c -+ gcc -nostartfiles -shared -rdynamic -o echo.so echo.c -fPIC -D$(TARGET) ++ gcc -nostartfiles -shared -rdynamic -o echo.so echo.c -fPIC \ ++ -D$(TARGET) $(TARGET_CFLAGS) + +dminfo.so: ../defs.h dminfo.c -+ gcc -nostartfiles -shared -rdynamic -o dminfo.so dminfo.c -fPIC -D$(TARGET) ++ gcc -nostartfiles -shared -rdynamic -o dminfo.so dminfo.c -fPIC \ ++ -D$(TARGET) $(TARGET_CFLAGS) + ---- crash/extensions/echo.c.orig 2006-09-13 11:10:23.000000000 -0400 +--- crash/extensions/echo.c.orig 2007-08-27 15:02:36.000000000 -0400 +++ crash/extensions/echo.c 2005-11-08 10:37:53.000000000 -0500 @@ -0,0 +1,105 @@ +/* echo.c - simple example of a crash extension @@ -150,7 +152,7 @@ +}; + + ---- crash/extensions/dminfo.c.orig 2006-09-13 11:10:23.000000000 -0400 +--- crash/extensions/dminfo.c.orig 2007-08-27 15:02:36.000000000 -0400 +++ crash/extensions/dminfo.c 2005-11-08 10:37:53.000000000 -0500 @@ -0,0 +1,1531 @@ +/* dminfo.c - crash extension module for device-mapper analysis @@ -1684,9 +1686,111 @@ +{ + return 0; +} ---- crash/gdb-6.1/gdb/symfile.c.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/gdb-6.1/gdb/symfile.c 2006-08-23 08:40:53.000000000 -0400 -@@ -3510,6 +3510,13 @@ +--- crash/gdb-6.1/gdb/symtab.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/gdb-6.1/gdb/symtab.c 2007-01-23 17:11:34.000000000 -0500 +@@ -4,7 +4,7 @@ + 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. + Portions Copyright (C) 2001, 2002 Mission Critical Linux, Inc. +- Copyright (c) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ Copyright (c) 2002, 2003, 2004, 2005, 2007 Red Hat, Inc. All rights reserved. + + This file is part of GDB. + +@@ -4523,14 +4523,54 @@ + struct symbol *sym; + struct expression *expr; + struct cleanup *old_chain; +- ++ int i; ++ int allsect = 0; ++ char *secname; ++ char buf[80]; ++ + gdb_current_load_module = lm = (struct load_module *)req->addr; + + req->name = lm->mod_namelist; + gdb_delete_symbol_file(req); + +- sprintf(req->buf, "add-symbol-file %s 0x%lx", lm->mod_namelist, +- lm->mod_text_start); ++ for (i = 0 ; i < lm->mod_sections; i++) { ++ if (STREQ(lm->mod_section_data[i].name, ".text") && ++ (lm->mod_section_data[i].flags & SEC_FOUND)) ++ allsect = 1; ++ } ++ ++ if (!allsect) { ++ sprintf(req->buf, "add-symbol-file %s 0x%lx", lm->mod_namelist, ++ lm->mod_text_start ? lm->mod_text_start : lm->mod_base); ++ if (lm->mod_data_start) { ++ sprintf(buf, " -s .data 0x%lx", lm->mod_data_start); ++ strcat(req->buf, buf); ++ } ++ if (lm->mod_bss_start) { ++ sprintf(buf, " -s .bss 0x%lx", lm->mod_bss_start); ++ strcat(req->buf, buf); ++ } ++ if (lm->mod_rodata_start) { ++ sprintf(buf, " -s .rodata 0x%lx", lm->mod_rodata_start); ++ strcat(req->buf, buf); ++ } ++ } else { ++ sprintf(req->buf, "add-symbol-file %s 0x%lx", lm->mod_namelist, ++ lm->mod_text_start); ++ for (i = 0; i < lm->mod_sections; i++) { ++ secname = lm->mod_section_data[i].name; ++ if ((lm->mod_section_data[i].flags & SEC_FOUND) && ++ !STREQ(secname, ".text")) { ++ sprintf(buf, " -s %s 0x%lx", secname, ++ lm->mod_section_data[i].offset + lm->mod_base); ++ strcat(req->buf, buf); ++ } ++ } ++ } ++ ++ if (gdb_CRASHDEBUG(1)) { ++ fprintf_filtered(gdb_stdout, "gdb_add_symbol_file: %s\n", req->buf); ++ } + + execute_command(req->buf, FALSE); + +--- crash/gdb-6.1/gdb/symfile.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/gdb-6.1/gdb/symfile.c 2007-01-23 15:15:36.000000000 -0500 +@@ -3,7 +3,7 @@ + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Portions Copyright (C) 2001, 2002 Mission Critical Linux, Inc. +- Copyright (c) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. All rights reserved. + + Contributed by Cygnus Support, using pieces from other GDB modules. + +@@ -1678,7 +1678,11 @@ + to load the program. */ + sect_opts[section_index].name = ".text"; + sect_opts[section_index].value = arg; ++#ifdef CRASH_MERGE ++ if (++section_index >= num_sect_opts) ++#else + if (++section_index > num_sect_opts) ++#endif + { + num_sect_opts *= 2; + sect_opts = ((struct sect_opt *) +@@ -1714,7 +1718,11 @@ + { + sect_opts[section_index].value = arg; + expecting_sec_addr = 0; ++#ifdef CRASH_MERGE ++ if (++section_index >= num_sect_opts) ++#else + if (++section_index > num_sect_opts) ++#endif + { + num_sect_opts *= 2; + sect_opts = ((struct sect_opt *) +@@ -3510,6 +3518,13 @@ bfd_byte * symfile_relocate_debug_section (bfd *abfd, asection *sectp, bfd_byte *buf) { @@ -1700,7 +1804,7 @@ /* We're only interested in debugging sections with relocation information. */ if ((sectp->flags & SEC_RELOC) == 0) ---- crash/gdb-6.1/gdb/ppc-linux-tdep.c.orig 2006-09-13 11:10:23.000000000 -0400 +--- crash/gdb-6.1/gdb/ppc-linux-tdep.c.orig 2007-08-27 15:02:36.000000000 -0400 +++ crash/gdb-6.1/gdb/ppc-linux-tdep.c 2005-07-14 11:08:17.000000000 -0400 @@ -0,0 +1,1116 @@ +/* Target-dependent code for GDB, the GNU debugger. @@ -2819,70 +2923,253 @@ + ppc_linux_init_abi); + add_core_fns (&ppc_linux_regset_core_fns); +} ---- crash/main.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/main.c 2006-08-31 15:56:58.000000000 -0400 -@@ -35,11 +35,15 @@ +--- crash/main.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/main.c 2007-08-21 16:02:46.000000000 -0400 +@@ -1,8 +1,8 @@ + /* main.c - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 +@@ -16,6 +16,7 @@ + */ + + #include "defs.h" ++#include "xen_hyper_defs.h" + #include + #include + +@@ -23,23 +24,37 @@ + 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 struct option long_options[] = { +- {"memory_module", 1, 0, 0}, +- {"memory_device", 1, 0, 0}, ++ {"memory_module", required_argument, 0, 0}, ++ {"memory_device", required_argument, 0, 0}, + {"no_kallsyms", 0, 0, 0}, + {"no_modules", 0, 0, 0}, + {"no_namelist_gzip", 0, 0, 0}, +- {"help", 0, 0, 0}, ++ {"help", optional_argument, 0, 'h'}, + {"data_debug", 0, 0, 0}, {"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", 1, 0, 0}, +- {"machdep", 1, 0, 0}, ++ {"machdep", required_argument, 0, 0}, {"version", 0, 0, 0}, {"buildinfo", 0, 0, 0}, + {"shadow_page_tables", 0, 0, 0}, -+ {"cpus", 1, 0, 0}, ++ {"cpus", required_argument, 0, 0}, + {"no_ikconfig", 0, 0, 0}, ++ {"hyper", 0, 0, 0}, ++ {"p2m_mfn", 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}, {0, 0, 0, 0} }; -@@ -55,7 +59,7 @@ +@@ -55,7 +70,7 @@ */ opterr = 0; optind = 0; - while((c = getopt_long(argc, argv, "LgH:h:e:i:sSvc:d:tf", -+ while((c = getopt_long(argc, argv, "LgH:h:e:i:sSvc:d:tfp:m:", ++ while((c = getopt_long(argc, argv, "Lkgh::e:i:sSvc:d:tfp:m:", long_options, &option_index)) != -1) { switch (c) { -@@ -77,6 +81,10 @@ +@@ -64,52 +79,55 @@ + "memory_module")) + pc->memory_module = optarg; + +- if (STREQ(long_options[option_index].name, ++ else if (STREQ(long_options[option_index].name, + "memory_device")) + pc->memory_device = optarg; + +- if (STREQ(long_options[option_index].name, ++ else if (STREQ(long_options[option_index].name, + "no_kallsyms")) + kt->flags |= NO_KALLSYMS; + +- if (STREQ(long_options[option_index].name, ++ else if (STREQ(long_options[option_index].name, + "no_modules")) kt->flags |= NO_MODULE_ACCESS; - if (STREQ(long_options[option_index].name, +- if (STREQ(long_options[option_index].name, ++ else if (STREQ(long_options[option_index].name, + "no_ikconfig")) + kt->flags |= NO_IKCONFIG; + -+ if (STREQ(long_options[option_index].name, ++ else if (STREQ(long_options[option_index].name, "no_namelist_gzip")) pc->flags |= NAMELIST_NO_GZIP; -@@ -98,6 +106,10 @@ +- if (STREQ(long_options[option_index].name, "help")) { +- program_usage(LONG_FORM); +- clean_exit(0); +- } +- +- if (STREQ(long_options[option_index].name, ++ else if (STREQ(long_options[option_index].name, + "data_debug")) + pc->flags |= DATADEBUG; + +- if (STREQ(long_options[option_index].name, ++ else if (STREQ(long_options[option_index].name, + "no_data_debug")) + pc->flags &= ~DATADEBUG; + +- if (STREQ(long_options[option_index].name, ++ else if (STREQ(long_options[option_index].name, + "no_kmem_cache")) vt->flags |= KMEM_CACHE_UNAVAIL; - if (STREQ(long_options[option_index].name, +- if (STREQ(long_options[option_index].name, ++ else if (STREQ(long_options[option_index].name, + "kmem_cache_delay")) + vt->flags |= KMEM_CACHE_DELAY; + -+ if (STREQ(long_options[option_index].name, ++ else if (STREQ(long_options[option_index].name, "readnow")) pc->flags |= READNOW; -@@ -123,6 +135,13 @@ +- if (STREQ(long_options[option_index].name, ++ else if (STREQ(long_options[option_index].name, + "smp")) + kt->flags |= SMP; + +- if (STREQ(long_options[option_index].name, ++ else if (STREQ(long_options[option_index].name, + "machdep")) + machdep->cmdline_arg = optarg; + +- if (STREQ(long_options[option_index].name, ++ else if (STREQ(long_options[option_index].name, + "version")) { + pc->flags |= VERSION_QUERY; + display_version(); +@@ -117,12 +135,69 @@ + clean_exit(0); + } + +- if (STREQ(long_options[option_index].name, ++ else if (STREQ(long_options[option_index].name, + "buildinfo")) { + dump_build_data(); clean_exit(0); } -+ if (STREQ(long_options[option_index].name, ++ else if (STREQ(long_options[option_index].name, + "shadow_page_tables")) + kt->xen_flags |= SHADOW_PAGE_TABLES; + -+ if (STREQ(long_options[option_index].name, "cpus")) ++ 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, "zero_excluded")) ++ *diskdump_flags |= ZERO_EXCLUDED; ++ ++ else if (STREQ(long_options[option_index].name, "no_panic")) ++ tt->flags |= PANIC_TASK_NOT_FOUND; ++ ++ 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, "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 { ++ error(INFO, "internal error: option %s unhandled\n", ++ long_options[option_index].name); ++ program_usage(SHORT_FORM); ++ } break; case 'f': -@@ -168,7 +187,7 @@ +@@ -133,14 +208,25 @@ + pc->flags |= KERNEL_DEBUG_QUERY; + break; + +- case 'H': +- cmd_usage(optarg, COMPLETE_HELP); +- clean_exit(0); +- + case 'h': +- cmd_usage(optarg, COMPLETE_HELP|PIPE_TO_LESS); ++ /* 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"; +@@ -168,7 +254,7 @@ case 's': pc->flags |= SILENT; pc->flags &= ~SCROLL; @@ -2891,7 +3178,7 @@ break; case 'L': -@@ -193,6 +212,14 @@ +@@ -193,14 +279,18 @@ set_vas_debug(pc->debug); break; @@ -2904,12 +3191,34 @@ + break; + default: - if (STREQ(argv[optind-1], "-h")) - program_usage(LONG_FORM); -@@ -264,6 +291,28 @@ - pc->readmem = read_netdump; - pc->writemem = write_netdump; - +- if (STREQ(argv[optind-1], "-h")) +- program_usage(LONG_FORM); +- else { +- error(INFO, "invalid option: %s\n", +- argv[optind-1]); +- program_usage(SHORT_FORM); +- } ++ error(INFO, "invalid option: %s\n", ++ argv[optind-1]); ++ program_usage(SHORT_FORM); + } + } + opterr = 1; +@@ -261,8 +351,36 @@ + } + pc->flags |= NETDUMP; + pc->dumpfile = argv[optind]; +- pc->readmem = read_netdump; +- pc->writemem = write_netdump; ++ ++ 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, @@ -2931,11 +3240,23 @@ + pc->dumpfile = argv[optind]; + pc->readmem = read_xendump; + pc->writemem = write_xendump; -+ + } else if (is_diskdump(argv[optind])) { if (pc->flags & MEMORY_SOURCES) { - error(INFO, -@@ -335,8 +384,6 @@ +@@ -322,6 +440,8 @@ + optind++; + } + ++ check_xen_hyper(); ++ + if (setjmp(pc->main_loop_env)) + clean_exit(1); + +@@ -332,11 +452,10 @@ + buf_init(); + cmdline_init(); + mem_init(); ++ hq_init(); machdep_init(PRE_SYMTAB); symtab_init(); machdep_init(PRE_GDB); @@ -2944,17 +3265,87 @@ datatype_init(); /* -@@ -361,7 +408,8 @@ +@@ -361,17 +480,28 @@ { if (!(pc->flags & GDB_INIT)) { gdb_session_init(); - kernel_init(POST_GDB); -+ read_in_kernel_config(IKCFG_INIT); -+ kernel_init(); - machdep_init(POST_GDB); - vm_init(); - hq_init(); -@@ -459,6 +507,9 @@ +- machdep_init(POST_GDB); +- vm_init(); +- hq_init(); +- module_init(); +- help_init(); +- task_init(); +- vfs_init(); +- net_init(); +- dev_init(); +- machdep_init(POST_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 { ++ 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); + +@@ -379,8 +509,17 @@ + * Display system statistics and current context. + */ + if (!(pc->flags & SILENT) && !(pc->flags & RUNTIME)) { +- display_sys_stats(); +- show_context(CURRENT_CONTEXT()); ++ if (XEN_HYPER_MODE()) { ++#ifdef XEN_HYPERVISOR_ARCH ++ xen_hyper_display_sys_stats(); ++ xen_hyper_show_vcpu_context(XEN_HYPER_VCPU_LAST_CONTEXT()); ++#else ++ error(FATAL, XEN_HYPERVISOR_NOT_SUPPORTED); ++#endif ++ } else { ++ display_sys_stats(); ++ show_context(CURRENT_CONTEXT()); ++ } + fprintf(fp, "\n"); + } + +@@ -426,8 +565,17 @@ + + if ((ct = get_command_table_entry(args[0]))) { + if (ct->flags & REFRESH_TASK_TABLE) { +- tt->refresh_task_table(); +- sort_context_array(); ++ 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 { ++ tt->refresh_task_table(); ++ sort_context_array(); ++ } + } + if (!STREQ(pc->curcmd, pc->program_name)) + pc->lastcmd = pc->curcmd; +@@ -459,6 +607,9 @@ pc->curcmd = pc->program_name; error(INFO, "command not found: %s\n", args[0]); @@ -2964,7 +3355,16 @@ } -@@ -591,6 +642,8 @@ +@@ -471,7 +622,7 @@ + struct command_table_entry *cp; + struct extension_table *ext; + +- for (cp = &base_command_table[0]; cp->name; cp++) { ++ for (cp = pc->cmd_table; cp->name; cp++) { + if (STREQ(cp->name, name)) + return cp; + } +@@ -591,6 +742,8 @@ int i; char *p1; char buf[BUFSIZE]; @@ -2973,7 +3373,29 @@ FILE *afp; char *program; -@@ -685,11 +738,11 @@ +@@ -625,7 +778,8 @@ + machdep->verify_paddr = generic_verify_paddr; + pc->redhat_debug_loc = DEFAULT_REDHAT_DEBUG_LOCATION; + pc->cmdgencur = 0; +- pc->cmdgenspec = ~pc->cmdgencur; ++ pc->cmd_table = linux_command_table; ++ kt->BUG_bytes = -1; + + /* + * Get gdb version before initializing it since this might be one +@@ -637,7 +791,10 @@ + * Set up the default scrolling behavior for terminal output. + */ + if (isatty(fileno(stdout))) { +- if (file_exists("/usr/bin/less", NULL)) { ++ 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)) { +@@ -685,11 +842,11 @@ pc->home = "(unknown)"; } else strcpy(pc->home, p1); @@ -2989,7 +3411,7 @@ else { while (fgets(buf, BUFSIZE, afp)) resolve_rc_cmd(buf, ALIAS_RCHOME); -@@ -698,11 +751,12 @@ +@@ -698,11 +855,12 @@ } } @@ -3006,7 +3428,16 @@ else { while (fgets(buf, BUFSIZE, afp)) resolve_rc_cmd(buf, ALIAS_RCLOCAL); -@@ -840,13 +894,22 @@ +@@ -712,6 +870,8 @@ + + if (STREQ(pc->editing_mode, "no_mode")) + pc->editing_mode = "vi"; ++ ++ machdep_init(SETUP_ENV); + } + + +@@ -840,13 +1000,22 @@ if (pc->flags & REM_S390D) sprintf(&buf[strlen(buf)], "%sREM_S390D", others++ ? "|" : ""); @@ -3031,7 +3462,7 @@ sprintf(&buf[strlen(buf)], "%sDISKDUMP", others++ ? "|" : ""); if (pc->flags & SYSMAP) -@@ -855,21 +918,24 @@ +@@ -855,21 +1024,36 @@ if (pc->flags & SYSMAP_ARG) sprintf(&buf[strlen(buf)], "%sSYSMAP_ARG", others++ ? "|" : ""); @@ -3058,24 +3489,104 @@ + 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) strcat(buf, ")"); -@@ -1017,6 +1083,13 @@ +@@ -933,10 +1117,36 @@ + fprintf(fp, " ifile_pipe: %lx\n", (ulong)pc->ifile_pipe); + fprintf(fp, " ifile_ofile: %lx\n", (ulong)pc->ifile_ofile); + fprintf(fp, " input_file: %s\n", pc->input_file); +- fprintf(fp, " scroll_command: %s\n", +- pc->scroll_command == SCROLL_NONE ? "(none)" : +- pc->scroll_command == SCROLL_LESS ? +- "/usr/bin/less" : "/bin/more"); ++ 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); +@@ -1008,6 +1218,8 @@ + 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, +@@ -1016,7 +1228,30 @@ + 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, " cmdgenspec: %ld\n", pc->cmdgenspec); +- fprintf(fp, " cmdgenspec: %ld\n", pc->cmdgenspec); + 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 ? "|" : ""); + fprintf(fp, ")\n"); ++ fprintf(fp, " curcmd_private: %llx\n", pc->curcmd_private); 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); -@@ -1051,6 +1124,10 @@ +@@ -1051,8 +1286,16 @@ fprintf(fp, " readmem: read_daemon()\n"); else if (pc->readmem == read_netdump) fprintf(fp, " readmem: read_netdump()\n"); @@ -3085,8 +3596,14 @@ + fprintf(fp, " readmem: read_kdump()\n"); else if (pc->readmem == read_memory_device) fprintf(fp, " readmem: read_memory_device()\n"); ++ else if (pc->readmem == read_xendump_hyper) ++ fprintf(fp, " readmem: read_xendump_hyper()\n"); ++ else if (pc->readmem == read_diskdump) ++ fprintf(fp, " readmem: read_diskdump()\n"); else -@@ -1065,6 +1142,10 @@ + fprintf(fp, " readmem: %lx\n", (ulong)pc->readmem); + if (pc->writemem == write_dev_mem) +@@ -1065,8 +1308,14 @@ fprintf(fp, " writemem: write_daemon()\n"); else if (pc->writemem == write_netdump) fprintf(fp, " writemem: write_netdump()\n"); @@ -3096,10 +3613,165 @@ + fprintf(fp, " writemem: write_kdump()\n"); else if (pc->writemem == write_memory_device) fprintf(fp, " writemem: write_memory_device()\n"); ++ else if (pc->writemem == write_diskdump) ++ fprintf(fp, " writemem: write_diskdump()\n"); else ---- crash/tools.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/tools.c 2006-07-10 11:35:06.000000000 -0400 -@@ -2004,6 +2004,10 @@ + fprintf(fp, " writemem: %lx\n", (ulong)pc->writemem); + +@@ -1100,3 +1349,28 @@ + + 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 ++} +--- crash/tools.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/tools.c 2007-07-26 14:11:50.000000000 -0400 +@@ -1,8 +1,8 @@ + /* tools.c - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 +@@ -18,12 +18,12 @@ + #include "defs.h" + #include + +-static int calculate(char *, ulong *, ulonglong *, ulong); + static void print_number(struct number_option *, int, int); + static long alloc_hq_entry(void); + struct hq_entry; + static void dealloc_hq_entry(struct hq_entry *); + static void show_options(void); ++static void dump_struct_members(struct list_data *, int, ulong); + + /* + * General purpose error reporting routine. Type INFO prints the message +@@ -63,6 +63,8 @@ + + if ((new_line = (buf[0] == '\n'))) + shift_string_left(buf, 1); ++ else if (pc->flags & PLEASE_WAIT) ++ new_line = TRUE; + + if (pc->stdpipe) { + fprintf(pc->stdpipe, "%s%s: %s%s", +@@ -1770,6 +1772,42 @@ + pc->flags & HASH ? "on" : "off"); + return; + ++ } else if (STREQ(args[optind], "unwind")) { ++ if (args[optind+1]) { ++ optind++; ++ if (STREQ(args[optind], "on")) { ++ if ((kt->flags & DWARF_UNWIND_CAPABLE) || ++ !runtime) { ++ kt->flags |= DWARF_UNWIND; ++ kt->flags &= ~NO_DWARF_UNWIND; ++ } ++ } else if (STREQ(args[optind], "off")) { ++ kt->flags &= ~DWARF_UNWIND; ++ if (!runtime) ++ kt->flags |= NO_DWARF_UNWIND; ++ } else if (IS_A_NUMBER(args[optind])) { ++ value = stol(args[optind], ++ FAULT_ON_ERROR, NULL); ++ if (value) { ++ if ((kt->flags & DWARF_UNWIND_CAPABLE) || ++ !runtime) { ++ kt->flags |= DWARF_UNWIND; ++ kt->flags &= ~NO_DWARF_UNWIND; ++ } ++ } else { ++ kt->flags &= ~DWARF_UNWIND; ++ if (!runtime) ++ kt->flags |= NO_DWARF_UNWIND; ++ } ++ } else ++ goto invalid_set_command; ++ } ++ ++ if (runtime) ++ fprintf(fp, "unwind: %s\n", ++ kt->flags & DWARF_UNWIND ? "on" : "off"); ++ return; ++ + } else if (STREQ(args[optind], "refresh")) { + if (args[optind+1]) { + optind++; +@@ -1806,7 +1844,14 @@ + pc->flags |= SCROLL; + else if (STREQ(args[optind], "off")) + pc->flags &= ~SCROLL; +- else if (IS_A_NUMBER(args[optind])) { ++ else if (STREQ(args[optind], "more")) ++ pc->scroll_command = SCROLL_MORE; ++ else if (STREQ(args[optind], "less")) ++ pc->scroll_command = SCROLL_LESS; ++ else if (STREQ(args[optind], "CRASHPAGER")) { ++ if (CRASHPAGER_valid()) ++ pc->scroll_command = SCROLL_CRASHPAGER; ++ } else if (IS_A_NUMBER(args[optind])) { + value = stol(args[optind], + FAULT_ON_ERROR, NULL); + if (value) +@@ -1817,9 +1862,25 @@ + goto invalid_set_command; + } + +- if (runtime) +- fprintf(fp, "scroll: %s\n", +- pc->flags & SCROLL ? "on" : "off"); ++ if (runtime) { ++ fprintf(fp, "scroll: %s ", ++ pc->flags & SCROLL ? "on" : "off"); ++ switch (pc->scroll_command) ++ { ++ case SCROLL_LESS: ++ fprintf(fp, "(/usr/bin/less)\n"); ++ break; ++ case SCROLL_MORE: ++ fprintf(fp, "(/bin/more)\n"); ++ break; ++ case SCROLL_NONE: ++ fprintf(fp, "(none)\n"); ++ break; ++ case SCROLL_CRASHPAGER: ++ fprintf(fp, "(CRASHPAGER: %s)\n", getenv("CRASHPAGER")); ++ break; ++ } ++ } + + return; + +@@ -2004,6 +2065,10 @@ pc->flags &= ~(DUMPFILE_TYPES); if (is_netdump(args[optind], NETDUMP_LOCAL)) pc->flags |= NETDUMP; @@ -3110,7 +3782,114 @@ else if (is_diskdump(args[optind])) pc->flags |= DISKDUMP; else if (is_lkcd_compressed_dump(args[optind])) -@@ -2896,11 +2900,25 @@ +@@ -2054,6 +2119,31 @@ + pc->flags |= DATADEBUG; + return; + ++ } else if (STREQ(args[optind], "zero_excluded")) { ++ ++ if (args[optind+1]) { ++ optind++; ++ if (STREQ(args[optind], "on")) ++ *diskdump_flags |= ZERO_EXCLUDED; ++ else if (STREQ(args[optind], "off")) ++ *diskdump_flags &= ~ZERO_EXCLUDED; ++ else if (IS_A_NUMBER(args[optind])) { ++ value = stol(args[optind], ++ FAULT_ON_ERROR, NULL); ++ if (value) ++ *diskdump_flags |= ZERO_EXCLUDED; ++ else ++ *diskdump_flags &= ~ZERO_EXCLUDED; ++ } else ++ goto invalid_set_command; ++ } ++ ++ if (runtime) ++ fprintf(fp, "zero_excluded: %s\n", ++ *diskdump_flags & ZERO_EXCLUDED ? ++ "on" : "off"); ++ return; ++ + } else if (runtime) { + ulong pid, task; + +@@ -2106,7 +2196,23 @@ + static void + show_options(void) + { +- fprintf(fp, " scroll: %s\n", pc->flags & SCROLL ? "on" : "off"); ++ fprintf(fp, " scroll: %s ", ++ pc->flags & SCROLL ? "on" : "off"); ++ switch (pc->scroll_command) ++ { ++ case SCROLL_LESS: ++ fprintf(fp, "(/usr/bin/less)\n"); ++ break; ++ case SCROLL_MORE: ++ fprintf(fp, "(/bin/more)\n"); ++ break; ++ case SCROLL_NONE: ++ fprintf(fp, "(none)\n"); ++ break; ++ case SCROLL_CRASHPAGER: ++ fprintf(fp, "(CRASHPAGER: %s)\n", getenv("CRASHPAGER")); ++ break; ++ } + fprintf(fp, " radix: %d (%s)\n", pc->output_radix, + pc->output_radix == 10 ? "decimal" : + pc->output_radix == 16 ? "hexadecimal" : "unknown"); +@@ -2121,6 +2227,8 @@ + fprintf(fp, " edit: %s\n", pc->editing_mode); + fprintf(fp, " namelist: %s\n", pc->namelist); + fprintf(fp, " dumpfile: %s\n", pc->dumpfile); ++ fprintf(fp, " unwind: %s\n", kt->flags & DWARF_UNWIND ? "on" : "off"); ++ fprintf(fp, " zero_excluded: %s\n", *diskdump_flags & ZERO_EXCLUDED ? "on" : "off"); + } + + +@@ -2336,6 +2444,7 @@ + char *element2; + struct syment *sp; + ++ opcode = 0; + value1 = value2 = 0; + ll_value1 = ll_value2 = 0; + +@@ -2550,7 +2659,7 @@ + * its real value. The allowable multipliers are k, K, m, M, g and G, for + * kilobytes, megabytes and gigabytes. + */ +-static int ++int + calculate(char *s, ulong *value, ulonglong *llvalue, ulong flags) + { + ulong factor, bias; +@@ -2832,7 +2941,9 @@ + break; + + case 's': +- ld->structname = optarg; ++ if (ld->structname_args++ == 0) ++ hq_open(); ++ hq_enter((ulong)optarg); + break; + + case 'o': +@@ -2871,6 +2982,12 @@ + cmd_usage(pc->curcmd, SYNOPSIS); + } + ++ if (ld->structname_args) { ++ ld->structname = (char **)GETBUF(sizeof(char *) * ld->structname_args); ++ retrieve_list((ulong *)ld->structname, ld->structname_args); ++ hq_close(); ++ } ++ + while (args[optind]) { + if (strstr(args[optind], ".") && + arg_to_datatype(args[optind], sm, RETURN_ON_ERROR) > 1) { +@@ -2896,11 +3013,25 @@ } /* @@ -3138,7 +3917,7 @@ /* * If the start is known, it's got to be an offset. -@@ -2941,7 +2959,8 @@ +@@ -2941,7 +3072,8 @@ ld->member_offset = value; ld->flags |= LIST_OFFSET_ENTERED; goto next_arg; @@ -3148,7 +3927,174 @@ !strstr(args[optind+1], ".")) error(FATAL, "symbol not found: %s\n", args[optind+1]); -@@ -4210,6 +4229,9 @@ +@@ -3002,8 +3134,12 @@ + hq_open(); + c = do_list(ld); + hq_close(); ++ ++ if (ld->structname_args) ++ FREEBUF(ld->structname); + } + ++ + /* + * Does the work for cmd_list() and any other function that requires the + * contents of a linked list. See cmd_list description above for details. +@@ -3013,7 +3149,7 @@ + { + ulong next, last, first; + ulong searchfor, readflag; +- int count, others; ++ int i, count, others; + + if (CRASHDEBUG(1)) { + others = 0; +@@ -3038,7 +3174,11 @@ + console("list_head_offset: %ld\n", ld->list_head_offset); + console(" end: %lx\n", ld->end); + console(" searchfor: %lx\n", ld->searchfor); +- console(" structname: %s\n", ld->structname); ++ console(" structname_args: %lx\n", ld->structname_args); ++ if (!ld->structname_args) ++ console(" structname: (unused)\n"); ++ for (i = 0; i < ld->structname_args; i++) ++ console(" structname[%d]: %s\n", i, ld->structname[i]); + console(" header: %s\n", ld->header); + } + +@@ -3065,20 +3205,21 @@ + fprintf(fp, "%lx\n", next - ld->list_head_offset); + + if (ld->structname) { +- switch (count_chars(ld->structname, '.')) +- { +- case 0: +- dump_struct(ld->structname, +- next - ld->list_head_offset, 0); +- break; +- case 1: +- dump_struct_member(ld->structname, +- next - ld->list_head_offset, 0); +- break; +- default: +- error(FATAL, +- "invalid structure reference: %s\n", +- ld->structname); ++ for (i = 0; i < ld->structname_args; i++) { ++ switch (count_chars(ld->structname[i], '.')) ++ { ++ case 0: ++ dump_struct(ld->structname[i], ++ next - ld->list_head_offset, 0); ++ break; ++ case 1: ++ dump_struct_members(ld, i, next); ++ break; ++ default: ++ error(FATAL, ++ "invalid structure reference: %s\n", ++ ld->structname[i]); ++ } + } + } + } +@@ -3148,6 +3289,42 @@ + } + + /* ++ * Issue a dump_struct_member() call for one or more structure ++ * members. Multiple members are passed in a comma-separated ++ * list using the the format: ++ * ++ * struct.member1,member2,member3 ++ */ ++void ++dump_struct_members(struct list_data *ld, int idx, ulong next) ++{ ++ int i, argc; ++ char *p1, *p2; ++ char *structname, *members; ++ char *arglist[MAXARGS]; ++ ++ structname = GETBUF(strlen(ld->structname[idx])+1); ++ members = GETBUF(strlen(ld->structname[idx])+1); ++ ++ strcpy(structname, ld->structname[idx]); ++ p1 = strstr(structname, ".") + 1; ++ ++ p2 = strstr(ld->structname[idx], ".") + 1; ++ strcpy(members, p2); ++ replace_string(members, ",", ' '); ++ argc = parse_line(members, arglist); ++ ++ for (i = 0; i < argc; i++) { ++ *p1 = NULLCHAR; ++ strcat(structname, arglist[i]); ++ dump_struct_member(structname, next - ld->list_head_offset, 0); ++ } ++ ++ FREEBUF(structname); ++ FREEBUF(members); ++} ++ ++/* + * The next set of functions are a general purpose hashing tool used to + * identify duplicate entries in a set of passed-in data, and if found, + * to fail the entry attempt. When a command wishes to verify a list +@@ -3552,6 +3729,52 @@ + return(-1); + } + ++/* ++ * For a given value, check to see if a hash queue entry exists. If an ++ * entry is found, return TRUE; for all other possibilities return FALSE. ++ */ ++int ++hq_entry_exists(ulong value) ++{ ++ struct hash_table *ht; ++ struct hq_entry *list_entry; ++ long hqi; ++ ++ if (!(pc->flags & HASH)) ++ return FALSE; ++ ++ ht = &hash_table; ++ ++ if (ht->flags & (HASH_QUEUE_NONE)) ++ return FALSE; ++ ++ if (!(ht->flags & HASH_QUEUE_OPEN)) ++ return FALSE; ++ ++ hqi = HQ_INDEX(value); ++ list_entry = ht->memptr + ht->queue_heads[hqi].next; ++ ++ while (TRUE) { ++ if (list_entry->value == value) ++ return TRUE; ++ ++ if (list_entry->next >= ht->count) { ++ error(INFO, corrupt_hq, ++ list_entry->value, ++ list_entry->next, ++ list_entry->order); ++ ht->flags |= HASH_QUEUE_NONE; ++ return FALSE; ++ } ++ ++ if (list_entry->next == 0) ++ break; ++ ++ list_entry = ht->memptr + list_entry->next; ++ } ++ ++ return FALSE; ++} + + /* + * K&R power function for integers +@@ -4210,6 +4433,9 @@ { ulonglong total, days, hours, minutes, seconds; @@ -3158,7 +4104,7 @@ total = (count)/(ulonglong)machdep->hz; days = total / SEC_DAYS; -@@ -4300,12 +4322,54 @@ +@@ -4300,12 +4526,58 @@ void command_not_supported() { @@ -3181,6 +4127,8 @@ + !DUMPFILE() || (pc->flags & RUNTIME)) + return; + ++ pc->flags |= PLEASE_WAIT; ++ + fprintf(fp, "\rplease wait... (%s)", s); + fflush(fp); +} @@ -3192,6 +4140,8 @@ + !DUMPFILE() || (pc->flags & RUNTIME)) + return; + ++ pc->flags &= ~PLEASE_WAIT; ++ + fprintf(fp, "\r \r"); + fflush(fp); +} @@ -3215,8 +4165,17 @@ + + return ((c2 == '\0') && (c1 == '/') && (*p1 == '\0')) ? 0 : c1 - c2; +} ---- crash/global_data.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/global_data.c 2006-08-14 11:40:07.000000000 -0400 +--- crash/global_data.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/global_data.c 2006-11-21 11:19:51.000000000 -0500 +@@ -68,7 +68,7 @@ + * To add a new command, declare it in defs.h and enter it in this table. + */ + +-struct command_table_entry base_command_table[] = { ++struct command_table_entry linux_command_table[] = { + {"*", cmd_pointer, help_pointer, 0}, + {"alias", cmd_alias, help_alias, 0}, + {"ascii", cmd_ascii, help_ascii, 0}, @@ -117,6 +117,9 @@ {"waitq", cmd_waitq, help_waitq, REFRESH_TASK_TABLE}, {"whatis", cmd_whatis, help_whatis, 0}, @@ -3227,8 +4186,19 @@ {(char *)NULL} }; ---- crash/memory.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/memory.c 2006-09-06 15:55:00.000000000 -0400 +--- crash/memory.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/memory.c 2007-07-27 12:03:17.000000000 -0400 +@@ -1,8 +1,8 @@ + /* memory.c - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002 Silicon Graphics, Inc. + * + * This program is free software; you can redistribute it and/or modify @@ -45,6 +45,8 @@ ulong *addrlist; int *kmem_bufctl; @@ -3283,7 +4253,7 @@ static int vm_area_page_dump(ulong, ulong, ulong, ulong, void *, struct reference *); static int dump_swap_info(ulong, ulong *, ulong *); -@@ -124,9 +135,24 @@ +@@ -124,9 +135,26 @@ static int compare_node_data(const void *, const void *); static void do_vm_flags(ulong); static void PG_reserved_flag_init(void); @@ -3307,10 +4277,12 @@ +static ulong next_online_pgdat(int); +static int vm_stat_init(void); +static int dump_vm_stat(char *, long *); ++static int generic_read_dumpfile(ulonglong, void *, long, char *, ulong); ++static int generic_write_dumpfile(ulonglong, void *, long, char *, ulong); /* * Memory display modes specific to this file. -@@ -142,6 +168,7 @@ +@@ -142,6 +170,7 @@ #define DECIMAL (0x100) #define UDECIMAL (0x200) #define ASCII_ENDLINE (0x400) @@ -3318,7 +4290,7 @@ static ulong DISPLAY_DEFAULT; -@@ -182,6 +209,13 @@ +@@ -182,6 +211,13 @@ MEMBER_OFFSET_INIT(mm_struct_mmap, "mm_struct", "mmap"); MEMBER_OFFSET_INIT(mm_struct_pgd, "mm_struct", "pgd"); MEMBER_OFFSET_INIT(mm_struct_rss, "mm_struct", "rss"); @@ -3332,7 +4304,7 @@ MEMBER_OFFSET_INIT(mm_struct_total_vm, "mm_struct", "total_vm"); MEMBER_OFFSET_INIT(mm_struct_start_code, "mm_struct", "start_code"); MEMBER_OFFSET_INIT(vm_area_struct_vm_mm, "vm_area_struct", "vm_mm"); -@@ -270,6 +304,7 @@ +@@ -270,6 +306,7 @@ STRUCT_SIZE_INIT(kmem_slab_s, "kmem_slab_s"); STRUCT_SIZE_INIT(slab_s, "slab_s"); STRUCT_SIZE_INIT(slab, "slab"); @@ -3340,7 +4312,7 @@ STRUCT_SIZE_INIT(pgd_t, "pgd_t"); if (!VALID_STRUCT(kmem_slab_s) && VALID_STRUCT(slab_s)) { -@@ -310,17 +345,49 @@ +@@ -310,17 +347,49 @@ !VALID_STRUCT(slab_s) && VALID_STRUCT(slab)) { vt->flags |= PERCPU_KMALLOC_V2; @@ -3401,7 +4373,7 @@ MEMBER_OFFSET_INIT(slab_list, "slab", "list"); MEMBER_OFFSET_INIT(slab_s_mem, "slab", "s_mem"); MEMBER_OFFSET_INIT(slab_inuse, "slab", "inuse"); -@@ -330,10 +397,6 @@ +@@ -330,10 +399,6 @@ MEMBER_OFFSET_INIT(array_cache_limit, "array_cache", "limit"); STRUCT_SIZE_INIT(array_cache, "array_cache"); @@ -3412,7 +4384,17 @@ MEMBER_OFFSET_INIT(kmem_list3_slabs_partial, "kmem_list3", "slabs_partial"); MEMBER_OFFSET_INIT(kmem_list3_slabs_full, -@@ -381,6 +444,19 @@ +@@ -343,6 +408,9 @@ + MEMBER_OFFSET_INIT(kmem_list3_free_objects, + "kmem_list3", "free_objects"); + MEMBER_OFFSET_INIT(kmem_list3_shared, "kmem_list3", "shared"); ++ } else if (MEMBER_EXISTS("kmem_cache", "cpu_slab") && ++ STRUCT_EXISTS("kmem_cache_node")) { ++ vt->flags |= KMALLOC_SLUB; + } else { + MEMBER_OFFSET_INIT(kmem_cache_s_c_nextp, + "kmem_cache_s", "c_nextp"); +@@ -381,6 +449,19 @@ "kmem_slab_s", "s_magic"); } @@ -3432,7 +4414,7 @@ if (machdep->init_kernel_pgd) machdep->init_kernel_pgd(); else if (symbol_exists("swapper_pg_dir")) { -@@ -415,10 +491,17 @@ +@@ -415,10 +496,17 @@ error(FATAL, "no swapper_pg_dir or cpu_pgd symbols exist?\n"); get_symbol_data("high_memory", sizeof(ulong), &vt->high_memory); @@ -3451,7 +4433,7 @@ vt->vmalloc_start = machdep->vmalloc_start(); if (IS_VMALLOC_ADDR(vt->mem_map)) vt->flags |= V_MEM_MAP; -@@ -478,7 +561,6 @@ +@@ -478,7 +566,6 @@ STRUCT_SIZE_INIT(free_area_struct, "free_area_struct"); STRUCT_SIZE_INIT(zone, "zone"); STRUCT_SIZE_INIT(zone_struct, "zone_struct"); @@ -3459,7 +4441,7 @@ STRUCT_SIZE_INIT(kmem_bufctl_t, "kmem_bufctl_t"); STRUCT_SIZE_INIT(swap_info_struct, "swap_info_struct"); STRUCT_SIZE_INIT(mm_struct, "mm_struct"); -@@ -488,13 +570,20 @@ +@@ -488,13 +575,20 @@ if (VALID_STRUCT(pglist_data)) { vt->flags |= ZONES; @@ -3483,7 +4465,7 @@ MEMBER_OFFSET_INIT(pglist_data_node_zones, "pglist_data", "node_zones"); -@@ -524,6 +613,7 @@ +@@ -524,6 +618,7 @@ ARRAY_LENGTH_INIT(vt->nr_zones, pglist_data_node_zones, "pglist_data.node_zones", NULL, SIZE_OPTION(zone_struct, zone)); @@ -3491,7 +4473,7 @@ if (VALID_STRUCT(zone_struct)) { MEMBER_OFFSET_INIT(zone_struct_free_pages, -@@ -539,6 +629,8 @@ +@@ -539,6 +634,8 @@ if (INVALID_MEMBER(zone_struct_size)) MEMBER_OFFSET_INIT(zone_struct_memsize, "zone_struct", "memsize"); @@ -3500,7 +4482,36 @@ MEMBER_OFFSET_INIT(zone_struct_zone_start_paddr, "zone_struct", "zone_start_paddr"); MEMBER_OFFSET_INIT(zone_struct_zone_start_mapnr, -@@ -640,13 +732,7 @@ +@@ -565,8 +662,17 @@ + vt->dump_free_pages = dump_free_pages_zones_v1; + + } else if (VALID_STRUCT(zone)) { +- MEMBER_OFFSET_INIT(zone_free_pages, +- "zone", "free_pages"); ++ MEMBER_OFFSET_INIT(zone_vm_stat, "zone", "vm_stat"); ++ MEMBER_OFFSET_INIT(zone_free_pages, "zone", "free_pages"); ++ if (INVALID_MEMBER(zone_free_pages) && ++ VALID_MEMBER(zone_vm_stat)) { ++ long nr_free_pages = 0; ++ if (!enumerator_value("NR_FREE_PAGES", &nr_free_pages)) ++ error(WARNING, ++ "cannot determine NR_FREE_PAGES enumerator\n"); ++ ASSIGN_OFFSET(zone_free_pages) = OFFSET(zone_vm_stat) + ++ (nr_free_pages * sizeof(long)); ++ } + MEMBER_OFFSET_INIT(zone_free_area, + "zone", "free_area"); + MEMBER_OFFSET_INIT(zone_zone_pgdat, +@@ -603,6 +709,8 @@ + vt->dump_kmem_cache = dump_kmem_cache_percpu_v1; + else if (vt->flags & PERCPU_KMALLOC_V2) + vt->dump_kmem_cache = dump_kmem_cache_percpu_v2; ++ else if (vt->flags & KMALLOC_SLUB) ++ vt->flags |= KMEM_CACHE_UNAVAIL; /* TBD */ + else + vt->dump_kmem_cache = dump_kmem_cache; + +@@ -640,13 +748,7 @@ kmem_cache_init(); PG_reserved_flag_init(); @@ -3515,41 +4526,49 @@ } /* -@@ -685,7 +771,7 @@ +@@ -685,7 +787,7 @@ memtype = KVADDR; count = -1; - while ((c = getopt(argcnt, args, "e:pudDuso:81:3:6:")) != EOF) { -+ while ((c = getopt(argcnt, args, "xme:pudDuso:81:3:6:")) != EOF) { ++ while ((c = getopt(argcnt, args, "xme:pfudDuso:81:3:6:")) != EOF) { switch(c) { case '8': -@@ -748,12 +834,12 @@ +@@ -748,12 +850,12 @@ break; case 'p': - memtype &= ~(UVADDR|KVADDR); -+ memtype &= ~(UVADDR|KVADDR|XENMACHADDR); ++ memtype &= ~(UVADDR|KVADDR|XENMACHADDR|FILEADDR); memtype = PHYSADDR; break; case 'u': - memtype &= ~(KVADDR|PHYSADDR); -+ memtype &= ~(KVADDR|PHYSADDR|XENMACHADDR); ++ memtype &= ~(KVADDR|PHYSADDR|XENMACHADDR|FILEADDR); memtype = UVADDR; break; -@@ -767,6 +853,17 @@ +@@ -767,6 +869,25 @@ flag |= UDECIMAL; break; + case 'm': + if (!(kt->flags & ARCH_XEN)) + error(FATAL, "-m option only applies to xen architecture\n"); -+ memtype &= ~(UVADDR|KVADDR); ++ memtype &= ~(UVADDR|KVADDR|FILEADDR); + memtype = XENMACHADDR; + break; + ++ case 'f': ++ if (!pc->dumpfile) ++ error(FATAL, ++ "-f option requires a dumpfile\n"); ++ memtype &= ~(KVADDR|UVADDR|PHYSADDR|XENMACHADDR); ++ memtype = FILEADDR; ++ break; ++ + case 'x': + flag |= NO_ASCII; + break; @@ -3557,7 +4576,7 @@ default: argerrs++; break; -@@ -830,7 +927,7 @@ +@@ -830,7 +951,7 @@ error(WARNING, "ending address ignored when count is specified\n"); @@ -3566,7 +4585,7 @@ flag |= ASCII_ENDLINE; if (memtype == KVADDR) { -@@ -839,7 +936,6 @@ +@@ -839,7 +960,6 @@ } display_memory(addr, count, flag, memtype); @@ -3574,17 +4593,20 @@ } /* -@@ -903,6 +999,9 @@ +@@ -903,6 +1023,12 @@ case PHYSADDR: addrtype = "PHYSADDR"; break; + case XENMACHADDR: + addrtype = "XENMACHADDR"; ++ break; ++ case FILEADDR: ++ addrtype = "FILEADDR"; + break; } if (CRASHDEBUG(4)) -@@ -970,7 +1069,8 @@ +@@ -970,7 +1096,8 @@ case DISPLAY_64: if ((flag & (HEXADECIMAL|SYMBOLIC|DISPLAY_DEFAULT)) == (HEXADECIMAL|SYMBOLIC|DISPLAY_DEFAULT)) { @@ -3594,7 +4616,7 @@ fprintf(fp, "%-16s ", value_to_symstr(mem.u64, buf, 0)); linelen += strlen(buf)+1; -@@ -993,7 +1093,8 @@ +@@ -993,7 +1120,8 @@ case DISPLAY_32: if ((flag & (HEXADECIMAL|SYMBOLIC|DISPLAY_DEFAULT)) == (HEXADECIMAL|SYMBOLIC|DISPLAY_DEFAULT)) { @@ -3604,7 +4626,109 @@ fprintf(fp, INT_PRLEN == 16 ? "%-16s " : "%-8s ", value_to_symstr(mem.u32, -@@ -1376,6 +1477,7 @@ +@@ -1138,7 +1266,7 @@ + size = sizeof(void*); + addr_entered = value_entered = FALSE; + +- while ((c = getopt(argcnt, args, "ukp81:3:6:")) != EOF) { ++ while ((c = getopt(argcnt, args, "fukp81:3:6:")) != EOF) { + switch(c) + { + case '8': +@@ -1173,17 +1301,33 @@ + break; + + case 'p': ++ memtype &= ~(UVADDR|KVADDR|FILEADDR); + memtype = PHYSADDR; + break; + + case 'u': ++ memtype &= ~(PHYSADDR|KVADDR|FILEADDR); + memtype = UVADDR; + break; + + case 'k': ++ memtype &= ~(PHYSADDR|UVADDR|FILEADDR); + memtype = KVADDR; + break; + ++ case 'f': ++ /* ++ * Unsupported, but can be forcibly implemented ++ * by removing the DUMPFILE() check above and ++ * recompiling. ++ */ ++ if (!pc->dumpfile) ++ error(FATAL, ++ "-f option requires a dumpfile\n"); ++ memtype &= ~(PHYSADDR|UVADDR|KVADDR); ++ memtype = FILEADDR; ++ break; ++ + default: + argerrs++; + break; +@@ -1262,6 +1406,9 @@ + case PHYSADDR: + break; + ++ case FILEADDR: ++ break; ++ + case AMBIGUOUS: + error(INFO, + "ambiguous address: %llx (requires -p, -u or -k)\n", +@@ -1309,6 +1456,8 @@ + raw_data_dump(ulong addr, long count, int symbolic) + { + long wordcnt; ++ ulonglong address; ++ int memtype; + + switch (sizeof(long)) + { +@@ -1328,9 +1477,20 @@ + break; + } + +- display_memory(addr, wordcnt, ++ if (pc->curcmd_flags & MEMTYPE_FILEADDR) { ++ address = pc->curcmd_private; ++ memtype = FILEADDR; ++ } else if (pc->curcmd_flags & MEMTYPE_UVADDR) { ++ address = (ulonglong)addr; ++ memtype = UVADDR; ++ } else { ++ address = (ulonglong)addr; ++ memtype = KVADDR; ++ } ++ ++ display_memory(address, wordcnt, + HEXADECIMAL|DISPLAY_DEFAULT|(symbolic ? SYMBOLIC : ASCII_ENDLINE), +- KVADDR); ++ memtype); + } + + /* +@@ -1351,7 +1511,7 @@ + * is appropriate: + * + * addr a user, kernel or physical memory address. +- * memtype addr type: UVADDR, KVADDR or PHYSADDR. ++ * memtype addr type: UVADDR, KVADDR, PHYSADDR, XENMACHADDR or FILEADDR + * buffer supplied buffer to read the data into. + * size number of bytes to read. + * type string describing the request -- helpful when the read fails. +@@ -1368,6 +1528,7 @@ + #define SEEK_ERRMSG "seek error: %s address: %llx type: \"%s\"\n" + #define READ_ERRMSG "read error: %s address: %llx type: \"%s\"\n" + #define WRITE_ERRMSG "write error: %s address: %llx type: \"%s\"\n" ++#define PAGE_EXCLUDED_ERRMSG "page excluded: %s address: %llx type: \"%s\"\n" + + int + readmem(ulonglong addr, int memtype, void *buffer, long size, +@@ -1376,6 +1537,7 @@ int fd; long cnt; physaddr_t paddr; @@ -3612,15 +4736,19 @@ char *bufptr; if (CRASHDEBUG(4)) -@@ -1424,6 +1526,7 @@ +@@ -1424,7 +1586,11 @@ break; case PHYSADDR: + case XENMACHADDR: break; ++ ++ case FILEADDR: ++ return generic_read_dumpfile(addr, buffer, size, type, error_handle); } -@@ -1449,6 +1552,17 @@ + while (size > 0) { +@@ -1449,6 +1615,17 @@ case PHYSADDR: paddr = addr; break; @@ -3638,7 +4766,7 @@ } /* -@@ -1460,7 +1574,7 @@ +@@ -1460,7 +1637,7 @@ cnt = size; switch (READMEM(fd, bufptr, cnt, @@ -3647,7 +4775,19 @@ { case SEEK_ERROR: if (PRINT_ERROR_MESSAGE) -@@ -1610,6 +1724,9 @@ +@@ -1472,6 +1649,11 @@ + error(INFO, READ_ERRMSG, memtype_string(memtype, 0), addr, type); + goto readmem_error; + ++ case PAGE_EXCLUDED: ++ if (PRINT_ERROR_MESSAGE) ++ error(INFO, PAGE_EXCLUDED_ERRMSG, memtype_string(memtype, 0), addr, type); ++ goto readmem_error; ++ + default: + break; + } +@@ -1610,6 +1792,9 @@ int read_memory_device(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) { @@ -3657,17 +4797,109 @@ if (!machdep->verify_paddr(paddr)) { if (CRASHDEBUG(1)) error(INFO, "verify_paddr(%lx) failed\n", paddr); -@@ -1754,6 +1871,9 @@ +@@ -1754,6 +1939,12 @@ case PHYSADDR: sprintf(membuf, debug ? "PHYSADDR" : "physical"); break; + case XENMACHADDR: + sprintf(membuf, debug ? "XENMACHADDR" : "xen machine"); ++ break; ++ case FILEADDR: ++ sprintf(membuf, debug ? "FILEADDR" : "dumpfile"); + break; default: if (debug) sprintf(membuf, "0x%x (?)", memtype); -@@ -2113,6 +2233,8 @@ +@@ -1849,6 +2040,10 @@ + + case PHYSADDR: + break; ++ ++ ++ case FILEADDR: ++ return generic_write_dumpfile(addr, buffer, size, type, error_handle); + } + + while (size > 0) { +@@ -1946,6 +2141,77 @@ + } + + /* ++ * Generic dumpfile read/write functions to handle FILEADDR ++ * memtype arguments to readmem() and writemem(). These are ++ * not to be confused with pc->readmem/writemem plug-ins. ++ */ ++static int ++generic_read_dumpfile(ulonglong addr, void *buffer, long size, char *type, ++ ulong error_handle) ++{ ++ int fd; ++ int retval; ++ ++ retval = TRUE; ++ ++ if (!pc->dumpfile) ++ error(FATAL, "command requires a dumpfile\n"); ++ ++ if ((fd = open(pc->dumpfile, O_RDONLY)) < 0) ++ error(FATAL, "%s: %s\n", pc->dumpfile, ++ strerror(errno)); ++ ++ if (lseek(fd, addr, SEEK_SET) == -1) { ++ if (PRINT_ERROR_MESSAGE) ++ error(INFO, SEEK_ERRMSG, ++ memtype_string(FILEADDR, 0), addr, type); ++ retval = FALSE; ++ } else if (read(fd, buffer, size) != size) { ++ if (PRINT_ERROR_MESSAGE) ++ error(INFO, READ_ERRMSG, ++ memtype_string(FILEADDR, 0), addr, type); ++ retval = FALSE; ++ } ++ ++ close(fd); ++ ++ return retval; ++} ++ ++static int ++generic_write_dumpfile(ulonglong addr, void *buffer, long size, char *type, ++ ulong error_handle) ++{ ++ int fd; ++ int retval; ++ ++ retval = TRUE; ++ ++ if (!pc->dumpfile) ++ error(FATAL, "command requires a dumpfile\n"); ++ ++ if ((fd = open(pc->dumpfile, O_WRONLY)) < 0) ++ error(FATAL, "%s: %s\n", pc->dumpfile, ++ strerror(errno)); ++ ++ if (lseek(fd, addr, SEEK_SET) == -1) { ++ if (PRINT_ERROR_MESSAGE) ++ error(INFO, SEEK_ERRMSG, ++ memtype_string(FILEADDR, 0), addr, type); ++ retval = FALSE; ++ } else if (write(fd, buffer, size) != size) { ++ if (PRINT_ERROR_MESSAGE) ++ error(INFO, WRITE_ERRMSG, ++ memtype_string(FILEADDR, 0), addr, type); ++ retval = FALSE; ++ } ++ ++ close(fd); ++ ++ return retval; ++} ++ ++/* + * Translates a kernel virtual address to its physical address. cmd_vtop() + * sets the verbose flag so that the pte translation gets displayed; all + * other callers quietly accept the translation. +@@ -2113,6 +2379,8 @@ break; } @@ -3676,7 +4908,7 @@ switch (memtype) { case UVADDR: fprintf(fp, "%s %s\n", -@@ -2126,9 +2248,12 @@ +@@ -2126,9 +2394,12 @@ return; } if (!uvtop(tc, vaddr, &paddr, 0)) { @@ -3691,7 +4923,7 @@ page_exists = FALSE; } else { fprintf(fp, "%s %s\n\n", -@@ -2161,9 +2286,13 @@ +@@ -2161,9 +2432,13 @@ } if (vtop_flags & USE_USER_PGD) { if (!uvtop(tc, vaddr, &paddr, 0)) { @@ -3707,7 +4939,7 @@ page_exists = FALSE; } else { fprintf(fp, "%s %s\n\n", -@@ -2176,9 +2305,13 @@ +@@ -2176,9 +2451,13 @@ uvtop(tc, vaddr, &paddr, VERBOSE); } else { if (!kvtop(tc, vaddr, &paddr, 0)) { @@ -3723,7 +4955,17 @@ page_exists = FALSE; } else { fprintf(fp, "%s %s\n\n", -@@ -2980,6 +3113,8 @@ +@@ -2839,7 +3118,8 @@ + + if (DO_REF_SEARCH(ref)) { + if (VM_REF_CHECK_DECVAL(ref, +- SWP_OFFSET(paddr))) { ++ THIS_KERNEL_VERSION >= LINUX(2,6,0) ? ++ __swp_offset(paddr) : SWP_OFFSET(paddr))) { + if (DO_REF_DISPLAY(ref)) + display = TRUE; + else { +@@ -2980,6 +3260,8 @@ return; tm->rss = ULONG(tt->mm_struct + OFFSET(mm_struct_rss)); @@ -3732,7 +4974,7 @@ tm->total_vm = ULONG(tt->mm_struct + OFFSET(mm_struct_total_vm)); tm->pgd_addr = ULONG(tt->mm_struct + OFFSET(mm_struct_pgd)); -@@ -3036,6 +3171,9 @@ +@@ -3036,6 +3318,9 @@ #define GET_INACTIVE_DIRTY (ADDRESS_SPECIFIED << 13) /* obsolete */ #define SLAB_GET_COUNTS (ADDRESS_SPECIFIED << 14) #define SLAB_WALKTHROUGH (ADDRESS_SPECIFIED << 15) @@ -3742,7 +4984,7 @@ #define GET_ALL \ (GET_SHARED_PAGES|GET_TOTALRAM_PAGES|GET_BUFFERS_PAGES|GET_SLAB_PAGES) -@@ -3046,7 +3184,7 @@ +@@ -3046,7 +3331,7 @@ int i; int c; int sflag, Sflag, pflag, fflag, Fflag, vflag; @@ -3751,7 +4993,7 @@ struct meminfo meminfo; ulonglong value[MAXARGS]; char buf[BUFSIZE]; -@@ -3055,13 +3193,17 @@ +@@ -3055,13 +3340,17 @@ spec_addr = 0; sflag = Sflag = pflag = fflag = Fflag = Pflag = 0; @@ -3771,7 +5013,7 @@ case 'n': nflag = 1; break; -@@ -3153,13 +3295,13 @@ +@@ -3153,13 +3442,13 @@ if (argerrs) cmd_usage(pc->curcmd, SYNOPSIS); @@ -3787,7 +5029,25 @@ kmem_cache_init(); while (args[optind]) { -@@ -3275,7 +3417,7 @@ +@@ -3198,8 +3487,6 @@ + if (pflag) { + meminfo.spec_addr = value[i]; + meminfo.flags = ADDRESS_SPECIFIED; +- if (meminfo.calls++) +- fprintf(fp, "\n"); + dump_mem_map(&meminfo); + pflag++; + } +@@ -3248,8 +3535,6 @@ + if (vflag) { + meminfo.spec_addr = value[i]; + meminfo.flags = ADDRESS_SPECIFIED; +- if (meminfo.calls++) +- fprintf(fp, "\n"); + dump_vmlist(&meminfo); + vflag++; + } +@@ -3275,7 +3560,7 @@ /* * no value arguments allowed! */ @@ -3796,7 +5056,7 @@ error(INFO, "no address arguments allowed with this option\n"); cmd_usage(pc->curcmd, SYNOPSIS); -@@ -3352,7 +3494,10 @@ +@@ -3352,7 +3637,10 @@ dump_page_lists(&meminfo); } @@ -3808,7 +5068,7 @@ cflag + Cflag + iflag + nflag + lflag + Lflag + meminfo.calls)) cmd_usage(pc->curcmd, SYNOPSIS); -@@ -3373,12 +3518,13 @@ +@@ -3373,12 +3661,13 @@ buf = (char *)GETBUF(SIZE(page)); if (!readmem(pageptr, KVADDR, buf, SIZE(page), @@ -3824,7 +5084,7 @@ if (count_bits_long(flags) == 1) vt->PG_reserved = flags; else -@@ -3386,12 +3532,50 @@ +@@ -3386,12 +3675,50 @@ if (CRASHDEBUG(2)) fprintf(fp, @@ -3876,7 +5136,7 @@ /* * dump_mem_map() displays basic data about each entry in the mem_map[] * array, or if an address is specified, just the mem_map[] entry for that -@@ -3438,22 +3622,20 @@ +@@ -3438,22 +3765,20 @@ #define PGMM_CACHED (512) static void @@ -3902,7 +5162,7 @@ char hdr[BUFSIZE]; char buf0[BUFSIZE]; char buf1[BUFSIZE]; -@@ -3462,6 +3644,7 @@ +@@ -3462,6 +3787,7 @@ char buf4[BUFSIZE]; char *page_cache; char *pcache; @@ -3910,7 +5170,7 @@ v22 = VALID_MEMBER(page_inode); /* page.inode vs. page.mapping */ -@@ -3549,22 +3732,52 @@ +@@ -3549,22 +3875,62 @@ done = FALSE; total_pages = 0; @@ -3930,7 +5190,15 @@ + * to the section with that page + */ + if (mi->flags & ADDRESS_SPECIFIED) { -+ ulong pfn = mi->spec_addr >> PAGESHIFT(); ++ ulong pfn; ++ physaddr_t tmp; ++ ++ if (pg_spec) { ++ if (!page_to_phys(mi->spec_addr, &tmp)) ++ return; ++ pfn = tmp >> PAGESHIFT(); ++ } else ++ pfn = mi->spec_addr >> PAGESHIFT(); + section_nr = pfn_to_section_nr(pfn); + } + @@ -3952,8 +5220,10 @@ + if (print_hdr) { - fprintf(fp, "%s%s", n ? "\n" : "", hdr); -+ fprintf(fp, "%s", hdr); ++ if (!(pc->curcmd_flags & HEADER_PRINTED)) ++ fprintf(fp, "%s", hdr); print_hdr = FALSE; ++ pc->curcmd_flags |= HEADER_PRINTED; } - nt = &vt->node_table[n]; @@ -3974,7 +5244,7 @@ i++, pp += SIZE(page), phys += PAGESIZE()) { if ((i % PGMM_CACHED) == 0) { -@@ -3581,7 +3794,7 @@ +@@ -3581,7 +3947,7 @@ continue; } @@ -3983,7 +5253,7 @@ } pcache = page_cache + ((i%PGMM_CACHED) * SIZE(page)); -@@ -3653,11 +3866,12 @@ +@@ -3653,11 +4019,12 @@ } continue; } @@ -3997,7 +5267,7 @@ mapping = ULONG(pcache + OFFSET(page_mapping)); index = ULONG(pcache + OFFSET(page_index)); -@@ -3700,6 +3914,20 @@ +@@ -3700,6 +4067,20 @@ space(MINSPACE), mkstring(buf4, 8, CENTER|RJUST, " "), " "); @@ -4018,7 +5288,7 @@ else fprintf(fp, "%s%s%s%s%s%s%8ld %2d ", mkstring(buf0, VADDR_PRLEN, -@@ -3862,88 +4090,533 @@ +@@ -3862,65 +4243,512 @@ FREEBUF(page_cache); } @@ -4082,10 +5352,23 @@ - * Compute bytes till end of page. - */ - cnt = PAGESIZE() - PAGEOFFSET(addr); -+ v22 = VALID_MEMBER(page_inode); /* page.inode vs. page.mapping */ - +- - if (cnt > size) - cnt = size; +- +- if (!readmem(addr, KVADDR, bufptr, size, +- "virtual page struct cache", RETURN_ON_ERROR|QUIET)) { +- BZERO(bufptr, size); +- if (!(vt->flags & V_MEM_MAP)) +- error(WARNING, +- "mem_map[] from %lx to %lx not accessible\n", +- addr, addr+size); +- } ++ v22 = VALID_MEMBER(page_inode); /* page.inode vs. page.mapping */ + +- addr += cnt; +- bufptr += cnt; +- size -= cnt; + if (v22) { + sprintf(hdr, "%s%s%s%s%s%s%s%sCNT FLAGS\n", + mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), @@ -4107,15 +5390,16 @@ + mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "MAPPING"), + space(MINSPACE), + mkstring(buf4, 8, CENTER|RJUST, "INDEX")); -+ } - -- if (!readmem(addr, KVADDR, bufptr, size, -- "virtual page struct cache", RETURN_ON_ERROR|QUIET)) { -- BZERO(bufptr, size); -- if (!(vt->flags & V_MEM_MAP)) -- error(WARNING, -- "mem_map[] from %lx to %lx not accessible\n", -- addr, addr+size); + } +-} +- +- +-/* +- * dump_page_hash_table() displays the entries in each page_hash_table. +- */ +- +-#define PGHASH_CACHED (1024) ++ + pg_spec = phys_spec = print_hdr = FALSE; + + switch (mi->flags) @@ -4141,63 +5425,33 @@ + default: + error(FATAL, "dump_mem_map: no memtype specified\n"); + break; - } ++ } + print_hdr = TRUE; + break; - -- addr += cnt; -- bufptr += cnt; -- size -= cnt; -- } --} ++ + case GET_ALL: + shared = 0; + reserved = 0; + buffers = 0; + slabs = 0; + break; - ++ + case GET_SHARED_PAGES: + shared = 0; + break; - --/* -- * dump_page_hash_table() displays the entries in each page_hash_table. -- */ ++ + case GET_TOTALRAM_PAGES: + reserved = 0; + break; - --#define PGHASH_CACHED (1024) ++ + case GET_BUFFERS_PAGES: + buffers = 0; + break; - --static void --dump_page_hash_table(struct meminfo *hi) --{ -- int i; -- int len, entry_len; -- ulong page_hash_table, head; -- struct list_data list_data, *ld; -- struct gnu_request req; -- long total_cached; -- long page_cache_size; -- ulong this_addr, searchpage; -- int errflag, found, cnt, populated, verbose; -- uint ival; -- ulong buffer_pages; -- char buf[BUFSIZE]; -- char hash_table[BUFSIZE]; -- char *pcache, *pghash_cache; ++ + case GET_SLAB_PAGES: + slabs = 0; + break; - -- if (!vt->page_hash_table) { -- if (hi->flags & VERBOSE) -- error(FATAL, -- "address_space page cache radix tree not supported\n"); ++ + default: + print_hdr = TRUE; + break; @@ -4209,8 +5463,10 @@ + + for (n = 0; n < vt->numnodes; n++) { + if (print_hdr) { -+ fprintf(fp, "%s%s", n ? "\n" : "", hdr); ++ if (!(pc->curcmd_flags & HEADER_PRINTED)) ++ fprintf(fp, "%s%s", n ? "\n" : "", hdr); + print_hdr = FALSE; ++ pc->curcmd_flags |= HEADER_PRINTED; + } + + nt = &vt->node_table[n]; @@ -4594,33 +5850,10 @@ + */ + +#define PGHASH_CACHED (1024) -+ -+static void -+dump_page_hash_table(struct meminfo *hi) -+{ -+ int i; -+ int len, entry_len; -+ ulong page_hash_table, head; -+ struct list_data list_data, *ld; -+ struct gnu_request req; -+ long total_cached; -+ long page_cache_size; -+ ulong this_addr, searchpage; -+ int errflag, found, cnt, populated, verbose; -+ uint ival; -+ ulong buffer_pages; -+ char buf[BUFSIZE]; -+ char hash_table[BUFSIZE]; -+ char *pcache, *pghash_cache; -+ -+ if (!vt->page_hash_table) { -+ if (hi->flags & VERBOSE) -+ error(FATAL, -+ "address_space page cache radix tree not supported\n"); - - if (symbol_exists("nr_pagecache")) { - buffer_pages = nr_blockdev_pages(); -@@ -4520,13 +5193,6 @@ + + static void + dump_page_hash_table(struct meminfo *hi) +@@ -4520,13 +5348,6 @@ */ static char *zone_hdr = "ZONE NAME SIZE FREE"; @@ -4634,7 +5867,7 @@ static void dump_free_pages_zones_v1(struct meminfo *fi) { -@@ -4610,7 +5276,7 @@ +@@ -4610,7 +5431,7 @@ } if (fi->flags == GET_FREE_HIGHMEM_PAGES) { @@ -4643,7 +5876,7 @@ readmem(node_zones+ OFFSET(zone_struct_free_pages), KVADDR, &value, sizeof(ulong), -@@ -4702,7 +5368,7 @@ +@@ -4702,7 +5523,7 @@ hq_close(); @@ -4652,7 +5885,7 @@ fi->retval = sum; return; } -@@ -4828,7 +5494,8 @@ +@@ -4828,7 +5649,8 @@ int order, errflag, do_search; ulong offset, verbose, value, sum, found; ulong this_addr; @@ -4662,7 +5895,7 @@ ulong zone_mem_map; ulong zone_start_paddr; ulong zone_start_pfn; -@@ -4886,7 +5553,6 @@ +@@ -4886,7 +5708,6 @@ node_zones = nt->pgdat + OFFSET(pglist_data_node_zones); for (i = 0; i < vt->nr_zones; i++) { @@ -4670,7 +5903,7 @@ if (fi->flags == GET_FREE_PAGES) { readmem(node_zones+ OFFSET(zone_free_pages), -@@ -4899,7 +5565,7 @@ +@@ -4899,7 +5720,7 @@ } if (fi->flags == GET_FREE_HIGHMEM_PAGES) { @@ -4679,7 +5912,7 @@ readmem(node_zones+ OFFSET(zone_free_pages), KVADDR, &value, sizeof(ulong), -@@ -4958,15 +5624,34 @@ +@@ -4958,15 +5779,34 @@ fprintf(fp, "%6ld ", value); @@ -4698,7 +5931,7 @@ zone_start_paddr = PTOB(zone_start_pfn); + if (!VALID_MEMBER(zone_zone_mem_map)) { -+ if (IS_SPARSEMEM()) { ++ if (IS_SPARSEMEM() || IS_DISCONTIGMEM()) { + zone_mem_map = 0; + if (size) { + phys = PTOB(zone_start_pfn); @@ -4717,7 +5950,7 @@ if (zone_mem_map) zone_start_mapnr = (zone_mem_map - nt->mem_map) / -@@ -4997,7 +5682,7 @@ +@@ -4997,7 +5837,7 @@ hq_close(); @@ -4726,7 +5959,7 @@ fi->retval = sum; return; } -@@ -5313,6 +5998,8 @@ +@@ -5313,6 +6153,8 @@ ulong freehighmem_pages; ulong totallowmem_pages; ulong freelowmem_pages; @@ -4735,7 +5968,7 @@ ulong pct; ulong value1, value2; uint tmp; -@@ -5334,6 +6021,14 @@ +@@ -5334,6 +6176,14 @@ get_buffers = meminfo.get_buffers; get_slabs = meminfo.get_slabs; @@ -4750,7 +5983,7 @@ fprintf(fp, kmeminfo_hdr); /* * Get total RAM based upon how the various versions of si_meminfo() -@@ -5409,12 +6104,26 @@ +@@ -5409,12 +6259,26 @@ } else get_symbol_data("page_cache_size", sizeof(long), &page_cache_size); @@ -4778,7 +6011,7 @@ pct = (page_cache_size * 100)/totalram_pages; fprintf(fp, "%10s %7ld %11s %3ld%% of TOTAL MEM\n", -@@ -5519,17 +6228,18 @@ +@@ -5519,17 +6383,18 @@ ulong nrpages; char *block_device_buf, *inode_buf, *address_space_buf; @@ -4802,7 +6035,7 @@ hq_open(); bdevcnt = do_list(ld); bdevlist = (ulong *)GETBUF(bdevcnt * sizeof(ulong)); -@@ -5575,15 +6285,17 @@ +@@ -5575,21 +6440,24 @@ char buf1[BUFSIZE]; char buf2[BUFSIZE]; ulong vmlist; @@ -4815,14 +6048,22 @@ + count = 0; while (next) { - if ((next == vmlist) && +- if ((next == vmlist) && - !(vi->flags & (GET_HIGHEST|GET_PHYS_TO_VMALLOC))) { ++ if (!(pc->curcmd_flags & HEADER_PRINTED) && (next == vmlist) && + !(vi->flags & (GET_HIGHEST|GET_PHYS_TO_VMALLOC| + GET_VMLIST_COUNT|GET_VMLIST))) { fprintf(fp, "%s ", mkstring(buf, MAX(strlen("VM_STRUCT"), VADDR_PRLEN), CENTER|LJUST, "VM_STRUCT")); -@@ -5599,6 +6311,20 @@ + fprintf(fp, "%s SIZE\n", + mkstring(buf, (VADDR_PRLEN * 2) + strlen(" - "), + CENTER|LJUST, "ADDRESS RANGE")); ++ pc->curcmd_flags |= HEADER_PRINTED; + } + + readmem(next+OFFSET(vm_struct_addr), KVADDR, +@@ -5599,6 +6467,20 @@ &size, sizeof(ulong), "vmlist size", FAULT_ON_ERROR); @@ -4843,7 +6084,7 @@ if (!(vi->flags & ADDRESS_SPECIFIED) || ((vi->memtype == KVADDR) && ((vi->spec_addr >= addr) && (vi->spec_addr < (addr+size))))) -@@ -5639,7 +6365,7 @@ +@@ -5639,7 +6521,7 @@ } } @@ -4852,7 +6093,7 @@ readmem(next+OFFSET(vm_struct_next), KVADDR, &next, sizeof(void *), "vmlist next", FAULT_ON_ERROR); -@@ -5647,6 +6373,9 @@ +@@ -5647,6 +6529,9 @@ if (vi->flags & GET_HIGHEST) vi->retval = addr+size; @@ -4862,7 +6103,7 @@ } /* -@@ -6136,9 +6865,14 @@ +@@ -6136,9 +7021,14 @@ if (vt->flags & KMEM_CACHE_UNAVAIL) return; @@ -4877,7 +6118,7 @@ if (!strlen(slab_hdr)) sprintf(slab_hdr, "SLAB%sMEMORY%sTOTAL ALLOCATED FREE\n", -@@ -6177,9 +6911,11 @@ +@@ -6177,9 +7067,11 @@ if (!readmem(cache, KVADDR, cache_buf, SIZE(kmem_cache_s), "kmem_cache_s buffer", RETURN_ON_ERROR)) { @@ -4890,7 +6131,7 @@ return; } -@@ -6190,6 +6926,13 @@ +@@ -6190,6 +7082,13 @@ if ((tmp = max_cpudata_limit(cache, &tmp2)) > max_limit) max_limit = tmp; @@ -4904,7 +6145,7 @@ if (tmp2 > max_cpus) max_cpus = tmp2; -@@ -6237,6 +6980,8 @@ +@@ -6237,6 +7136,8 @@ NULL, 0); } @@ -4913,7 +6154,7 @@ vt->flags |= KMEM_CACHE_INIT; } -@@ -6250,25 +6995,32 @@ +@@ -6250,25 +7151,32 @@ ulong cpudata[NR_CPUS]; int limit; ulong max_limit; @@ -4959,7 +6200,7 @@ if (limit > max_limit) max_limit = limit; } -@@ -6279,22 +7031,89 @@ +@@ -6279,22 +7187,89 @@ kmem_cache_s_array: @@ -5056,7 +6297,7 @@ } /* -@@ -6353,6 +7172,7 @@ +@@ -6353,6 +7328,7 @@ #define KMEM_OBJECT_ADDR_INUSE (4) #define KMEM_OBJECT_ADDR_CACHED (5) #define KMEM_ON_SLAB (6) @@ -5064,7 +6305,7 @@ #define DUMP_KMEM_CACHE_INFO_V1() \ { \ -@@ -6408,7 +7228,7 @@ +@@ -6408,7 +7384,7 @@ { \ char b1[BUFSIZE], b2[BUFSIZE]; \ ulong allocated, freeobjs; \ @@ -5073,7 +6314,7 @@ allocated = si->s_inuse - si->cpucached_slab; \ freeobjs = si->c_num - allocated - si->cpucached_slab; \ } else { \ -@@ -6419,8 +7239,8 @@ +@@ -6419,8 +7395,8 @@ mkstring(b1, VADDR_PRLEN, LJUST|LONG_HEX, MKSTR(si->slab)), \ mkstring(b2, VADDR_PRLEN, LJUST|LONG_HEX, MKSTR(si->s_mem)), \ si->c_num, allocated, \ @@ -5084,7 +6325,7 @@ } static void -@@ -6857,6 +7677,13 @@ +@@ -6857,6 +7833,13 @@ for (i = 0; i < vt->kmem_max_cpus; i++) si->cpudata[i] = (ulong *) GETBUF(vt->kmem_max_limit * sizeof(ulong)); @@ -5098,7 +6339,7 @@ cnt = 0; -@@ -6939,7 +7766,10 @@ +@@ -6939,7 +7922,10 @@ "kmem_cache_s num", FAULT_ON_ERROR); si->c_num = (ulong)tmp_val; @@ -5110,7 +6351,7 @@ if (!(si->flags & (ADDRESS_SPECIFIED|GET_SLAB_PAGES))) { DUMP_KMEM_CACHE_INFO_V2(); -@@ -6953,12 +7783,16 @@ +@@ -6953,12 +7939,16 @@ if (si->flags & (VERBOSE|ADDRESS_SPECIFIED)) { @@ -5129,7 +6370,7 @@ if (si->found) { fprintf(fp, kmem_cache_hdr); -@@ -7005,7 +7839,14 @@ +@@ -7005,7 +7995,14 @@ " %lx (cpu %d cache)\n", (ulong)si->spec_addr, si->cpu); break; @@ -5145,7 +6386,7 @@ break; } -@@ -7033,6 +7874,7 @@ +@@ -7033,6 +8030,7 @@ FREEBUF(si->kmem_bufctl); for (i = 0; i < vt->kmem_max_cpus; i++) FREEBUF(si->cpudata[i]); @@ -5153,55 +6394,15 @@ } -@@ -7569,73 +8411,298 @@ - } while (si->slab != slab_chains[s] && !list_borked); - } - -- FREEBUF(slab_buf); -+ FREEBUF(slab_buf); -+ if (!list_borked) -+ save_slab_data(si); -+ break; -+ -+ case SLAB_WALKTHROUGH: -+ specified_slab = si->slab; -+ si->flags |= SLAB_WALKTHROUGH; -+ si->flags &= ~SLAB_GET_COUNTS; -+ -+ for (s = 0; s < SLAB_CHAINS; s++) { -+ if (!slab_chains[s]) -+ continue; -+ -+ if (!specified_slab) { -+ if (!readmem(slab_chains[s], -+ KVADDR, &si->slab, sizeof(ulong), -+ "slabs", QUIET|RETURN_ON_ERROR)) { -+ error(INFO, -+ "%s: %s list: bad slab pointer: %lx\n", -+ si->curname, -+ slab_chain_name_v2[s], -+ slab_chains[s]); -+ list_borked = 1; -+ continue; -+ } -+ last = slab_chains[s]; -+ } else -+ last = 0; -+ -+ if (si->slab == slab_chains[s]) -+ continue; -+ -+ if (CRASHDEBUG(1)) { -+ fprintf(fp, "search cache: [%s] ", si->curname); -+ if (si->flags & ADDRESS_SPECIFIED) -+ fprintf(fp, "for %llx", si->spec_addr); -+ fprintf(fp, "\n"); -+ } -+ -+ do { -+ if (received_SIGINT()) -+ restart(0); -+ +@@ -7613,29 +8611,254 @@ + if (received_SIGINT()) + restart(0); + +- if (!verify_slab_v2(si, last, s)) { +- list_borked = 1; +- continue; +- } +- last = si->slab - OFFSET(slab_list); + if (!verify_slab_v2(si, last, s)) { + list_borked = 1; + continue; @@ -5354,15 +6555,14 @@ + } + } + - if (!list_borked) - save_slab_data(si); - break; - - case SLAB_WALKTHROUGH: -- specified_slab = si->slab; ++ if (!list_borked) ++ save_slab_data(si); ++ break; ++ ++ case SLAB_WALKTHROUGH: + specified_slab = si->slab; - si->flags |= SLAB_WALKTHROUGH; - si->flags &= ~SLAB_GET_COUNTS; ++ si->flags |= SLAB_WALKTHROUGH; ++ si->flags &= ~SLAB_GET_COUNTS; + slab_buf = GETBUF(SIZE(slab)); + for (index=0; (index < vt->kmem_cache_len_nodes) && start_address[index]; index++) + { @@ -5378,27 +6578,19 @@ + slab_chains[0], slab_chains[1], slab_chains[2]); + } -- for (s = 0; s < SLAB_CHAINS; s++) { -- if (!slab_chains[s]) -- continue; +- dump_slab_percpu_v2(si); + for (s = 0; s < SLAB_CHAINS; s++) { + if (!slab_chains[s]) + continue; - - if (!specified_slab) { - if (!readmem(slab_chains[s], -- KVADDR, &si->slab, sizeof(ulong), -- "slabs", QUIET|RETURN_ON_ERROR)) { -- error(INFO, -- "%s: %s list: bad slab pointer: %lx\n", ++ ++ if (!specified_slab) { ++ if (!readmem(slab_chains[s], + KVADDR, &si->slab, sizeof(ulong), + "slabs", QUIET|RETURN_ON_ERROR)) { + error(INFO, + "%s: %s list: bad slab pointer: %lx\n", - si->curname, - slab_chain_name_v2[s], -- slab_chains[s]); -- list_borked = 1; ++ si->curname, ++ slab_chain_name_v2[s], + slab_chains[s]); + list_borked = 1; + continue; @@ -5408,12 +6600,14 @@ + last = 0; + + if (si->slab == slab_chains[s]) - continue; ++ continue; + + readmem(si->slab, KVADDR, slab_buf, + SIZE(slab), "slab buffer", + FAULT_ON_ERROR); -+ + +- if (si->found) { +- return; + si->s_mem = ULONG(slab_buf + + OFFSET(slab_s_mem)); + @@ -5423,23 +6617,7 @@ + fprintf(fp, "for %llx", si->spec_addr); + fprintf(fp, "\n"); } -- last = slab_chains[s]; -- } else -- last = 0; -- -- if (si->slab == slab_chains[s]) -- continue; -- -- if (CRASHDEBUG(1)) { -- fprintf(fp, "search cache: [%s] ", si->curname); -- if (si->flags & ADDRESS_SPECIFIED) -- fprintf(fp, "for %llx", si->spec_addr); -- fprintf(fp, "\n"); -- } - -- do { -- if (received_SIGINT()) -- restart(0); ++ + do { + if (received_SIGINT()) + { @@ -5447,22 +6625,7 @@ + FREEBUF(slab_buf); + restart(0); + } - -- if (!verify_slab_v2(si, last, s)) { -- list_borked = 1; -- continue; -- } -- last = si->slab - OFFSET(slab_list); -- -- dump_slab_percpu_v2(si); -- -- if (si->found) { -- return; -- } -- -- readmem(si->slab+OFFSET(slab_list), -- KVADDR, &si->slab, sizeof(ulong), -- "slab list", FAULT_ON_ERROR); ++ + if (!verify_slab_v2(si, last, s)) { + list_borked = 1; + continue; @@ -5477,6 +6640,10 @@ + return; + } +- readmem(si->slab+OFFSET(slab_list), +- KVADDR, &si->slab, sizeof(ulong), +- "slab list", FAULT_ON_ERROR); +- - si->slab -= OFFSET(slab_list); + readmem(si->slab+OFFSET(slab_list), + KVADDR, &si->slab, sizeof(ulong), @@ -5496,7 +6663,7 @@ } /* -@@ -7750,6 +8817,11 @@ +@@ -7750,6 +8973,11 @@ { int i; @@ -5508,7 +6675,7 @@ if (ACTIVE()) return; -@@ -7840,7 +8912,7 @@ +@@ -7840,7 +9068,7 @@ if (si->flags & ADDRESS_SPECIFIED) { if (INSLAB(si->slab, si) && (si->spec_addr >= si->slab) && @@ -5517,7 +6684,7 @@ si->found = KMEM_SLAB_ADDR; return; } -@@ -8213,7 +9285,7 @@ +@@ -8213,7 +9441,7 @@ */ if (si->c_flags & SLAB_CFLGS_BUFCTL) { @@ -5526,7 +6693,7 @@ obj = si->s_mem + ((next - si->s_index) * si->c_offset); DUMP_SLAB_OBJECT(); -@@ -8263,7 +9335,7 @@ +@@ -8263,7 +9491,7 @@ dump_slab_objects_percpu(struct meminfo *si) { int i, j; @@ -5535,7 +6702,7 @@ ulong cnt, expected; ulong obj; -@@ -8285,6 +9357,7 @@ +@@ -8285,6 +9513,7 @@ for (i = 0, obj = si->s_mem; i < si->c_num; i++, obj += si->size) { on_free_list = FALSE; on_cpudata_list = FALSE; @@ -5543,7 +6710,7 @@ for (j = 0; j < si->c_num; j++) { if (obj == si->addrlist[j]) { -@@ -8294,13 +9367,26 @@ +@@ -8294,13 +9523,26 @@ } on_cpudata_list = check_cpudata_list(si, obj); @@ -5571,7 +6738,7 @@ if (on_free_list) { if (!(si->flags & ADDRESS_SPECIFIED)) -@@ -8324,6 +9410,17 @@ +@@ -8324,6 +9566,17 @@ return; } } @@ -5589,7 +6756,7 @@ } else { if (!(si->flags & ADDRESS_SPECIFIED)) fprintf(fp, " [%lx]\n", obj); -@@ -8349,7 +9446,10 @@ +@@ -8349,7 +9602,10 @@ /* * Determine how many of the "inuse" slab objects are actually cached * in the kmem_cache_s header. Set the per-slab count and update the @@ -5601,7 +6768,7 @@ */ static void -@@ -8357,16 +9457,35 @@ +@@ -8357,16 +9613,35 @@ { int i; ulong obj; @@ -5637,7 +6804,7 @@ } } -@@ -8423,7 +9542,8 @@ +@@ -8423,7 +9698,8 @@ } /* @@ -5647,7 +6814,7 @@ */ static void gather_cpudata_list_v2(struct meminfo *si) -@@ -8431,6 +9551,7 @@ +@@ -8431,6 +9707,7 @@ int i, j; int avail; ulong cpudata[NR_CPUS]; @@ -5655,7 +6822,7 @@ readmem(si->cache+OFFSET(kmem_cache_s_array), KVADDR, &cpudata[0], -@@ -8466,8 +9587,152 @@ +@@ -8466,8 +9743,152 @@ if (CRASHDEBUG(2)) for (j = 0; j < avail; j++) @@ -5809,7 +6976,7 @@ } /* -@@ -8491,6 +9756,27 @@ +@@ -8491,6 +9912,27 @@ return FALSE; } @@ -5837,7 +7004,41 @@ /* * Search the various memory subsystems for instances of this address. -@@ -8690,6 +9976,16 @@ +@@ -8624,6 +10066,33 @@ + ulong ppstart, ppend; + struct node_table *nt; + ulong pgnum, node_size; ++ ulong nr, sec_addr; ++ ulong nr_mem_sections; ++ ulong coded_mem_map, mem_map, end_mem_map; ++ physaddr_t section_paddr; ++ ++ if (IS_SPARSEMEM()) { ++ nr_mem_sections = NR_MEM_SECTIONS(); ++ for (nr = 0; nr <= nr_mem_sections ; nr++) { ++ if ((sec_addr = valid_section_nr(nr))) { ++ coded_mem_map = section_mem_map_addr(sec_addr); ++ mem_map = sparse_decode_mem_map(coded_mem_map, nr); ++ end_mem_map = mem_map + (PAGES_PER_SECTION() * SIZE(page)); ++ ++ if ((addr >= mem_map) && (addr < end_mem_map)) { ++ if ((addr - mem_map) % SIZE(page)) ++ return FALSE; ++ if (phys) { ++ section_paddr = PTOB(section_nr_to_pfn(nr)); ++ pgnum = (addr - mem_map) / SIZE(page); ++ *phys = section_paddr + (pgnum * PAGESIZE()); ++ } ++ return TRUE; ++ } ++ } ++ } ++ return FALSE; ++ } + + for (n = 0; n < vt->numnodes; n++) { + nt = &vt->node_table[n]; +@@ -8690,6 +10159,16 @@ physaddr_t pstart, pend; ulong node_size; @@ -5854,7 +7055,7 @@ for (n = 0; n < vt->numnodes; n++) { nt = &vt->node_table[n]; if ((vt->flags & V_MEM_MAP) && (vt->numnodes == 1)) -@@ -8775,12 +10071,15 @@ +@@ -8775,12 +10254,15 @@ int i; struct node_table *nt; int others; @@ -5870,7 +7071,7 @@ if (vt->flags & ZONES) fprintf(fp, "%sZONES", others++ ? "|" : ""); if (vt->flags & PERCPU_KMALLOC_V1) -@@ -8797,6 +10096,19 @@ +@@ -8797,6 +10279,21 @@ fprintf(fp, "%sKMEM_CACHE_UNAVAIL", others++ ? "|" : ""); if (vt->flags & DISCONTIGMEM) fprintf(fp, "%sDISCONTIGMEM", others++ ? "|" : ""); @@ -5886,11 +7087,13 @@ + fprintf(fp, "%sPERCPU_KMALLOC_V2_NODES", others++ ? "|" : "");\ + if (vt->flags & VM_STAT) + fprintf(fp, "%sVM_STAT", others++ ? "|" : "");\ ++ if (vt->flags & KMALLOC_SLUB) ++ fprintf(fp, "%sKMALLOC_SLUB", others++ ? "|" : "");\ + fprintf(fp, ")\n"); if (vt->kernel_pgd[0] == vt->kernel_pgd[1]) fprintf(fp, " kernel_pgd[NR_CPUS]: %lx ...\n", -@@ -8825,6 +10137,7 @@ +@@ -8825,6 +10322,7 @@ fprintf(fp, " kmem_max_cpus: %ld\n", vt->kmem_max_cpus); fprintf(fp, " kmem_cache_count: %ld\n", vt->kmem_cache_count); fprintf(fp, " kmem_cache_namelen: %d\n", vt->kmem_cache_namelen); @@ -5898,7 +7101,7 @@ fprintf(fp, " PG_reserved: %lx\n", vt->PG_reserved); fprintf(fp, " PG_slab: %ld\n", vt->PG_slab); fprintf(fp, " paddr_prlen: %d\n", vt->paddr_prlen); -@@ -8834,12 +10147,12 @@ +@@ -8834,12 +10332,13 @@ for (i = 0; i < vt->numnodes; i++) { nt = &vt->node_table[i]; fprintf(fp, " node_table[%d]: \n", i); @@ -5911,13 +7114,14 @@ + fprintf(fp, " id: %d\n", nt->node_id); + fprintf(fp, " pgdat: %lx\n", nt->pgdat); + fprintf(fp, " size: %ld\n", nt->size); ++ fprintf(fp, " present: %ld\n", nt->present); + fprintf(fp, " mem_map: %lx\n", nt->mem_map); + fprintf(fp, " start_paddr: %llx\n", nt->start_paddr); + fprintf(fp, " start_mapnr: %ld\n", nt->start_mapnr); } fprintf(fp, " dump_free_pages: "); -@@ -8869,6 +10182,25 @@ +@@ -8869,6 +10368,25 @@ fprintf(fp, " nr_swapfiles: %d\n", vt->nr_swapfiles); fprintf(fp, " last_swap_read: %lx\n", vt->last_swap_read); fprintf(fp, " swap_info_struct: %lx\n", (ulong)vt->swap_info_struct); @@ -5943,7 +7147,25 @@ dump_vma_cache(VERBOSE); } -@@ -9321,6 +10653,43 @@ +@@ -8891,12 +10409,16 @@ + console(" id: %d\n", nt->node_id); + console(" pgdat: %lx\n", nt->pgdat); + console(" size: %ld\n", nt->size); ++ console(" present: %ld\n", nt->present); + console(" mem_map: %lx\n", nt->mem_map); + console(" start_paddr: %lx\n", nt->start_paddr); + console(" start_mapnr: %ld\n", nt->start_mapnr); + } + +- total += (uint64_t)((uint64_t)nt->size * (uint64_t)PAGESIZE()); ++ if (nt->present) ++ total += (uint64_t)((uint64_t)nt->present * (uint64_t)PAGESIZE()); ++ else ++ total += (uint64_t)((uint64_t)nt->size * (uint64_t)PAGESIZE()); + } + + return total; +@@ -9321,6 +10843,43 @@ } /* @@ -5987,7 +7209,7 @@ * Return the next kernel virtual address page that comes after * the passed-in address. */ -@@ -9348,6 +10717,8 @@ +@@ -9348,6 +10907,8 @@ if (IS_VMALLOC_ADDR(vaddr_orig)) { if (IS_VMALLOC_ADDR(vaddr) && (vaddr < vmalloc_limit)) { @@ -5996,7 +7218,7 @@ *nextvaddr = vaddr; return TRUE; } -@@ -9377,6 +10748,7 @@ +@@ -9377,6 +10938,7 @@ /* * We're in the physical range. */ @@ -6004,7 +7226,7 @@ return TRUE; } -@@ -9446,7 +10818,7 @@ +@@ -9446,7 +11008,7 @@ totalswap = totalused = 0; for (i = 0; i < vt->nr_swapfiles; i++, @@ -6013,7 +7235,7 @@ fill_swap_info(swap_info); flags = INT(vt->swap_info_struct + -@@ -9471,8 +10843,12 @@ +@@ -9471,8 +11033,12 @@ prio = INT(vt->swap_info_struct + OFFSET(swap_info_struct_prio)); @@ -6028,7 +7250,7 @@ swap_map = ULONG(vt->swap_info_struct + OFFSET(swap_info_struct_swap_map)); -@@ -9486,7 +10862,7 @@ +@@ -9486,7 +11052,7 @@ } else if (VALID_MEMBER (swap_info_struct_old_block_size)) { get_pathname(file_to_dentry(swap_file), @@ -6037,7 +7259,22 @@ } else { get_pathname(swap_file, buf, BUFSIZE, 1, 0); } -@@ -9741,14 +11117,16 @@ +@@ -9551,8 +11117,12 @@ + if (!pte) + return NULL; + +- sprintf(buf, "%s OFFSET: %lld", +- get_swapdev(SWP_TYPE(pte), swapdev), SWP_OFFSET(pte)); ++ if (THIS_KERNEL_VERSION >= LINUX(2,6,0)) ++ sprintf(buf, "%s OFFSET: %lld", ++ get_swapdev(__swp_type(pte), swapdev), __swp_offset(pte)); ++ else ++ sprintf(buf, "%s OFFSET: %llx", ++ get_swapdev(SWP_TYPE(pte), swapdev), SWP_OFFSET(pte)); + + return buf; + } +@@ -9741,14 +11311,16 @@ dump_memory_nodes(int initialize) { int i, j; @@ -6047,8 +7284,9 @@ ulong node_start_paddr; ulong node_start_pfn; ulong node_start_mapnr; - ulong node_spanned_pages; +- ulong node_spanned_pages; - ulong free_pages, zone_size, node_size; ++ ulong node_spanned_pages, node_present_pages; + ulong free_pages, zone_size, node_size, cum_zone_size; ulong zone_start_paddr, zone_start_mapnr, zone_mem_map; + physaddr_t phys; @@ -6056,7 +7294,7 @@ ulong zone_start_pfn; ulong bdata; ulong pgdat; -@@ -9761,31 +11139,54 @@ +@@ -9761,31 +11333,55 @@ char buf5[BUFSIZE]; struct node_table *nt; @@ -6093,6 +7331,7 @@ + fprintf(fp, " id: %d\n", nt->node_id); + fprintf(fp, " pgdat: %lx\n", nt->pgdat); + fprintf(fp, " size: %ld\n", nt->size); ++ fprintf(fp, " present: %ld\n", nt->present); + fprintf(fp, " mem_map: %lx\n", nt->mem_map); + fprintf(fp, " start_paddr: %llx\n", nt->start_paddr); + fprintf(fp, " start_mapnr: %ld\n", nt->start_mapnr); @@ -6132,7 +7371,7 @@ if (n >= vt->numnodes) error(FATAL, "numnodes out of sync with pgdat_list?\n"); -@@ -9794,9 +11195,14 @@ +@@ -9794,9 +11390,14 @@ readmem(pgdat+OFFSET(pglist_data_node_id), KVADDR, &id, sizeof(int), "pglist node_id", FAULT_ON_ERROR); @@ -6150,7 +7389,7 @@ if (VALID_MEMBER(pglist_data_node_start_paddr)) readmem(pgdat+OFFSET(pglist_data_node_start_paddr), -@@ -9808,6 +11214,11 @@ +@@ -9808,6 +11409,11 @@ "pglist node_start_pfn", FAULT_ON_ERROR); node_start_mapnr = node_start_pfn; node_start_paddr = PTOB(node_start_pfn); @@ -6162,7 +7401,25 @@ } else error(INFO, "cannot determine zone starting physical address\n"); -@@ -9840,6 +11251,16 @@ +@@ -9827,6 +11433,13 @@ + node_size = node_spanned_pages; + } else error(INFO, "cannot determine zone size\n"); + ++ if (VALID_MEMBER(pglist_data_node_present_pages)) ++ readmem(pgdat+OFFSET(pglist_data_node_present_pages), ++ KVADDR, &node_present_pages, sizeof(ulong), ++ "pglist node_present_pages", FAULT_ON_ERROR); ++ else ++ node_present_pages = 0; ++ + readmem(pgdat+OFFSET(pglist_data_bdata), KVADDR, &bdata, + sizeof(ulong), "pglist bdata", FAULT_ON_ERROR); + +@@ -9837,9 +11450,21 @@ + nt->size = 0; /* initialize below */ + else + nt->size = node_size; ++ nt->present = node_present_pages; nt->mem_map = node_mem_map; nt->start_paddr = node_start_paddr; nt->start_mapnr = node_start_mapnr; @@ -6172,6 +7429,7 @@ + fprintf(fp, " id: %d\n", nt->node_id); + fprintf(fp, " pgdat: %lx\n", nt->pgdat); + fprintf(fp, " size: %ld\n", nt->size); ++ fprintf(fp, " present: %ld\n", nt->present); + fprintf(fp, " mem_map: %lx\n", nt->mem_map); + fprintf(fp, " start_paddr: %llx\n", nt->start_paddr); + fprintf(fp, " start_mapnr: %ld\n", nt->start_mapnr); @@ -6179,7 +7437,7 @@ } if (!initialize) { -@@ -9896,9 +11317,10 @@ +@@ -9896,9 +11521,10 @@ } node_zones = pgdat + OFFSET(pglist_data_node_zones); @@ -6191,7 +7449,7 @@ if (VALID_MEMBER(zone_struct_size)) readmem(node_zones+OFFSET(zone_struct_size), -@@ -9915,6 +11337,7 @@ +@@ -9915,6 +11541,7 @@ "zone spanned_pages", FAULT_ON_ERROR); } else error(FATAL, "zone_struct has neither size nor memsize field\n"); @@ -6199,7 +7457,7 @@ readmem(node_zones+ OFFSET_OPTION(zone_struct_free_pages, zone_free_pages), KVADDR, &free_pages, -@@ -9926,12 +11349,24 @@ +@@ -9926,12 +11553,24 @@ if (!read_string(value, buf1, BUFSIZE-1)) sprintf(buf1, "(unknown) "); if (VALID_STRUCT(zone_struct)) { @@ -6230,7 +7488,7 @@ readmem(node_zones+ OFFSET(zone_struct_zone_start_mapnr), KVADDR, &zone_start_mapnr, -@@ -9946,28 +11381,65 @@ +@@ -9946,28 +11585,65 @@ "node_zones zone_start_pfn", FAULT_ON_ERROR); zone_start_paddr = PTOB(zone_start_pfn); @@ -6303,7 +7561,7 @@ fprintf(fp, "%s %s %s\n", mkstring(buf1, VADDR_PRLEN, RJUST|LONG_HEX,MKSTR(zone_mem_map)), -@@ -9981,12 +11453,22 @@ +@@ -9981,12 +11657,22 @@ node_zones += SIZE_OPTION(zone_struct, zone); } @@ -6332,22 +7590,32 @@ if ((n+1) < vt->numnodes) pgdat = vt->node_table[n+1].pgdat; else -@@ -9996,6 +11478,9 @@ +@@ -9994,8 +11680,15 @@ + } + } - if (n != vt->numnodes) - error(FATAL, "numnodes out of sync with pgdat_list?\n"); +- if (n != vt->numnodes) +- error(FATAL, "numnodes out of sync with pgdat_list?\n"); ++ if (n != vt->numnodes) { ++ if (CRASHDEBUG(2)) ++ error(NOTE, "changing numnodes from %d to %d\n", ++ vt->numnodes, n); ++ vt->numnodes = n; ++ } + + if (!initialize && IS_SPARSEMEM()) + dump_mem_sections(); } /* -@@ -10011,19 +11496,21 @@ +@@ -10011,20 +11704,25 @@ * Override numnodes -- some kernels may leave it at 1 on a system * with multiple memory nodes. */ - get_symbol_data("pgdat_list", sizeof(void *), &pgdat); -- ++ if ((vt->flags & NODES) && (VALID_MEMBER(pglist_data_node_next) || ++ VALID_MEMBER(pglist_data_pgdat_next))) { + - for (n = 0; pgdat; n++) { - readmem(pgdat + OFFSET_OPTION(pglist_data_node_next, - pglist_data_pgdat_next), KVADDR, @@ -6359,7 +7627,7 @@ - error(NOTE, "changing numnodes from %d to %d\n", - vt->numnodes, n); - vt->numnodes = n; -+ if (vt->flags & NODES) { +- } + get_symbol_data("pgdat_list", sizeof(void *), &pgdat); + + for (n = 0; pgdat; n++) { @@ -6374,10 +7642,12 @@ + vt->numnodes, n); + vt->numnodes = n; + } - } ++ } else ++ vt->flags &= ~NODES; if (!(vt->node_table = (struct node_table *) -@@ -10072,6 +11559,9 @@ + malloc(sizeof(struct node_table) * vt->numnodes))) +@@ -10072,6 +11770,9 @@ { uint psz; @@ -6387,7 +7657,7 @@ if (REMOTE_MEMSRC()) return remote_page_size(); -@@ -10081,6 +11571,14 @@ +@@ -10081,6 +11782,14 @@ psz = diskdump_page_size(); break; @@ -6402,7 +7672,7 @@ case NETDUMP: psz = netdump_page_size(); break; -@@ -10115,6 +11613,48 @@ +@@ -10115,6 +11824,50 @@ } /* @@ -6424,11 +7694,13 @@ + case 'k': + case 'K': + LASTCHAR(s) = NULLCHAR; -+ if (decimal(s, 0)) -+ k = 1024; -+ else ++ if (!decimal(s, 0)) { + err = TRUE; -+ break; ++ break; ++ } ++ k = 1024; ++ ++ /* FALLTHROUGH */ + + default: + if (decimal(s, 0)) @@ -6451,7 +7723,7 @@ * Return the vmalloc address referenced by the first vm_struct * on the vmlist. This can normally be used by the machine-specific * xxx_vmalloc_start() routines. -@@ -10127,6 +11667,9 @@ +@@ -10127,6 +11880,9 @@ get_symbol_data("vmlist", sizeof(void *), &vmlist); @@ -6461,7 +7733,7 @@ if (!readmem(vmlist+OFFSET(vm_struct_addr), KVADDR, &addr, sizeof(void *), "first vmlist addr", RETURN_ON_ERROR)) non_matching_kernel(); -@@ -10186,6 +11729,10 @@ +@@ -10186,6 +11942,10 @@ retval = remote_memory_used(); else if (pc->flags & NETDUMP) retval = netdump_memory_used(); @@ -6472,7 +7744,7 @@ else if (pc->flags & DISKDUMP) retval = diskdump_memory_used(); else if (pc->flags & LKCD) -@@ -10201,6 +11748,10 @@ +@@ -10201,6 +11961,10 @@ retval = remote_free_memory(); else if (pc->flags & NETDUMP) retval = netdump_free_memory(); @@ -6483,7 +7755,7 @@ else if (pc->flags & DISKDUMP) retval = diskdump_free_memory(); else if (pc->flags & LKCD) -@@ -10216,6 +11767,10 @@ +@@ -10216,6 +11980,10 @@ retval = remote_memory_dump(0); else if (pc->flags & NETDUMP) retval = netdump_memory_dump(fp); @@ -6494,7 +7766,7 @@ else if (pc->flags & DISKDUMP) retval = diskdump_memory_dump(fp); else if (pc->flags & LKCD) -@@ -10238,3 +11793,536 @@ +@@ -10238,3 +12006,563 @@ return retval; } @@ -6756,8 +8028,12 @@ + if (!symbol_exists("node_online_map")) + return 0; + -+ len = get_symbol_type("node_online_map", NULL, &req) == TYPE_CODE_UNDEF ? -+ sizeof(ulong) : req.length; ++ if (LKCD_KERNTYPES()) { ++ if ((len = STRUCT_SIZE("nodemask_t")) < 0) ++ error(FATAL, "cannot determine type nodemask_t\n"); ++ } else ++ len = get_symbol_type("node_online_map", NULL, &req) ++ == TYPE_CODE_UNDEF ? sizeof(ulong) : req.length; + + if (!(vt->node_online_map = (ulong *)malloc(len))) + error(FATAL, "cannot malloc node_online_map\n"); @@ -6826,27 +8102,36 @@ + /* + * Default -- look for type: struct pglist_data node_data[] + */ -+ if (get_symbol_type("node_data", NULL, NULL) != TYPE_CODE_ARRAY) -+ goto pgdat2; ++ if (LKCD_KERNTYPES()) { ++ if (!kernel_symbol_exists("node_data")) ++ goto pgdat2; ++ /* ++ * Just index into node_data[] without checking that it is ++ * an array; kerntypes have no such symbol information. ++ */ ++ } else { ++ if (get_symbol_type("node_data", NULL, NULL) != TYPE_CODE_ARRAY) ++ goto pgdat2; + -+ open_tmpfile(); -+ sprintf(buf, "whatis node_data"); -+ if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) { -+ close_tmpfile(); -+ goto pgdat2; -+ } -+ rewind(pc->tmpfile); -+ while (fgets(buf, BUFSIZE, pc->tmpfile)) { -+ if (STRNEQ(buf, "type = ")) -+ break; -+ } -+ close_tmpfile(); ++ open_tmpfile(); ++ sprintf(buf, "whatis node_data"); ++ if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) { ++ close_tmpfile(); ++ goto pgdat2; ++ } ++ rewind(pc->tmpfile); ++ while (fgets(buf, BUFSIZE, pc->tmpfile)) { ++ if (STRNEQ(buf, "type = ")) ++ break; ++ } ++ close_tmpfile(); + -+ if ((!strstr(buf, "struct pglist_data *") && -+ !strstr(buf, "pg_data_t *")) || -+ (count_chars(buf, '[') != 1) || -+ (count_chars(buf, ']') != 1)) -+ goto pgdat2; ++ if ((!strstr(buf, "struct pglist_data *") && ++ !strstr(buf, "pg_data_t *")) || ++ (count_chars(buf, '[') != 1) || ++ (count_chars(buf, ']') != 1)) ++ goto pgdat2; ++ } + + if (!readmem(symbol_value("node_data") + (node * sizeof(void *)), + KVADDR, &pgdat, sizeof(void *), "node_data", RETURN_ON_ERROR) || @@ -6856,27 +8141,32 @@ + return pgdat; + +pgdat2: -+ if (get_symbol_type("pgdat_list", NULL, NULL) != TYPE_CODE_ARRAY) -+ goto pgdat3; ++ if (LKCD_KERNTYPES()) { ++ if (!kernel_symbol_exists("pgdat_list")) ++ goto pgdat3; ++ } else { ++ if (get_symbol_type("pgdat_list",NULL,NULL) != TYPE_CODE_ARRAY) ++ goto pgdat3; + -+ open_tmpfile(); -+ sprintf(buf, "whatis pgdat_list"); -+ if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) { -+ close_tmpfile(); -+ goto pgdat3; -+ } -+ rewind(pc->tmpfile); -+ while (fgets(buf, BUFSIZE, pc->tmpfile)) { -+ if (STRNEQ(buf, "type = ")) -+ break; -+ } -+ close_tmpfile(); ++ open_tmpfile(); ++ sprintf(buf, "whatis pgdat_list"); ++ if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) { ++ close_tmpfile(); ++ goto pgdat3; ++ } ++ rewind(pc->tmpfile); ++ while (fgets(buf, BUFSIZE, pc->tmpfile)) { ++ if (STRNEQ(buf, "type = ")) ++ break; ++ } ++ close_tmpfile(); + -+ if ((!strstr(buf, "struct pglist_data *") && -+ !strstr(buf, "pg_data_t *")) || -+ (count_chars(buf, '[') != 1) || -+ (count_chars(buf, ']') != 1)) -+ goto pgdat3; ++ if ((!strstr(buf, "struct pglist_data *") && ++ !strstr(buf, "pg_data_t *")) || ++ (count_chars(buf, '[') != 1) || ++ (count_chars(buf, ']') != 1)) ++ goto pgdat3; ++ } + + if (!readmem(symbol_value("pgdat_list") + (node * sizeof(void *)), + KVADDR, &pgdat, sizeof(void *), "pgdat_list", RETURN_ON_ERROR) || @@ -6913,27 +8203,36 @@ + /* + * look for type: type = atomic_long_t [] + */ -+ if (!symbol_exists("vm_stat") || -+ get_symbol_type("vm_stat", NULL, NULL) != TYPE_CODE_ARRAY) -+ goto bailout; ++ if (LKCD_KERNTYPES()) { ++ if (!symbol_exists("vm_stat")) ++ goto bailout; ++ /* ++ * Just assume that vm_stat is an array; there is ++ * no symbol info in a kerntypes file. ++ */ ++ } else { ++ if (!symbol_exists("vm_stat") || ++ get_symbol_type("vm_stat", NULL, NULL) != TYPE_CODE_ARRAY) ++ goto bailout; + -+ open_tmpfile(); -+ sprintf(buf, "whatis vm_stat"); -+ if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) { -+ close_tmpfile(); -+ goto bailout; -+ } -+ rewind(pc->tmpfile); -+ while (fgets(buf, BUFSIZE, pc->tmpfile)) { -+ if (STRNEQ(buf, "type = ")) -+ break; -+ } -+ close_tmpfile(); ++ open_tmpfile(); ++ sprintf(buf, "whatis vm_stat"); ++ if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) { ++ close_tmpfile(); ++ goto bailout; ++ } ++ rewind(pc->tmpfile); ++ while (fgets(buf, BUFSIZE, pc->tmpfile)) { ++ if (STRNEQ(buf, "type = ")) ++ break; ++ } ++ close_tmpfile(); + -+ if (!strstr(buf, "atomic_long_t") || -+ (count_chars(buf, '[') != 1) || -+ (count_chars(buf, ']') != 1)) -+ goto bailout; ++ if (!strstr(buf, "atomic_long_t") || ++ (count_chars(buf, '[') != 1) || ++ (count_chars(buf, ']') != 1)) ++ goto bailout; ++ } + + open_tmpfile(); + req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request)); @@ -7031,20 +8330,57 @@ + + return FALSE; +} ---- crash/filesys.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/filesys.c 2006-07-06 16:46:08.000000000 -0400 +--- crash/filesys.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/filesys.c 2007-07-20 11:11:57.000000000 -0400 @@ -1,8 +1,8 @@ /* filesys.c - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002, 2003, 2004, 2005 David Anderson - * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson -+ * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 -@@ -190,7 +190,15 @@ +@@ -18,7 +18,7 @@ + #include "defs.h" + #include + +-static void show_mounts(ulong, int); ++static void show_mounts(ulong, int, struct task_context *); + static int find_booted_kernel(void); + static int find_booted_system_map(void); + static int verify_utsname(char *); +@@ -33,7 +33,7 @@ + static int open_file_reference(struct reference *); + static void memory_source_init(void); + static int get_pathname_component(ulong, ulong, int, char *, char *); +-static ulong *get_mount_list(int *); ++static ulong *get_mount_list(int *, struct task_context *); + char *inode_type(char *, char *); + static void match_proc_version(void); + static void get_live_memory_source(void); +@@ -43,6 +43,7 @@ + static int memory_driver_init(void); + static int create_memory_device(dev_t); + static void *radix_tree_lookup(ulong, ulong, int); ++static int match_file_string(char *, char *, char *); + + #define DENTRY_CACHE (20) + #define INODE_CACHE (20) +@@ -99,6 +100,10 @@ + } + + if (pc->namelist) { ++ if (XEN_HYPER_MODE() && !pc->dumpfile) ++ error(FATAL, ++ "Xen hypervisor mode requires a dumpfile\n"); ++ + if (!pc->dumpfile && !get_proc_version()) + error(INFO, "/proc/version: %s\n", + strerror(errno)); +@@ -190,7 +195,15 @@ if (!netdump_init(pc->dumpfile, fp)) error(FATAL, "%s: initialization failed\n", pc->dumpfile); @@ -7061,7 +8397,45 @@ if (!diskdump_init(pc->dumpfile, fp)) error(FATAL, "%s: initialization failed\n", pc->dumpfile); -@@ -253,7 +261,11 @@ +@@ -217,10 +230,7 @@ + static void + match_proc_version(void) + { +- char command[BUFSIZE]; +- char buffer[BUFSIZE]; +- FILE *pipe; +- int found; ++ char buffer[BUFSIZE], *p1, *p2; + + if (pc->flags & KERNEL_DEBUG_QUERY) + return; +@@ -228,24 +238,7 @@ + if (!strlen(kt->proc_version)) + return; + +- sprintf(command, "/usr/bin/strings %s", pc->namelist); +- if ((pipe = popen(command, "r")) == NULL) { +- error(INFO, "%s: %s\n", pc->namelist, strerror(errno)); +- return; +- } +- +- found = FALSE; +- while (fgets(buffer, BUFSIZE-1, pipe)) { +- if (!strstr(buffer, "Linux version 2.")) +- continue; +- +- if (STREQ(buffer, kt->proc_version)) +- found = TRUE; +- break; +- } +- pclose(pipe); +- +- if (found) { ++ if (match_file_string(pc->namelist, kt->proc_version, buffer)) { + if (CRASHDEBUG(1)) { + fprintf(fp, "/proc/version:\n%s", kt->proc_version); + fprintf(fp, "%s:\n%s", pc->namelist, buffer); +@@ -253,7 +246,29 @@ return; } @@ -7070,19 +8444,183 @@ + pc->namelist, + strlen(pc->namelist) > 39 ? "\n " : " "); + ++ /* ++ * find_booted_system_map() requires VTOP(), which used to be a ++ * hardwired masking of the kernel address. But some architectures ++ * may not know what their physical base address is at this point, ++ * and others may have different machdep->kvbase values, so for all ++ * but the 0-based kernel virtual address architectures, bail out ++ * here with a relevant error message. ++ */ ++ if (!machine_type("S390") && !machine_type("S390X")) { ++ p1 = &kt->proc_version[strlen("Linux version ")]; ++ p2 = strstr(p1, " "); ++ *p2 = NULLCHAR; ++ error(WARNING, "/proc/version indicates kernel version: %s\n", p1); ++ error(FATAL, "please use the vmlinux file for that kernel version, or try using\n" ++ " the System.map for that kernel version as an additional argument.\n", p1); ++ clean_exit(1); ++ } ++ + if (find_booted_system_map()) pc->flags |= SYSMAP; } -@@ -1131,6 +1143,7 @@ - char *arglist[MAXARGS*2]; - ulong vfsmount = 0; +@@ -303,14 +318,12 @@ + for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) + cnt++; + +- if ((searchdirs = (char **)malloc(cnt * sizeof(char *))) +- == NULL) { ++ if ((searchdirs = calloc(cnt, sizeof(char *))) == NULL) { + error(INFO, "/usr/src/ directory list malloc: %s\n", + strerror(errno)); + closedir(dirp); + return default_searchdirs; + } +- BZERO(searchdirs, cnt * sizeof(char *)); + + for (i = 0; i < DEFAULT_SEARCHDIRS; i++) + searchdirs[i] = default_searchdirs[i]; +@@ -345,6 +358,16 @@ + closedir(dirp); + + searchdirs[cnt] = NULL; ++ } else { ++ if ((searchdirs = calloc(cnt, sizeof(char *))) == NULL) { ++ error(INFO, "search directory list malloc: %s\n", ++ strerror(errno)); ++ closedir(dirp); ++ return default_searchdirs; ++ } ++ for (i = 0; i < DEFAULT_SEARCHDIRS; i++) ++ searchdirs[i] = default_searchdirs[i]; ++ cnt = DEFAULT_SEARCHDIRS; + } + + if (redhat_kernel_directory_v1(dirbuf)) { +@@ -483,13 +506,11 @@ + find_booted_kernel(void) + { + char kernel[BUFSIZE]; +- char command[BUFSIZE]; + char buffer[BUFSIZE]; + char **searchdirs; + int i, preferred, wrapped; + DIR *dirp; + struct dirent *dp; +- FILE *pipe; + int found; + + pc->flags |= FINDKERNEL; +@@ -538,24 +559,11 @@ + !is_elf_file(kernel)) + continue; + +- sprintf(command, "/usr/bin/strings %s", kernel); +- if ((pipe = popen(command, "r")) == NULL) { +- error(INFO, "%s: %s\n", +- kernel, strerror(errno)); +- continue; +- } +- + if (CRASHDEBUG(1)) + fprintf(fp, "find_booted_kernel: check: %s\n", + kernel); + +- while (fgets(buffer, BUFSIZE-1, pipe)) { +- if (STREQ(buffer, kt->proc_version)) { +- found = TRUE; +- break; +- } +- } +- pclose(pipe); ++ found = match_file_string(kernel, kt->proc_version, buffer); + + if (found) + break; +@@ -797,30 +805,14 @@ + static int + verify_utsname(char *system_map) + { +- char command[BUFSIZE]; + char buffer[BUFSIZE]; +- FILE *pipe; +- int found; + ulong value; + struct new_utsname new_utsname; + +- sprintf(command, "/usr/bin/strings %s", system_map); +- if ((pipe = popen(command, "r")) == NULL) +- return FALSE; +- + if (CRASHDEBUG(1)) + fprintf(fp, "verify_utsname: check: %s\n", system_map); + +- found = FALSE; +- while (fgets(buffer, BUFSIZE-1, pipe)) { +- if (strstr(buffer, "D system_utsname")) { +- found = TRUE; +- break; +- } +- } +- pclose(pipe); +- +- if (!found) ++ if (!match_file_string(system_map, "D system_utsname", buffer)) + return FALSE; + + if (extract_hex(buffer, &value, NULLCHAR, TRUE) && +@@ -1125,6 +1117,8 @@ + { + int i; + int c, found; ++ struct task_context *tc, *namespace_context; ++ ulong value; + char *spec_string; + char buf1[BUFSIZE]; + char buf2[BUFSIZE]; +@@ -1133,7 +1127,9 @@ int flags = 0; -+ int mh_flag = 1; int save_next; - while ((c = getopt(argcnt, args, "if")) != EOF) { -@@ -1181,7 +1194,7 @@ +- while ((c = getopt(argcnt, args, "if")) != EOF) { ++ namespace_context = pid_to_context(1); ++ ++ while ((c = getopt(argcnt, args, "ifn:")) != EOF) { + switch(c) + { + case 'i': +@@ -1144,6 +1140,19 @@ + flags |= MOUNT_PRINT_FILES; + break; + ++ case 'n': ++ switch (str_to_context(optarg, &value, &tc)) { ++ case STR_PID: ++ case STR_TASK: ++ namespace_context = tc; ++ break; ++ case STR_INVALID: ++ error(FATAL, "invalid task or pid value: %s\n", ++ optarg); ++ break; ++ } ++ break; ++ + default: + argerrs++; + break; +@@ -1162,7 +1171,7 @@ + shift_string_left(spec_string, 2); + + open_tmpfile(); +- show_mounts(0, MOUNT_PRINT_ALL); ++ show_mounts(0, MOUNT_PRINT_ALL, namespace_context); + + found = FALSE; + rewind(pc->tmpfile); +@@ -1181,16 +1190,20 @@ continue; for (i = 0; i < c; i++) { @@ -7091,19 +8629,101 @@ found = TRUE; } if (found) { -@@ -1190,7 +1203,10 @@ + fp = pc->saved_fp; + if (flags) { sscanf(buf2,"%lx",&vfsmount); - show_mounts(vfsmount, flags); +- show_mounts(vfsmount, flags); ++ show_mounts(vfsmount, flags, ++ namespace_context); } else { - fprintf(fp, mount_hdr); -+ if (mh_flag) { ++ if (!(pc->curcmd_flags & HEADER_PRINTED)) { + fprintf(fp, mount_hdr); -+ mh_flag = 0; ++ pc->curcmd_flags |= HEADER_PRINTED; + } fprintf(fp, buf2); } found = FALSE; -@@ -1706,12 +1722,20 @@ +@@ -1200,7 +1213,7 @@ + close_tmpfile(); + } while (args[++optind]); + } else +- show_mounts(0, flags); ++ show_mounts(0, flags, namespace_context); + } + + /* +@@ -1208,7 +1221,7 @@ + */ + + static void +-show_mounts(ulong one_vfsmount, int flags) ++show_mounts(ulong one_vfsmount, int flags, struct task_context *namespace_context) + { + ulong one_vfsmount_list; + long sb_s_files; +@@ -1246,7 +1259,7 @@ + mount_cnt = 1; + mntlist = &one_vfsmount_list; + } else +- mntlist = get_mount_list(&mount_cnt); ++ mntlist = get_mount_list(&mount_cnt, namespace_context); + + if (!strlen(mount_hdr)) { + devlen = strlen("DEVNAME"); +@@ -1408,11 +1421,11 @@ + * Allocate and fill a list of the currently-mounted vfsmount pointers. + */ + static ulong * +-get_mount_list(int *cntptr) ++get_mount_list(int *cntptr, struct task_context *namespace_context) + { + struct list_data list_data, *ld; + int mount_cnt; +- ulong *mntlist, namespace, root; ++ ulong *mntlist, namespace, root, nsproxy, mnt_ns; + struct task_context *tc; + + ld = &list_data; +@@ -1421,9 +1434,26 @@ + if (symbol_exists("vfsmntlist")) { + get_symbol_data("vfsmntlist", sizeof(void *), &ld->start); + ld->end = symbol_value("vfsmntlist"); ++ } else if (VALID_MEMBER(task_struct_nsproxy)) { ++ tc = namespace_context; ++ ++ readmem(tc->task + OFFSET(task_struct_nsproxy), KVADDR, ++ &nsproxy, sizeof(void *), "task nsproxy", ++ FAULT_ON_ERROR); ++ if (!readmem(nsproxy + OFFSET(nsproxy_mnt_ns), KVADDR, ++ &mnt_ns, sizeof(void *), "nsproxy mnt_ns", ++ RETURN_ON_ERROR|QUIET)) ++ error(FATAL, "cannot determine mount list location!\n"); ++ if (!readmem(mnt_ns + OFFSET(mnt_namespace_root), KVADDR, ++ &root, sizeof(void *), "mnt_namespace root", ++ RETURN_ON_ERROR|QUIET)) ++ error(FATAL, "cannot determine mount list location!\n"); ++ ++ ld->start = root + OFFSET(vfsmount_mnt_list); ++ ld->end = mnt_ns + OFFSET(mnt_namespace_list); ++ + } else if (VALID_MEMBER(namespace_root)) { +- if (!(tc = pid_to_context(1))) +- tc = CURRENT_CONTEXT(); ++ tc = namespace_context; + + readmem(tc->task + OFFSET(task_struct_namespace), KVADDR, + &namespace, sizeof(void *), "task namespace", +@@ -1497,7 +1527,7 @@ + goto nopath; + + if (VALID_MEMBER(file_f_vfsmnt)) { +- mntlist = get_mount_list(&mount_cnt); ++ mntlist = get_mount_list(&mount_cnt, pid_to_context(1)); + vfsmount_buf = GETBUF(SIZE(vfsmount)); + + for (m = found = 0, vfsmnt = mntlist; +@@ -1706,15 +1736,30 @@ MEMBER_OFFSET_INIT(fs_struct_pwd, "fs_struct", "pwd"); MEMBER_OFFSET_INIT(fs_struct_rootmnt, "fs_struct", "rootmnt"); MEMBER_OFFSET_INIT(fs_struct_pwdmnt, "fs_struct", "pwdmnt"); @@ -7128,7 +8748,33 @@ MEMBER_OFFSET_INIT(file_f_dentry, "file", "f_dentry"); MEMBER_OFFSET_INIT(file_f_vfsmnt, "file", "f_vfsmnt"); MEMBER_OFFSET_INIT(file_f_count, "file", "f_count"); -@@ -1762,6 +1786,8 @@ ++ if (INVALID_MEMBER(file_f_dentry)) { ++ MEMBER_OFFSET_INIT(file_f_path, "file", "f_path"); ++ MEMBER_OFFSET_INIT(path_mnt, "path", "mnt"); ++ MEMBER_OFFSET_INIT(path_dentry, "path", "dentry"); ++ ASSIGN_OFFSET(file_f_dentry) = OFFSET(file_f_path) + OFFSET(path_dentry); ++ ASSIGN_OFFSET(file_f_vfsmnt) = OFFSET(file_f_path) + OFFSET(path_mnt); ++ } + MEMBER_OFFSET_INIT(dentry_d_inode, "dentry", "d_inode"); + MEMBER_OFFSET_INIT(dentry_d_parent, "dentry", "d_parent"); + MEMBER_OFFSET_INIT(dentry_d_covers, "dentry", "d_covers"); +@@ -1736,10 +1781,15 @@ + MEMBER_OFFSET_INIT(vfsmount_mnt_mountpoint, + "vfsmount", "mnt_mountpoint"); + MEMBER_OFFSET_INIT(namespace_root, "namespace", "root"); ++ MEMBER_OFFSET_INIT(task_struct_nsproxy, "task_struct", "nsproxy"); + if (VALID_MEMBER(namespace_root)) { + MEMBER_OFFSET_INIT(namespace_list, "namespace", "list"); + MEMBER_OFFSET_INIT(task_struct_namespace, + "task_struct", "namespace"); ++ } else if (VALID_MEMBER(task_struct_nsproxy)) { ++ MEMBER_OFFSET_INIT(nsproxy_mnt_ns, "nsproxy", "mnt_ns"); ++ MEMBER_OFFSET_INIT(mnt_namespace_root, "mnt_namespace", "root"); ++ MEMBER_OFFSET_INIT(mnt_namespace_list, "mnt_namespace", "list"); + } else if (THIS_KERNEL_VERSION >= LINUX(2,4,20)) { + if (CRASHDEBUG(2)) + fprintf(fp, "hardwiring namespace stuff\n"); +@@ -1762,6 +1812,8 @@ STRUCT_SIZE_INIT(umode_t, "umode_t"); STRUCT_SIZE_INIT(dentry, "dentry"); STRUCT_SIZE_INIT(files_struct, "files_struct"); @@ -7137,7 +8783,22 @@ STRUCT_SIZE_INIT(file, "file"); STRUCT_SIZE_INIT(inode, "inode"); STRUCT_SIZE_INIT(vfsmount, "vfsmount"); -@@ -1998,8 +2024,9 @@ +@@ -1777,8 +1829,12 @@ + + if (symbol_exists("height_to_maxindex")) { + int tmp; +- ARRAY_LENGTH_INIT(tmp, height_to_maxindex, +- "height_to_maxindex", NULL, 0); ++ if (LKCD_KERNTYPES()) ++ ARRAY_LENGTH_INIT_ALT(tmp, "height_to_maxindex", ++ "radix_tree_preload.nodes", NULL, 0); ++ else ++ ARRAY_LENGTH_INIT(tmp, height_to_maxindex, ++ "height_to_maxindex", NULL, 0); + STRUCT_SIZE_INIT(radix_tree_root, "radix_tree_root"); + STRUCT_SIZE_INIT(radix_tree_node, "radix_tree_node"); + MEMBER_OFFSET_INIT(radix_tree_root_height, +@@ -1998,8 +2054,9 @@ open_files_dump(ulong task, int flags, struct reference *ref) { struct task_context *tc; @@ -7149,7 +8810,7 @@ ulong fs_struct_addr; char *dentry_buf, *fs_struct_buf; ulong root_dentry, pwd_dentry; -@@ -2027,6 +2054,8 @@ +@@ -2027,6 +2084,8 @@ BZERO(root_pathname, BUFSIZE); BZERO(pwd_pathname, BUFSIZE); files_struct_buf = GETBUF(SIZE(files_struct)); @@ -7158,7 +8819,7 @@ fill_task_struct(task); sprintf(files_header, " FD%s%s%s%s%s%s%sTYPE%sPATH\n", -@@ -2107,24 +2136,42 @@ +@@ -2107,24 +2166,45 @@ files_struct_addr = ULONG(tt->task_struct + OFFSET(task_struct_files)); @@ -7192,8 +8853,11 @@ + if (fdtable_addr) { + readmem(fdtable_addr, KVADDR, fdtable_buf, + SIZE(fdtable), "fdtable buffer", FAULT_ON_ERROR); -+ max_fdset = INT(fdtable_buf + -+ OFFSET(fdtable_max_fdset)); ++ if (VALID_MEMBER(fdtable_max_fdset)) ++ max_fdset = INT(fdtable_buf + ++ OFFSET(fdtable_max_fdset)); ++ else ++ max_fdset = -1; + max_fds = INT(fdtable_buf + + OFFSET(fdtable_max_fds)); + } @@ -7211,7 +8875,7 @@ FREEBUF(files_struct_buf); return; } -@@ -2146,8 +2193,12 @@ +@@ -2146,8 +2226,12 @@ } } @@ -7226,7 +8890,7 @@ if (open_fds_addr) { if (VALID_MEMBER(files_struct_open_fds_init) && -@@ -2157,16 +2208,21 @@ +@@ -2157,16 +2241,21 @@ OFFSET(files_struct_open_fds_init), &open_fds, sizeof(fd_set)); else @@ -7251,7 +8915,17 @@ FREEBUF(files_struct_buf); return; } -@@ -2220,6 +2276,8 @@ +@@ -2175,7 +2264,8 @@ + for (;;) { + unsigned long set; + i = j * __NFDBITS; +- if (i >= max_fdset || i >= max_fds) ++ if (((max_fdset >= 0) && (i >= max_fdset)) || ++ (i >= max_fds)) + break; + set = open_fds.__fds_bits[j++]; + while (set) { +@@ -2220,6 +2310,8 @@ if (ref && (ref->cmdflags & FILES_REF_FOUND)) fprintf(fp, "\n"); @@ -7260,7 +8934,7 @@ FREEBUF(files_struct_buf); } -@@ -2494,6 +2552,20 @@ +@@ -2494,6 +2586,20 @@ } /* @@ -7281,20 +8955,156 @@ * get_pathname() fills in a pathname string for an ending dentry * See __d_path() in the kernel for help fixing problems. */ ---- crash/help.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/help.c 2006-08-29 17:03:09.000000000 -0400 +@@ -3575,3 +3681,29 @@ + + return TRUE; + } ++ ++static int ++match_file_string(char *filename, char *string, char *buffer) ++{ ++ int found; ++ char command[BUFSIZE]; ++ FILE *pipe; ++ ++ ++ sprintf(command, "/usr/bin/strings %s", filename); ++ if ((pipe = popen(command, "r")) == NULL) { ++ error(INFO, "%s: %s\n", filename, strerror(errno)); ++ return FALSE; ++ } ++ ++ found = FALSE; ++ while (fgets(buffer, BUFSIZE-1, pipe)) { ++ if (strstr(buffer, string)) { ++ found = TRUE; ++ break; ++ } ++ } ++ pclose(pipe); ++ ++ return found; ++} +--- crash/help.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/help.c 2007-07-20 15:17:26.000000000 -0400 @@ -1,8 +1,8 @@ /* help.c - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002, 2003, 2004, 2005 David Anderson - * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson -+ * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 -@@ -239,7 +239,7 @@ +@@ -19,7 +19,6 @@ + + static void reshuffle_cmdlist(void); + static int sort_command_name(const void *, const void *); +-static void display_help_screen(char *); + static void display_commands(void); + static void display_copying_info(void); + static void display_warranty_info(void); +@@ -106,34 +105,33 @@ + void + program_usage(int form) + { +- int i; +- char **p; +- FILE *less; ++ if (form == SHORT_FORM) { ++ fprintf(fp, program_usage_info[0], pc->program_name); ++ fprintf(fp, "\nEnter \"%s -h\" for details.\n", ++ pc->program_name); ++ clean_exit(1); ++ } else { ++ FILE *scroll; ++ char *scroll_command; ++ char **p; ++ ++ if ((scroll_command = setup_scroll_command()) && ++ (scroll = popen(scroll_command, "w"))) ++ fp = scroll; ++ else ++ scroll = NULL; + +- if (form == LONG_FORM) +- less = popen("/usr/bin/less", "w"); +- else +- less = NULL; +- +- p = program_usage_info; +- +- if (form == LONG_FORM) { +- if (less) +- fp = less; +- for (i = 0; program_usage_info[i]; i++, p++) { +- fprintf(fp, *p, pc->program_name); ++ for (p = program_usage_info; *p; p++) { ++ fprintf(fp, *p, pc->program_name); + fprintf(fp, "\n"); + } +- } else { +- fprintf(fp, *p, pc->program_name); +- fprintf(fp, "\nEnter \"%s -h\" for details.\n", +- pc->program_name); +- } +- fflush(fp); +- if (less) +- pclose(less); ++ fflush(fp); + +- clean_exit(1); ++ if (scroll) ++ pclose(scroll); ++ ++ clean_exit(0); ++ } + } + + +@@ -147,14 +145,16 @@ + struct command_table_entry *cp; + struct extension_table *ext; + +- for (pc->ncmds = 0, cp = &base_command_table[0]; cp->name; cp++) { ++ for (pc->ncmds = 0, cp = pc->cmd_table; cp->name; cp++) { + if (!(cp->flags & HIDDEN_COMMAND)) + pc->ncmds++; + } + + for (ext = extension_table; ext; ext = ext->next) { +- for (cp = ext->command_table; cp->name; cp++) +- pc->ncmds++; ++ for (cp = ext->command_table; cp->name; cp++) { ++ if (!(cp->flags & (CLEANUP|HIDDEN_COMMAND))) ++ pc->ncmds++; ++ } + } + + if (!pc->cmdlist) { +@@ -188,14 +188,16 @@ + for (i = 0; i < pc->cmdlistsz; i++) + pc->cmdlist[i] = NULL; + +- for (cnt = 0, cp = &base_command_table[0]; cp->name; cp++) { ++ for (cnt = 0, cp = pc->cmd_table; cp->name; cp++) { + if (!(cp->flags & HIDDEN_COMMAND)) + pc->cmdlist[cnt++] = cp->name; + } + + for (ext = extension_table; ext; ext = ext->next) { +- for (cp = ext->command_table; cp->name; cp++) +- pc->cmdlist[cnt++] = cp->name; ++ for (cp = ext->command_table; cp->name; cp++) { ++ if (!(cp->flags & (CLEANUP|HIDDEN_COMMAND))) ++ pc->cmdlist[cnt++] = cp->name; ++ } + } + + if (cnt > pc->cmdlistsz) +@@ -239,7 +241,7 @@ oflag = 0; while ((c = getopt(argcnt, args, @@ -7303,7 +9113,7 @@ switch(c) { case 'e': -@@ -303,7 +303,11 @@ +@@ -303,7 +305,11 @@ return; case 'k': @@ -7316,7 +9126,7 @@ return; case 's': -@@ -349,6 +353,7 @@ +@@ -349,6 +355,7 @@ fprintf(fp, " -D - dumpfile memory usage\n"); fprintf(fp, " -f - filesys table\n"); fprintf(fp, " -k - kernel_table\n"); @@ -7324,7 +9134,25 @@ fprintf(fp, " -M machine specific\n"); fprintf(fp, " -m - machdep_table\n"); fprintf(fp, " -s - symbol table data\n"); -@@ -508,16 +513,16 @@ +@@ -389,7 +396,7 @@ + if (oflag) + dump_offset_table(args[optind], FALSE); + else +- cmd_usage(args[optind], COMPLETE_HELP); ++ cmd_usage(args[optind], COMPLETE_HELP|MUST_HELP); + optind++; + } while (args[optind]); + } +@@ -398,7 +405,7 @@ + * Format and display the help menu. + */ + +-static void ++void + display_help_screen(char *indent) + { + int i, j, rows; +@@ -508,16 +515,16 @@ " active perform the command(s) on the active thread on each CPU.\n", " If none of the task-identifying arguments above are entered, the command", " will be performed on all tasks.\n", @@ -7345,25 +9173,166 @@ +" files run the \"files\" command (optional flag: -R)", +" net run the \"net\" command (optional flags: -s -S -R)", +" set run the \"set\" command", -+" sig run the \"sig\" command", ++" sig run the \"sig\" command (optional flag: -g)", +" vtop run the \"vtop\" command (optional flags: -c -u -k)\n", " flag Pass this optional flag to the command selected.", " argument Pass this argument to the command selected.", " ", -@@ -1037,7 +1042,7 @@ +@@ -651,6 +658,10 @@ + " argument is entered, the current value of the %s variable is shown. These", + " are the %s variables, acceptable arguments, and purpose:\n", + " scroll on | off controls output scrolling.", ++" scroll less /usr/bin/less as the output scrolling program.", ++" scroll more /bin/more as the output scrolling program.", ++" scroll CRASHPAGER use CRASHPAGER environment variable as the", ++" output scrolling program.", + " radix 10 | 16 sets output radix to 10 or 16.", + " refresh on | off controls internal task list refresh.", + " print_max number set maximum number of array elements to print.", +@@ -665,6 +676,8 @@ + " edit vi | emacs set line editing mode (from .%src file only).", + " namelist filename name of kernel (from .%src file only).", + " dumpfile filename name of core dumpfile (from .%src file only).", ++" zero_excluded on | off controls whether excluded pages from a dumpfile", ++" should return zero-filled memory.", + " ", + " Internal variables may be set in four manners:\n", + " 1. entering the set command in $HOME/.%src.", +@@ -694,11 +707,11 @@ + " STATE: TASK_RUNNING (PANIC)\n", + " Turn off output scrolling:\n", + " %s> set scroll off", +-" scroll: off", ++" scroll: off (/usr/bin/less)", + " ", + " Show the current state of %s internal variables:\n", + " %s> set -v", +-" scroll: on", ++" scroll: on (/usr/bin/less)", + " radix: 10 (decimal)", + " refresh: on", + " print_max: 256", +@@ -710,6 +723,7 @@ + " edit: vi", + " namelist: vmlinux", + " dumpfile: vmcore", ++" zero_excluded: off", + " ", + " Show the current context:\n", + " %s> set", +@@ -787,7 +801,7 @@ + char *help_ps[] = { + "ps", + "display process status information", +-"[-k|-u][-s][-p|-c|-t|-l] [pid | taskp | command] ...", ++"[-k|-u][-s][-p|-c|-t|-l|-a|-g|-r] [pid | taskp | command] ...", + " This command displays process status for selected, or all, processes" , + " in the system. If no arguments are entered, the process data is", + " is displayed for all processes. Selected process identifiers can be", +@@ -822,8 +836,9 @@ + " On SMP machines, the active task on each CPU will be highlighted by an", + " angle bracket (\">\") preceding its information.", + " ", +-" Alternatively, information regarding parent-child relationships, or", +-" per-task time usage data may be displayed:", ++" Alternatively, information regarding parent-child relationships,", ++" per-task time usage data, argument/environment data, thread groups,", ++" or resource limits may be displayed:", + " ", + " -p display the parental hierarchy of selected, or all, tasks.", + " -c display the children of selected, or all, tasks.", +@@ -832,6 +847,10 @@ + " -l display the task last_run or timestamp value, whichever applies,", + " of selected, or all, tasks; the list is sorted with the most", + " recently-run task (largest last_run/timestamp) shown first.", ++" -a display the command line arguments and environment strings of", ++" selected, or all, user-mode tasks.", ++" -g display tasks by thread group, of selected, or all, tasks.", ++" -r display resource limits (rlimits) of selected, or all, tasks.", + "\nEXAMPLES", + " Show the process status of all current tasks:\n", + " %s> ps", +@@ -1031,13 +1050,73 @@ + " 381 1 0 c34ddf28 IN 0.2 1316 224 automount", + " 391 1 1 c2777f28 IN 0.2 1316 224 automount", + " ...", ++" ", ++" Display the argument and environment data for the automount task:\n", ++" %s> ps -a automount", ++" PID: 3948 TASK: f722ee30 CPU: 0 COMMAND: \"automount\"", ++" ARG: /usr/sbin/automount --timeout=60 /net program /etc/auto.net", ++" ENV: SELINUX_INIT=YES", ++" CONSOLE=/dev/console", ++" TERM=linux", ++" INIT_VERSION=sysvinit-2.85", ++" PATH=/sbin:/usr/sbin:/bin:/usr/bin", ++" LC_MESSAGES=en_US", ++" RUNLEVEL=3", ++" runlevel=3", ++" PWD=/", ++" LANG=ja_JP.UTF-8", ++" PREVLEVEL=N", ++" previous=N", ++" HOME=/", ++" SHLVL=2", ++" _=/usr/sbin/automount", ++" ", ++" Display the tasks in the thread group containing task c20ab0b0:\n", ++" %s> ps -g c20ab0b0", ++" PID: 6425 TASK: f72f50b0 CPU: 0 COMMAND: \"firefox-bin\"", ++" PID: 6516 TASK: f71bf1b0 CPU: 0 COMMAND: \"firefox-bin\"", ++" PID: 6518 TASK: d394b930 CPU: 0 COMMAND: \"firefox-bin\"", ++" PID: 6520 TASK: c20aa030 CPU: 0 COMMAND: \"firefox-bin\"", ++" PID: 6523 TASK: c20ab0b0 CPU: 0 COMMAND: \"firefox-bin\"", ++" PID: 6614 TASK: f1f181b0 CPU: 0 COMMAND: \"firefox-bin\"", ++" ", ++" Display the tasks in the thread group for each instance of the", ++" program named \"multi-thread\":\n", ++" %s> ps -g multi-thread", ++" PID: 2522 TASK: 1003f0dc7f0 CPU: 1 COMMAND: \"multi-thread\"", ++" PID: 2523 TASK: 10037b13030 CPU: 1 COMMAND: \"multi-thread\"", ++" PID: 2524 TASK: 1003e064030 CPU: 1 COMMAND: \"multi-thread\"", ++" PID: 2525 TASK: 1003e13a7f0 CPU: 1 COMMAND: \"multi-thread\"", ++" ", ++" PID: 2526 TASK: 1002f82b7f0 CPU: 1 COMMAND: \"multi-thread\"", ++" PID: 2527 TASK: 1003e1737f0 CPU: 1 COMMAND: \"multi-thread\"", ++" PID: 2528 TASK: 10035b4b7f0 CPU: 1 COMMAND: \"multi-thread\"", ++" PID: 2529 TASK: 1003f0c37f0 CPU: 1 COMMAND: \"multi-thread\"", ++" PID: 2530 TASK: 10035597030 CPU: 1 COMMAND: \"multi-thread\"", ++" PID: 2531 TASK: 100184be7f0 CPU: 1 COMMAND: \"multi-thread\"", ++" ", ++" Display the resource limits of \"bash\" task 13896:\n", ++" %s> ps -r 13896", ++" PID: 13896 TASK: cf402000 CPU: 0 COMMAND: \"bash\"", ++" RLIMIT CURRENT MAXIMUM", ++" CPU (unlimited) (unlimited)", ++" FSIZE (unlimited) (unlimited)", ++" DATA (unlimited) (unlimited)", ++" STACK 10485760 (unlimited)", ++" CORE (unlimited) (unlimited)", ++" RSS (unlimited) (unlimited)", ++" NPROC 4091 4091", ++" NOFILE 1024 1024", ++" MEMLOCK 4096 4096", ++" AS (unlimited) (unlimited)", ++" LOCKS (unlimited) (unlimited)", + NULL + }; + char *help_rd[] = { "rd", "read memory", -"[-dDsup][-8|-16|-32|-64][-o offs][-e addr] [address|symbol] [count]", -+"[-dDsupxm][-8|-16|-32|-64][-o offs][-e addr] [address|symbol] [count]", ++"[-dDsupxmf][-8|-16|-32|-64][-o offs][-e addr] [address|symbol] [count]", " This command displays the contents of memory, with the output formatted", " in several different manners. The starting address may be entered either", " symbolically or by address. The default output size is the size of a long", -@@ -1046,9 +1051,11 @@ +@@ -1046,9 +1125,12 @@ " -p address argument is a physical address.", " -u address argument is a user virtual address; only required on", " processors with common user and kernel virtual address spaces.", +" -m address argument is a xen host machine address.", ++" -f address argument is a dumpfile offset.", " -d display output in signed decimal format (default is hexadecimal).", " -D display output in unsigned decimal format (default is hexadecimal).", " -s displays output symbolically when appropriate.", @@ -7371,7 +9340,17 @@ #ifdef NOTDEF " -o Shows offset value from the starting address.", #endif -@@ -1155,7 +1162,7 @@ +@@ -1064,7 +1146,8 @@ + " 3. -u specifies a user virtual address, but is only necessary on", + " processors with common user and kernel virtual address spaces.", + " symbol symbol of starting address to read.", +-" count number of memory locations to display (default is 1).", ++" count number of memory locations to display (default is 1); if entered,", ++" must be the last argument on the command line.", + "\nEXAMPLES", + " Display the kernel_version string:\n", + " %s> rd kernel_version 4 ", +@@ -1155,7 +1238,7 @@ "bt", "backtrace", #if defined(GDB_6_0) || defined(GDB_6_1) @@ -7380,7 +9359,7 @@ #else "[-a|-r|-t|-l|-e|-f|-g] [-R ref] [ -I ip ] [-S sp] [pid | taskp]", #endif -@@ -1167,6 +1174,9 @@ +@@ -1167,14 +1250,26 @@ " pages of memory containing the task_union structure.", " -t display all text symbols found from the last known stack location", " to the top of the stack. (helpful if the back trace fails)", @@ -7389,20 +9368,42 @@ +" fails or the -t option starts too high in the process stack).", " -l show file and line number of each stack trace text location.", " -e search the stack for possible kernel and user mode exception frames.", - " -E search the IRQ stacks (x86, x86_64 and PPC64), and the exception", -@@ -1175,6 +1185,11 @@ +-" -E search the IRQ stacks (x86, x86_64 and PPC64), and the exception", ++" -E search the IRQ stacks (x86, x86_64 and ppc64), and the exception", + " stacks (x86_64) for possible exception frames; all other arguments", + " will be ignored since this is not a context-sensitive operation.", " -f display all stack data contained in a frame; this option can be", - " used to determine the arguments passed to each function (x86 only);", - " on IA64, the argument register contents are dumped.", -+" -o use old backtrace method, permissable only on kernels that were", -+" compiled without the -fomit-frame_pointer (x86 only).", -+" -O use old backtrace method by default, permissable only on kernels", -+" that were compiled without the -fomit-frame_pointer; subsequent", -+" usage of this option toggles the backtrace method (x86 only).", +-" used to determine the arguments passed to each function (x86 only);", +-" on IA64, the argument register contents are dumped.", ++" used to determine the arguments passed to each function; on ia64,", ++" the argument register contents are dumped.", ++" -o x86: use old backtrace method, permissable only on kernels that were", ++" compiled without the -fomit-frame_pointer.", ++" x86_64: use old backtrace method, which dumps potentially stale", ++" kernel text return addresses found on the stack.", ++" -O x86: use old backtrace method by default, permissable only on kernels", ++" that were compiled without the -fomit-frame_pointer; subsequent usage", ++" of this option toggles the backtrace method.", ++" x86_64: use old backtrace method by default; subsequent usage of this", ++" option toggles the backtrace method.", #if !defined(GDB_6_0) && !defined(GDB_6_1) " -g use gdb stack trace code. (alpha only)", #endif -@@ -1439,12 +1454,13 @@ +@@ -1189,11 +1284,8 @@ + " Note that all examples below are for x86 only. The output format will differ", + " for other architectures. x86 backtraces from kernels that were compiled", + " with the --fomit-frame-pointer CFLAG occasionally will drop stack frames,", +-" or display a stale frame reference. x86_64 backtraces are only slightly", +-" more intelligent than those generated from kernel oops messages; text return", +-" addresses shown in the back trace may include stale references. When in", +-" doubt as to the accuracy of a backtrace, the -t option may help fill in", +-" the blanks.\n", ++" or display a stale frame reference. When in doubt as to the accuracy of a", ++" backtrace, the -t or -T options may help fill in the blanks.\n", + "EXAMPLES", + " Display the stack trace of the active task(s) when the kernel panicked:\n", + " %s> bt -a", +@@ -1439,12 +1531,13 @@ " called \"echo\", which simply echoes back all arguments passed to it.", " Note the comments contained within it for further details. To build it,", " cut and paste the following output into a file, and call it, for example,", @@ -7420,7 +9421,72 @@ " located in the current directory, or in the user's $HOME directory.", " ", "---------------------------------- cut here ----------------------------------", -@@ -2013,7 +2029,7 @@ +@@ -1583,7 +1676,8 @@ + " This command displays the timer queue entries, both old- and new-style,", + " in chronological order. In the case of the old-style timers, the", + " timer_table array index is shown; in the case of the new-style timers, ", +-" the timer_list address is shown.", ++" the timer_list address is shown. On later kernels, the timer data is", ++" per-cpu.", + "\nEXAMPLES", + " %s> timer", + " JIFFIES", +@@ -1610,6 +1704,37 @@ + " 372010 c2323f7c c0112d6c ", + " 372138 c2191f10 c0112d6c ", + " 8653052 c1f13f10 c0112d6c ", ++" ", ++" Display the timer queue on a 2-cpu system:\n", ++" %s> timer", ++" TVEC_BASES[0]: c1299be0", ++" JIFFIES", ++" 18256298", ++" EXPIRES TIMER_LIST FUNCTION", ++" 18256406 cd5ddec0 c01232bb ", ++" 18256677 ceea93e0 c011e3cc ", ++" 18256850 ceea7f64 c01232bb ", ++" 18258751 cd1d4f64 c01232bb ", ++" 18258792 cf5782f0 c011e3cc ", ++" 18261266 c03c9f80 c022fad5 ", ++" 18262196 c02dc2e0 c0233329 ", ++" 18270518 ceb8bf1c c01232bb ", ++" 18271327 c03c9120 c0222074 ", ++" 18271327 c03ca580 c0233ace ", ++" 18272532 c02d1e18 c0129946 ", ++" 18276518 c03c9fc0 c022fd40 ", ++" 18332334 ceea9970 c011e3cc ", ++" 18332334 cfb6a840 c011e3cc ", ++" 18665378 cec25ec0 c01232bb ", ++" TVEC_BASES[1]: c12a1be0", ++" JIFFIES", ++" 18256298", ++" EXPIRES TIMER_LIST FUNCTION", ++" 18256493 c02c7d00 c013dad5 ", ++" 18256499 c12a2db8 c0129946 ", ++" 18277900 ceebaec0 c01232bb ", ++" 18283769 cf739f64 c01232bb ", ++" 18331902 cee8af64 c01232bb ", + NULL + }; + +@@ -1905,7 +2030,7 @@ + char *help_irq[] = { + "irq", + "IRQ data", +-"[-d | -b | [index ...]]", ++"[[[index ...] | -u] | -d | -b]", + " This command collaborates the data in an irq_desc_t, along with its", + " associated hw_interrupt_type and irqaction structure data, into a", + " consolidated per-IRQ display. Alternatively, the intel interrupt", +@@ -1913,6 +2038,7 @@ + " If no index value argument(s) nor any options are entered, the IRQ", + " data for all IRQs will be displayed.\n", + " index a valid IRQ index.", ++" -u dump data for in-use IRQs only.", + " -d dump the intel interrupt descriptor table.", + " -b dump bottom half data.", + "\nEXAMPLES", +@@ -2013,7 +2139,7 @@ char *help_sys[] = { "sys", "system data", @@ -7429,7 +9495,7 @@ " This command displays system-specific data. If no arguments are entered,\n" " the same system data shown during %s invocation is shown.\n", " -c [name|number] If no name or number argument is entered, dump all", -@@ -2023,6 +2039,8 @@ +@@ -2023,6 +2149,8 @@ " that number is displayed. If the current output radix", " has been set to 16, the system call numbers will be ", " displayed in hexadecimal.", @@ -7438,7 +9504,7 @@ " -panic Panic a live system. Requires write permission to", " /dev/mem. Results in the %s context causing an", " \"Attempted to kill the idle task!\" panic. (The dump", -@@ -2043,6 +2061,27 @@ +@@ -2043,6 +2171,27 @@ " VERSION: #24 SMP Mon Oct 11 17:41:40 CDT 1999", " MACHINE: i686 (500 MHz)", " MEMORY: 1 GB", @@ -7466,9 +9532,353 @@ "\n Dump the system call table:\n", " %s> sys -c", " NUM SYSTEM CALL FILE AND LINE NUMBER", -@@ -3324,7 +3363,8 @@ +@@ -2191,13 +2340,18 @@ + char *help_mount[] = { + "mount", + "mounted filesystem data", +-"[-f] [-i] [vfsmount | superblock | devname | dirname | inode]", ++"[-f] [-i] [-n pid|task] [vfsmount|superblock|devname|dirname|inode]", + " This command displays basic information about the currently-mounted", + " filesystems. The per-filesystem dirty inode list or list of open", + " files for the filesystem may also be displayed.\n", + " -f dump dentries and inodes for open files in each filesystem.", + " -i dump all dirty inodes associated with each filesystem.\n", +-" Filesystems may be selected in the following forms:\n", ++" For kernels supporting namespaces, the -n option may be used to", ++" display the mounted filesystems with respect to the namespace of a", ++" specified task:\n", ++" -n pid a process PID.", ++" -n task a hexadecimal task_struct pointer.\n", ++" Specific filesystems may be selected using the following forms:\n", + " vfsmount hexadecimal address of filesystem vfsmount structure.", + " superblock hexadecimal address of filesystem super_block structure.", + " devname device name of filesystem.", +@@ -2721,22 +2875,22 @@ + char *help_sig[] = { + "sig", + "task signal handling", +-"[[-l] | [-s sigset]] | [pid | taskp] ...", ++"[[-l] | [-s sigset]] | [-g] [pid | taskp] ...", + " This command displays signal-handling data of one or more tasks. Multiple", + " task or PID numbers may be entered; if no arguments are entered, the signal", + " handling data of the current context will be displayed. The default display", + " shows:", + " ", +-" 1. Whether the task has an unblocked signal pending.", +-" 2. The contents of the \"signal\" and \"blocked\" sigset_t structures", +-" from the task_struct, both of which are represented as a 64-bit ", +-" hexadecimal value.", +-" 3. A formatted dump of the \"sig\" signal_struct structure referenced by", ++" 1. A formatted dump of the \"sig\" signal_struct structure referenced by", + " the task_struct. For each defined signal, it shows the sigaction", + " structure address, the signal handler, the signal sigset_t mask ", + " (also expressed as a 64-bit hexadecimal value), and the flags.", +-" 4. For each queued signal, if any, its signal number and associated", +-" siginfo structure address.", ++" 2. Whether the task has an unblocked signal pending.", ++" 3. The contents of the \"blocked\" and \"signal\" sigset_t structures", ++" from the task_struct/signal_struct, both of which are represented ", ++" as a 64-bit hexadecimal value.", ++" 4. For each queued signal, private and/or shared, if any, its signal", ++" number and associated siginfo structure address.", + " ", + " The -l option lists the signal numbers and their name(s). The -s option", + " translates a 64-bit hexadecimal value representing the contents of a", +@@ -2744,56 +2898,105 @@ + " ", + " pid a process PID.", + " taskp a hexadecimal task_struct pointer.", ++" -g displays signal information for all threads in a task's ", ++" thread group.", + " -l displays the defined signal numbers and names.", + " -s sigset translates a 64-bit hexadecimal value representing a sigset_t", + " into a list of signal names associated with the bits set.", + "\nEXAMPLES", +-" Dump the signal-handling data of PID 614:\n", +-" %s> sig 614", +-" PID: 614 TASK: c6f26000 CPU: 1 COMMAND: \"httpd\"", +-" SIGPENDING: no", +-" SIGNAL: 0000000000000000", +-" BLOCKED: 0000000000000000", +-" SIGNAL_STRUCT: c1913800 COUNT: 1", ++" Dump the signal-handling data of PID 8970:\n", ++" %s> sig 8970", ++" PID: 8970 TASK: f67d8560 CPU: 1 COMMAND: \"procsig\"", ++" SIGNAL_STRUCT: f6018680 COUNT: 1", + " SIG SIGACTION HANDLER MASK FLAGS ", +-" [1] c1913804 8057c98 0000000000000201 0 ", +-" [2] c1913818 8057c8c 0000000000000000 0 ", +-" [3] c191382c SIG_DFL 0000000000000000 0 ", +-" [4] c1913840 8057bd8 0000000000000000 80000000 (SA_RESETHAND)", +-" [5] c1913854 SIG_DFL 0000000000000000 0 ", +-" [6] c1913868 8057bd8 0000000000000000 80000000 (SA_RESETHAND)", +-" [7] c191387c 8057bd8 0000000000000000 80000000 (SA_RESETHAND)", +-" [8] c1913890 SIG_DFL 0000000000000000 0 ", +-" [9] c19138a4 SIG_DFL 0000000000000000 0 ", +-" [10] c19138b8 8057c98 0000000000000201 0 ", +-" [11] c19138cc 8057bd8 0000000000000000 80000000 (SA_RESETHAND)", +-" [12] c19138e0 SIG_DFL 0000000000000000 0 ", +-" [13] c19138f4 SIG_IGN 0000000000000000 0 ", +-" [14] c1913908 SIG_DFL 0000000000000000 0 ", +-" [15] c191391c 8057c8c 0000000000000000 0 ", +-" [16] c1913930 SIG_DFL 0000000000000000 0 ", +-" [17] c1913944 SIG_DFL 0000000000000000 0 ", +-" [18] c1913958 SIG_DFL 0000000000000000 0 ", +-" [19] c191396c SIG_DFL 0000000000000000 0 ", +-" [20] c1913980 SIG_DFL 0000000000000000 0 ", +-" [21] c1913994 SIG_DFL 0000000000000000 0 ", +-" [22] c19139a8 SIG_DFL 0000000000000000 0 ", +-" [23] c19139bc SIG_DFL 0000000000000000 0 ", +-" [24] c19139d0 SIG_DFL 0000000000000000 0 ", +-" [25] c19139e4 SIG_DFL 0000000000000000 0 ", +-" [26] c19139f8 SIG_DFL 0000000000000000 0 ", +-" [27] c1913a0c SIG_DFL 0000000000000000 0 ", +-" [28] c1913a20 SIG_DFL 0000000000000000 0 ", +-" [29] c1913a34 SIG_DFL 0000000000000000 0 ", +-" [30] c1913a48 SIG_DFL 0000000000000000 0 ", +-" [31] c1913a5c SIG_DFL 0000000000000000 0 ", +-" SIGQUEUE: (empty)", ++" [1] f7877684 SIG_DFL 0000000000000000 0 ", ++" [2] f7877698 SIG_DFL 0000000000000000 0 ", ++" ...", ++" [8] f7877710 SIG_DFL 0000000000000000 0 ", ++" [9] f7877724 SIG_DFL 0000000000000000 0 ", ++" [10] f7877738 804867a 0000000000000000 80000000 (SA_RESETHAND)", ++" [11] f787774c SIG_DFL 0000000000000000 0 ", ++" [12] f7877760 804867f 0000000000000000 10000004 (SA_SIGINFO|SA_RESTART)", ++" [13] f7877774 SIG_DFL 0000000000000000 0 ", ++" ...", ++" [31] f78778dc SIG_DFL 0000000000000000 0 ", ++" [32] f78778f0 SIG_DFL 0000000000000000 0 ", ++" [33] f7877904 SIG_DFL 0000000000000000 0 ", ++" [34] f7877918 804867f 0000000000000000 10000004 (SA_SIGINFO|SA_RESTART)", ++" [35] f787792c SIG_DFL 0000000000000000 0 ", ++" [36] f7877940 SIG_DFL 0000000000000000 0 ", ++" ...", ++" [58] f7877af8 SIG_DFL 0000000000000000 0 ", ++" [59] f7877b0c SIG_DFL 0000000000000000 0 ", ++" [60] f7877b20 SIG_DFL 0000000000000000 0 ", ++" [61] f7877b34 SIG_DFL 0000000000000000 0 ", ++" [62] f7877b48 SIG_DFL 0000000000000000 0 ", ++" [63] f7877b5c SIG_DFL 0000000000000000 0 ", ++" [64] f7877b70 804867f 0000000000000000 10000004 (SA_SIGINFO|SA_RESTART)", ++" SIGPENDING: no", ++" BLOCKED: 8000000200000800", ++" PRIVATE_PENDING", ++" SIGNAL: 0000000200000800", ++" SIGQUEUE: SIG SIGINFO ", ++" 12 f51b9c84", ++" 34 f51b9594", ++" SHARED_PENDING", ++" SIGNAL: 8000000000000800", ++" SIGQUEUE: SIG SIGINFO ", ++" 12 f51b9188", ++" 64 f51b9d18", ++" 64 f51b9500", ++" ", ++" Dump the signal-handling data for all tasks in the thread group containing", ++" PID 2578:\n", ++" %s> sig -g 2578", ++" PID: 2387 TASK: f617d020 CPU: 0 COMMAND: \"slapd\"", ++" SIGNAL_STRUCT: f7dede00 COUNT: 6", ++" SIG SIGACTION HANDLER MASK FLAGS", ++" [1] c1f60c04 a258a7 0000000000000000 10000000 (SA_RESTART)", ++" [2] c1f60c18 a258a7 0000000000000000 10000000 (SA_RESTART)", ++" [3] c1f60c2c SIG_DFL 0000000000000000 0", ++" [4] c1f60c40 SIG_DFL 0000000000000000 0", ++" [5] c1f60c54 a258a7 0000000000000000 10000000 (SA_RESTART)", ++" [6] c1f60c68 SIG_DFL 0000000000000000 0", ++" [7] c1f60c7c SIG_DFL 0000000000000000 0", ++" [8] c1f60c90 SIG_DFL 0000000000000000 0", ++" [9] c1f60ca4 SIG_DFL 0000000000000000 0", ++" [10] c1f60cb8 a25911 0000000000000000 10000000 (SA_RESTART)", ++" ...", ++" [64] c1f610f0 SIG_DFL 0000000000000000 0", ++" SHARED_PENDING", ++" SIGNAL: 0000000000000000", ++" SIGQUEUE: (empty)", ++" ", ++" PID: 2387 TASK: f617d020 CPU: 0 COMMAND: \"slapd\"", ++" SIGPENDING: no", ++" BLOCKED: 0000000000000000", ++" PRIVATE_PENDING", ++" SIGNAL: 0000000000000000", ++" SIGQUEUE: (empty)", ++" ", ++" PID: 2392 TASK: f6175aa0 CPU: 0 COMMAND: \"slapd\"", ++" SIGPENDING: no", ++" BLOCKED: 0000000000000000", ++" PRIVATE_PENDING", ++" SIGNAL: 0000000000000000", ++" SIGQUEUE: (empty)", ++" ", ++" PID: 2523 TASK: f7cd4aa0 CPU: 1 COMMAND: \"slapd\"", ++" SIGPENDING: no", ++" BLOCKED: 0000000000000000", ++" PRIVATE_PENDING", ++" SIGNAL: 0000000000000000", ++" SIGQUEUE: (empty)", ++" ", ++" ...", + " ", + " Translate the sigset_t mask value, cut-and-pasted from the signal handling", + " data from signals 1 and 10 above:", + " ", +-" %s> sig -s 0000000000000201", +-" SIGHUP SIGUSR1", ++" %s> sig -s 800A000000000201", ++" SIGHUP SIGUSR1 SIGRTMAX-14 SIGRTMAX-12 SIGRTMAX", + " ", + " List the signal numbers and their names:", + " ", +@@ -2829,6 +3032,40 @@ + " [29] SIGIO/SIGPOLL", + " [30] SIGPWR", + " [31] SIGSYS", ++" [32] SIGRTMIN", ++" [33] SIGRTMIN+1", ++" [34] SIGRTMIN+2", ++" [35] SIGRTMIN+3", ++" [36] SIGRTMIN+4", ++" [37] SIGRTMIN+5", ++" [38] SIGRTMIN+6", ++" [39] SIGRTMIN+7", ++" [40] SIGRTMIN+8", ++" [41] SIGRTMIN+9", ++" [42] SIGRTMIN+10", ++" [43] SIGRTMIN+11", ++" [44] SIGRTMIN+12", ++" [45] SIGRTMIN+13", ++" [46] SIGRTMIN+14", ++" [47] SIGRTMIN+15", ++" [48] SIGRTMIN+16", ++" [49] SIGRTMAX-15", ++" [50] SIGRTMAX-14", ++" [51] SIGRTMAX-13", ++" [52] SIGRTMAX-12", ++" [53] SIGRTMAX-11", ++" [54] SIGRTMAX-10", ++" [55] SIGRTMAX-9", ++" [56] SIGRTMAX-8", ++" [57] SIGRTMAX-7", ++" [58] SIGRTMAX-6", ++" [59] SIGRTMAX-5", ++" [60] SIGRTMAX-4", ++" [61] SIGRTMAX-3", ++" [62] SIGRTMAX-2", ++" [63] SIGRTMAX-1", ++" [64] SIGRTMAX", ++ + + NULL + }; +@@ -2836,8 +3073,8 @@ + char *help_struct[] = { + "struct", + "structure contents", +-"struct_name[.member] [[-o][-l offset][-r] [address | symbol] [count]]\n" +-" [-c count]", ++"struct_name[.member[,member]][-o][-l offset][-rfu] [address | symbol]\n" ++" [count | -c count]", + " This command displays either a structure definition, or a formatted display", + " of the contents of a structure at a specified address. When no address is", + " specified, the structure definition is shown along with the structure size.", +@@ -2845,7 +3082,8 @@ + " the scope of the data displayed to that particular member; when no address", + " is specified, the member's offset and definition are shown.\n", + " struct_name name of a C-code structure used by the kernel.", +-" .member name of a structure member.", ++" .member name of a structure member; to display multiple members of a", ++" structure, use a comma-separated list of members.", + " -o show member offsets when displaying structure definitions.", + " -l offset if the address argument is a pointer to a list_head structure", + " that is embedded in the target data structure, the offset", +@@ -2854,6 +3092,9 @@ + " 1. in \"structure.member\" format.", + " 2. a number of bytes. ", + " -r raw dump of structure data.", ++" -f address argument is a dumpfile offset.", ++" -u address argument is a user virtual address in the current", ++" context.", + " address hexadecimal address of a structure; if the address points", + " to an embedded list_head structure contained within the", + " target data structure, then the \"-l\" option must be used.", +@@ -2944,6 +3185,21 @@ + " struct mm_struct {", + " [12] pgd_t *pgd;", + " }\n", ++" Display the flags and virtual members of 4 contigous page structures", ++" in the mem_map page structure array:\n", ++" %s> page.flags,virtual c101196c 4", ++" flags = 0x8000,", ++" virtual = 0xc04b0000", ++" ", ++" flags = 0x8000,", ++" virtual = 0xc04b1000", ++" ", ++" flags = 0x8000,", ++" virtual = 0xc04b2000", ++" ", ++" flags = 0x8000,", ++" virtual = 0xc04b3000", ++" ", + " Display the array of tcp_sl_timer structures declared by tcp_slt_array[]:\n", + " %s> struct tcp_sl_timer tcp_slt_array 4", + " struct tcp_sl_timer {", +@@ -3052,8 +3308,8 @@ + char *help_union[] = { + "union", + "union contents", +-"union_name[.member] [[-o][-l offset][-r] [address | symbol] [count]]\n" +-" [-c count]", ++"union_name[.member[,member]] [-o][-l offset][-rfu] [address | symbol]\n" ++" [count | -c count]", + " This command displays either a union definition, or a formatted display", + " of the contents of a union at a specified address. When no address is", + " specified, the union definition is shown along with the union size.", +@@ -3061,7 +3317,8 @@ + " the scope of the data displayed to that particular member; when no address", + " is specified, the member's offset (always 0) and definition are shown.\n", + " union_name name of a C-code union used by the kernel.", +-" .member name of a union member.", ++" .member name of a union member; to display multiple members of a", ++" union, use a comma-separated list of members.", + " -o show member offsets when displaying union definitions.", + " (always 0)", + " -l offset if the address argument is a pointer to a list_head structure", +@@ -3071,6 +3328,9 @@ + " 1. in \"structure.member\" format.", + " 2. a number of bytes. ", + " -r raw dump of union data.", ++" -f address argument is a dumpfile offset.", ++" -u address argument is a user virtual address in the current", ++" context.", + " address hexadecimal address of a union; if the address points", + " to an embedded list_head structure contained within the", + " target union structure, then the \"-l\" option must be used.", +@@ -3152,7 +3412,7 @@ + char *help_mod[] = { + "mod", + "module information and loading of symbols and debugging data", +-"[ -s module [objfile] | -d module | -S [directory] | -D | -r ] ", ++"[ -s module [objfile] | -d module | -S [directory] | -D | -r | -o ] ", + " With no arguments, this command displays basic information of the currently", + " installed modules, consisting of the module address, name, size, the", + " object file name (if known), and whether the module was compiled with", +@@ -3203,6 +3463,7 @@ + " -r Reinitialize module data. All currently-loaded symbolic", + " and debugging data will be deleted, and the installed", + " module list will be updated (live system only).", ++" -o Load module symbols with old mechanism.", + " ", + " After symbolic and debugging data have been loaded, backtraces and text", + " disassembly will be displayed appropriately. Depending upon the processor", +@@ -3322,9 +3583,10 @@ + char *help__list[] = { + "list", "linked list", - "[[-o] offset] [-e end] [-s struct[.member]] [-H] start", +-"[[-o] offset] [-e end] [-s struct[.member]] [-H] start", ++"[[-o] offset] [-e end] [-s struct[.member[,member]]] [-H] start", " This command dumps the contents of a linked list. The entries in a linked", -" are typically data structures that are tied together in one of two formats:", +" list are typically data structures that are tied together in one of two", @@ -7476,7 +9886,7 @@ " ", " 1. A starting address points to a data structure; that structure contains", " a member that is a pointer to the next structure, and so on. The list", -@@ -3335,7 +3375,7 @@ +@@ -3335,7 +3597,7 @@ " c. a pointer to the first item pointed to by the start address.", " d. a pointer to its containing structure.", " ", @@ -7485,7 +9895,16 @@ " within the data structures in the list. The linked list is headed by an", " external LIST_HEAD, which is simply a list_head structure initialized to", " point to itself, signifying that the list is empty:", -@@ -3377,8 +3417,9 @@ +@@ -3370,15 +3632,17 @@ + " entered.", + " -s struct For each address in list, format and print as this type of", + " structure; use the \"struct.member\" format in order to display", +-" a particular member of the structure.", ++" a particular member of the structure. To display multiple", ++" members of a structure, use a comma-separated list of members.", + " ", + " The meaning of the \"start\" argument, which can be expressed either", + " symbolically or in hexadecimal format, depends upon whether the -H option", " is pre-pended or not:", " ", " start The address of the first structure in the list.", @@ -7497,7 +9916,97 @@ "\nEXAMPLES", " Note that each task_struct is linked to its parent's task_struct via the", " p_pptr member:", -@@ -3555,7 +3596,7 @@ +@@ -3416,31 +3680,66 @@ + " The list of currently-registered file system types are headed up by a", + " struct file_system_type pointer named \"file_systems\", and linked by", + " the \"next\" field in each file_system_type structure. The following", +-" sequence displays the address and name of each registered file system type:", ++" sequence displays the structure address followed by the name and ", ++" fs_flags members of each registered file system type:", + " ", + " %s> p file_systems", +-" file_systems = $2 = (struct file_system_type *) 0xc02ebea0", +-" %s> list file_system_type.next -s file_system_type.name 0xc02ebea0", +-" c02ebea0", +-" name = 0xc0280372 \"proc\", ", +-" c02fd4a0", +-" name = 0xc02bf348 \"sockfs\", ", +-" c02eb544", +-" name = 0xc027c25a \"tmpfs\", ", +-" c02eb52c", +-" name = 0xc027c256 \"shm\", ", +-" c02ebbe0", +-" name = 0xc027e054 \"pipefs\", ", +-" c02ec9c0", +-" name = 0xc0283c13 \"ext2\", ", +-" c02ecaa8", +-" name = 0xc0284567 \"iso9660\", ", +-" c02ecc08", +-" name = 0xc0284cf5 \"nfs\", ", +-" c02edc60", +-" name = 0xc028d832 \"autofs\", ", +-" c02edfa0", +-" name = 0xc028e1e0 \"devpts\"", ++" file_systems = $1 = (struct file_system_type *) 0xc03adc90", ++" %s> list file_system_type.next -s file_system_type.name,fs_flags 0xc03adc90", ++" c03adc90", ++" name = 0xc02c05c8 \"rootfs\",", ++" fs_flags = 0x30,", ++" c03abf94", ++" name = 0xc02c0319 \"bdev\",", ++" fs_flags = 0x10,", ++" c03acb40", ++" name = 0xc02c07c4 \"proc\",", ++" fs_flags = 0x8,", ++" c03e9834", ++" name = 0xc02cfc83 \"sockfs\",", ++" fs_flags = 0x10,", ++" c03ab8e4", ++" name = 0xc02bf512 \"tmpfs\",", ++" fs_flags = 0x20,", ++" c03ab8c8", ++" name = 0xc02c3d6b \"shm\",", ++" fs_flags = 0x20,", ++" c03ac394", ++" name = 0xc02c03cf \"pipefs\",", ++" fs_flags = 0x10,", ++" c03ada74", ++" name = 0xc02c0e6b \"ext2\",", ++" fs_flags = 0x1,", ++" c03adc74", ++" name = 0xc02c0e70 \"ramfs\",", ++" fs_flags = 0x20,", ++" c03ade74", ++" name = 0xc02c0e76 \"hugetlbfs\",", ++" fs_flags = 0x20,", ++" c03adf8c", ++" name = 0xc02c0f84 \"iso9660\",", ++" fs_flags = 0x1,", ++" c03aec14", ++" name = 0xc02c0ffd \"devpts\",", ++" fs_flags = 0x8,", ++" c03e93f4", ++" name = 0xc02cf1b9 \"pcihpfs\",", ++" fs_flags = 0x28,", ++" e0831a14", ++" name = 0xe082f89f \"ext3\",", ++" fs_flags = 0x1,", ++" e0846af4", ++" name = 0xe0841ac6 \"usbdevfs\",", ++" fs_flags = 0x8,", ++" e0846b10", ++" name = 0xe0841acf \"usbfs\",", ++" fs_flags = 0x8,", ++" e0992370", ++" name = 0xe099176c \"autofs\",", ++" fs_flags = 0x0,", ++" e2dcc030", ++" name = 0xe2dc8849 \"nfs\",", ++" fs_flags = 0x48000,", + " ", + " In some kernels, the system run queue is a linked list headed up by the", + " \"runqueue_head\", which is defined like so:", +@@ -3555,7 +3854,7 @@ char *help_kmem[] = { "kmem", "kernel memory", @@ -7506,7 +10015,7 @@ " This command displays information about the use of kernel memory.\n", " -f displays the contents of the system free memory headers.", " also verifies that the page count equals nr_free_pages.", -@@ -3569,13 +3610,14 @@ +@@ -3569,13 +3868,14 @@ " -S displays all kmalloc() slab data, including all slab objects,", " and whether each object is in use or is free.", " -v displays the vmlist entries.", @@ -7523,7 +10032,7 @@ " all slab cache names and addresses are listed.", " -P declares that the following address argument is a physical address.", " address when used without any flag, the address can be a kernel virtual,", -@@ -3781,6 +3823,24 @@ +@@ -3781,6 +4081,24 @@ " c2f8ab60 c8095000 - c8097000 8192", " c2f519e0 c8097000 - c8099000 8192", " ", @@ -7548,7 +10057,34 @@ " Determine (and verify) the page cache size:\n", " %s> kmem -c", " page_cache_size: 18431 (verified)", -@@ -4419,10 +4479,11 @@ +@@ -3979,18 +4297,21 @@ + char *help_dis[] = { + "dis", + "disassemble", +-"[-r][-l][-u] [address | symbol | (expression)] [count]", ++"[-r][-l][-u][-b [num]] [address | symbol | (expression)] [count]", + " This command disassembles source code instructions starting (or ending) at", + " a text address that may be expressed by value, symbol or expression:\n", + " -r (reverse) displays all instructions from the start of the ", + " routine up to and including the designated address.", + " -l displays source code line number data in addition to the ", + " disassembly output.", +-" -u address is a user virtual address; otherwise the address is ", +-" assumed to be a kernel virtual address. If this option is", +-" used, then -r and -l are ignored.", ++" -u address is a user virtual address in the current context;", ++" otherwise the address is assumed to be a kernel virtual address.", ++" If this option is used, then -r and -l are ignored.", ++" -b [num] modify the pre-calculated number of encoded bytes to skip after", ++" a kernel BUG (\"ud2a\") instruction; with no argument, displays", ++" the current number of bytes being skipped. (x86 and x86_64 only)", + " address starting hexadecimal text address.", +-" symbol symbol of starting text address. On PPC64, the symbol", ++" symbol symbol of starting text address. On ppc64, the symbol", + " preceded by '.' is used.", + " (expression) expression evaluating to a starting text address.", + " count the number of instructions to be disassembled (default is 1).", +@@ -4419,10 +4740,11 @@ " Display various network related data:\n", " -a display the ARP cache.", " -s display open network socket/sock addresses, their family and type,", @@ -7562,7 +10098,7 @@ " value into a standard numbers-and-dots notation.", " -R ref socket or sock address, or file descriptor.", " pid a process PID.", -@@ -4450,8 +4511,8 @@ +@@ -4450,8 +4772,8 @@ " Display the sockets for PID 2517, using both -s and -S output formats:\n", " %s> net -s 2517", " PID: 2517 TASK: c1598000 CPU: 1 COMMAND: \"rlogin\"", @@ -7573,7 +10109,7 @@ " ", " %s> net -S 2517", " PID: 2517 TASK: c1598000 CPU: 1 COMMAND: \"rlogin\"", -@@ -4497,52 +4558,52 @@ +@@ -4497,52 +4819,52 @@ " From \"foreach\", find all tasks with references to socket c08ea3cc:\n", " %s> foreach net -s -R c08ea3cc", " PID: 2184 TASK: c7026000 CPU: 1 COMMAND: \"klines.kss\"", @@ -7650,24 +10186,175 @@ " ", NULL }; -@@ -4854,9 +4915,11 @@ +@@ -4584,21 +4906,22 @@ + void + cmd_usage(char *cmd, int helpflag) + { +- int i; +- int found; +- char **p; ++ char **p, *scroll_command; + struct command_table_entry *cp; + char buf[BUFSIZE]; +- struct alias_data *ad; +- FILE *less; ++ FILE *scroll; ++ int i; + +- if (helpflag & PIPE_TO_LESS) { +- if ((less = popen("/usr/bin/less", "w")) != NULL) +- fp = less; +- helpflag &= ~PIPE_TO_LESS; +- } else +- less = NULL; +- ++ if (helpflag & PIPE_TO_SCROLL) { ++ if ((scroll_command = setup_scroll_command()) && ++ (scroll = popen(scroll_command, "w"))) ++ fp = scroll; ++ else ++ scroll = NULL; ++ } else { ++ scroll_command = NULL; ++ scroll = NULL; ++ } + + if (STREQ(cmd, "copying")) { + display_copying_info(); +@@ -4641,46 +4964,50 @@ + goto done_usage; + } + +- found = FALSE; +-retry: +- if ((cp = get_command_table_entry(cmd))) { +- if ((p = cp->help_data)) +- found = TRUE; +- } ++ /* look up command, possibly through an alias */ ++ for (;;) { ++ struct alias_data *ad; ++ ++ cp = get_command_table_entry(cmd); ++ if (cp != NULL) ++ break; /* found command */ ++ ++ /* try for an alias */ ++ ad = is_alias(cmd); ++ if (ad == NULL) ++ break; /* neither command nor alias */ + +- /* +- * Check for alias names or gdb commands. +- */ +- if (!found) { +- if ((ad = is_alias(cmd))) { +- cmd = ad->args[0]; +- goto retry; +- } ++ cmd = ad->args[0]; ++ cp = get_command_table_entry(cmd); ++ } + +- if (helpflag == SYNOPSIS) { +- fprintf(fp, +- "No usage data for the \"%s\" command is available.\n", ++ if (cp == NULL || (p = cp->help_data) == NULL) { ++ if (helpflag & SYNOPSIS) { ++ fprintf(fp, ++ "No usage data for the \"%s\" command" ++ " is available.\n", + cmd); + RESTART(); + } + +- if (STREQ(pc->curcmd, "help")) { +- if (cp) +- fprintf(fp, +- "No help data for the \"%s\" command is available.\n", ++ if (helpflag & MUST_HELP) { ++ if (cp || !(pc->flags & GDB_INIT)) ++ fprintf(fp, ++ "No help data for the \"%s\" command" ++ " is available.\n", + cmd); + else if (!gdb_pass_through(concat_args(buf, 0, FALSE), + NULL, GNU_RETURN_ON_ERROR)) + fprintf(fp, +- "No help data for \"%s\" is available.\n", +- cmd); ++ "No help data for \"%s\" is available.\n", ++ cmd); + } + goto done_usage; + } + + p++; + +- if (helpflag == SYNOPSIS) { ++ if (helpflag & SYNOPSIS) { + p++; + fprintf(fp, "Usage: %s ", cmd); + fprintf(fp, *p, pc->program_name, pc->program_name); +@@ -4711,10 +5038,12 @@ + + done_usage: + +- if (less) { +- fflush(less); +- pclose(less); ++ if (scroll) { ++ fflush(scroll); ++ pclose(scroll); + } ++ if (scroll_command) ++ FREEBUF(scroll_command); + } + + +@@ -4812,7 +5141,9 @@ + "The default output radix for gdb output and certain %s commands is", + "hexadecimal. This can be changed to decimal by entering \"set radix 10\"", + "or the alias \"dec\". It can be reverted back to hexadecimal by entering", +-"\"set radix 16\" or the alias \"hex\".", ++"\"set radix 16\" or the alias \"hex\".\n", ++"To execute an external shell command, precede the command with an \"!\".", ++"To escape to a shell, enter \"!\" alone.", + " ", + NULL + }; +@@ -4854,10 +5185,13 @@ static char *version_info[] = { -"Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc.", -"Copyright (C) 2004, 2005 IBM Corporation", -"Copyright (C) 1999-2005 Hewlett-Packard Co", -+"Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.", +-"Copyright (C) 1999, 2002 Silicon Graphics, Inc.", ++"Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc.", +"Copyright (C) 2004, 2005, 2006 IBM Corporation", +"Copyright (C) 1999-2006 Hewlett-Packard Co", -+"Copyright (C) 2005 Fujitsu Limited", ++"Copyright (C) 2005, 2006 Fujitsu Limited", ++"Copyright (C) 2006, 2007 VA Linux Systems Japan K.K.", +"Copyright (C) 2005 NEC Corporation", - "Copyright (C) 1999, 2002 Silicon Graphics, Inc.", ++"Copyright (C) 1999, 2002, 2007 Silicon Graphics, Inc.", "Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.", "This program is free software, covered by the GNU General Public License,", ---- crash/task.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/task.c 2006-09-06 15:53:39.000000000 -0400 -@@ -27,6 +27,7 @@ + "and you are welcome to change it and/or distribute copies of it under", +--- crash/task.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/task.c 2007-07-31 16:09:39.000000000 -0400 +@@ -1,8 +1,8 @@ + /* task.c - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 +@@ -27,11 +27,15 @@ static void refresh_pidhash_task_table(void); static void refresh_pid_hash_task_table(void); static void refresh_hlist_task_table(void); @@ -7675,15 +10362,62 @@ static struct task_context *store_context(struct task_context *, ulong, char *); static void refresh_context(ulong, ulong); static void parent_list(ulong); -@@ -49,6 +50,7 @@ + static void child_list(ulong); + static void show_task_times(struct task_context *, ulong); ++static void show_task_args(struct task_context *); ++static void show_task_rlimit(struct task_context *); ++static void show_tgid_list(ulong); + static int compare_start_time(const void *, const void *); + static int start_time_timespec(void); + static ulonglong convert_start_time(ulonglong, ulonglong); +@@ -46,11 +50,26 @@ + static void dump_runq(void); + static void dump_runqueues(void); + static void dump_prio_array(int, ulong, char *); ++struct rb_root; ++static struct rb_node *rb_first(struct rb_root *); ++struct rb_node; ++static struct rb_node *rb_next(struct rb_node *); ++static struct rb_node *rb_parent(struct rb_node *, struct rb_node *); ++static struct rb_node *rb_right(struct rb_node *, struct rb_node *); ++static struct rb_node *rb_left(struct rb_node *, struct rb_node *); ++static void dump_CFS_runqueues(void); ++static void dump_RT_prio_array(int, ulong, char *); static void task_struct_member(struct task_context *,ulong,struct reference *); static void signal_reference(struct task_context *, ulong, struct reference *); - static void dump_signal_data(struct task_context *); +-static void dump_signal_data(struct task_context *); ++static void do_sig_thread_group(ulong); ++static void dump_signal_data(struct task_context *, ulong); ++#define TASK_LEVEL (0x1) ++#define THREAD_GROUP_LEVEL (0x2) ++#define TASK_INDENT (0x4) +static int sigrt_minmax(int *, int *); static void signame_list(void); - static ulonglong task_signal(ulong); +-static ulonglong task_signal(ulong); ++static void sigqueue_list(ulong); ++static ulonglong task_signal(ulong, ulong*); static ulonglong task_blocked(ulong); -@@ -193,6 +195,8 @@ + static void translate_sigset(ulonglong); + static ulonglong sigaction_mask(ulong); +@@ -151,8 +170,15 @@ + get_idle_threads(&tt->idle_threads[0], kt->cpus); + } + +- MEMBER_OFFSET_INIT(task_struct_thread_info, "task_struct", +- "thread_info"); ++ if (MEMBER_EXISTS("task_struct", "thread_info")) ++ MEMBER_OFFSET_INIT(task_struct_thread_info, "task_struct", ++ "thread_info"); ++ else if (MEMBER_EXISTS("task_struct", "stack")) ++ MEMBER_OFFSET_INIT(task_struct_thread_info, "task_struct", ++ "stack"); ++ else ++ ASSIGN_OFFSET(task_struct_thread_info) = INVALID_OFFSET; ++ + if (VALID_MEMBER(task_struct_thread_info)) { + MEMBER_OFFSET_INIT(thread_info_task, "thread_info", "task"); + MEMBER_OFFSET_INIT(thread_info_cpu, "thread_info", "cpu"); +@@ -193,6 +219,8 @@ MEMBER_OFFSET_INIT(pid_link_pid, "pid_link", "pid"); MEMBER_OFFSET_INIT(pid_hash_chain, "pid", "hash_chain"); @@ -7692,8 +10426,20 @@ MEMBER_OFFSET_INIT(pid_pid_chain, "pid", "pid_chain"); STRUCT_SIZE_INIT(task_struct, "task_struct"); -@@ -219,15 +223,7 @@ +@@ -207,6 +235,8 @@ + + MEMBER_OFFSET_INIT(signal_struct_count, "signal_struct", "count"); + MEMBER_OFFSET_INIT(signal_struct_action, "signal_struct", "action"); ++ MEMBER_OFFSET_INIT(signal_struct_shared_pending, "signal_struct", ++ "shared_pending"); + + MEMBER_OFFSET_INIT(k_sigaction_sa, "k_sigaction", "sa"); + +@@ -217,17 +247,10 @@ + if (INVALID_MEMBER(sigpending_head)) + MEMBER_OFFSET_INIT(sigpending_list, "sigpending", "list"); MEMBER_OFFSET_INIT(sigpending_signal, "sigpending", "signal"); ++ MEMBER_SIZE_INIT(sigpending_signal, "sigpending", "signal"); STRUCT_SIZE_INIT(sigqueue, "sigqueue"); - if (VALID_STRUCT(sigqueue)) { @@ -7709,7 +10455,7 @@ STRUCT_SIZE_INIT(sighand_struct, "sighand_struct"); if (VALID_STRUCT(sighand_struct)) -@@ -249,6 +245,19 @@ +@@ -249,6 +272,19 @@ STRUCT_SIZE_INIT(cputime_t, "cputime_t"); @@ -7729,20 +10475,59 @@ if (VALID_MEMBER(runqueue_arrays)) MEMBER_OFFSET_INIT(task_struct_run_list, "task_struct", "run_list"); -@@ -302,7 +311,11 @@ +@@ -279,12 +315,6 @@ + error(FATAL, + "pidhash and pid_hash both exist -- cannot distinquish between them\n"); + +- /* +- * NOTE: We rely on PIDTYPE_PID staying at enum value of 0, because +- * evan at the lowest level in gdb, I can't seem to find where +- * the actual value is stored via the struct type. (?) +- * Should be safe, though... +- */ + if (symbol_exists("pid_hash") && symbol_exists("pidhash_shift")) { + int pidhash_shift; + +@@ -302,7 +332,24 @@ tt->refresh_task_table = refresh_pid_hash_task_table; } else { tt->pidhash_addr = symbol_value("pid_hash"); - tt->refresh_task_table = refresh_hlist_task_table; -+ if (!get_array_length("pid_hash", NULL, sizeof(void *)) && -+ VALID_STRUCT(pid_link)) -+ tt->refresh_task_table = refresh_hlist_task_table_v2; -+ else -+ tt->refresh_task_table = refresh_hlist_task_table; ++ if (LKCD_KERNTYPES()) { ++ if (VALID_STRUCT(pid_link)) ++ tt->refresh_task_table = ++ refresh_hlist_task_table_v2; ++ else ++ tt->refresh_task_table = ++ refresh_hlist_task_table; ++ builtin_array_length("pid_hash", ++ tt->pidhash_len, NULL); ++ } else { ++ if (!get_array_length("pid_hash", NULL, ++ sizeof(void *)) && VALID_STRUCT(pid_link)) ++ tt->refresh_task_table = ++ refresh_hlist_task_table_v2; ++ else ++ tt->refresh_task_table = ++ refresh_hlist_task_table; ++ } } tt->flags |= PID_HASH; -@@ -987,9 +1000,7 @@ +@@ -353,8 +400,11 @@ + set_context(NO_TASK, active_pid); + tt->this_task = pid_to_task(active_pid); + } +- else ++ else { ++ please_wait("determining panic task"); + set_context(get_panic_context(), NO_PID); ++ please_wait_done(); ++ } + + sort_context_array(); + +@@ -987,9 +1037,7 @@ return; if (DUMPFILE()) { /* impossible */ @@ -7753,7 +10538,7 @@ if (!symbol_exists("panic_threads")) tt->flags |= POPULATE_PANIC; } -@@ -1152,11 +1163,7 @@ +@@ -1152,11 +1200,7 @@ FREEBUF(pid_hash); @@ -7766,7 +10551,22 @@ if (ACTIVE() && (tt->flags & TASK_INIT_DONE)) refresh_context(curtask, curpid); -@@ -1192,9 +1199,7 @@ +@@ -1176,12 +1220,14 @@ + { + int i; + ulong *pid_hash; ++ struct syment *sp; + ulong pidhash_array; + ulong kpp; + char *tp; + ulong next, pnext, pprev; + char *nodebuf; + int plen, len, cnt; ++ long value; + struct task_context *tc; + ulong curtask; + ulong curpid; +@@ -1192,9 +1238,7 @@ return; if (DUMPFILE()) { /* impossible */ @@ -7777,7 +10577,64 @@ if (!symbol_exists("panic_threads")) tt->flags |= POPULATE_PANIC; } -@@ -1394,12 +1399,229 @@ +@@ -1211,8 +1255,21 @@ + curpid = CURRENT_PID(); + } + +- if (!(plen = get_array_length("pid_hash", NULL, sizeof(void *)))) +- error(FATAL, "cannot determine pid_hash array dimensions\n"); ++ if (!(plen = get_array_length("pid_hash", NULL, sizeof(void *)))) { ++ /* ++ * Workaround for gcc omitting debuginfo data for pid_hash. ++ */ ++ if (enumerator_value("PIDTYPE_MAX", &value)) { ++ if ((sp = next_symbol("pid_hash", NULL)) && ++ (((sp->value - tt->pidhash_addr) / sizeof(void *)) < value)) ++ error(WARNING, "possible pid_hash array mis-handling\n"); ++ plen = (int)value; ++ } else { ++ error(WARNING, ++ "cannot determine pid_hash array dimensions\n"); ++ plen = 1; ++ } ++ } + + pid_hash = (ulong *)GETBUF(plen * sizeof(void *)); + +@@ -1228,6 +1285,16 @@ + * The zero'th (PIDTYPE_PID) entry is the hlist_head array + * that we want. + */ ++ if (CRASHDEBUG(1)) { ++ if (!enumerator_value("PIDTYPE_PID", &value)) ++ error(WARNING, ++ "possible pid_hash array mis-handling: PIDTYPE_PID: (unknown)\n"); ++ else if (value != 0) ++ error(WARNING, ++ "possible pid_hash array mis-handling: PIDTYPE_PID: %d \n", ++ value); ++ } ++ + pidhash_array = pid_hash[0]; + FREEBUF(pid_hash); + +@@ -1345,6 +1412,15 @@ + } + } + ++ if (cnt > tt->max_tasks) { ++ tt->max_tasks = cnt + TASK_SLUSH; ++ allocate_task_space(tt->max_tasks); ++ hq_close(); ++ if (!DUMPFILE()) ++ retries++; ++ goto retry_pid_hash; ++ } ++ + BZERO(tt->task_local, tt->max_tasks * sizeof(void *)); + cnt = retrieve_list((ulong *)tt->task_local, cnt); + +@@ -1394,12 +1470,238 @@ FREEBUF(pid_hash); FREEBUF(nodebuf); @@ -7955,8 +10812,17 @@ + console(" chained task: %lx (node: %lx) next: %lx pprev: %lx\n", + next, kpp, pnext, pprev); + } - } - ++ } ++ ++ if (cnt > tt->max_tasks) { ++ tt->max_tasks = cnt + TASK_SLUSH; ++ allocate_task_space(tt->max_tasks); ++ hq_close(); ++ if (!DUMPFILE()) ++ retries++; ++ goto retry_pid_hash; ++ } ++ + BZERO(tt->task_local, tt->max_tasks * sizeof(void *)); + cnt = retrieve_list((ulong *)tt->task_local, cnt); + @@ -8001,8 +10867,8 @@ + tc++; + tt->running_tasks++; + } -+ } -+ + } + + FREEBUF(pid_hash); + FREEBUF(nodebuf); + @@ -8011,7 +10877,387 @@ if (ACTIVE() && (tt->flags & TASK_INIT_DONE)) refresh_context(curtask, curpid); -@@ -2229,11 +2451,8 @@ +@@ -1426,6 +1728,8 @@ + do_verify = 1; + else if (tt->refresh_task_table == refresh_pid_hash_task_table) + do_verify = 2; ++ else if (tt->refresh_task_table == refresh_hlist_task_table_v2) ++ do_verify = 2; + else + do_verify = 0; + +@@ -1581,6 +1885,9 @@ + char * + fill_task_struct(ulong task) + { ++ if (XEN_HYPER_MODE()) ++ return NULL; ++ + if (!IS_LAST_TASK_READ(task)) { + if (!readmem(task, KVADDR, tt->task_struct, + SIZE(task_struct), "fill_task_struct", +@@ -1632,6 +1939,9 @@ + bt->stackbase); + } + ++ if (XEN_HYPER_MODE()) ++ return; ++ + if (!IS_LAST_TASK_READ(bt->task)) { + if (bt->stackbase == bt->task) { + BCOPY(bt->stackbuf, tt->task_struct, SIZE(task_struct)); +@@ -1893,7 +2203,7 @@ + BZERO(&psinfo, sizeof(struct psinfo)); + flag = 0; + +- while ((c = getopt(argcnt, args, "stcpkul")) != EOF) { ++ while ((c = getopt(argcnt, args, "gstcpkular")) != EOF) { + switch(c) + { + case 'k': +@@ -1907,21 +2217,31 @@ + break; + + /* +- * The remaining flags are all mutually-exclusive. ++ * The a, t, c, p, g and l flags are all mutually-exclusive. + */ ++ case 'g': ++ flag &= ~(PS_EXCLUSIVE); ++ flag |= PS_TGID_LIST; ++ break; ++ ++ case 'a': ++ flag &= ~(PS_EXCLUSIVE); ++ flag |= PS_ARGV_ENVP; ++ break; ++ + case 't': ++ flag &= ~(PS_EXCLUSIVE); + flag |= PS_TIMES; +- flag &= ~(PS_CHILD_LIST|PS_PPID_LIST|PS_LAST_RUN); + break; + + case 'c': ++ flag &= ~(PS_EXCLUSIVE); + flag |= PS_CHILD_LIST; +- flag &= ~(PS_PPID_LIST|PS_TIMES|PS_LAST_RUN); + break; + + case 'p': ++ flag &= ~(PS_EXCLUSIVE); + flag |= PS_PPID_LIST; +- flag &= ~(PS_CHILD_LIST|PS_TIMES|PS_LAST_RUN); + break; + + case 'l': +@@ -1932,14 +2252,19 @@ + argerrs++; + break; + } ++ flag &= ~(PS_EXCLUSIVE); + flag |= PS_LAST_RUN; +- flag &= ~(PS_CHILD_LIST|PS_TIMES|PS_PPID_LIST); + break; + + case 's': + flag |= PS_KSTACKP; + break; + ++ case 'r': ++ flag &= ~(PS_EXCLUSIVE); ++ flag |= PS_RLIMIT; ++ break; ++ + default: + argerrs++; + break; +@@ -2020,6 +2345,18 @@ + show_last_run(tc); \ + continue; \ + } \ ++ if (flag & PS_ARGV_ENVP) { \ ++ show_task_args(tc); \ ++ continue; \ ++ } \ ++ if (flag & PS_RLIMIT) { \ ++ show_task_rlimit(tc); \ ++ continue; \ ++ } \ ++ if (flag & PS_TGID_LIST) { \ ++ show_tgid_list(tc->task); \ ++ continue; \ ++ } \ + get_task_mem_usage(tc->task, tm); \ + fprintf(fp, "%s", is_task_active(tc->task) ? "> " : " "); \ + fprintf(fp, "%5ld %5ld %2s %s %3s", \ +@@ -2050,7 +2387,7 @@ + char buf2[BUFSIZE]; + char buf3[BUFSIZE]; + +- if (!(flag & (PS_PPID_LIST|PS_CHILD_LIST|PS_TIMES|PS_LAST_RUN))) ++ if (!(flag & PS_EXCLUSIVE)) + fprintf(fp, + " PID PPID CPU %s ST %%MEM VSZ RSS COMM\n", + flag & PS_KSTACKP ? +@@ -2076,6 +2413,8 @@ + return; + } + ++ pc->curcmd_flags |= TASK_SPECIFIED; ++ + for (ac = 0; ac < psi->argc; ac++) { + tm = &task_mem_usage; + tc = FIRST_CONTEXT(); +@@ -2096,8 +2435,15 @@ + break; + + case PS_BY_CMD: +- if (STREQ(tc->comm, psi->comm[ac])) +- print = TRUE; ++ if (STREQ(tc->comm, psi->comm[ac])) { ++ if (flag & PS_TGID_LIST) { ++ if (tc->pid == task_tgid(tc->task)) ++ print = TRUE; ++ else ++ print = FALSE; ++ } else ++ print = TRUE; ++ } + break; + } + +@@ -2145,6 +2491,229 @@ + } + + /* ++ * Show the argv and envp strings pointed to by mm_struct->arg_start ++ * and mm_struct->env_start. The user addresses need to broken up ++ * into physical on a page-per-page basis because we typically are ++ * not going to be working in the context of the target task. ++ */ ++static void ++show_task_args(struct task_context *tc) ++{ ++ ulong arg_start, arg_end, env_start, env_end; ++ char *buf, *bufptr, *p1; ++ char *as, *ae, *es, *ee; ++ physaddr_t paddr; ++ ulong uvaddr, size, cnt; ++ int c, d; ++ ++ print_task_header(fp, tc, 0); ++ ++ if (!tc || !tc->mm_struct) { /* probably a kernel thread */ ++ error(INFO, "no user stack\n\n"); ++ return; ++ } ++ ++ if (!task_mm(tc->task, TRUE)) ++ return; ++ ++ if (INVALID_MEMBER(mm_struct_arg_start)) { ++ MEMBER_OFFSET_INIT(mm_struct_arg_start, "mm_struct", "arg_start"); ++ MEMBER_OFFSET_INIT(mm_struct_arg_end, "mm_struct", "arg_end"); ++ MEMBER_OFFSET_INIT(mm_struct_env_start, "mm_struct", "env_start"); ++ MEMBER_OFFSET_INIT(mm_struct_env_end, "mm_struct", "env_end"); ++ } ++ ++ arg_start = ULONG(tt->mm_struct + OFFSET(mm_struct_arg_start)); ++ arg_end = ULONG(tt->mm_struct + OFFSET(mm_struct_arg_end)); ++ env_start = ULONG(tt->mm_struct + OFFSET(mm_struct_env_start)); ++ env_end = ULONG(tt->mm_struct + OFFSET(mm_struct_env_end)); ++ ++ if (CRASHDEBUG(1)) { ++ fprintf(fp, "arg_start: %lx arg_end: %lx (%ld)\n", ++ arg_start, arg_end, arg_end - arg_start); ++ fprintf(fp, "env_start: %lx env_end: %lx (%ld)\n", ++ env_start, env_end, env_end - env_start); ++ } ++ ++ buf = GETBUF(env_end - arg_start + 1); ++ ++ uvaddr = arg_start; ++ size = env_end - arg_start; ++ bufptr = buf; ++ ++ while (size > 0) { ++ if (!uvtop(tc, uvaddr, &paddr, 0)) { ++ error(INFO, "cannot access user stack address: %lx\n\n", ++ uvaddr); ++ goto bailout; ++ } ++ ++ cnt = PAGESIZE() - PAGEOFFSET(uvaddr); ++ ++ if (cnt > size) ++ cnt = size; ++ ++ if (!readmem(paddr, PHYSADDR, bufptr, cnt, ++ "user stack contents", RETURN_ON_ERROR|QUIET)) { ++ error(INFO, "cannot access user stack address: %lx\n\n", ++ uvaddr); ++ goto bailout; ++ } ++ ++ uvaddr += cnt; ++ bufptr += cnt; ++ size -= cnt; ++ } ++ ++ as = buf; ++ ae = &buf[arg_end - arg_start]; ++ es = &buf[env_start - arg_start]; ++ ee = &buf[env_end - arg_start]; ++ ++ fprintf(fp, "ARG: "); ++ for (p1 = as, c = 0; p1 < ae; p1++) { ++ if (*p1 == NULLCHAR) { ++ if (c) ++ fprintf(fp, " "); ++ c = 0; ++ } else { ++ fprintf(fp, "%c", *p1); ++ c++; ++ } ++ } ++ ++ fprintf(fp, "\nENV: "); ++ for (p1 = es, c = d = 0; p1 < ee; p1++) { ++ if (*p1 == NULLCHAR) { ++ if (c) ++ fprintf(fp, "\n"); ++ c = 0; ++ } else { ++ fprintf(fp, "%s%c", !c && (p1 != es) ? " " : "", *p1); ++ c++, d++; ++ } ++ } ++ fprintf(fp, "\n%s", d ? "" : "\n"); ++ ++bailout: ++ FREEBUF(buf); ++} ++ ++char *rlim_names[] = { ++ /* 0 */ "CPU", ++ /* 1 */ "FSIZE", ++ /* 2 */ "DATA", ++ /* 3 */ "STACK", ++ /* 4 */ "CORE", ++ /* 5 */ "RSS", ++ /* 6 */ "NPROC", ++ /* 7 */ "NOFILE", ++ /* 8 */ "MEMLOCK", ++ /* 9 */ "AS", ++ /* 10 */ "LOCKS", ++ /* 11 */ "SIGPENDING", ++ /* 12 */ "MSGQUEUE", ++ /* 13 */ "NICE", ++ /* 14 */ "RTPRIO", ++ NULL, ++}; ++ ++#ifndef RLIM_INFINITY ++#define RLIM_INFINITY (~0UL) ++#endif ++ ++/* ++ * Show the current and maximum rlimit values. ++ */ ++static void ++show_task_rlimit(struct task_context *tc) ++{ ++ int i, j, len1, len2, rlimit_index; ++ int in_task_struct, in_signal_struct; ++ char *rlimit_buffer; ++ ulong *p1, rlim_addr; ++ char buf1[BUFSIZE]; ++ char buf2[BUFSIZE]; ++ char buf3[BUFSIZE]; ++ ++ if (!VALID_MEMBER(task_struct_rlim) && !VALID_MEMBER(signal_struct_rlim)) { ++ MEMBER_OFFSET_INIT(task_struct_rlim, "task_struct", "rlim"); ++ MEMBER_OFFSET_INIT(signal_struct_rlim, "signal_struct", "rlim"); ++ STRUCT_SIZE_INIT(rlimit, "rlimit"); ++ if (!VALID_MEMBER(task_struct_rlim) && ++ !VALID_MEMBER(signal_struct_rlim)) ++ error(FATAL, "cannot determine rlimit array location\n"); ++ } else if (!VALID_STRUCT(rlimit)) ++ error(FATAL, "cannot determine rlimit structure definition\n"); ++ ++ in_task_struct = in_signal_struct = FALSE; ++ ++ if (VALID_MEMBER(task_struct_rlim)) { ++ rlimit_index = get_array_length("task_struct.rlim", NULL, 0); ++ in_task_struct = TRUE; ++ } else if (VALID_MEMBER(signal_struct_rlim)) { ++ if (!VALID_MEMBER(task_struct_signal)) ++ error(FATAL, "cannot determine rlimit array location\n"); ++ rlimit_index = get_array_length("signal_struct.rlim", NULL, 0); ++ in_signal_struct = TRUE; ++ } ++ ++ if (!rlimit_index) ++ error(FATAL, "cannot determine rlimit array size\n"); ++ ++ for (i = len1 = 0; i < rlimit_index; i++) { ++ if ((j = strlen(rlim_names[i])) > len1) ++ len1 = j; ++ } ++ len2 = strlen("(unlimited)"); ++ ++ rlimit_buffer = GETBUF(rlimit_index * SIZE(rlimit)); ++ ++ print_task_header(fp, tc, 0); ++ ++ fill_task_struct(tc->task); ++ ++ if (in_task_struct) { ++ BCOPY(tt->task_struct + OFFSET(task_struct_rlim), ++ rlimit_buffer, rlimit_index * SIZE(rlimit)); ++ } else if (in_signal_struct) { ++ rlim_addr = ULONG(tt->task_struct + OFFSET(task_struct_signal)); ++ if (!readmem(rlim_addr + OFFSET(signal_struct_rlim), ++ KVADDR, rlimit_buffer, rlimit_index * SIZE(rlimit), ++ "signal_struct rlimit array", RETURN_ON_ERROR)) { ++ FREEBUF(rlimit_buffer); ++ return; ++ } ++ } ++ ++ fprintf(fp, " %s %s %s\n", ++ mkstring(buf1, len1, RJUST, "RLIMIT"), ++ mkstring(buf2, len2, CENTER|RJUST, "CURRENT"), ++ mkstring(buf3, len2, CENTER|RJUST, "MAXIMUM")); ++ ++ for (p1 = (ulong *)rlimit_buffer, i = 0; i < rlimit_index; i++) { ++ fprintf(fp, " %s ", mkstring(buf1, len1, RJUST, ++ rlim_names[i] ? rlim_names[i] : "(unknown)")); ++ if (*p1 == (ulong)RLIM_INFINITY) ++ fprintf(fp, "(unlimited) "); ++ else ++ fprintf(fp, "%s ", mkstring(buf1, len2, ++ CENTER|LJUST|LONG_DEC, MKSTR(*p1))); ++ p1++; ++ if (*p1 == (ulong)RLIM_INFINITY) ++ fprintf(fp, "(unlimited)\n"); ++ else ++ fprintf(fp, "%s\n", mkstring(buf1, len2, ++ CENTER|LJUST|LONG_DEC, MKSTR(*p1))); ++ p1++; ++ } ++ ++ fprintf(fp, "\n"); ++ ++ FREEBUF(rlimit_buffer); ++} ++ ++/* + * Put either the task_struct address or kernel stack pointer into a string. + * If the kernel stack pointer is requested, piggy-back on top of the + * back trace code to avoid having to deal with machine dependencies, +@@ -2229,11 +2798,8 @@ use_kernel_timeval = STRUCT_EXISTS("kernel_timeval"); get_symbol_data("jiffies", sizeof(long), &jiffies); @@ -8025,7 +11271,7 @@ tsp = task_start_times; tc = tcp ? tcp : FIRST_CONTEXT(); -@@ -2330,8 +2549,7 @@ +@@ -2330,8 +2896,7 @@ for (i = 0, tsp = task_start_times; i < tasks; i++, tsp++) { print_task_header(fp, tsp->tc, 0); fprintf(fp, " RUN TIME: %s\n", symbol_exists("jiffies_64") ? @@ -8035,7 +11281,7 @@ convert_time(jiffies - tsp->start_time, buf1)); fprintf(fp, " START TIME: %llu\n", tsp->start_time); if (VALID_MEMBER(task_struct_times)) { -@@ -2397,15 +2615,33 @@ +@@ -2397,15 +2962,33 @@ static ulonglong convert_start_time(ulonglong start_time, ulonglong current) { @@ -8072,7 +11318,122 @@ default: break; } -@@ -2938,12 +3174,17 @@ +@@ -2511,6 +3094,54 @@ + } + + /* ++ * Dump the children of a task. ++ */ ++static void ++show_tgid_list(ulong task) ++{ ++ int i; ++ int cnt; ++ struct task_context *tc; ++ ulong tgid; ++ ++ tc = task_to_context(task); ++ tgid = task_tgid(task); ++ ++ if (tc->pid != tgid) { ++ if (pc->curcmd_flags & TASK_SPECIFIED) { ++ if (!(tc = tgid_to_context(tgid))) ++ return; ++ task = tc->task; ++ } else ++ return; ++ } ++ ++ if ((tc->pid == 0) && (pc->curcmd_flags & IDLE_TASK_SHOWN)) ++ return; ++ ++ print_task_header(fp, tc, 0); ++ ++ tc = FIRST_CONTEXT(); ++ for (i = cnt = 0; i < RUNNING_TASKS(); i++, tc++) { ++ if (tc->task == task) ++ continue; ++ ++ if (task_tgid(tc->task) == tgid) { ++ INDENT(2); ++ print_task_header(fp, tc, 0); ++ cnt++; ++ if (tc->pid == 0) ++ pc->curcmd_flags |= IDLE_TASK_SHOWN; ++ } ++ } ++ ++ if (!cnt) ++ fprintf(fp, " (no threads)\n"); ++ ++ fprintf(fp, "\n"); ++} ++ ++/* + * Return the first task found that belongs to a pid. + */ + ulong +@@ -2580,6 +3211,26 @@ + return NULL; + } + ++/* ++ * Return a tgid's parent task_context structure. ++ */ ++struct task_context * ++tgid_to_context(ulong parent_tgid) ++{ ++ int i; ++ struct task_context *tc; ++ ulong tgid; ++ ++ tc = FIRST_CONTEXT(); ++ for (i = 0; i < RUNNING_TASKS(); i++, tc++) { ++ tgid = task_tgid(tc->task); ++ if ((tgid == parent_tgid) && (tgid == tc->pid)) ++ return tc; ++ } ++ ++ return NULL; ++} ++ + + /* + * Return the task_context structure of the first task found with a pid, +@@ -2821,15 +3472,15 @@ + int + comm_exists(char *s) + { +- int i; ++ int i, cnt; + struct task_context *tc; + + tc = FIRST_CONTEXT(); +- for (i = 0; i < RUNNING_TASKS(); i++, tc++) ++ for (i = cnt = 0; i < RUNNING_TASKS(); i++, tc++) + if (STREQ(tc->comm, s)) +- return TRUE; ++ cnt++; + +- return FALSE; ++ return cnt; + } + + /* +@@ -2925,7 +3576,11 @@ + fprintf(fp, "COMMAND: \"%s\"\n", tc->comm); + INDENT(indent); + fprintf(fp, " TASK: %lx ", tc->task); +- if ((cnt = TASKS_PER_PID(tc->pid)) > 1) ++ if ((machdep->flags & (INIT|MCA)) && (tc->pid == 0)) ++ cnt = comm_exists(tc->comm); ++ else ++ cnt = TASKS_PER_PID(tc->pid); ++ if (cnt > 1) + fprintf(fp, "(1 of %d) ", cnt); + if (tt->flags & THREAD_INFO) + fprintf(fp, "[THREAD_INFO: %lx]", tc->thread_info); +@@ -2938,19 +3593,27 @@ if (is_task_active(tc->task)) { if (machdep->flags & HWRESET) fprintf(fp, "(HARDWARE RESET)"); @@ -8082,6 +11443,8 @@ else if (machdep->flags & INIT) fprintf(fp, "(INIT)"); - else if (kt->cpu_flags[tc->processor] & NMI) ++ else if ((machdep->flags & MCA) && (tc->task == tt->panic_task)) ++ fprintf(fp, "(MCA)"); + else if ((tc->processor >= 0) && + (tc->processor < NR_CPUS) && + (kt->cpu_flags[tc->processor] & NMI)) @@ -8092,7 +11455,52 @@ else if (tc->task == tt->panic_task) fprintf(fp, "(PANIC)"); else -@@ -3411,6 +3652,9 @@ + fprintf(fp, "(ACTIVE)"); + } + +- if (!(pc->flags & RUNTIME) && (tt->flags & PANIC_TASK_NOT_FOUND) && ++ if (!(pc->flags & RUNTIME) && !ACTIVE() && ++ (tt->flags & PANIC_TASK_NOT_FOUND) && + !SYSRQ_TASK(tc->task)) { + fprintf(fp, "\n"); INDENT(indent); + if (machine_type("S390") || machine_type("S390X")) +@@ -3182,6 +3845,22 @@ + return flags; + } + ++/* ++ * Return a task's tgid. ++ */ ++ulong ++task_tgid(ulong task) ++{ ++ uint tgid; ++ ++ fill_task_struct(task); ++ ++ tgid = tt->last_task_read ? ++ UINT(tt->task_struct + OFFSET(task_struct_tgid)) : 0; ++ ++ return (ulong)tgid; ++} ++ + ulonglong + task_last_run(ulong task) + { +@@ -3368,6 +4047,12 @@ + task = NO_TASK; + tc = FIRST_CONTEXT(); + ++ /* ++ * --no_panic command line option ++ */ ++ if (tt->flags & PANIC_TASK_NOT_FOUND) ++ goto use_task_0; ++ + if (symbol_exists("panic_threads") && + symbol_exists("panicmsg") && + symbol_exists("panic_processor")) { +@@ -3411,6 +4096,9 @@ use_task_0: @@ -8102,7 +11510,7 @@ tt->flags |= PANIC_TASK_NOT_FOUND; tc = FIRST_CONTEXT(); return(tc->task); -@@ -3448,49 +3692,68 @@ +@@ -3448,49 +4136,73 @@ int msg_found; BZERO(buf, BUFSIZE); @@ -8198,6 +11606,11 @@ + get_symbol_data("sysrq_pressed", sizeof(int), + &msg_found); + } ++ rewind(pc->tmpfile); ++ while (!msg_found && fgets(buf, BUFSIZE, pc->tmpfile)) { ++ if (strstr(buf, "Kernel panic - ")) ++ msg_found = TRUE; ++ } + + close_tmpfile(); + @@ -8206,7 +11619,7 @@ return(buf); } -@@ -3517,7 +3780,7 @@ +@@ -3517,7 +4229,7 @@ BZERO(&foreach_data, sizeof(struct foreach_data)); fd = &foreach_data; @@ -8215,7 +11628,7 @@ switch(c) { case 'R': -@@ -3560,6 +3823,10 @@ +@@ -3560,6 +4272,10 @@ fd->flags |= FOREACH_r_FLAG; break; @@ -8226,7 +11639,56 @@ case 't': fd->flags |= FOREACH_t_FLAG; break; -@@ -3962,7 +4229,12 @@ +@@ -3754,12 +4470,14 @@ + foreach(struct foreach_data *fd) + { + int i, j, k, a; +- struct task_context *tc; ++ struct task_context *tc, *tgc; + int specified; + int doit; + int subsequent; + ulong cmdflags; ++ ulong tgid; + struct reference reference, *ref; ++ int print_header; + struct bt_info bt_info, *bt; + + /* +@@ -3797,6 +4515,8 @@ + fd->reference ? fd->reference : ""); + } + ++ print_header = TRUE; ++ + for (k = 0; k < fd->keys; k++) { + switch(fd->keyword_array[k]) + { +@@ -3881,6 +4601,14 @@ + error(FATAL, + "sig: -l and -s options are not applicable\n"); + } ++ if (fd->flags & FOREACH_g_FLAG) { ++ if (!hq_open()) { ++ error(INFO, ++ "cannot hash thread group tasks\n"); ++ fd->flags &= ~FOREACH_g_FLAG; ++ } else ++ print_header = FALSE; ++ } + break; + + case FOREACH_TEST: +@@ -3941,7 +4669,7 @@ + if (fd->reference) { + BZERO(ref, sizeof(struct reference)); + ref->str = fd->reference; +- } else ++ } else if (print_header) + print_task_header(fp, tc, subsequent++); + + for (k = 0; k < fd->keys; k++) { +@@ -3962,7 +4690,12 @@ bt->flags |= BT_SYMBOLIC_ARGS; if (fd->flags & FOREACH_t_FLAG) bt->flags |= BT_TEXT_SYMBOLS; @@ -8240,7 +11702,45 @@ bt->flags |= BT_OLD_BACK_TRACE; if (fd->flags & FOREACH_e_FLAG) bt->flags |= BT_EFRAME_SEARCH; -@@ -4188,6 +4460,12 @@ +@@ -4010,8 +4743,14 @@ + + case FOREACH_SIG: + pc->curcmd = "sig"; +- do_sig(tc->task, FOREACH_SIG, +- fd->reference ? ref : NULL); ++ if (fd->flags & FOREACH_g_FLAG) { ++ tgid = task_tgid(tc->task); ++ tgc = tgid_to_context(tgid); ++ if (hq_enter(tgc->task)) ++ do_sig_thread_group(tgc->task); ++ } else ++ do_sig(tc->task, FOREACH_SIG, ++ fd->reference ? ref : NULL); + break; + + case FOREACH_SET: +@@ -4075,6 +4814,11 @@ + nlm_files_dump(); + } + break; ++ ++ case FOREACH_SIG: ++ if (fd->flags & FOREACH_g_FLAG) ++ hq_close(); ++ break; + } + } + +@@ -4161,7 +4905,7 @@ + fd = &foreach_data; + fd->keys = 1; + fd->keyword_array[0] = FOREACH_BT; +- fd->flags |= FOREACH_t_FLAG; ++ fd->flags |= (FOREACH_t_FLAG|FOREACH_o_FLAG); + + dietask = lasttask = NO_TASK; + +@@ -4188,6 +4932,12 @@ break; } @@ -8253,18 +11753,18 @@ if (strstr(buf, " die at ")) { switch (dietask) { -@@ -4211,6 +4489,10 @@ +@@ -4211,6 +4961,10 @@ if (dietask == (NO_TASK+1)) error(WARNING, "multiple active tasks have called die\n\n"); -+ if (CRASHDEBUG(1)) ++ if (CRASHDEBUG(1) && found) + error(INFO, "panic_search: %lx (via foreach bt)\n", + lasttask); + found_panic_task: populate_panic_threads(); -@@ -4229,6 +4511,9 @@ +@@ -4229,6 +4983,9 @@ } } @@ -8274,7 +11774,7 @@ return NULL; } -@@ -4240,25 +4525,28 @@ +@@ -4240,25 +4997,28 @@ { ulong task; @@ -8314,7 +11814,7 @@ return NO_TASK; } -@@ -4298,14 +4586,17 @@ +@@ -4298,14 +5058,17 @@ tc = FIRST_CONTEXT(); for (i = 0; i < RUNNING_TASKS(); i++, tc++) { @@ -8334,7 +11834,7 @@ tt->panic_threads[0] = get_dumpfile_panic_task(); } -@@ -4331,7 +4622,7 @@ +@@ -4331,7 +5094,7 @@ void dump_task_table(int verbose) { @@ -8343,7 +11843,7 @@ struct task_context *tc; char buf[BUFSIZE]; int others, wrap, flen; -@@ -4363,6 +4654,8 @@ +@@ -4363,6 +5126,8 @@ fprintf(fp, "refresh_pid_hash_task_table()\n"); else if (tt->refresh_task_table == refresh_hlist_task_table) fprintf(fp, "refresh_hlist_task_table()\n"); @@ -8352,18 +11852,18 @@ else fprintf(fp, "%lx\n", (ulong)tt->refresh_task_table); -@@ -4443,7 +4736,9 @@ +@@ -4443,7 +5208,9 @@ wrap = sizeof(void *) == SIZEOF_32BIT ? 8 : 4; flen = sizeof(void *) == SIZEOF_32BIT ? 8 : 16; - for (i = 0; i < NR_CPUS; i++) { -+ nr_cpus = kt->kernel_NR_CPUS ? kt->kernel_NR_CPUS : nr_cpus; ++ nr_cpus = kt->kernel_NR_CPUS ? kt->kernel_NR_CPUS : NR_CPUS; + + for (i = 0; i < nr_cpus; i++) { if ((i % wrap) == 0) fprintf(fp, "\n "); fprintf(fp, "%.*lx ", flen, tt->panic_threads[i]); -@@ -4451,7 +4746,7 @@ +@@ -4451,7 +5218,7 @@ fprintf(fp, "\n"); fprintf(fp, " panic_ksp:"); @@ -8372,7 +11872,7 @@ if ((i % wrap) == 0) fprintf(fp, "\n "); fprintf(fp, "%.*lx ", flen, tt->panic_ksp[i]); -@@ -4459,7 +4754,7 @@ +@@ -4459,7 +5226,7 @@ fprintf(fp, "\n"); fprintf(fp, " hardirq_ctx:"); @@ -8381,7 +11881,7 @@ if ((i % wrap) == 0) fprintf(fp, "\n "); fprintf(fp, "%.*lx ", flen, tt->hardirq_ctx[i]); -@@ -4467,7 +4762,7 @@ +@@ -4467,7 +5234,7 @@ fprintf(fp, "\n"); fprintf(fp, " hardirq_tasks:"); @@ -8390,7 +11890,7 @@ if ((i % wrap) == 0) fprintf(fp, "\n "); fprintf(fp, "%.*lx ", flen, tt->hardirq_tasks[i]); -@@ -4475,7 +4770,7 @@ +@@ -4475,7 +5242,7 @@ fprintf(fp, "\n"); fprintf(fp, " softirq_ctx:"); @@ -8399,7 +11899,7 @@ if ((i % wrap) == 0) fprintf(fp, "\n "); fprintf(fp, "%.*lx ", flen, tt->softirq_ctx[i]); -@@ -4483,7 +4778,7 @@ +@@ -4483,7 +5250,7 @@ fprintf(fp, "\n"); fprintf(fp, " softirq_tasks:"); @@ -8408,7 +11908,7 @@ if ((i % wrap) == 0) fprintf(fp, "\n "); fprintf(fp, "%.*lx ", flen, tt->softirq_tasks[i]); -@@ -4491,7 +4786,7 @@ +@@ -4491,7 +5258,7 @@ fprintf(fp, "\n"); fprintf(fp, " idle_threads:"); @@ -8417,7 +11917,7 @@ if ((i % wrap) == 0) fprintf(fp, "\n "); fprintf(fp, "%.*lx ", flen, tt->idle_threads[i]); -@@ -4499,7 +4794,7 @@ +@@ -4499,7 +5266,7 @@ fprintf(fp, "\n"); fprintf(fp, " active_set:"); @@ -8426,7 +11926,17 @@ if ((i % wrap) == 0) fprintf(fp, "\n "); fprintf(fp, "%.*lx ", flen, tt->active_set[i]); -@@ -4799,23 +5094,47 @@ +@@ -4546,6 +5313,9 @@ + if ((tc->pid == 0) && !STREQ(tc->comm, pc->program_name)) + return TRUE; + ++ if (_ZOMBIE_ == TASK_STATE_UNINITIALIZED) ++ initialize_task_state(); ++ + if (IS_ZOMBIE(task) || IS_EXITING(task)) + return FALSE; + +@@ -4799,23 +5569,55 @@ tt->flags &= ~ACTIVE_SET; } @@ -8468,6 +11978,14 @@ + } \ + \ + if (panic_task && die_task) { \ ++ if ((panic_task > (NO_TASK+1)) && \ ++ (panic_task == die_task)) { \ ++ if (CRASHDEBUG(1)) \ ++ fprintf(fp, \ ++ "get_active_set_panic_task: %lx (panic)\n", \ ++ panic_task); \ ++ return panic_task; \ ++ } \ + error(WARNING, \ + "multiple active tasks have called die and/or panic\n\n"); \ + goto no_panic_task_found; \ @@ -8489,7 +12007,7 @@ while (fgets(buf, BUFSIZE, pc->tmpfile)) { \ if (strstr(buf, " die+")) { \ switch (die_task) \ -@@ -4833,12 +5152,23 @@ +@@ -4833,12 +5635,30 @@ { \ case NO_TASK: \ panic_task = task; \ @@ -8505,30 +12023,49 @@ + strstr(buf, " .crash_kexec+")) { \ + crash_kexec_task = task; \ + } \ ++ if (strstr(buf, " machine_kexec+") || \ ++ strstr(buf, " .machine_kexec+")) { \ ++ crash_kexec_task = task; \ ++ } \ + if (strstr(buf, " xen_panic_event+") || \ + strstr(buf, " .xen_panic_event+")){ \ + xen_panic_task = task; \ + xendump_panic_hook(buf); \ + } \ ++ if (machine_type("IA64") && XENDUMP_DUMPFILE() && !xen_panic_task && \ ++ strstr(buf, " sysrq_handle_crashdump+")) \ ++ xen_sysrq_task = task; \ } /* -@@ -4850,11 +5180,12 @@ +@@ -4850,11 +5670,14 @@ int i, j, found; ulong task; char buf[BUFSIZE]; - ulong panic_task, die_task; + ulong panic_task, die_task, crash_kexec_task; + ulong xen_panic_task; ++ ulong xen_sysrq_task; char *tp; struct task_context *tc; - panic_task = die_task = NO_TASK; + panic_task = die_task = crash_kexec_task = xen_panic_task = NO_TASK; ++ xen_sysrq_task = NO_TASK; for (i = 0; i < NR_CPUS; i++) { if (!(task = tt->active_set[i])) -@@ -4875,7 +5206,7 @@ +@@ -4867,15 +5690,16 @@ + if ((tp = fill_task_struct(task))) { + if ((tc = store_context(NULL, task, tp))) + tt->running_tasks++; ++ else ++ continue; + } +- continue; + } + + open_tmpfile(); raw_stack_dump(GET_STACKBASE(task), STACKSIZE()); rewind(pc->tmpfile); @@ -8537,7 +12074,7 @@ close_tmpfile(); } -@@ -4903,7 +5234,7 @@ +@@ -4903,7 +5727,7 @@ raw_stack_dump(tt->hardirq_ctx[i], SIZE(thread_union)); rewind(pc->tmpfile); @@ -8546,7 +12083,7 @@ close_tmpfile(); } -@@ -4930,7 +5261,7 @@ +@@ -4930,7 +5754,7 @@ raw_stack_dump(tt->softirq_ctx[i], SIZE(thread_union)); rewind(pc->tmpfile); @@ -8555,7 +12092,7 @@ close_tmpfile(); } -@@ -4938,6 +5269,20 @@ +@@ -4938,6 +5762,28 @@ RESOLVE_PANIC_AND_DIE_CALLERS(); } @@ -8567,6 +12104,14 @@ + return crash_kexec_task; + } + ++ if (xen_sysrq_task) { ++ if (CRASHDEBUG(1)) ++ error(INFO, ++ "get_active_set_panic_task: %lx (sysrq_handle_crashdump)\n", ++ xen_sysrq_task); ++ return xen_sysrq_task; ++ } ++ +no_panic_task_found: + + if (CRASHDEBUG(1)) @@ -8576,7 +12121,240 @@ return NO_TASK; } -@@ -5174,6 +5519,9 @@ +@@ -4997,6 +5843,11 @@ + ulong *tlist; + struct task_context *tc; + ++ if (VALID_MEMBER(rq_cfs)) { ++ dump_CFS_runqueues(); ++ return; ++ } ++ + if (VALID_MEMBER(runqueue_arrays)) { + dump_runqueues(); + return; +@@ -5169,11 +6020,230 @@ + } + } + ++/* ++ * CFS scheduler uses Red-Black trees to maintain run queue. ++ */ ++struct rb_node ++{ ++ unsigned long rb_parent_color; ++#define RB_RED 0 ++#define RB_BLACK 1 ++ struct rb_node *rb_right; ++ struct rb_node *rb_left; ++}; ++ ++struct rb_root ++{ ++ struct rb_node *rb_node; ++}; ++ ++static struct rb_node * ++rb_first(struct rb_root *root) ++{ ++ struct rb_root rloc; ++ struct rb_node *n; ++ struct rb_node nloc; ++ ++ readmem((ulong)root, KVADDR, &rloc, sizeof(struct rb_root), ++ "rb_root", FAULT_ON_ERROR); ++ ++ n = rloc.rb_node; ++ if (!n) ++ return NULL; ++ while (rb_left(n, &nloc)) ++ n = nloc.rb_left; ++ ++ return n; ++} ++ ++static struct rb_node * ++rb_parent(struct rb_node *node, struct rb_node *nloc) ++{ ++ readmem((ulong)node, KVADDR, nloc, sizeof(struct rb_node), ++ "rb_node", FAULT_ON_ERROR); ++ ++ return (struct rb_node *)(nloc->rb_parent_color & ~3); ++} ++ ++static struct rb_node * ++rb_right(struct rb_node *node, struct rb_node *nloc) ++{ ++ readmem((ulong)node, KVADDR, nloc, sizeof(struct rb_node), ++ "rb_node", FAULT_ON_ERROR); ++ ++ return nloc->rb_right; ++} ++ ++static struct rb_node * ++rb_left(struct rb_node *node, struct rb_node *nloc) ++{ ++ readmem((ulong)node, KVADDR, nloc, sizeof(struct rb_node), ++ "rb_node", FAULT_ON_ERROR); ++ ++ return nloc->rb_left; ++} ++ ++static struct rb_node * ++rb_next(struct rb_node *node) ++{ ++ struct rb_node nloc; ++ struct rb_node *parent; ++ ++ parent = rb_parent(node, &nloc); ++ ++ if (parent == node) ++ return NULL; ++ ++ if (nloc.rb_right) { ++ node = nloc.rb_right; ++ while (rb_left(node, &nloc)) ++ node = nloc.rb_left; ++ return node; ++ } ++ ++ while ((parent = rb_parent(node, &nloc)) && (node == rb_right(parent, &nloc))) ++ node = parent; ++ ++ return parent; ++} ++ ++static void ++dump_CFS_runqueues(void) ++{ ++ int cpu; ++ ulong runq; ++ char *runqbuf; ++ ulong leftmost, tasks_timeline; ++ struct task_context *tc; ++ long nr_running, cfs_rq_nr_running; ++ struct rb_root *root; ++ struct rb_node *node; ++ ++ if (INVALID_MEMBER(rq_rt)) { ++ MEMBER_OFFSET_INIT(rq_rt, "rq", "rt"); ++ MEMBER_OFFSET_INIT(rq_nr_running, "rq", "nr_running"); ++ MEMBER_OFFSET_INIT(task_struct_se, "task_struct", "se"); ++ MEMBER_OFFSET_INIT(sched_entity_run_node, "sched_entity", ++ "run_node"); ++ MEMBER_OFFSET_INIT(cfs_rq_rb_leftmost, "cfs_rq", "rb_leftmost"); ++ MEMBER_OFFSET_INIT(cfs_rq_nr_running, "cfs_rq", "nr_running"); ++ MEMBER_OFFSET_INIT(cfs_rq_tasks_timeline, "cfs_rq", ++ "tasks_timeline"); ++ MEMBER_OFFSET_INIT(rt_rq_active, "rt_rq", "active"); ++ MEMBER_OFFSET_INIT(task_struct_run_list, "task_struct", ++ "run_list"); ++ } ++ ++ if (!symbol_exists("per_cpu__runqueues")) ++ error(FATAL, "per_cpu__runqueues does not exist\n"); ++ ++ runq = symbol_value("per_cpu__runqueues"); ++ ++ runqbuf = GETBUF(SIZE(runqueue)); ++ ++ for (cpu = 0; cpu < kt->cpus; cpu++) { ++ if ((kt->flags & SMP) && (kt->flags & PER_CPU_OFF)) { ++ runq = symbol_value("per_cpu__runqueues") + ++ kt->__per_cpu_offset[cpu]; ++ } else ++ runq = symbol_value("per_cpu__runqueues"); ++ ++ fprintf(fp, "RUNQUEUES[%d]: %lx\n", cpu, runq); ++ ++ readmem(runq, KVADDR, runqbuf, SIZE(runqueue), ++ "per-cpu rq", FAULT_ON_ERROR); ++ leftmost = ULONG(runqbuf + OFFSET(rq_cfs) + ++ OFFSET(cfs_rq_rb_leftmost)); ++ tasks_timeline = ULONG(runqbuf + OFFSET(rq_cfs) + ++ OFFSET(cfs_rq_tasks_timeline)); ++ nr_running = LONG(runqbuf + OFFSET(rq_nr_running)); ++ cfs_rq_nr_running = ULONG(runqbuf + OFFSET(rq_cfs) + ++ OFFSET(cfs_rq_nr_running)); ++ ++ dump_RT_prio_array(nr_running != cfs_rq_nr_running, ++ runq + OFFSET(rq_rt) + OFFSET(rt_rq_active), ++ &runqbuf[OFFSET(rq_rt) + OFFSET(rt_rq_active)]); ++ ++ root = (struct rb_root *)(runq + OFFSET(rq_cfs) + OFFSET(cfs_rq_tasks_timeline)); ++ fprintf(fp, " CFS RB_ROOT: %lx\n", (ulong)root); ++ ++ if (!leftmost) ++ continue; ++ ++ for (node = rb_first(root); node; node = rb_next(node)) { ++ tc = task_to_context((ulong)node - OFFSET(task_struct_se) - ++ OFFSET(sched_entity_run_node)); ++ if (!tc) ++ continue; ++ INDENT(2); ++ print_task_header(fp, tc, FALSE); ++ } ++ } ++} ++ ++static void ++dump_RT_prio_array(int active, ulong k_prio_array, char *u_prio_array) ++{ ++ int i, c, cnt, qheads; ++ ulong offset, kvaddr, uvaddr; ++ ulong list_head[2]; ++ struct list_data list_data, *ld; ++ struct task_context *tc; ++ ulong *tlist; ++ ++ fprintf(fp, " RT PRIO_ARRAY: %lx\n", k_prio_array); ++ ++ if (!active) ++ return; ++ ++ qheads = (i = ARRAY_LENGTH(prio_array_queue)) ? ++ i : get_array_length("prio_array.queue", NULL, SIZE(list_head)); ++ ++ ld = &list_data; ++ ++ for (i = 0; i < qheads; i++) { ++ offset = OFFSET(prio_array_queue) + (i * SIZE(list_head)); ++ kvaddr = k_prio_array + offset; ++ uvaddr = (ulong)u_prio_array + offset; ++ BCOPY((char *)uvaddr, (char *)&list_head[0], sizeof(ulong)*2); ++ ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "prio_array[%d] @ %lx => %lx/%lx\n", ++ i, kvaddr, list_head[0], list_head[1]); ++ ++ if ((list_head[0] == kvaddr) && (list_head[1] == kvaddr)) ++ continue; ++ ++ fprintf(fp, " [%3d] ", i); ++ ++ BZERO(ld, sizeof(struct list_data)); ++ ld->start = list_head[0]; ++ ld->list_head_offset = OFFSET(task_struct_run_list); ++ ld->end = kvaddr; ++ hq_open(); ++ cnt = do_list(ld); ++ hq_close(); ++ tlist = (ulong *)GETBUF((cnt) * sizeof(ulong)); ++ cnt = retrieve_list(tlist, cnt); ++ for (c = 0; c < cnt; c++) { ++ if (!(tc = task_to_context(tlist[c]))) ++ continue; ++ if (c) ++ INDENT(8); ++ print_task_header(fp, tc, FALSE); ++ } ++ FREEBUF(tlist); ++ } ++} ++ + #undef _NSIG + #define _NSIG 64 #define _NSIG_BPW machdep->bits #define _NSIG_WORDS (_NSIG / _NSIG_BPW) @@ -8586,7 +12364,7 @@ static struct signame { char *name; char *altname; -@@ -5209,23 +5557,56 @@ +@@ -5209,23 +6279,56 @@ /* 28 */ {"SIGWINCH", NULL}, /* 29 */ {"SIGIO", "SIGPOLL"}, /* 30 */ {"SIGPWR", NULL}, @@ -8623,7 +12401,11 @@ - continue; + sigrtmax = sigrt_minmax(&min, &max); + j = 1; -+ + +- fprintf(fp, "%s[%d] %s", i < 10 ? " " : "", +- i, signame[i].name); +- if (signame[i].altname) +- fprintf(fp, "/%s", signame[i].altname); + for (i = 1; i <= sigrtmax; i++) { + if ((i == SIGRTMIN) || (i == sigrtmax)) { + fprintf(fp, "[%d] %s", i, @@ -8639,11 +12421,7 @@ + } else { + if (!signame[i].name) + continue; - -- fprintf(fp, "%s[%d] %s", i < 10 ? " " : "", -- i, signame[i].name); -- if (signame[i].altname) -- fprintf(fp, "/%s", signame[i].altname); ++ + fprintf(fp, "%s[%d] %s", i < 10 ? " " : "", + i, signame[i].name); + if (signame[i].altname) @@ -8652,7 +12430,7 @@ fprintf(fp, "\n"); } } -@@ -5236,8 +5617,7 @@ +@@ -5236,8 +6339,7 @@ static void translate_sigset(ulonglong sigset) { @@ -8662,7 +12440,7 @@ char buf[BUFSIZE]; if (!sigset) { -@@ -5246,21 +5626,42 @@ +@@ -5246,21 +6348,42 @@ } len = 0; @@ -8711,24 +12489,137 @@ } fprintf(fp, "\n"); } -@@ -5403,11 +5804,11 @@ +@@ -5290,13 +6413,14 @@ + struct task_context *tc; + ulong *tasklist; + char *siglist; ++ int thread_group = FALSE; + + tasklist = (ulong *)GETBUF((MAXARGS+NR_CPUS)*sizeof(ulong)); + ref = (struct reference *)GETBUF(sizeof(struct reference)); + siglist = GETBUF(BUFSIZE); + ref->str = siglist; + +- while ((c = getopt(argcnt, args, "lR:s:")) != EOF) { ++ while ((c = getopt(argcnt, args, "lR:s:g")) != EOF) { + switch(c) + { + case 's': +@@ -5314,6 +6438,10 @@ + signame_list(); + return; + ++ case 'g': ++ pc->curcmd_flags |= TASK_SPECIFIED; ++ thread_group = TRUE; ++ break; + default: + argerrs++; + break; +@@ -5360,12 +6488,67 @@ + tasklist[tcnt++] = CURRENT_TASK(); + + for (c = 0; c < tcnt; c++) { +- do_sig(tasklist[c], 0, strlen(ref->str) ? ref : NULL); +- fprintf(fp, "\n"); ++ if (thread_group) ++ do_sig_thread_group(tasklist[c]); ++ else { ++ do_sig(tasklist[c], 0, strlen(ref->str) ? ref : NULL); ++ fprintf(fp, "\n"); ++ } + } + + } + ++ ++/* ++ * Do the work for the "sig -g" command option, coming from sig or foreach. ++ */ ++static void ++do_sig_thread_group(ulong task) ++{ ++ int i; ++ int cnt; ++ struct task_context *tc; ++ ulong tgid; ++ ++ tc = task_to_context(task); ++ tgid = task_tgid(task); ++ ++ if (tc->pid != tgid) { ++ if (pc->curcmd_flags & TASK_SPECIFIED) { ++ if (!(tc = tgid_to_context(tgid))) ++ return; ++ task = tc->task; ++ } else ++ return; ++ } ++ ++ if ((tc->pid == 0) && (pc->curcmd_flags & IDLE_TASK_SHOWN)) ++ return; ++ ++ print_task_header(fp, tc, 0); ++ dump_signal_data(tc, THREAD_GROUP_LEVEL); ++ fprintf(fp, "\n "); ++ print_task_header(fp, tc, 0); ++ dump_signal_data(tc, TASK_LEVEL|TASK_INDENT); ++ ++ tc = FIRST_CONTEXT(); ++ for (i = cnt = 0; i < RUNNING_TASKS(); i++, tc++) { ++ if (tc->task == task) ++ continue; ++ ++ if (task_tgid(tc->task) == tgid) { ++ fprintf(fp, "\n "); ++ print_task_header(fp, tc, 0); ++ dump_signal_data(tc, TASK_LEVEL|TASK_INDENT); ++ cnt++; ++ if (tc->pid == 0) ++ pc->curcmd_flags |= IDLE_TASK_SHOWN; ++ } ++ } ++ ++ fprintf(fp, "\n"); ++} ++ + /* + * Do the work for the sig command, coming from sig or foreach. + */ +@@ -5381,7 +6564,7 @@ + else { + if (!(flags & FOREACH_TASK)) + print_task_header(fp, tc, 0); +- dump_signal_data(tc); ++ dump_signal_data(tc, TASK_LEVEL|THREAD_GROUP_LEVEL); + } + } + +@@ -5401,40 +6584,34 @@ + * Dump all signal-handling data for a task. + */ static void - dump_signal_data(struct task_context *tc) +-dump_signal_data(struct task_context *tc) ++dump_signal_data(struct task_context *tc, ulong flags) { - int i, others, use_sighand; +- int translate, sig, sigpending; + int i, sigrtmax, others, use_sighand; - int translate, sig, sigpending; ++ int translate, sigpending; uint ti_flags; ulonglong sigset, blocked, mask; - ulong signal_struct, kaddr, handler, flags, sigqueue, next; -+ ulong signal_struct, kaddr, handler, flags, sigqueue, sigqueue_save, next; ++ ulong signal_struct, kaddr, handler, sa_flags, sigqueue; ulong sighand_struct; long size; char *signal_buf, *uaddr; -@@ -5416,6 +5817,15 @@ ++ ulong shared_pending, signal; + char buf1[BUFSIZE]; + char buf2[BUFSIZE]; char buf3[BUFSIZE]; char buf4[BUFSIZE]; +- sigset = task_signal(tc->task); + if (VALID_STRUCT(sigqueue) && !VALID_MEMBER(sigqueue_next)) { + MEMBER_OFFSET_INIT(sigqueue_next, "sigqueue", "next"); + MEMBER_OFFSET_INIT(sigqueue_list, "sigqueue", "list"); @@ -8738,42 +12629,473 @@ + MEMBER_OFFSET_INIT(signal_queue_info, "signal_queue", "info"); + } + - sigset = task_signal(tc->task); ++ sigset = task_signal(tc->task, 0); if (!tt->last_task_read) return; -@@ -5474,7 +5884,9 @@ - } else - use_sighand = FALSE; +- blocked = task_blocked(tc->task); +- +- if (VALID_MEMBER(task_struct_sigpending)) +- sigpending = INT(tt->task_struct + +- OFFSET(task_struct_sigpending)); +- else if (VALID_MEMBER(thread_info_flags)) { +- fill_thread_info(tc->thread_info); +- ti_flags = UINT(tt->thread_info + OFFSET(thread_info_flags)); +- sigpending = ti_flags & (1<task_struct + +@@ -5443,143 +6620,259 @@ + signal_struct = ULONG(tt->task_struct + + OFFSET(task_struct_signal)); + +- fprintf(fp, "SIGNAL_STRUCT: %lx ", signal_struct); +- + size = MAX(SIZE(signal_struct), VALID_SIZE(signal_queue) ? + SIZE(signal_queue) : SIZE(sigqueue)); + if (VALID_SIZE(sighand_struct)) + size = MAX(size, SIZE(sighand_struct)); + signal_buf = GETBUF(size); + +- readmem(signal_struct, KVADDR, signal_buf, +- SIZE(signal_struct), "signal_struct buffer", +- FAULT_ON_ERROR); +- fprintf(fp, "COUNT: %d\n", +- INT(signal_buf + OFFSET(signal_struct_count))); +- +- fprintf(fp, " SIG %s %s %s %s\n", +- mkstring(buf1, VADDR_PRLEN == 8 ? 9 : VADDR_PRLEN, +- CENTER, "SIGACTION"), ++ if (signal_struct) ++ readmem(signal_struct, KVADDR, signal_buf, ++ SIZE(signal_struct), "signal_struct buffer", ++ FAULT_ON_ERROR); ++ ++ /* ++ * Signal dispositions (thread group level). ++ */ ++ if (flags & THREAD_GROUP_LEVEL) { ++ if (flags & TASK_INDENT) ++ INDENT(2); ++ fprintf(fp, "SIGNAL_STRUCT: %lx ", signal_struct); ++ if (!signal_struct) { ++ fprintf(fp, "\n"); ++ return; ++ } ++ fprintf(fp, "COUNT: %d\n", ++ INT(signal_buf + OFFSET(signal_struct_count))); ++ ++ if (flags & TASK_INDENT) ++ INDENT(2); ++ fprintf(fp, " SIG %s %s %s %s\n", ++ mkstring(buf1, VADDR_PRLEN == 8 ? 9 : VADDR_PRLEN, ++ CENTER, "SIGACTION"), + mkstring(buf2, UVADDR_PRLEN, RJUST, "HANDLER"), + mkstring(buf3, 16, CENTER, "MASK"), + mkstring(buf4, VADDR_PRLEN, LJUST, "FLAGS")); + +- if (VALID_MEMBER(task_struct_sighand)) { +- sighand_struct = ULONG(tt->task_struct + +- OFFSET(task_struct_sighand)); +- readmem(sighand_struct, KVADDR, signal_buf, +- SIZE(sighand_struct), "sighand_struct buffer", +- FAULT_ON_ERROR); +- use_sighand = TRUE; +- } else +- use_sighand = FALSE; +- - for (i = 1; i < _NSIG; i++) { -+ sigrtmax = sigrt_minmax(NULL, NULL); -+ -+ for (i = 1; i <= sigrtmax; i++) { - fprintf(fp, "%s[%d] ", i < 10 ? " " : "", i); +- fprintf(fp, "%s[%d] ", i < 10 ? " " : "", i); +- +- if (use_sighand) { +- kaddr = sighand_struct + OFFSET(sighand_struct_action) + +- ((i-1) * SIZE(k_sigaction)); +- uaddr = signal_buf + OFFSET(sighand_struct_action) + +- ((i-1) * SIZE(k_sigaction)); +- } else { +- kaddr = signal_struct + OFFSET(signal_struct_action) + +- ((i-1) * SIZE(k_sigaction)); +- uaddr = signal_buf + OFFSET(signal_struct_action) + +- ((i-1) * SIZE(k_sigaction)); +- } ++ if (VALID_MEMBER(task_struct_sighand)) { ++ sighand_struct = ULONG(tt->task_struct + ++ OFFSET(task_struct_sighand)); ++ readmem(sighand_struct, KVADDR, signal_buf, ++ SIZE(sighand_struct), "sighand_struct buffer", ++ FAULT_ON_ERROR); ++ use_sighand = TRUE; ++ } else ++ use_sighand = FALSE; - if (use_sighand) { -@@ -5580,6 +5992,8 @@ - else - fprintf(fp, "SIGQUEUE: (empty)\n"); +- handler = ULONG(uaddr + OFFSET(sigaction_sa_handler)); +- switch ((long)handler) +- { +- case -1: +- mkstring(buf1, UVADDR_PRLEN, RJUST, "SIG_ERR"); +- break; +- case 0: +- mkstring(buf1, UVADDR_PRLEN, RJUST, "SIG_DFL"); +- break; +- case 1: +- mkstring(buf1, UVADDR_PRLEN, RJUST, "SIG_IGN"); +- break; +- default: +- mkstring(buf1, UVADDR_PRLEN, RJUST|LONG_HEX, +- MKSTR(handler)); +- break; +- } ++ sigrtmax = sigrt_minmax(NULL, NULL); -+ sigqueue_save = sigqueue; +- mask = sigaction_mask((ulong)uaddr); +- flags = ULONG(uaddr + OFFSET(sigaction_sa_flags)); ++ for (i = 1; i <= sigrtmax; i++) { ++ if (flags & TASK_INDENT) ++ INDENT(2); + +- fprintf(fp, "%s%s %s %016llx %lx ", +- space(MINSPACE-1), +- mkstring(buf2,UVADDR_PRLEN,LJUST|LONG_HEX,MKSTR(kaddr)), +- buf1, +- mask, +- flags); +- +- if (flags) { +- others = 0; translate = 1; +- if (flags & SA_NOCLDSTOP) +- fprintf(fp, "%s%sSA_NOCLDSTOP", +- translate-- > 0 ? "(" : "", +- others++ ? "|" : ""); ++ fprintf(fp, "%s[%d] ", i < 10 ? " " : "", i); ++ ++ if (use_sighand) { ++ kaddr = sighand_struct + ++ OFFSET(sighand_struct_action) + ++ ((i-1) * SIZE(k_sigaction)); ++ uaddr = signal_buf + ++ OFFSET(sighand_struct_action) + ++ ((i-1) * SIZE(k_sigaction)); ++ } else { ++ kaddr = signal_struct + ++ OFFSET(signal_struct_action) + ++ ((i-1) * SIZE(k_sigaction)); ++ uaddr = signal_buf + ++ OFFSET(signal_struct_action) + ++ ((i-1) * SIZE(k_sigaction)); ++ } ++ ++ handler = ULONG(uaddr + OFFSET(sigaction_sa_handler)); ++ switch ((long)handler) ++ { ++ case -1: ++ mkstring(buf1, UVADDR_PRLEN, RJUST, "SIG_ERR"); ++ break; ++ case 0: ++ mkstring(buf1, UVADDR_PRLEN, RJUST, "SIG_DFL"); ++ break; ++ case 1: ++ mkstring(buf1, UVADDR_PRLEN, RJUST, "SIG_IGN"); ++ break; ++ default: ++ mkstring(buf1, UVADDR_PRLEN, RJUST|LONG_HEX, ++ MKSTR(handler)); ++ break; ++ } ++ ++ mask = sigaction_mask((ulong)uaddr); ++ sa_flags = ULONG(uaddr + OFFSET(sigaction_sa_flags)); ++ ++ fprintf(fp, "%s%s %s %016llx %lx ", ++ space(MINSPACE-1), ++ mkstring(buf2, ++ UVADDR_PRLEN,LJUST|LONG_HEX,MKSTR(kaddr)), ++ buf1, ++ mask, ++ sa_flags); ++ ++ if (sa_flags) { ++ others = 0; translate = 1; ++ if (sa_flags & SA_NOCLDSTOP) ++ fprintf(fp, "%s%sSA_NOCLDSTOP", ++ translate-- > 0 ? "(" : "", ++ others++ ? "|" : ""); + #ifdef SA_RESTORER +- if (flags & SA_RESTORER) +- fprintf(fp, "%s%sSA_RESTORER", +- translate-- > 0 ? "(" : "", +- others++ ? "|" : ""); ++ if (sa_flags & SA_RESTORER) ++ fprintf(fp, "%s%sSA_RESTORER", ++ translate-- > 0 ? "(" : "", ++ others++ ? "|" : ""); + #endif + #ifdef SA_NOCLDWAIT +- if (flags & SA_NOCLDWAIT) +- fprintf(fp, "%s%sSA_NOCLDWAIT", +- translate-- > 0 ? "(" : "", +- others++ ? "|" : ""); ++ if (sa_flags & SA_NOCLDWAIT) ++ fprintf(fp, "%s%sSA_NOCLDWAIT", ++ translate-- > 0 ? "(" : "", ++ others++ ? "|" : ""); + #endif +- if (flags & SA_SIGINFO) +- fprintf(fp, "%s%sSA_SIGINFO", +- translate-- > 0 ? "(" : "", +- others++ ? "|" : ""); +- if (flags & SA_ONSTACK) +- fprintf(fp, "%s%sSA_ONSTACK", +- translate-- > 0 ? "(" : "", +- others++ ? "|" : ""); +- if (flags & SA_RESTART) +- fprintf(fp, "%s%sSA_RESTART", +- translate-- > 0 ? "(" : "", +- others++ ? "|" : ""); +- if (flags & SA_NODEFER) +- fprintf(fp, "%s%sSA_NODEFER", +- translate-- > 0 ? "(" : "", +- others++ ? "|" : ""); +- if (flags & SA_RESETHAND) +- fprintf(fp, "%s%sSA_RESETHAND", +- translate-- > 0 ? "(" : "", +- others++ ? "|" : ""); +- if (translate < 1) +- fprintf(fp, ")"); +- } +- +- fprintf(fp, "\n"); +- } +- +- if (VALID_MEMBER(task_struct_sigqueue)) +- sigqueue = ULONG(tt->task_struct + +- OFFSET(task_struct_sigqueue)); +- +- else if (VALID_MEMBER(task_struct_pending)) +- sigqueue = ULONG(tt->task_struct + +- OFFSET(task_struct_pending) + +- OFFSET_OPTION(sigpending_head, sigpending_list)); +- +- if (VALID_MEMBER(sigqueue_list) && empty_list(sigqueue)) +- sigqueue = 0; +- +- if (sigqueue) +- fprintf(fp, "SIGQUEUE: SIG %s\n", +- mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "SIGINFO")); +- else +- fprintf(fp, "SIGQUEUE: (empty)\n"); ++ if (sa_flags & SA_SIGINFO) ++ fprintf(fp, "%s%sSA_SIGINFO", ++ translate-- > 0 ? "(" : "", ++ others++ ? "|" : ""); ++ if (sa_flags & SA_ONSTACK) ++ fprintf(fp, "%s%sSA_ONSTACK", ++ translate-- > 0 ? "(" : "", ++ others++ ? "|" : ""); ++ if (sa_flags & SA_RESTART) ++ fprintf(fp, "%s%sSA_RESTART", ++ translate-- > 0 ? "(" : "", ++ others++ ? "|" : ""); ++ if (sa_flags & SA_NODEFER) ++ fprintf(fp, "%s%sSA_NODEFER", ++ translate-- > 0 ? "(" : "", ++ others++ ? "|" : ""); ++ if (sa_flags & SA_RESETHAND) ++ fprintf(fp, "%s%sSA_RESETHAND", ++ translate-- > 0 ? "(" : "", ++ others++ ? "|" : ""); ++ if (translate < 1) ++ fprintf(fp, ")"); ++ } ++ ++ fprintf(fp, "\n"); ++ } ++ } ++ ++ if (flags & TASK_LEVEL) { ++ /* ++ * Pending signals (task level). ++ */ ++ if (VALID_MEMBER(task_struct_sigpending)) ++ sigpending = INT(tt->task_struct + ++ OFFSET(task_struct_sigpending)); ++ else if (VALID_MEMBER(thread_info_flags)) { ++ fill_thread_info(tc->thread_info); ++ ti_flags = UINT(tt->thread_info + OFFSET(thread_info_flags)); ++ sigpending = ti_flags & (1<task); ++ if (flags & TASK_INDENT) ++ INDENT(2); ++ fprintf(fp, " BLOCKED: %016llx\n", blocked); ++ ++ /* ++ * Pending queue (task level). ++ */ ++ ++ if (flags & TASK_INDENT) ++ INDENT(2); ++ if (VALID_MEMBER(signal_struct_shared_pending)) { ++ fprintf(fp, "PRIVATE_PENDING\n"); ++ if (flags & TASK_INDENT) ++ INDENT(2); ++ } ++ fprintf(fp, " SIGNAL: %016llx\n", sigset); ++ ++ if (VALID_MEMBER(task_struct_sigqueue)) ++ sigqueue = ULONG(tt->task_struct + ++ OFFSET(task_struct_sigqueue)); ++ ++ else if (VALID_MEMBER(task_struct_pending)) ++ sigqueue = ULONG(tt->task_struct + ++ OFFSET(task_struct_pending) + ++ OFFSET_OPTION(sigpending_head, ++ sigpending_list)); ++ ++ if (VALID_MEMBER(sigqueue_list) && empty_list(sigqueue)) ++ sigqueue = 0; ++ ++ if (flags & TASK_INDENT) ++ INDENT(2); ++ if (sigqueue) { ++ fprintf(fp, " SIGQUEUE: SIG %s\n", ++ mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "SIGINFO")); ++ sigqueue_list(sigqueue); ++ } else ++ fprintf(fp, " SIGQUEUE: (empty)\n"); ++ } ++ ++ /* ++ * Pending queue (thread group level). ++ */ ++ if ((flags & THREAD_GROUP_LEVEL) && ++ VALID_MEMBER(signal_struct_shared_pending)) { + ++ fprintf(fp, "SHARED_PENDING\n"); ++ shared_pending = signal_struct + OFFSET(signal_struct_shared_pending); ++ signal = shared_pending + OFFSET(sigpending_signal); ++ readmem(signal, KVADDR, signal_buf,SIZE(sigpending_signal), ++ "signal", FAULT_ON_ERROR); ++ sigset = task_signal(0, (ulong*)signal_buf); ++ if (flags & TASK_INDENT) ++ INDENT(2); ++ fprintf(fp, " SIGNAL: %016llx\n", sigset); ++ sigqueue = (shared_pending + ++ OFFSET_OPTION(sigpending_head, sigpending_list) + ++ OFFSET(list_head_next)); ++ readmem(sigqueue,KVADDR, signal_buf, ++ SIZE(sigqueue), "sigqueue", FAULT_ON_ERROR); ++ sigqueue = ULONG(signal_buf); ++ ++ if (VALID_MEMBER(sigqueue_list) && empty_list(sigqueue)) ++ sigqueue = 0; ++ if (flags & TASK_INDENT) ++ INDENT(2); ++ if (sigqueue) { ++ fprintf(fp, " SIGQUEUE: SIG %s\n", ++ mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "SIGINFO")); ++ sigqueue_list(sigqueue); ++ } else ++ fprintf(fp, " SIGQUEUE: (empty)\n"); ++ } ++ FREEBUF(signal_buf); ++} ++ ++/* ++ * Dump a pending signal queue (private/shared). ++ */ ++ ++static void sigqueue_list(ulong sigqueue) { ++ ulong sigqueue_save, next; ++ int sig; ++ char *signal_buf; ++ long size; ++ size = VALID_SIZE(signal_queue) ? SIZE(signal_queue) : SIZE(sigqueue); ++ signal_buf = GETBUF(size); ++ ++ sigqueue_save = sigqueue; while (sigqueue) { readmem(sigqueue, KVADDR, signal_buf, SIZE_OPTION(signal_queue, sigqueue), -@@ -5597,6 +6011,9 @@ +@@ -5597,14 +6890,17 @@ OFFSET(siginfo_si_signo)); } +- fprintf(fp, " %3d %lx\n", + if (sigqueue_save == next) + break; + - fprintf(fp, " %3d %lx\n", ++ fprintf(fp, " %3d %lx\n", sig, sigqueue + OFFSET_OPTION(signal_queue_info, sigqueue_info)); ---- crash/kernel.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/kernel.c 2006-09-05 12:01:04.000000000 -0400 -@@ -20,7 +20,7 @@ + + sigqueue = next; + } +- + FREEBUF(signal_buf); ++ + } + + /* +@@ -5614,12 +6910,13 @@ + */ + + static ulonglong +-task_signal(ulong task) ++task_signal(ulong task, ulong *signal) + { + ulonglong sigset; + ulong *sigset_ptr; + +- fill_task_struct(task); ++ if (task) { ++ fill_task_struct(task); + + if (!tt->last_task_read) + return 0; +@@ -5633,6 +6930,10 @@ + OFFSET(task_struct_signal)); + } else + return 0; ++ } else if (signal) { ++ sigset_ptr = signal; ++ } else ++ return 0; + + switch (_NSIG_WORDS) + { +--- crash/kernel.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/kernel.c 2007-07-31 16:05:45.000000000 -0400 +@@ -1,8 +1,8 @@ + /* kernel.c - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 +@@ -16,11 +16,12 @@ + */ + + #include "defs.h" ++#include "xen_hyper_defs.h" + #include static void do_module_cmd(ulong, char *, ulong, char *, char *); static char *find_module_objfile(char *, char *, char *); @@ -8782,12 +13104,16 @@ static char *get_loadavg(char *); static void get_lkcd_regs(struct bt_info *, ulong *, ulong *); static void dump_sys_call_table(char *, int); -@@ -42,327 +42,365 @@ +@@ -42,328 +43,435 @@ static void verify_namelist(void); static char *debug_kernel_version(char *); static int restore_stack(struct bt_info *); +static ulong __xen_m2p(ulonglong, ulong); ++static int search_mapping_page(ulong, ulong *, ulong *, ulong *); +static void read_in_kernel_config_err(int, char *); ++static void BUG_bytes_init(void); ++static int BUG_x86(void); ++static int BUG_x86_64(void); /* @@ -8803,6 +13129,7 @@ + char *p1, *p2, buf[BUFSIZE]; struct syment *sp1, *sp2; + char *rqstruct; ++ char *irq_desc_type_name; if (pc->flags & KERNEL_DEBUG_QUERY) return; @@ -8846,16 +13173,26 @@ - (sp2->value > sp1->value)) - kt->flags |= SMP|PER_CPU_OFF; + /* -+ * If Xen architecture, default to writable page tables; for now -+ * it can be overridden with the --shared_page_tables command -+ * line option. ++ * For the Xen architecture, default to writable page tables unless: ++ * ++ * (1) it's an "xm save" CANONICAL_PAGE_TABLES dumpfile, or ++ * (2) the --shadow_page_tables option was explicitly entered. ++ * ++ * But if the "phys_to_maching_mapping" array does not exist, and ++ * it's not an "xm save" canonical dumpfile, then we have no choice ++ * but to presume shadow page tables. + */ + if (symbol_exists("xen_start_info")) { + kt->flags |= ARCH_XEN; + if (!(kt->xen_flags & (SHADOW_PAGE_TABLES|CANONICAL_PAGE_TABLES))) + kt->xen_flags |= WRITABLE_PAGE_TABLES; -+ get_symbol_data("phys_to_machine_mapping", sizeof(ulong), -+ &kt->phys_to_machine_mapping); ++ if (symbol_exists("phys_to_machine_mapping")) ++ get_symbol_data("phys_to_machine_mapping", sizeof(ulong), ++ &kt->phys_to_machine_mapping); ++ else if (!(kt->xen_flags & CANONICAL_PAGE_TABLES)) { ++ kt->xen_flags &= ~WRITABLE_PAGE_TABLES; ++ kt->xen_flags |= SHADOW_PAGE_TABLES; ++ } + if (machine_type("X86")) + get_symbol_data("max_pfn", sizeof(ulong), &kt->p2m_table_size); + if (machine_type("X86_64")) @@ -8878,8 +13215,9 @@ + kt->cpus = 1; + + if ((sp1 = symbol_search("__per_cpu_start")) && -+ (sp2 = symbol_search("__per_cpu_end")) && -+ (sp1->type == 'A') && (sp2->type == 'A') && ++ (sp2 = symbol_search("__per_cpu_end")) && ++ (sp1->type == 'A' || sp1->type == 'D') && ++ (sp2->type == 'A' || sp2->type == 'D') && + (sp2->value > sp1->value)) + kt->flags |= SMP|PER_CPU_OFF; @@ -8932,7 +13270,32 @@ - case POST_GDB: - if (symbol_exists("__per_cpu_offset")) { -- i = get_array_length("__per_cpu_offset", NULL, 0); ++ strncpy(buf, kt->utsname.release, MIN(strlen(kt->utsname.release), 65)); ++ if (ascii_string(kt->utsname.release)) { ++ p1 = p2 = buf; ++ while (*p2 != '.') ++ p2++; ++ *p2 = NULLCHAR; ++ kt->kernel_version[0] = atoi(p1); ++ p1 = ++p2; ++ while (*p2 != '.') ++ p2++; ++ *p2 = NULLCHAR; ++ kt->kernel_version[1] = atoi(p1); ++ p1 = ++p2; ++ while ((*p2 >= '0') && (*p2 <= '9')) ++ p2++; ++ *p2 = NULLCHAR; ++ kt->kernel_version[2] = atoi(p1); ++ } ++ ++ verify_version(); ++ ++ if (symbol_exists("__per_cpu_offset")) { ++ if (LKCD_KERNTYPES()) ++ i = get_cpus_possible(); ++ else + i = get_array_length("__per_cpu_offset", NULL, 0); - get_symbol_data("__per_cpu_offset", - sizeof(long)*(i <= NR_CPUS ? i : NR_CPUS), - &kt->__per_cpu_offset[0]); @@ -9003,33 +13366,10 @@ - } else - kt->cpus = machdep->get_smp_cpus(); - } -+ strncpy(buf, kt->utsname.release, MIN(strlen(kt->utsname.release), 65)); -+ if (ascii_string(kt->utsname.release)) { -+ p1 = p2 = buf; -+ while (*p2 != '.') -+ p2++; -+ *p2 = NULLCHAR; -+ kt->kernel_version[0] = atoi(p1); -+ p1 = ++p2; -+ while (*p2 != '.') -+ p2++; -+ *p2 = NULLCHAR; -+ kt->kernel_version[1] = atoi(p1); -+ p1 = ++p2; -+ while ((*p2 >= '0') && (*p2 <= '9')) -+ p2++; -+ *p2 = NULLCHAR; -+ kt->kernel_version[2] = atoi(p1); -+ } -+ -+ verify_version(); -+ -+ if (symbol_exists("__per_cpu_offset")) { -+ i = get_array_length("__per_cpu_offset", NULL, 0); -+ get_symbol_data("__per_cpu_offset", -+ sizeof(long)*(i <= NR_CPUS ? i : NR_CPUS), -+ &kt->__per_cpu_offset[0]); -+ kt->flags |= PER_CPU_OFF; ++ get_symbol_data("__per_cpu_offset", ++ sizeof(long)*((i && (i <= NR_CPUS)) ? i : NR_CPUS), ++ &kt->__per_cpu_offset[0]); ++ kt->flags |= PER_CPU_OFF; + } + if (STRUCT_EXISTS("runqueue")) + rqstruct = "runqueue"; @@ -9078,6 +13418,8 @@ + STRUCT_SIZE_INIT(runqueue, rqstruct); + STRUCT_SIZE_INIT(prio_array, "prio_array"); + ++ MEMBER_OFFSET_INIT(rq_cfs, "rq", "cfs"); ++ + /* + * In 2.4, smp_send_stop() sets smp_num_cpus back to 1 + * in some, but not all, architectures. So if a count @@ -9135,23 +13477,75 @@ - MEMBER_OFFSET_INIT(irq_desc_t_action, "irq_desc_t", "action"); - MEMBER_OFFSET_INIT(irq_desc_t_depth, "irq_desc_t", "depth"); - MEMBER_OFFSET_INIT(hw_interrupt_type_typename, -- "hw_interrupt_type", "typename"); -- MEMBER_OFFSET_INIT(hw_interrupt_type_startup, -- "hw_interrupt_type", "startup"); -- MEMBER_OFFSET_INIT(hw_interrupt_type_shutdown, -- "hw_interrupt_type", "shutdown"); ++ if ((kt->flags & SMP) && ACTIVE() && (kt->cpus == 1) && ++ (kt->flags & PER_CPU_OFF)) ++ kt->cpus = machdep->get_smp_cpus(); ++ ++ if (kt->cpus_override && (c = atoi(kt->cpus_override))) { ++ error(WARNING, "forcing cpu count to: %d\n\n", c); ++ kt->cpus = c; ++ } ++ ++ if (kt->cpus > NR_CPUS) { ++ error(WARNING, ++ "%s number of cpus (%d) greater than compiled-in NR_CPUS (%d)\n", ++ kt->cpus_override && atoi(kt->cpus_override) ? ++ "configured" : "calculated", kt->cpus, NR_CPUS); ++ error(FATAL, "recompile crash with larger NR_CPUS\n"); ++ } ++ ++ STRUCT_SIZE_INIT(spinlock_t, "spinlock_t"); ++ verify_spinlock(); ++ ++ STRUCT_SIZE_INIT(list_head, "list_head"); ++ MEMBER_OFFSET_INIT(list_head_next, "list_head", "next"); ++ MEMBER_OFFSET_INIT(list_head_prev, "list_head", "prev"); ++ if (OFFSET(list_head_next) != 0) ++ error(WARNING, ++ "list_head.next offset: %ld: list command may fail\n", ++ OFFSET(list_head_next)); ++ ++ MEMBER_OFFSET_INIT(hlist_node_next, "hlist_node", "next"); ++ MEMBER_OFFSET_INIT(hlist_node_pprev, "hlist_node", "pprev"); ++ STRUCT_SIZE_INIT(hlist_head, "hlist_head"); ++ STRUCT_SIZE_INIT(hlist_node, "hlist_node"); ++ ++ if (STRUCT_EXISTS("irq_desc_t")) ++ irq_desc_type_name = "irq_desc_t"; ++ else ++ irq_desc_type_name = "irq_desc"; ++ ++ STRUCT_SIZE_INIT(irq_desc_t, irq_desc_type_name); ++ MEMBER_OFFSET_INIT(irq_desc_t_status, irq_desc_type_name, "status"); ++ if (MEMBER_EXISTS(irq_desc_type_name, "handler")) ++ MEMBER_OFFSET_INIT(irq_desc_t_handler, irq_desc_type_name, "handler"); ++ else ++ MEMBER_OFFSET_INIT(irq_desc_t_chip, irq_desc_type_name, "chip"); ++ MEMBER_OFFSET_INIT(irq_desc_t_action, irq_desc_type_name, "action"); ++ MEMBER_OFFSET_INIT(irq_desc_t_depth, irq_desc_type_name, "depth"); ++ if (STRUCT_EXISTS("hw_interrupt_type")) { ++ MEMBER_OFFSET_INIT(hw_interrupt_type_typename, + "hw_interrupt_type", "typename"); + MEMBER_OFFSET_INIT(hw_interrupt_type_startup, + "hw_interrupt_type", "startup"); + MEMBER_OFFSET_INIT(hw_interrupt_type_shutdown, + "hw_interrupt_type", "shutdown"); - MEMBER_OFFSET_INIT(hw_interrupt_type_handle, - "hw_interrupt_type", "handle"); -- MEMBER_OFFSET_INIT(hw_interrupt_type_enable, -- "hw_interrupt_type", "enable"); -- MEMBER_OFFSET_INIT(hw_interrupt_type_disable, -- "hw_interrupt_type", "disable"); ++ MEMBER_OFFSET_INIT(hw_interrupt_type_handle, ++ "hw_interrupt_type", "handle"); + MEMBER_OFFSET_INIT(hw_interrupt_type_enable, + "hw_interrupt_type", "enable"); + MEMBER_OFFSET_INIT(hw_interrupt_type_disable, + "hw_interrupt_type", "disable"); - MEMBER_OFFSET_INIT(hw_interrupt_type_ack, -- "hw_interrupt_type", "ack"); ++ MEMBER_OFFSET_INIT(hw_interrupt_type_ack, + "hw_interrupt_type", "ack"); - MEMBER_OFFSET_INIT(hw_interrupt_type_end, -- "hw_interrupt_type", "end"); -- MEMBER_OFFSET_INIT(hw_interrupt_type_set_affinity, -- "hw_interrupt_type", "set_affinity"); ++ MEMBER_OFFSET_INIT(hw_interrupt_type_end, + "hw_interrupt_type", "end"); + MEMBER_OFFSET_INIT(hw_interrupt_type_set_affinity, + "hw_interrupt_type", "set_affinity"); - MEMBER_OFFSET_INIT(irqaction_handler, "irqaction", "handler"); - MEMBER_OFFSET_INIT(irqaction_flags, "irqaction", "flags"); - MEMBER_OFFSET_INIT(irqaction_mask, "irqaction", "mask"); @@ -9209,61 +13603,41 @@ - MEMBER_OFFSET_INIT(wait_queue_next, - "wait_queue", "next"); - } -+ if ((kt->flags & SMP) && ACTIVE() && (kt->cpus == 1) && -+ (kt->flags & PER_CPU_OFF)) -+ kt->cpus = machdep->get_smp_cpus(); -+ -+ if (kt->cpus_override && (c = atoi(kt->cpus_override))) { -+ error(WARNING, "forcing cpu count to: %d\n\n", c); -+ kt->cpus = c; ++ } else { /* ++ * On later kernels where hw_interrupt_type was replaced ++ * by irq_chip ++ */ ++ MEMBER_OFFSET_INIT(irq_chip_typename, ++ "irq_chip", "name"); ++ MEMBER_OFFSET_INIT(irq_chip_startup, ++ "irq_chip", "startup"); ++ MEMBER_OFFSET_INIT(irq_chip_shutdown, ++ "irq_chip", "shutdown"); ++ MEMBER_OFFSET_INIT(irq_chip_enable, ++ "irq_chip", "enable"); ++ MEMBER_OFFSET_INIT(irq_chip_disable, ++ "irq_chip", "disable"); ++ MEMBER_OFFSET_INIT(irq_chip_ack, ++ "irq_chip", "ack"); ++ MEMBER_OFFSET_INIT(irq_chip_mask, ++ "irq_chip", "mask"); ++ MEMBER_OFFSET_INIT(irq_chip_mask_ack, ++ "irq_chip", "mask_ack"); ++ MEMBER_OFFSET_INIT(irq_chip_unmask, ++ "irq_chip", "unmask"); ++ MEMBER_OFFSET_INIT(irq_chip_eoi, ++ "irq_chip", "eoi"); ++ MEMBER_OFFSET_INIT(irq_chip_end, ++ "irq_chip", "end"); ++ MEMBER_OFFSET_INIT(irq_chip_set_affinity, ++ "irq_chip", "set_affinity"); ++ MEMBER_OFFSET_INIT(irq_chip_retrigger, ++ "irq_chip", "retrigger"); ++ MEMBER_OFFSET_INIT(irq_chip_set_type, ++ "irq_chip", "set_type"); ++ MEMBER_OFFSET_INIT(irq_chip_set_wake, ++ "irq_chip", "set_wake"); + } -+ -+ if (kt->cpus > NR_CPUS) { -+ error(WARNING, -+ "%s number of cpus (%d) greater than compiled-in NR_CPUS (%d)\n", -+ kt->cpus_override && atoi(kt->cpus_override) ? -+ "configured" : "calculated", kt->cpus, NR_CPUS); -+ error(FATAL, "recompile crash with larger NR_CPUS\n"); -+ } -+ -+ STRUCT_SIZE_INIT(spinlock_t, "spinlock_t"); -+ verify_spinlock(); -+ -+ STRUCT_SIZE_INIT(list_head, "list_head"); -+ MEMBER_OFFSET_INIT(list_head_next, "list_head", "next"); -+ MEMBER_OFFSET_INIT(list_head_prev, "list_head", "prev"); -+ if (OFFSET(list_head_next) != 0) -+ error(WARNING, -+ "list_head.next offset: %ld: list command may fail\n", -+ OFFSET(list_head_next)); -+ -+ MEMBER_OFFSET_INIT(hlist_node_next, "hlist_node", "next"); -+ MEMBER_OFFSET_INIT(hlist_node_pprev, "hlist_node", "pprev"); -+ STRUCT_SIZE_INIT(hlist_head, "hlist_head"); -+ STRUCT_SIZE_INIT(hlist_node, "hlist_node"); -+ -+ MEMBER_OFFSET_INIT(irq_desc_t_status, "irq_desc_t", "status"); -+ MEMBER_OFFSET_INIT(irq_desc_t_handler, "irq_desc_t", "handler"); -+ MEMBER_OFFSET_INIT(irq_desc_t_action, "irq_desc_t", "action"); -+ MEMBER_OFFSET_INIT(irq_desc_t_depth, "irq_desc_t", "depth"); -+ MEMBER_OFFSET_INIT(hw_interrupt_type_typename, -+ "hw_interrupt_type", "typename"); -+ MEMBER_OFFSET_INIT(hw_interrupt_type_startup, -+ "hw_interrupt_type", "startup"); -+ MEMBER_OFFSET_INIT(hw_interrupt_type_shutdown, -+ "hw_interrupt_type", "shutdown"); -+ MEMBER_OFFSET_INIT(hw_interrupt_type_handle, -+ "hw_interrupt_type", "handle"); -+ MEMBER_OFFSET_INIT(hw_interrupt_type_enable, -+ "hw_interrupt_type", "enable"); -+ MEMBER_OFFSET_INIT(hw_interrupt_type_disable, -+ "hw_interrupt_type", "disable"); -+ MEMBER_OFFSET_INIT(hw_interrupt_type_ack, -+ "hw_interrupt_type", "ack"); -+ MEMBER_OFFSET_INIT(hw_interrupt_type_end, -+ "hw_interrupt_type", "end"); -+ MEMBER_OFFSET_INIT(hw_interrupt_type_set_affinity, -+ "hw_interrupt_type", "set_affinity"); + MEMBER_OFFSET_INIT(irqaction_handler, "irqaction", "handler"); + MEMBER_OFFSET_INIT(irqaction_flags, "irqaction", "flags"); + MEMBER_OFFSET_INIT(irqaction_mask, "irqaction", "mask"); @@ -9271,8 +13645,6 @@ + MEMBER_OFFSET_INIT(irqaction_dev_id, "irqaction", "dev_id"); + MEMBER_OFFSET_INIT(irqaction_next, "irqaction", "next"); + -+ STRUCT_SIZE_INIT(irq_desc_t, "irq_desc_t"); -+ + STRUCT_SIZE_INIT(irq_cpustat_t, "irq_cpustat_t"); + MEMBER_OFFSET_INIT(irq_cpustat_t___softirq_active, + "irq_cpustat_t", "__softirq_active"); @@ -9441,9 +13813,43 @@ + if (!(kt->flags & NO_KALLSYMS)) + kt->flags |= KALLSYMS_V2; } ++ ++ if (!(kt->flags & DWARF_UNWIND)) ++ kt->flags |= NO_DWARF_UNWIND; ++ ++ BUG_bytes_init(); } -@@ -471,6 +509,9 @@ + /* +@@ -377,7 +485,7 @@ + { + char buf[BUFSIZE]; + ulong linux_banner; +- int argc; ++ int argc, len; + char *arglist[MAXARGS]; + char *p1, *p2; + struct syment *sp; +@@ -389,7 +497,7 @@ + + if (!(sp = symbol_search("linux_banner"))) + error(FATAL, "linux_banner symbol does not exist?\n"); +- else if (sp->type == 'R') ++ else if ((sp->type == 'R') || (sp->type == 'r')) + linux_banner = symbol_value("linux_banner"); + else + get_symbol_data("linux_banner", sizeof(ulong), &linux_banner); +@@ -405,7 +513,8 @@ + error(WARNING, "cannot read linux_banner string\n"); + + if (ACTIVE()) { +- if (strlen(kt->proc_version) && !STREQ(buf, kt->proc_version)) { ++ len = strlen(kt->proc_version) - 1; ++ if ((len > 0) && (strncmp(buf, kt->proc_version, len) != 0)) { + if (CRASHDEBUG(1)) { + fprintf(fp, "/proc/version:\n%s", + kt->proc_version); +@@ -471,6 +580,9 @@ } } @@ -9453,24 +13859,335 @@ return; bad_match: -@@ -1140,7 +1181,10 @@ +@@ -614,6 +726,10 @@ + if (pc->flags & KERNEL_DEBUG_QUERY) + return; + ++ /* the kerntypes may not match in terms of gcc version or SMP */ ++ if (LKCD_KERNTYPES()) ++ return; ++ + if (!strlen(kt->utsname.version)) + return; + +@@ -740,7 +856,7 @@ + { + int c; + int do_load_module_filter, do_machdep_filter, reverse; +- int unfiltered, user_mode, count_entered; ++ int unfiltered, user_mode, count_entered, bug_bytes_entered; + ulong curaddr; + ulong revtarget; + ulong count; +@@ -754,7 +870,16 @@ + char buf4[BUFSIZE]; + char buf5[BUFSIZE]; + +- reverse = count_entered = FALSE; ++ if ((argcnt == 2) && STREQ(args[1], "-b")) { ++ fprintf(fp, "encoded bytes being skipped after ud2a: "); ++ if (kt->BUG_bytes < 0) ++ fprintf(fp, "undetermined\n"); ++ else ++ fprintf(fp, "%d\n", kt->BUG_bytes); ++ return; ++ } ++ ++ reverse = count_entered = bug_bytes_entered = FALSE; + sp = NULL; + unfiltered = user_mode = do_machdep_filter = do_load_module_filter = 0; + +@@ -763,7 +888,7 @@ + req->flags |= GNU_FROM_TTY_OFF|GNU_RETURN_ON_ERROR; + req->count = 1; + +- while ((c = getopt(argcnt, args, "ulrx")) != EOF) { ++ while ((c = getopt(argcnt, args, "ulrxb:B:")) != EOF) { + switch(c) + { + case 'x': +@@ -786,6 +911,12 @@ + BZERO(buf4, BUFSIZE); + break; + ++ case 'B': ++ case 'b': ++ kt->BUG_bytes = atoi(optarg); ++ bug_bytes_entered = TRUE; ++ break; ++ + default: + argerrs++; + break; +@@ -846,7 +977,7 @@ + if (user_mode) { + sprintf(buf1, "x/%ldi 0x%lx", + req->count ? req->count : 1, req->addr); +- pc->cmdgenspec = pc->cmdgencur; ++ pc->curcmd_flags |= MEMTYPE_UVADDR; + gdb_pass_through(buf1, NULL, 0); + return; + } +@@ -962,7 +1093,9 @@ + close_tmpfile(); + } + } +- else cmd_usage(pc->curcmd, SYNOPSIS); ++ else if (bug_bytes_entered) ++ return; ++ else cmd_usage(pc->curcmd, SYNOPSIS); + + if (!reverse) { + FREEBUF(req->buf); +@@ -1053,6 +1186,185 @@ + FREEBUF(req); + } + ++/* ++ * x86 and x86_64 kernels may have file/line-number encoding ++ * asm()'d in just after the "ud2a" instruction, which confuses ++ * the disassembler and the x86 backtracer. Determine the ++ * number of bytes to skip. ++ */ ++static void ++BUG_bytes_init(void) ++{ ++ if (machine_type("X86")) ++ kt->BUG_bytes = BUG_x86(); ++ else if (machine_type("X86_64")) ++ kt->BUG_bytes = BUG_x86_64(); ++} ++ ++static int ++BUG_x86(void) ++{ ++ struct syment *sp, *spn; ++ char buf1[BUFSIZE]; ++ char buf2[BUFSIZE]; ++ char *arglist[MAXARGS]; ++ ulong vaddr, fileptr; ++ int found; ++ ++ /* ++ * Prior to 2.4.19, a call to do_BUG() preceded ++ * the standalone ud2a instruction. ++ */ ++ if (THIS_KERNEL_VERSION < LINUX(2,4,19)) ++ return 0; ++ ++ /* ++ * 2.6.20 introduced __bug_table support for i386, ++ * but even if CONFIG_DEBUG_BUGVERBOSE is not configured, ++ * the ud2a stands alone. ++ */ ++ if (THIS_KERNEL_VERSION >= LINUX(2,6,20)) ++ return 0; ++ ++ /* ++ * For previous kernel versions, it may depend upon ++ * whether CONFIG_DEBUG_BUGVERBOSE was configured: ++ * ++ * #ifdef CONFIG_DEBUG_BUGVERBOSE ++ * #define BUG() \ ++ * __asm__ __volatile__( "ud2\n" \ ++ * "\t.word %c0\n" \ ++ * "\t.long %c1\n" \ ++ * : : "i" (__LINE__), "i" (__FILE__)) ++ * #else ++ * #define BUG() __asm__ __volatile__("ud2\n") ++ * #endif ++ * ++ * But that's not necessarily true, since there are ++ * pre-2.6.11 versions that force it like so: ++ * ++ * #if 1 /- Set to zero for a slightly smaller kernel -/ ++ * #define BUG() \ ++ * __asm__ __volatile__( "ud2\n" \ ++ * "\t.word %c0\n" \ ++ * "\t.long %c1\n" \ ++ * : : "i" (__LINE__), "i" (__FILE__)) ++ * #else ++ * #define BUG() __asm__ __volatile__("ud2\n") ++ * #endif ++ */ ++ ++ /* ++ * This works if in-kernel config data is available. ++ */ ++ if ((THIS_KERNEL_VERSION >= LINUX(2,6,11)) && ++ (kt->flags & BUGVERBOSE_OFF)) ++ return 0; ++ ++ /* ++ * At this point, it's a pretty safe bet that it's configured, ++ * but to be sure, disassemble a known BUG() caller and ++ * verify that the encoding is there. ++ */ ++ ++#define X86_BUG_BYTES (6) /* sizeof(short) + sizeof(pointer) */ ++ ++ if (!(sp = symbol_search("do_exit")) || ++ !(spn = next_symbol(NULL, sp))) ++ return X86_BUG_BYTES; ++ ++ sprintf(buf1, "x/%ldi 0x%lx", spn->value - sp->value, sp->value); ++ ++ found = FALSE; ++ open_tmpfile(); ++ gdb_pass_through(buf1, pc->tmpfile, GNU_RETURN_ON_ERROR); ++ rewind(pc->tmpfile); ++ while (fgets(buf2, BUFSIZE, pc->tmpfile)) { ++ if (parse_line(buf2, arglist) < 3) ++ continue; ++ ++ if ((vaddr = htol(arglist[0], RETURN_ON_ERROR, NULL)) >= spn->value) ++ continue; ++ ++ if (STREQ(arglist[2], "ud2a")) { ++ found = TRUE; ++ break; ++ } ++ } ++ close_tmpfile(); ++ ++ if (!found || !readmem(vaddr+4, KVADDR, &fileptr, sizeof(ulong), ++ "BUG filename pointer", RETURN_ON_ERROR|QUIET)) ++ return X86_BUG_BYTES; ++ ++ if (!IS_KVADDR(fileptr)) { ++ if (CRASHDEBUG(1)) ++ fprintf(fp, ++ "no filename pointer: kt->BUG_bytes: 0\n"); ++ return 0; ++ } ++ ++ if (!read_string(fileptr, buf1, BUFSIZE-1)) ++ error(WARNING, ++ "cannot read BUG (ud2a) encoded filename address: %lx\n", ++ fileptr); ++ else if (CRASHDEBUG(1)) ++ fprintf(fp, "BUG bytes filename encoding: [%s]\n", buf1); ++ ++ return X86_BUG_BYTES; ++} ++ ++static int ++BUG_x86_64(void) ++{ ++ /* ++ * 2.6.20 introduced __bug_table support for x86_64, ++ * but even if CONFIG_DEBUG_BUGVERBOSE is not configured, ++ * the ud2a stands alone. ++ */ ++ if (THIS_KERNEL_VERSION >= LINUX(2,6,20)) ++ return 0; ++ ++ /* ++ * The original bug_frame structure looks like this, which ++ * causes the disassembler to go off into the weeds: ++ * ++ * struct bug_frame { ++ * unsigned char ud2[2]; ++ * char *filename; ++ * unsigned short line; ++ * } ++ * ++ * In 2.6.13, fake push and ret instructions were encoded ++ * into the frame so that the disassembly would at least ++ * "work", although the two fake instructions show nonsensical ++ * arguments: ++ * ++ * struct bug_frame { ++ * unsigned char ud2[2]; ++ * unsigned char push; ++ * signed int filename; ++ * unsigned char ret; ++ * unsigned short line; ++ * } ++ */ ++ ++ if (STRUCT_EXISTS("bug_frame")) ++ return (int)(STRUCT_SIZE("bug_frame") - 2); ++ ++ return 0; ++} ++ ++ ++/* ++ * Callback from gdb disassembly code. ++ */ ++int ++kernel_BUG_encoding_bytes(void) ++{ ++ return kt->BUG_bytes; ++} ++ + #ifdef NOT_USED + /* + * To avoid premature stoppage/extension of a dis that includes +@@ -1094,7 +1406,8 @@ + } + + #define FRAMESIZE_DEBUG_MESSAGE \ +-"usage: bt -F [size|clear|dump|seek|noseek|validate|novalidate] [-I eip]\n If eip: set its associated framesize to size.\n \"validate/novalidate\" will turn on/off V bit for this eip entry.\n If !eip: \"clear\" will clear the framesize cache and RA seek/noseek flags.\n \"dump\" will dump the current framesize cache entries.\n \"seek/noseek\" turns on/off RA seeking.\n \"validate/novalidate\" turns on/off V bit for all current entries.\n" ++"\nx86 usage: bt -F [size|clear|dump|seek|noseek|validate|novalidate] [-I eip]\n If eip: set its associated framesize to size.\n \"validate/novalidate\" will turn on/off V bit for this eip entry.\n If !eip: \"clear\" will clear the framesize cache and RA seek/noseek flags.\n \"dump\" will dump the current framesize cache entries.\n \"seek/noseek\" turns on/off RA seeking.\n \"validate/novalidate\" turns on/off V bit for all current entries.\n\nx86_64 usage: bt -F [clear|dump|validate] [-I rip]\n If rip: \"validate\" will verbosely recalculate the framesize.\n If !rip: \"clear\" will clear the framesize cache.\n \"dump\" will dump the current framesize cache entries.\n" ++ + + /* + * Display a kernel stack backtrace. Arguments may be any number pid or task +@@ -1108,18 +1421,25 @@ + * -s displays arguments symbolically. + */ + ++void ++clone_bt_info(struct bt_info *orig, struct bt_info *new, ++ struct task_context *tc) ++{ ++ BCOPY(orig, new, sizeof(*new)); ++ new->stackbuf = NULL; ++ new->tc = tc; ++ new->task = tc->task; ++ new->stackbase = GET_STACKBASE(tc->task); ++ new->stacktop = GET_STACKTOP(tc->task); ++} ++ + #define BT_SETUP(TC) \ +- BCOPY(&bt_setup, bt, sizeof(struct bt_info)); \ ++ clone_bt_info(&bt_setup, bt, (TC)); \ + if (refptr) { \ + BZERO(&reference, sizeof(struct reference)); \ + bt->ref = &reference; \ + bt->ref->str = refptr; \ +- } \ +- bt->tc = (TC); \ +- bt->task = ((TC)->task); \ +- bt->stackbase = GET_STACKBASE((TC)->task); \ +- bt->stacktop = GET_STACKTOP((TC)->task); \ +- bt->stackbuf = NULL; ++ } + + void + cmd_bt(void) +@@ -1140,8 +1460,11 @@ bt = &bt_info; BZERO(bt, sizeof(struct bt_info)); - while ((c = getopt(argcnt, args, "fF:I:S:aloreEgstd:R:")) != EOF) { +- switch(c) + if (kt->flags & USE_OLD_BT) + bt->flags |= BT_OLD_BACK_TRACE; + + while ((c = getopt(argcnt, args, "fF:I:S:aloreEgstTd:R:O")) != EOF) { - switch(c) ++ switch (c) { case 'f': -@@ -1151,6 +1195,28 @@ + bt->flags |= BT_FULL; +@@ -1151,6 +1474,28 @@ bt->flags |= BT_OLD_BACK_TRACE; break; + case 'O': -+ if (!machine_type("X86")) ++ if (!(machine_type("X86") || machine_type("X86_64"))) + option_not_supported(c); + else if (kt->flags & USE_OLD_BT) { + /* @@ -9494,7 +14211,17 @@ case 'R': if (refptr) error(INFO, "only one -R option allowed\n"); -@@ -1241,6 +1307,8 @@ +@@ -1217,6 +1562,9 @@ + } else if (*optarg == '-') { + hook.esp = dtol(optarg+1, FAULT_ON_ERROR, NULL); + hook.esp = (ulong)(0 - (long)hook.esp); ++ } else if (STREQ(optarg, "dwarf") || STREQ(optarg, "cfi")) { ++ if (!(kt->flags & DWARF_UNWIND_CAPABLE)) ++ return; + } else + hook.esp = dtol(optarg, FAULT_ON_ERROR, NULL); + break; +@@ -1241,6 +1589,8 @@ bt->flags |= BT_SYMBOLIC_ARGS; break; @@ -9503,7 +14230,55 @@ case 't': bt->flags |= BT_TEXT_SYMBOLS; break; -@@ -1350,9 +1418,10 @@ +@@ -1255,6 +1605,11 @@ + } + } + ++ if (XEN_HYPER_MODE()) { ++ if (bt->flags & BT_EFRAME_SEARCH) ++ argerrs++; ++ } ++ + if (argerrs) + cmd_usage(pc->curcmd, SYNOPSIS); + +@@ -1286,6 +1641,35 @@ + return; + } + ++ if (XEN_HYPER_MODE()) { ++#ifdef XEN_HYPERVISOR_ARCH ++ /* "task" means vcpu for xen hypervisor */ ++ if (active) { ++ for (c = 0; c < XEN_HYPER_MAX_CPUS(); c++) { ++ if (!xen_hyper_test_pcpu_id(c)) ++ continue; ++ fake_tc.task = xen_hyper_pcpu_to_active_vcpu(c); ++ BT_SETUP(&fake_tc); ++ xen_hyper_print_bt_header(fp, fake_tc.task, subsequent++); ++ back_trace(bt); ++ } ++ } else { ++ if (args[optind]) { ++ fake_tc.task = xen_hyper_pcpu_to_active_vcpu( ++ convert(args[optind], 0, NULL, NUM_DEC | NUM_HEX)); ++ } else { ++ fake_tc.task = XEN_HYPER_VCPU_LAST_CONTEXT()->vcpu; ++ } ++ BT_SETUP(&fake_tc); ++ xen_hyper_print_bt_header(fp, fake_tc.task, 0); ++ back_trace(bt); ++ } ++ return; ++#else ++ error(FATAL, XEN_HYPERVISOR_NOT_SUPPORTED); ++#endif ++ } ++ + if (active) { + if (ACTIVE()) + error(FATAL, +@@ -1350,9 +1734,10 @@ char buf[BUFSIZE]; if (bt->flags & BT_TEXT_SYMBOLS) { @@ -9517,7 +14292,7 @@ } if (bt->hp) -@@ -1435,6 +1504,9 @@ +@@ -1435,6 +1820,9 @@ i < LONGS_PER_STACK; i++, up++) { if (is_kernel_text(*up)) fprintf(fp, "%lx: %s\n", @@ -9527,7 +14302,7 @@ bt->task + (i * sizeof(long)), value_to_symstr(*up, buf, 0)); } -@@ -1461,8 +1533,8 @@ +@@ -1461,20 +1849,26 @@ if (bt->hp) { if (bt->hp->esp && !INSTACK(bt->hp->esp, bt)) error(INFO, @@ -9538,9 +14313,13 @@ eip = bt->hp->eip; esp = bt->hp->esp; -@@ -1471,10 +1543,14 @@ + machdep->get_stack_frame(bt, eip ? NULL : &eip, + esp ? NULL : &esp); - } else if (NETDUMP_DUMPFILE()) +- } else if (NETDUMP_DUMPFILE()) ++ } else if (XEN_HYPER_MODE()) ++ machdep->get_stack_frame(bt, &eip, &esp); ++ else if (NETDUMP_DUMPFILE()) get_netdump_regs(bt, &eip, &esp); + else if (KDUMP_DUMPFILE()) + get_kdump_regs(bt, &eip, &esp); @@ -9553,7 +14332,7 @@ else machdep->get_stack_frame(bt, &eip, &esp); -@@ -1486,6 +1562,13 @@ +@@ -1486,6 +1880,13 @@ if (bt->flags & (BT_TEXT_SYMBOLS|BT_TEXT_SYMBOLS_PRINT|BT_TEXT_SYMBOLS_NOPRINT)) { @@ -9567,7 +14346,15 @@ if (machdep->flags & MACHDEP_BT_TEXT) { bt->instptr = eip; bt->stkptr = esp; -@@ -1721,6 +1804,13 @@ +@@ -1666,6 +2067,7 @@ + fprintf(fp, " flags: %llx\n", bt->flags); + fprintf(fp, " instptr: %lx\n", bt->instptr); + fprintf(fp, " stkptr: %lx\n", bt->stkptr); ++ fprintf(fp, " bptr: %lx\n", bt->bptr); + fprintf(fp, " stackbase: %lx\n", bt->stackbase); + fprintf(fp, " stacktop: %lx\n", bt->stacktop); + fprintf(fp, " tc: %lx ", (ulong)bt->tc); +@@ -1721,6 +2123,13 @@ *esp = *(up-1); return; } @@ -9581,7 +14368,7 @@ if (STREQ(sym, "smp_stop_cpu_interrupt")) { *eip = *up; *esp = bt->task + -@@ -1837,8 +1927,8 @@ +@@ -1837,8 +2246,8 @@ return; } @@ -9592,16 +14379,17 @@ kt->kernel_module = sp->value; kt->module_list = (ulong)list.next; modules_found = TRUE; -@@ -1873,6 +1963,8 @@ +@@ -1873,14 +2282,17 @@ kallsymsbuf = kt->flags & KALLSYMS_V1 ? GETBUF(SIZE(kallsyms_header)) : NULL; + please_wait("gathering module symbol data"); + for (mod = kt->module_list; mod != kt->kernel_module; mod = mod_next) { - if (CRASHDEBUG(7)) +- if (CRASHDEBUG(7)) ++ if (CRASHDEBUG(3)) fprintf(fp, "module: %lx\n", mod); -@@ -1880,7 +1972,8 @@ + if (!readmem(mod, KVADDR, modbuf, SIZE(module), "module struct", RETURN_ON_ERROR|QUIET)) { error(WARNING, @@ -9611,7 +14399,7 @@ kt->mods_installed = 0; kt->flags |= NO_MODULE_ACCESS; FREEBUF(modbuf); -@@ -1914,7 +2007,8 @@ +@@ -1914,7 +2326,8 @@ kallsymsbuf, SIZE(kallsyms_header), "kallsyms_header", RETURN_ON_ERROR|QUIET)) { error(WARNING, @@ -9621,7 +14409,7 @@ } else { nsyms = UINT(kallsymsbuf + OFFSET(kallsyms_header_symbols)); -@@ -1947,6 +2041,8 @@ +@@ -1947,6 +2360,8 @@ store_module_symbols_v2(total, kt->mods_installed); break; } @@ -9630,7 +14418,36 @@ } -@@ -2459,7 +2555,7 @@ +@@ -2112,7 +2527,7 @@ + address = 0; + flag = LIST_MODULE_HDR; + +- while ((c = getopt(argcnt, args, "rd:Ds:St:")) != EOF) { ++ while ((c = getopt(argcnt, args, "rd:Ds:St:o")) != EOF) { + switch(c) + { + case 'r': +@@ -2145,6 +2560,19 @@ + cmd_usage(pc->curcmd, SYNOPSIS); + break; + ++ /* ++ * Revert to using old-style add-symbol-file command ++ * for KMOD_V2 kernels. ++ */ ++ case 'o': ++ if (flag) ++ cmd_usage(pc->curcmd, SYNOPSIS); ++ if (kt->flags & KMOD_V1) ++ error(INFO, ++ "-o option is not applicable to this kernel version\n"); ++ st->flags |= USE_OLD_ADD_SYM; ++ return; ++ + case 't': + if (is_directory(optarg)) + tree = optarg; +@@ -2459,7 +2887,7 @@ static char * @@ -9639,7 +14456,47 @@ { char buf[BUFSIZE]; char file[BUFSIZE]; -@@ -2592,6 +2688,32 @@ +@@ -2477,16 +2905,20 @@ + strcpy(file, filename); + #ifdef MODULES_IN_CWD + else { +- sprintf(file, "%s.o", modref); +- if (access(file, R_OK) == 0) { +- retbuf = GETBUF(strlen(file)+1); +- strcpy(retbuf, file); +- if (CRASHDEBUG(1)) +- fprintf(fp, +- "find_module_objfile: [%s] file in cwd\n", +- retbuf); +- return retbuf; +- } ++ char *fileext[] = { "ko", "o"}; ++ int i; ++ for (i = 0; i < 2; i++) { ++ sprintf(file, "%s.%s", modref, fileext[i]); ++ if (access(file, R_OK) == 0) { ++ retbuf = GETBUF(strlen(file)+1); ++ strcpy(retbuf, file); ++ if (CRASHDEBUG(1)) ++ fprintf(fp, ++ "find_module_objfile: [%s] file in cwd\n", ++ retbuf); ++ return retbuf; ++ } ++ } + } + #else + else +@@ -2505,6 +2937,8 @@ + if ((st->flags & INSMOD_BUILTIN) && !filename) { + sprintf(buf, "__insmod_%s_O/", modref); + if (symbol_query(buf, NULL, &sp) == 1) { ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "search: INSMOD_BUILTIN %s\n", sp->name); + BZERO(buf, BUFSIZE); + p1 = strstr(sp->name, "/"); + if ((p2 = strstr(sp->name, file))) +@@ -2592,6 +3026,32 @@ return retbuf; } @@ -9672,7 +14529,7 @@ /* * Unlink any temporary remote module object files. -@@ -2787,6 +2909,8 @@ +@@ -2787,6 +3247,8 @@ do { if (sflag) dump_sys_call_table(args[optind], cnt++); @@ -9681,7 +14538,17 @@ else cmd_usage(args[optind], COMPLETE_HELP); optind++; -@@ -2876,7 +3000,7 @@ +@@ -2867,6 +3329,9 @@ + if (NETDUMP_DUMPFILE() && is_partial_netdump()) + fprintf(fp, " [PARTIAL DUMP]"); + ++ if (DISKDUMP_DUMPFILE() && is_partial_diskdump()) ++ fprintf(fp, " [PARTIAL DUMP]"); ++ + fprintf(fp, "\n"); + } + +@@ -2876,7 +3341,7 @@ get_symbol_data("xtime", sizeof(struct timespec), &kt->date); fprintf(fp, " DATE: %s\n", strip_linefeeds(ctime(&kt->date.tv_sec))); @@ -9690,7 +14557,7 @@ fprintf(fp, "LOAD AVERAGE: %s\n", get_loadavg(buf)); fprintf(fp, " TASKS: %ld\n", RUNNING_TASKS()); fprintf(fp, " NODENAME: %s\n", uts->nodename); -@@ -2891,6 +3015,9 @@ +@@ -2891,10 +3356,17 @@ #ifdef WHO_CARES fprintf(fp, " DOMAINNAME: %s\n", uts->domainname); #endif @@ -9700,7 +14567,16 @@ if (DUMPFILE()) { fprintf(fp, " PANIC: "); if (machdep->flags & HWRESET) -@@ -2952,28 +3079,42 @@ +- fprintf(fp, "HARDWARE RESET\n"); ++ fprintf(fp, "(HARDWARE RESET)\n"); ++ else if (machdep->flags & INIT) ++ fprintf(fp, "(INIT)\n"); ++ else if (machdep->flags & MCA) ++ fprintf(fp, "(MCA)\n"); + else { + strip_linefeeds(get_panicmsg(buf)); + fprintf(fp, "\"%s\"%s\n", buf, +@@ -2952,28 +3424,42 @@ /* * Calculate and return the uptime. */ @@ -9759,7 +14635,7 @@ #define FSHIFT 11 /* nr of bits of precision */ #define FIXED_1 (1<> FSHIFT) -@@ -3048,9 +3189,9 @@ +@@ -3048,9 +3534,9 @@ struct syment *sp, *spn; long size; #ifdef S390X @@ -9771,7 +14647,7 @@ #endif if (GDB_PATCHED()) error(INFO, "line numbers are not available\n"); -@@ -3068,6 +3209,8 @@ +@@ -3068,6 +3554,8 @@ readmem(symbol_value("sys_call_table"), KVADDR, sys_call_table, size, "sys_call_table", FAULT_ON_ERROR); @@ -9780,7 +14656,7 @@ if (spec) open_tmpfile(); -@@ -3080,13 +3223,17 @@ +@@ -3080,13 +3568,17 @@ "%3x " : "%3d ", i); fprintf(fp, "invalid sys_call_table entry: %lx (%s)\n", @@ -9800,7 +14676,7 @@ /* * For system call symbols whose first instruction is -@@ -3181,9 +3328,9 @@ +@@ -3181,16 +3673,16 @@ * "help -k" output */ void @@ -9812,7 +14688,15 @@ struct new_utsname *uts; int others; -@@ -3225,6 +3372,12 @@ + others = 0; + uts = &kt->utsname; + +- fprintf(fp, " flags: %lx (", kt->flags); ++ fprintf(fp, " flags: %lx\n (", kt->flags); + if (kt->flags & NO_MODULE_ACCESS) + fprintf(fp, "%sNO_MODULE_ACCESS", others++ ? "|" : ""); + if (kt->flags & TVEC_BASES_V1) +@@ -3225,6 +3717,28 @@ fprintf(fp, "%sKMOD_V2", others++ ? "|" : ""); if (kt->flags & KALLSYMS_V2) fprintf(fp, "%sKALLSYMS_V2", others++ ? "|" : ""); @@ -9822,10 +14706,26 @@ + fprintf(fp, "%sARCH_XEN", others++ ? "|" : ""); + if (kt->flags & NO_IKCONFIG) + fprintf(fp, "%sNO_IKCONFIG", others++ ? "|" : ""); ++ if (kt->flags & DWARF_UNWIND) ++ fprintf(fp, "%sDWARF_UNWIND", others++ ? "|" : ""); ++ if (kt->flags & NO_DWARF_UNWIND) ++ fprintf(fp, "%sNO_DWARF_UNWIND", others++ ? "|" : ""); ++ if (kt->flags & DWARF_UNWIND_MEMORY) ++ fprintf(fp, "%sDWARF_UNWIND_MEMORY", others++ ? "|" : ""); ++ if (kt->flags & DWARF_UNWIND_EH_FRAME) ++ fprintf(fp, "%sDWARF_UNWIND_EH_FRAME", others++ ? "|" : ""); ++ if (kt->flags & DWARF_UNWIND_MODULES) ++ fprintf(fp, "%sDWARF_UNWIND_MODULES", others++ ? "|" : ""); ++ if (kt->flags & BUGVERBOSE_OFF) ++ fprintf(fp, "%sBUGVERBOSE_OFF", others++ ? "|" : ""); ++ if (kt->flags & RELOC_SET) ++ fprintf(fp, "%sRELOC_SET", others++ ? "|" : ""); ++ if (kt->flags & RELOC_FORCE) ++ fprintf(fp, "%sRELOC_FORCE", others++ ? "|" : ""); fprintf(fp, ")\n"); fprintf(fp, " stext: %lx\n", kt->stext); fprintf(fp, " etext: %lx\n", kt->etext); -@@ -3234,8 +3387,10 @@ +@@ -3234,8 +3748,10 @@ fprintf(fp, " init_end: %lx\n", kt->init_end); fprintf(fp, " end: %lx\n", kt->end); fprintf(fp, " cpus: %d\n", kt->cpus); @@ -9836,8 +14736,12 @@ if (kt->display_bh == display_bh_1) fprintf(fp, " display_bh: display_bh_1()\n"); else if (kt->display_bh == display_bh_2) -@@ -3265,19 +3420,50 @@ +@@ -3263,21 +3779,61 @@ + kt->kernel_version[1], kt->kernel_version[2]); + fprintf(fp, " gcc_version: %d.%d.%d\n", kt->gcc_version[0], kt->gcc_version[1], kt->gcc_version[2]); ++ fprintf(fp, " BUG_bytes: %d\n", kt->BUG_bytes); ++ fprintf(fp, " relocate: %lx\n", kt->relocate); fprintf(fp, " runq_siblings: %d\n", kt->runq_siblings); fprintf(fp, " __rq_idx[NR_CPUS]: "); - for (i = 0; i < NR_CPUS; i++) @@ -9877,22 +14781,417 @@ + for (i = 0; verbose && (i < P2M_MAPPING_CACHE); i++) { + if (!kt->p2m_mapping_cache[i].mapping) + continue; -+ fprintf(fp, " [%d] mapping: %lx mfn: %lx\n", ++ fprintf(fp, " [%d] mapping: %lx start: %lx end: %lx (%ld mfns)\n", + i, kt->p2m_mapping_cache[i].mapping, -+ kt->p2m_mapping_cache[i].mfn); ++ kt->p2m_mapping_cache[i].start, ++ kt->p2m_mapping_cache[i].end, ++ kt->p2m_mapping_cache[i].end - kt->p2m_mapping_cache[i].start + 1); + } + fprintf(fp, " last_mapping_read: %lx\n", kt->last_mapping_read); + fprintf(fp, " p2m_cache_index: %ld\n", kt->p2m_cache_index); + fprintf(fp, " p2m_pages_searched: %ld\n", kt->p2m_pages_searched); -+ fprintf(fp, " p2m_cache_hits: %ld ", kt->p2m_cache_hits); ++ fprintf(fp, " p2m_mfn_cache_hits: %ld ", kt->p2m_mfn_cache_hits); + if (kt->p2m_pages_searched) -+ fprintf(fp, "(%ld%%)\n", kt->p2m_cache_hits * 100 / kt->p2m_pages_searched); ++ fprintf(fp, "(%ld%%)\n", kt->p2m_mfn_cache_hits * 100 / kt->p2m_pages_searched); ++ else ++ fprintf(fp, "\n"); ++ fprintf(fp, " p2m_page_cache_hits: %ld ", kt->p2m_page_cache_hits); ++ if (kt->p2m_pages_searched) ++ fprintf(fp, "(%ld%%)\n", kt->p2m_page_cache_hits * 100 / kt->p2m_pages_searched); + else + fprintf(fp, "\n"); } /* -@@ -4475,9 +4661,16 @@ +@@ -3314,7 +3870,7 @@ + if (machine_type("S390") || machine_type("S390X")) + command_not_supported(); + +- while ((c = getopt(argcnt, args, "db")) != EOF) { ++ while ((c = getopt(argcnt, args, "dbu")) != EOF) { + switch(c) + { + case 'd': +@@ -3344,6 +3900,17 @@ + kt->display_bh(); + return; + ++ case 'u': ++ pc->curcmd_flags |= IRQ_IN_USE; ++ if (kernel_symbol_exists("no_irq_chip")) ++ pc->curcmd_private = (ulonglong)symbol_value("no_irq_chip"); ++ else if (kernel_symbol_exists("no_irq_type")) ++ pc->curcmd_private = (ulonglong)symbol_value("no_irq_type"); ++ else ++ error(WARNING, ++ "irq: -u option ignored: \"no_irq_chip\" or \"no_irq_type\" symbols do not exist\n"); ++ break; ++ + default: + argerrs++; + break; +@@ -3362,6 +3929,8 @@ + return; + } + ++ pc->curcmd_flags &= ~IRQ_IN_USE; ++ + while (args[optind]) { + i = dtoi(args[optind], FAULT_ON_ERROR, NULL); + if (i >= nr_irqs) +@@ -3402,13 +3971,22 @@ + + readmem(irq_desc_addr + OFFSET(irq_desc_t_status), KVADDR, &status, + sizeof(int), "irq_desc entry", FAULT_ON_ERROR); +- readmem(irq_desc_addr + OFFSET(irq_desc_t_handler), KVADDR, &handler, +- sizeof(long), "irq_desc entry", FAULT_ON_ERROR); ++ if (VALID_MEMBER(irq_desc_t_handler)) ++ readmem(irq_desc_addr + OFFSET(irq_desc_t_handler), KVADDR, ++ &handler, sizeof(long), "irq_desc entry", ++ FAULT_ON_ERROR); ++ else if (VALID_MEMBER(irq_desc_t_chip)) ++ readmem(irq_desc_addr + OFFSET(irq_desc_t_chip), KVADDR, ++ &handler, sizeof(long), "irq_desc entry", ++ FAULT_ON_ERROR); + readmem(irq_desc_addr + OFFSET(irq_desc_t_action), KVADDR, &action, + sizeof(long), "irq_desc entry", FAULT_ON_ERROR); + readmem(irq_desc_addr + OFFSET(irq_desc_t_depth), KVADDR, &depth, + sizeof(int), "irq_desc entry", FAULT_ON_ERROR); + ++ if (!action && (handler == (ulong)pc->curcmd_private)) ++ return; ++ + fprintf(fp, " IRQ: %d\n", irq); + fprintf(fp, " STATUS: %x %s", status, status ? "(" : ""); + others = 0; +@@ -3441,19 +4019,30 @@ + } else + fprintf(fp, "%lx\n", handler); + +- if (handler) { +- readmem(handler+OFFSET(hw_interrupt_type_typename), KVADDR, +- &tmp1, sizeof(void *), +- "hw_interrupt_type typename", FAULT_ON_ERROR); ++ if (handler) { ++ if (VALID_MEMBER(hw_interrupt_type_typename)) ++ readmem(handler+OFFSET(hw_interrupt_type_typename), ++ KVADDR, &tmp1, sizeof(void *), ++ "hw_interrupt_type typename", FAULT_ON_ERROR); ++ else if (VALID_MEMBER(irq_chip_typename)) ++ readmem(handler+OFFSET(irq_chip_typename), ++ KVADDR, &tmp1, sizeof(void *), ++ "hw_interrupt_type typename", FAULT_ON_ERROR); ++ + fprintf(fp, " typename: %lx ", tmp1); + BZERO(buf, BUFSIZE); + if (read_string(tmp1, buf, BUFSIZE-1)) + fprintf(fp, "\"%s\"", buf); + fprintf(fp, "\n"); + +- readmem(handler+OFFSET(hw_interrupt_type_startup), KVADDR, +- &tmp1, sizeof(void *), +- "hw_interrupt_type startup", FAULT_ON_ERROR); ++ if (VALID_MEMBER(hw_interrupt_type_startup)) ++ readmem(handler+OFFSET(hw_interrupt_type_startup), ++ KVADDR, &tmp1, sizeof(void *), ++ "hw_interrupt_type startup", FAULT_ON_ERROR); ++ else if (VALID_MEMBER(irq_chip_startup)) ++ readmem(handler+OFFSET(irq_chip_startup), ++ KVADDR, &tmp1, sizeof(void *), ++ "hw_interrupt_type startup", FAULT_ON_ERROR); + fprintf(fp, " startup: %lx ", tmp1); + if (is_kernel_text(tmp1)) + fprintf(fp, "<%s>", value_to_symstr(tmp1, buf, 0)); +@@ -3464,9 +4053,15 @@ + value_to_symstr(tmp2, buf, 0)); + fprintf(fp, "\n"); + +- readmem(handler+OFFSET(hw_interrupt_type_shutdown), KVADDR, +- &tmp1, sizeof(void *), +- "hw_interrupt_type shutdown", FAULT_ON_ERROR); ++ if (VALID_MEMBER(hw_interrupt_type_shutdown)) ++ readmem(handler+OFFSET(hw_interrupt_type_shutdown), ++ KVADDR, &tmp1, sizeof(void *), ++ "hw_interrupt_type shutdown", FAULT_ON_ERROR); ++ else if (VALID_MEMBER(irq_chip_shutdown)) ++ readmem(handler+OFFSET(irq_chip_shutdown), ++ KVADDR, &tmp1, sizeof(void *), ++ "hw_interrupt_type shutdown", FAULT_ON_ERROR); ++ + fprintf(fp, " shutdown: %lx ", tmp1); + if (is_kernel_text(tmp1)) + fprintf(fp, "<%s>", value_to_symstr(tmp1, buf, 0)); +@@ -3494,9 +4089,14 @@ + fprintf(fp, "\n"); + } + +- readmem(handler+OFFSET(hw_interrupt_type_enable), KVADDR, +- &tmp1, sizeof(void *), +- "hw_interrupt_type enable", FAULT_ON_ERROR); ++ if (VALID_MEMBER(hw_interrupt_type_enable)) ++ readmem(handler+OFFSET(hw_interrupt_type_enable), ++ KVADDR, &tmp1, sizeof(void *), ++ "hw_interrupt_type enable", FAULT_ON_ERROR); ++ else if (VALID_MEMBER(irq_chip_enable)) ++ readmem(handler+OFFSET(irq_chip_enable), ++ KVADDR, &tmp1, sizeof(void *), ++ "hw_interrupt_type enable", FAULT_ON_ERROR); + fprintf(fp, " enable: %lx ", tmp1); + if (is_kernel_text(tmp1)) + fprintf(fp, "<%s>", value_to_symstr(tmp1, buf, 0)); +@@ -3507,9 +4107,14 @@ + value_to_symstr(tmp2, buf, 0)); + fprintf(fp, "\n"); + +- readmem(handler+OFFSET(hw_interrupt_type_disable), KVADDR, +- &tmp1, sizeof(void *), +- "hw_interrupt_type disable", FAULT_ON_ERROR); ++ if (VALID_MEMBER(hw_interrupt_type_disable)) ++ readmem(handler+OFFSET(hw_interrupt_type_disable), ++ KVADDR, &tmp1, sizeof(void *), ++ "hw_interrupt_type disable", FAULT_ON_ERROR); ++ else if (VALID_MEMBER(irq_chip_disable)) ++ readmem(handler+OFFSET(irq_chip_disable), ++ KVADDR, &tmp1, sizeof(void *), ++ "hw_interrupt_type disable", FAULT_ON_ERROR); + fprintf(fp, " disable: %lx ", tmp1); + if (is_kernel_text(tmp1)) + fprintf(fp, "<%s>", value_to_symstr(tmp1, buf, 0)); +@@ -3534,27 +4139,119 @@ + fprintf(fp, "<%s>", + value_to_symstr(tmp2, buf, 0)); + fprintf(fp, "\n"); ++ } else if (VALID_MEMBER(irq_chip_ack)) { ++ readmem(handler+OFFSET(irq_chip_ack), KVADDR, ++ &tmp1, sizeof(void *), ++ "irq_chip ack", FAULT_ON_ERROR); ++ fprintf(fp, " ack: %lx ", tmp1); ++ if (is_kernel_text(tmp1)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp1, buf, 0)); ++ else if (readmem(tmp1, KVADDR, &tmp2, ++ sizeof(ulong), "ack indirection", ++ RETURN_ON_ERROR|QUIET) && is_kernel_text(tmp2)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp2, buf, 0)); ++ fprintf(fp, "\n"); + } + +- if (VALID_MEMBER(hw_interrupt_type_end)) { +- readmem(handler+OFFSET(hw_interrupt_type_end), KVADDR, +- &tmp1, sizeof(void *), +- "hw_interrupt_type end", FAULT_ON_ERROR); +- fprintf(fp, " end: %lx ", tmp1); ++ if (VALID_MEMBER(irq_chip_mask)) { ++ readmem(handler+OFFSET(irq_chip_mask), KVADDR, ++ &tmp1, sizeof(void *), ++ "irq_chip mask", FAULT_ON_ERROR); ++ fprintf(fp, " mask: %lx ", tmp1); + if (is_kernel_text(tmp1)) +- fprintf(fp, "<%s>", ++ fprintf(fp, "<%s>", + value_to_symstr(tmp1, buf, 0)); + else if (readmem(tmp1, KVADDR, &tmp2, +- sizeof(ulong), "end indirection", ++ sizeof(ulong), "mask indirection", + RETURN_ON_ERROR|QUIET) && is_kernel_text(tmp2)) + fprintf(fp, "<%s>", + value_to_symstr(tmp2, buf, 0)); + fprintf(fp, "\n"); + } +- +- if (VALID_MEMBER(hw_interrupt_type_set_affinity)) { +- readmem(handler+OFFSET(hw_interrupt_type_set_affinity), +- KVADDR, &tmp1, sizeof(void *), ++ ++ if (VALID_MEMBER(irq_chip_mask_ack)) { ++ readmem(handler+OFFSET(irq_chip_mask_ack), KVADDR, ++ &tmp1, sizeof(void *), ++ "irq_chip mask_ack", FAULT_ON_ERROR); ++ fprintf(fp, " mask_ack: %lx ", tmp1); ++ if (is_kernel_text(tmp1)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp1, buf, 0)); ++ else if (readmem(tmp1, KVADDR, &tmp2, ++ sizeof(ulong), "mask_ack indirection", ++ RETURN_ON_ERROR|QUIET) && is_kernel_text(tmp2)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp2, buf, 0)); ++ fprintf(fp, "\n"); ++ } ++ ++ if (VALID_MEMBER(irq_chip_unmask)) { ++ readmem(handler+OFFSET(irq_chip_unmask), KVADDR, ++ &tmp1, sizeof(void *), ++ "irq_chip unmask", FAULT_ON_ERROR); ++ fprintf(fp, " unmask: %lx ", tmp1); ++ if (is_kernel_text(tmp1)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp1, buf, 0)); ++ else if (readmem(tmp1, KVADDR, &tmp2, ++ sizeof(ulong), "unmask indirection", ++ RETURN_ON_ERROR|QUIET) && is_kernel_text(tmp2)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp2, buf, 0)); ++ fprintf(fp, "\n"); ++ } ++ ++ if (VALID_MEMBER(irq_chip_eoi)) { ++ readmem(handler+OFFSET(irq_chip_eoi), KVADDR, ++ &tmp1, sizeof(void *), ++ "irq_chip eoi", FAULT_ON_ERROR); ++ fprintf(fp, " eoi: %lx ", tmp1); ++ if (is_kernel_text(tmp1)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp1, buf, 0)); ++ else if (readmem(tmp1, KVADDR, &tmp2, ++ sizeof(ulong), "eoi indirection", ++ RETURN_ON_ERROR|QUIET) && is_kernel_text(tmp2)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp2, buf, 0)); ++ fprintf(fp, "\n"); ++ } ++ ++ if (VALID_MEMBER(hw_interrupt_type_end)) { ++ readmem(handler+OFFSET(hw_interrupt_type_end), KVADDR, ++ &tmp1, sizeof(void *), ++ "hw_interrupt_type end", FAULT_ON_ERROR); ++ fprintf(fp, " end: %lx ", tmp1); ++ if (is_kernel_text(tmp1)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp1, buf, 0)); ++ else if (readmem(tmp1, KVADDR, &tmp2, ++ sizeof(ulong), "end indirection", ++ RETURN_ON_ERROR|QUIET) && is_kernel_text(tmp2)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp2, buf, 0)); ++ fprintf(fp, "\n"); ++ } else if (VALID_MEMBER(irq_chip_end)) { ++ readmem(handler+OFFSET(irq_chip_end), KVADDR, ++ &tmp1, sizeof(void *), ++ "irq_chip end", FAULT_ON_ERROR); ++ fprintf(fp, " end: %lx ", tmp1); ++ if (is_kernel_text(tmp1)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp1, buf, 0)); ++ else if (readmem(tmp1, KVADDR, &tmp2, ++ sizeof(ulong), "end indirection", ++ RETURN_ON_ERROR|QUIET) && is_kernel_text(tmp2)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp2, buf, 0)); ++ fprintf(fp, "\n"); ++ } ++ ++ if (VALID_MEMBER(hw_interrupt_type_set_affinity)) { ++ readmem(handler+OFFSET(hw_interrupt_type_set_affinity), ++ KVADDR, &tmp1, sizeof(void *), + "hw_interrupt_type set_affinity", + FAULT_ON_ERROR); + fprintf(fp, " set_affinity: %lx ", tmp1); +@@ -3567,6 +4264,66 @@ + fprintf(fp, "<%s>", + value_to_symstr(tmp2, buf, 0)); + fprintf(fp, "\n"); ++ } else if (VALID_MEMBER(irq_chip_set_affinity)) { ++ readmem(handler+OFFSET(irq_chip_set_affinity), ++ KVADDR, &tmp1, sizeof(void *), ++ "irq_chip set_affinity", ++ FAULT_ON_ERROR); ++ fprintf(fp, " set_affinity: %lx ", tmp1); ++ if (is_kernel_text(tmp1)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp1, buf, 0)); ++ else if (readmem(tmp1, KVADDR, &tmp2, ++ sizeof(ulong), "set_affinity indirection", ++ RETURN_ON_ERROR|QUIET) && is_kernel_text(tmp2)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp2, buf, 0)); ++ fprintf(fp, "\n"); ++ } ++ if (VALID_MEMBER(irq_chip_retrigger)) { ++ readmem(handler+OFFSET(irq_chip_retrigger), KVADDR, ++ &tmp1, sizeof(void *), ++ "irq_chip retrigger", FAULT_ON_ERROR); ++ fprintf(fp, " retrigger: %lx ", tmp1); ++ if (is_kernel_text(tmp1)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp1, buf, 0)); ++ else if (readmem(tmp1, KVADDR, &tmp2, ++ sizeof(ulong), "retrigger indirection", ++ RETURN_ON_ERROR|QUIET) && is_kernel_text(tmp2)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp2, buf, 0)); ++ fprintf(fp, "\n"); ++ } ++ if (VALID_MEMBER(irq_chip_set_type)) { ++ readmem(handler+OFFSET(irq_chip_set_type), KVADDR, ++ &tmp1, sizeof(void *), ++ "irq_chip set_type", FAULT_ON_ERROR); ++ fprintf(fp, " set_type: %lx ", tmp1); ++ if (is_kernel_text(tmp1)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp1, buf, 0)); ++ else if (readmem(tmp1, KVADDR, &tmp2, ++ sizeof(ulong), "set_type indirection", ++ RETURN_ON_ERROR|QUIET) && is_kernel_text(tmp2)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp2, buf, 0)); ++ fprintf(fp, "\n"); ++ } ++ if (VALID_MEMBER(irq_chip_set_wake)) { ++ readmem(handler+OFFSET(irq_chip_set_wake), KVADDR, ++ &tmp1, sizeof(void *), ++ "irq_chip set wake", FAULT_ON_ERROR); ++ fprintf(fp, " set_wake: %lx ", tmp1); ++ if (is_kernel_text(tmp1)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp1, buf, 0)); ++ else if (readmem(tmp1, KVADDR, &tmp2, ++ sizeof(ulong), "set_wake indirection", ++ RETURN_ON_ERROR|QUIET) && is_kernel_text(tmp2)) ++ fprintf(fp, "<%s>", ++ value_to_symstr(tmp2, buf, 0)); ++ fprintf(fp, "\n"); + } + } + +@@ -4146,7 +4903,7 @@ + } + + /* +- * 2.6 per-cpu timers, using "per_cpu__tvec_bases". XXX ++ * 2.6 per-cpu timers, using "per_cpu__tvec_bases". + */ + + static void +@@ -4220,8 +4977,12 @@ + else + tvec_bases = symbol_value("per_cpu__tvec_bases"); + +- fprintf(fp, "TVEC_BASES[%d]: %lx\n", cpu, +- tvec_bases + SIZE(tvec_t_base_s)); ++ if (symbol_exists("boot_tvec_bases")) { ++ readmem(tvec_bases, KVADDR, &tvec_bases, sizeof(void *), ++ "per-cpu tvec_bases", FAULT_ON_ERROR); ++ } ++ ++ fprintf(fp, "TVEC_BASES[%d]: %lx\n", cpu, tvec_bases); + + sprintf(buf1, "%ld", highest); + flen = MAX(strlen(buf1), strlen("JIFFIES")); +@@ -4320,6 +5081,11 @@ + else + tvec_bases = symbol_value("per_cpu__tvec_bases"); + ++ if (symbol_exists("boot_tvec_bases")) { ++ readmem(tvec_bases, KVADDR, &tvec_bases, sizeof(void *), ++ "per-cpu tvec_bases", FAULT_ON_ERROR); ++ } ++ + tv[1].base = tvec_bases + + OFFSET(tvec_t_base_s_tv1); + tv[1].end = tv[1].base + SIZE(tvec_root_s); +@@ -4475,9 +5241,16 @@ ld->start = vec[i]; ld->list_head_offset = offset; ld->end = vec_kvaddr; @@ -9910,7 +15209,7 @@ if (!timer_cnt) continue; timer_list = (ulong *)GETBUF(timer_cnt * sizeof(ulong)); -@@ -4708,21 +4901,412 @@ +@@ -4708,21 +5481,569 @@ machdep->last_pgd_read = 0; machdep->last_pmd_read = 0; machdep->last_ptbl_read = 0; @@ -9937,15 +15236,20 @@ return 0; - get_symbol_data("cpu_online_map", sizeof(ulong), &cpu_online_map); -+ len = get_symbol_type("cpu_online_map", NULL, &req) == TYPE_CODE_UNDEF ? -+ sizeof(ulong) : req.length; ++ if (LKCD_KERNTYPES()) { ++ if ((len = STRUCT_SIZE("cpumask_t")) < 0) ++ error(FATAL, "cannot determine type cpumask_t\n"); ++ } else ++ len = get_symbol_type("cpu_online_map", NULL, &req) == ++ TYPE_CODE_UNDEF ? sizeof(ulong) : req.length; + buf = GETBUF(len); + + online = 0; + + if (readmem(symbol_value("cpu_online_map"), KVADDR, buf, len, + "cpu_online_map", RETURN_ON_ERROR)) { -+ + +- return count_bits_long(cpu_online_map); + maskptr = (ulong *)buf; + for (i = 0; i < (len/sizeof(ulong)); i++, maskptr++) + online += count_bits_long(*maskptr); @@ -9959,6 +15263,47 @@ +} + +/* ++ * For kernels containing at least the cpu_possible_map, used ++ * to determine the cpu count (of online and offline cpus). ++ */ ++int ++get_cpus_possible() ++{ ++ int i, len, possible; ++ struct gnu_request req; ++ char *buf; ++ ulong *maskptr; ++ ++ if (!symbol_exists("cpu_possible_map")) ++ return 0; ++ ++ if (LKCD_KERNTYPES()) { ++ if ((len = STRUCT_SIZE("cpumask_t")) < 0) ++ error(FATAL, "cannot determine type cpumask_t\n"); ++ } else ++ len = get_symbol_type("cpu_possible_map", NULL, &req) == ++ TYPE_CODE_UNDEF ? sizeof(ulong) : req.length; ++ buf = GETBUF(len); ++ ++ possible = 0; ++ ++ if (readmem(symbol_value("cpu_possible_map"), KVADDR, buf, len, ++ "cpu_possible_map", RETURN_ON_ERROR)) { ++ ++ maskptr = (ulong *)buf; ++ for (i = 0; i < (len/sizeof(ulong)); i++, maskptr++) ++ possible += count_bits_long(*maskptr); ++ ++ FREEBUF(buf); ++ if (CRASHDEBUG(1)) ++ error(INFO, "get_cpus_possible: possible: %d\n", ++ possible); ++ } ++ ++ return possible; ++} ++ ++/* + * Xen machine-address to pseudo-physical-page translator. + */ +ulonglong @@ -9984,6 +15329,7 @@ +__xen_m2p(ulonglong machine, ulong mfn) +{ + ulong mapping, kmfn, pfn, p, i, c; ++ ulong start, end; + ulong *mp; + + mp = (ulong *)kt->m2p_page; @@ -9994,7 +15340,8 @@ + */ + for (c = 0; c < P2M_MAPPING_CACHE; c++) { + if (kt->p2m_mapping_cache[c].mapping && -+ (kt->p2m_mapping_cache[c].mfn == mfn)) { ++ ((mfn >= kt->p2m_mapping_cache[c].start) && ++ (mfn <= kt->p2m_mapping_cache[c].end))) { + + if (kt->p2m_mapping_cache[c].mapping != kt->last_mapping_read) { + if (!readmem(kt->p2m_mapping_cache[c].mapping, KVADDR, @@ -10004,7 +15351,8 @@ + "phys_to_machine_mapping page\n"); + else + kt->last_mapping_read = kt->p2m_mapping_cache[c].mapping; -+ } ++ } else ++ kt->p2m_page_cache_hits++; + + for (i = 0; i < XEN_PFNS_PER_PAGE; i++) { + kmfn = (*(mp+i)) & ~XEN_FOREIGN_FRAME; @@ -10017,7 +15365,7 @@ + " i: %ld pfn: %lx (%llx)\n", + mfn, machine, p, + i, pfn, XEN_PFN_TO_PSEUDO(pfn)); -+ kt->p2m_cache_hits++; ++ kt->p2m_mfn_cache_hits++; + + return pfn; + } @@ -10047,25 +15395,21 @@ + + kt->p2m_pages_searched++; + -+ for (i = 0; i < XEN_PFNS_PER_PAGE; i++) -+ { -+ kmfn = (*(mp+i)) & ~XEN_FOREIGN_FRAME; -+ if (kmfn == mfn) { -+ pfn = p + i; -+ if (CRASHDEBUG(1)) -+ console("pages: %d mfn: %lx (%llx) p: %ld" -+ " i: %ld pfn: %lx (%llx)\n", -+ (p/XEN_PFNS_PER_PAGE)+1, mfn, machine, -+ p, i, pfn, XEN_PFN_TO_PSEUDO(pfn)); ++ if (search_mapping_page(mfn, &i, &start, &end)) { ++ pfn = p + i; ++ if (CRASHDEBUG(1)) ++ console("pages: %d mfn: %lx (%llx) p: %ld" ++ " i: %ld pfn: %lx (%llx)\n", ++ (p/XEN_PFNS_PER_PAGE)+1, mfn, machine, ++ p, i, pfn, XEN_PFN_TO_PSEUDO(pfn)); + -+ c = kt->p2m_cache_index; -+ kt->p2m_mapping_cache[c].mfn = mfn; -+ kt->p2m_mapping_cache[c].mapping = mapping; -+ kt->p2m_cache_index = (c+1) % P2M_MAPPING_CACHE; - -- return count_bits_long(cpu_online_map); -+ return pfn; -+ } ++ c = kt->p2m_cache_index; ++ kt->p2m_mapping_cache[c].start = start; ++ kt->p2m_mapping_cache[c].end = end; ++ kt->p2m_mapping_cache[c].mapping = mapping; ++ kt->p2m_cache_index = (c+1) % P2M_MAPPING_CACHE; ++ ++ return pfn; + } + + mapping += PAGESIZE(); @@ -10077,6 +15421,113 @@ + return (XEN_MFN_NOT_FOUND); +} + ++/* ++ * Search for an mfn in the current mapping page, and if found, ++ * determine the range of contiguous mfns that it's contained ++ * within (if any). ++ */ ++#define PREV_UP 0x1 ++#define NEXT_UP 0x2 ++#define PREV_DOWN 0x4 ++#define NEXT_DOWN 0x8 ++ ++static int ++search_mapping_page(ulong mfn, ulong *index, ulong *startptr, ulong *endptr) ++{ ++ int n, found; ++ ulong i, kmfn; ++ ulong flags, start, end, next, prev, curr; ++ ulong *mp; ++ ++ mp = (ulong *)kt->m2p_page; ++ ++ for (i = 0, found = FALSE; i < XEN_PFNS_PER_PAGE; i++) { ++ kmfn = (*(mp+i)) & ~XEN_FOREIGN_FRAME; ++ ++ if (kmfn == mfn) { ++ found = TRUE; ++ *index = i; ++ break; ++ } ++ } ++ ++ if (found) { ++ flags = 0; ++ next = prev = XEN_MFN_NOT_FOUND; ++ start = end = kmfn; ++ ++ if (i) ++ prev = (*(mp+(i-1))) & ~XEN_FOREIGN_FRAME; ++ if ((i+1) != XEN_PFNS_PER_PAGE) ++ next = (*(mp+(i+1))) & ~XEN_FOREIGN_FRAME; ++ ++ if (prev == (kmfn-1)) ++ flags |= PREV_UP; ++ else if (prev == (kmfn+1)) ++ flags |= PREV_DOWN; ++ ++ if (next == (kmfn+1)) ++ flags |= NEXT_UP; ++ else if (next == (kmfn-1)) ++ flags |= NEXT_DOWN; ++ ++ /* Should be impossible, but just in case... */ ++ if ((flags & PREV_UP) && (flags & NEXT_DOWN)) ++ flags &= ~NEXT_DOWN; ++ else if ((flags & PREV_DOWN) && (flags & NEXT_UP)) ++ flags &= ~NEXT_UP; ++ ++ if (flags & (PREV_UP|PREV_DOWN)) { ++ start = prev; ++ ++ for (n = (i-2); n >= 0; n--) { ++ curr = (*(mp+n)) & ~XEN_FOREIGN_FRAME; ++ if (flags & PREV_UP) { ++ if (curr == (start-1)) ++ start = curr; ++ } else { ++ if (curr == (start+1)) ++ start = curr; ++ } ++ } ++ ++ } ++ ++ if (flags & (NEXT_UP|NEXT_DOWN)) { ++ end = next; ++ ++ for (n = (i+2); n < XEN_PFNS_PER_PAGE; n++) { ++ curr = (*(mp+n)) & ~XEN_FOREIGN_FRAME; ++ if (flags & NEXT_UP) { ++ if (curr == (end+1)) ++ end = curr; ++ } else { ++ if (curr == (end-1)) ++ end = curr; ++ } ++ } ++ ++ ++ } ++ ++ if (start > end) { ++ curr = start; ++ start = end; ++ end = curr; ++ } ++ ++ *startptr = start; ++ *endptr = end; ++ ++ if (CRASHDEBUG(2)) ++ fprintf(fp, "mfn: %lx -> start: %lx end: %lx (%ld mfns)\n", ++ mfn, start, end, end - start); ++ } ++ ++ return found; ++} ++ ++ + +/* + * Read the relevant IKCONFIG (In Kernel Config) data if available. @@ -10086,6 +15537,7 @@ + "CONFIG_NR_CPUS", + "CONFIG_PGTABLE_4", + "CONFIG_HZ", ++ "CONFIG_DEBUG_BUGVERBOSE", + NULL, +}; + @@ -10219,9 +15671,13 @@ + while (whitespace(*ln)) + ln++; + -+ /* skip comments */ -+ if (*ln == '#') ++ /* skip comments -- except when looking for "not set" */ ++ if (*ln == '#') { ++ if (strstr(ln, "CONFIG_DEBUG_BUGVERBOSE") && ++ strstr(ln, "not set")) ++ kt->flags |= BUGVERBOSE_OFF; + continue; ++ } + + /* Find '=' */ + if ((head = strchr(ln, '=')) != NULL) { @@ -10327,8 +15783,19 @@ + break; + } } ---- crash/gdb_interface.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/gdb_interface.c 2006-08-18 14:58:45.000000000 -0400 +--- crash/gdb_interface.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/gdb_interface.c 2007-07-31 16:05:22.000000000 -0400 +@@ -1,8 +1,8 @@ + /* gdb_interface.c - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 @@ -31,9 +31,6 @@ { argc = 1; @@ -10339,7 +15806,19 @@ if (pc->flags & SILENT) { if (pc->flags & READNOW) argv[argc++] = "--readnow"; -@@ -206,12 +203,17 @@ +@@ -198,20 +195,28 @@ + retry: + BZERO(req->buf, BUFSIZE); + req->command = GNU_GET_DATATYPE; +- req->name = "task_struct"; ++ req->name = XEN_HYPER_MODE() ? "page_info" : "task_struct"; + req->flags = GNU_RETURN_ON_ERROR; + gdb_interface(req); + + if (req->flags & GNU_COMMAND_FAILED) { ++ if (XEN_HYPER_MODE()) ++ no_debugging_data(WARNING); /* just bail out */ ++ if (!debug_data_pulled_in) { if (CRASHDEBUG(1)) error(INFO, @@ -10359,7 +15838,25 @@ gdb_interface(req); if (!(req->flags & GNU_COMMAND_FAILED)) goto retry; -@@ -556,6 +558,14 @@ +@@ -237,11 +242,16 @@ + sprintf(req->buf, "set height 0"); + gdb_interface(req); + ++ req->command = GNU_PASS_THROUGH; ++ req->name = NULL, req->flags = 0; ++ sprintf(req->buf, "set width 0"); ++ gdb_interface(req); ++ + /* + * Patch gdb's symbol values with the correct values from either + * the System.map or non-debug vmlinux, whichever is in effect. + */ +- if ((pc->flags & SYSMAP) || ++ if ((pc->flags & SYSMAP) || (kt->flags & (RELOC_SET|RELOC_FORCE)) || + (pc->namelist_debug && !pc->debuginfo_file)) { + req->command = GNU_PATCH_SYMBOL_VALUES; + req->flags = GNU_RETURN_ON_ERROR; +@@ -556,6 +566,14 @@ error_hook = NULL; @@ -10374,9 +15871,144 @@ if (pc->cur_gdb_cmd) { pc->last_gdb_cmd = pc->cur_gdb_cmd; pc->cur_gdb_cmd = 0; ---- crash/configure.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/configure.c 2006-08-22 14:44:48.000000000 -0400 -@@ -1121,14 +1121,14 @@ +@@ -619,6 +637,7 @@ + "clear", "disable", "enable", "condition", "ignore", "frame", + "select-frame", "f", "up", "down", "catch", "tcatch", "return", + "file", "exec-file", "core-file", "symbol-file", "load", "si", "ni", ++ "shell", + NULL /* must be last */ + }; + +@@ -628,7 +647,7 @@ + }; + + #define RESTRICTED_GDB_COMMAND \ +- "restricted gdb command: %s\n%s\"%s\" may only be used in a .gdbinit file or in a command file.\n%sThe .gdbinit file is read automatically during %s initialization.\n%sOther user-defined command files may be read interactively during\n%s%s runtime by using the gdb \"source\" command." ++ "restricted gdb command: %s\n%s\"%s\" may only be used in a .gdbinit file or in a command file.\n%sThe .gdbinit file is read automatically during %s initialization.\n%sOther user-defined command files may be read interactively during\n%s%s runtime by using the gdb \"source\" command.\n" + + static int + is_restricted_command(char *cmd, ulong flags) +@@ -722,8 +741,10 @@ + if (pc->cur_req->flags & GNU_NO_READMEM) + return TRUE; + +- if (UNIQUE_COMMAND("dis")) ++ if (pc->curcmd_flags & MEMTYPE_UVADDR) + memtype = UVADDR; ++ else if (pc->curcmd_flags & MEMTYPE_FILEADDR) ++ memtype = FILEADDR; + else if (!IS_KVADDR(addr)) { + if (STREQ(pc->curcmd, "gdb") && + STRNEQ(pc->cur_req->buf, "x/")) { +@@ -740,12 +761,11 @@ + if (CRASHDEBUG(1)) + console("gdb_readmem_callback[%d]: %lx %d\n", + memtype, addr, len); +- +-#ifdef OLDWAY +- return(readmem(addr, KVADDR, buf, len, +- "gdb_readmem_callback", RETURN_ON_ERROR)); +-#endif + ++ if (memtype == FILEADDR) ++ return(readmem(pc->curcmd_private, memtype, buf, len, ++ "gdb_readmem_callback", RETURN_ON_ERROR)); ++ + switch (len) + { + case SIZEOF_8BIT: +--- crash/configure.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/configure.c 2007-06-04 11:58:33.000000000 -0400 +@@ -1,8 +1,8 @@ + /* configure.c - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 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 +@@ -56,7 +56,7 @@ + + void build_configure(void); + void release_configure(char *); +-void make_rh_rpm_package(char *); ++void make_rh_rpm_package(char *, int); + void unconfigure(void); + void set_warnings(int); + void show_configuration(void); +@@ -222,7 +222,7 @@ + + setup_gdb_defaults(); + +- while ((c = getopt(argc, argv, "gsqnWwubdr:p:")) > 0) { ++ while ((c = getopt(argc, argv, "gsqnWwubdr:p:P:")) > 0) { + switch (c) { + case 'q': + target_data.flags |= QUIET; +@@ -239,7 +239,10 @@ + release_configure(optarg); + break; + case 'p': +- make_rh_rpm_package(optarg); ++ make_rh_rpm_package(optarg, 0); ++ break; ++ case 'P': ++ make_rh_rpm_package(optarg, 1); + break; + case 'W': + case 'w': +@@ -566,10 +569,11 @@ + * Create an .rh_rpm_package file if the passed-in variable is set. + */ + void +-make_rh_rpm_package(char *package) ++make_rh_rpm_package(char *package, int release) + { +- char *p; ++ char *p, *cur; + FILE *fp; ++ char buf[256]; + + if ((strcmp(package, "remove") == 0)) { + if (file_exists(".rh_rpm_package")) { +@@ -589,6 +593,33 @@ + if (!strlen(++p)) + return; + ++ if (release) { ++ if (!(fp = popen("./crash -v", "r"))) { ++ fprintf(stderr, "cannot execute \"crash -v\"\n"); ++ exit(1); ++ } ++ cur = NULL; ++ while (fgets(buf, 256, fp)) { ++ if (strncmp(buf, "crash ", 6) == 0) { ++ cur = &buf[6]; ++ break; ++ } ++ } ++ fclose(fp); ++ ++ if (!cur) { ++ fprintf(stderr, "cannot get version from \"crash -v\"\n"); ++ exit(1); ++ } ++ strip_linefeeds(cur); ++ ++ if (strcmp(cur, p) != 0) { ++ fprintf(stderr, "./crash version: %s\n", cur); ++ fprintf(stderr, "release version: %s\n", p); ++ exit(1); ++ } ++ } ++ + if ((fp = fopen(".rh_rpm_package", "w")) == NULL) { + perror("fopen"); + fprintf(stderr, "cannot open .rh_rpm_package\n"); +@@ -1121,14 +1152,14 @@ printf("#\n"); printf("# crash core analysis suite\n"); printf("#\n"); @@ -10393,17 +16025,59 @@ printf("Distribution: Linux 2.2 or greater\n"); printf("Vendor: Red Hat, Inc.\n"); printf("Packager: Dave Anderson \n"); -@@ -1141,7 +1141,7 @@ +@@ -1141,7 +1172,18 @@ printf("%%description\n"); printf("The core analysis suite is a self-contained tool that can be used to\n"); printf("investigate either live systems, kernel core dumps created from the\n"); - printf("netdump and diskdump packages from Red Hat Linux, the mcore kernel patch\n"); + printf("netdump, diskdump and kdump facilities from Red Hat Linux, the mcore kernel patch\n"); ++ printf("offered by Mission Critical Linux, or the LKCD kernel patch.\n"); ++ printf("\n"); ++ printf("%%package devel\n"); ++ printf("Requires: %%{name} = %%{version}\n"); ++ printf("Summary: crash utility for live systems; netdump, diskdump, kdump, LKCD or mcore dumpfiles\n"); ++ printf("Group: Development/Debuggers\n"); ++ printf("\n"); ++ printf("%%description devel\n"); ++ printf("The core analysis suite is a self-contained tool that can be used to\n"); ++ printf("investigate either live systems, kernel core dumps created from the\n"); ++ printf("netdump, diskdump and kdump packages from Red Hat Linux, the mcore kernel patch\n"); printf("offered by Mission Critical Linux, or the LKCD kernel patch.\n"); printf("\n"); printf("%%prep\n"); ---- crash/net.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/net.c 2006-05-11 11:23:41.000000000 -0400 +@@ -1158,6 +1200,8 @@ + printf("make DESTDIR=%%{buildroot} install\n"); + printf("mkdir -p %%{buildroot}%%{_mandir}/man8\n"); + printf("cp crash.8 %%{buildroot}%%{_mandir}/man8/crash.8\n"); ++ printf("mkdir -p %%{buildroot}%%{_includedir}/crash\n"); ++ printf("cp defs.h %%{buildroot}%%{_includedir}/crash\n"); + printf("\n"); + printf("%%clean\n"); + printf("rm -rf %%{buildroot}\n"); +@@ -1167,6 +1211,10 @@ + printf("%%{_mandir}/man8/crash.8*\n"); + /* printf("/usr/bin/crashd\n"); */ + printf("%%doc README\n"); ++ printf("\n"); ++ printf("%%files devel\n"); ++ printf("%%defattr(-,root,root)\n"); ++ printf("%%{_includedir}/*\n"); + } + + /* +--- crash/net.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/net.c 2007-02-21 12:09:35.000000000 -0500 +@@ -1,8 +1,8 @@ + /* net.c - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 @@ -50,6 +50,7 @@ #define STRUCT_NET_DEVICE (0x4) #define SOCK_V1 (0x8) @@ -10663,7 +16337,7 @@ int max_fdset = 0; int max_fds = 0; ulong open_fds_addr = 0; -@@ -1004,32 +1118,51 @@ +@@ -1004,32 +1118,54 @@ sizeof(void *), "task files contents", FAULT_ON_ERROR); if (files_struct_addr) { @@ -10687,9 +16361,12 @@ + readmem(files_struct_addr + OFFSET(files_struct_fdt), KVADDR, + &fdtable_addr, sizeof(void *), "fdtable buffer", + FAULT_ON_ERROR); -+ readmem(fdtable_addr + OFFSET(fdtable_max_fdset), -+ KVADDR, &max_fdset, sizeof(int), -+ "fdtable_struct max_fdset", FAULT_ON_ERROR); ++ if (VALID_MEMBER(fdtable_max_fdset)) ++ readmem(fdtable_addr + OFFSET(fdtable_max_fdset), ++ KVADDR, &max_fdset, sizeof(int), ++ "fdtable_struct max_fdset", FAULT_ON_ERROR); ++ else ++ max_fdset = -1; + readmem(fdtable_addr + OFFSET(fdtable_max_fds), + KVADDR, &max_fds, sizeof(int), "fdtable_struct max_fds", + FAULT_ON_ERROR); @@ -10733,7 +16410,16 @@ if (!open_fds_addr || !fd) { if (!NET_REFERENCE_CHECK(ref)) fprintf(fp, "No open sockets.\n"); -@@ -1096,9 +1229,9 @@ +@@ -1061,7 +1197,7 @@ + for (;;) { + unsigned long set; + i = j * __NFDBITS; +- if ((i >= max_fdset) || (i >= max_fds)) ++ if (((max_fdset >= 0) && (i >= max_fdset)) || (i >= max_fds)) + break; + set = open_fds.__fds_bits[j++]; + while (set) { +@@ -1096,9 +1232,9 @@ */ static char *socket_hdr_32 = @@ -10745,7 +16431,7 @@ static int sym_socket_dump(ulong file, -@@ -1223,7 +1356,12 @@ +@@ -1223,7 +1359,12 @@ dump_struct("sock", sock, 0); break; case SOCK_V2: @@ -10759,8 +16445,8 @@ break; } break; ---- crash/dev.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/dev.c 2005-11-23 11:09:44.000000000 -0500 +--- crash/dev.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/dev.c 2006-12-22 14:19:41.000000000 -0500 @@ -91,13 +91,13 @@ switch(c) { @@ -10777,8 +16463,83 @@ option_not_supported(c); do_pci(); return; ---- crash/alpha.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/alpha.c 2006-08-02 10:34:16.000000000 -0400 +@@ -1957,29 +1955,44 @@ + unsigned int class; + unsigned short device, vendor; + unsigned char busno; +- ulong *devlist, bus, devfn, tmp; ++ ulong *devlist, bus, devfn, prev, next; + char buf1[BUFSIZE]; + char buf2[BUFSIZE]; + char buf3[BUFSIZE]; + +- fprintf(fp, "%s BU:SL.FN CLASS: VENDOR-DEVICE\n", +- mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "PCI_DEV")); ++ if (!symbol_exists("pci_devices")) ++ error(FATAL, "no PCI devices found on this system.\n"); + + BZERO(&pcilist_data, sizeof(struct list_data)); + + if (VALID_MEMBER(pci_dev_global_list)) { +- get_symbol_data("pci_devices", sizeof(void *), &tmp); +- readmem(tmp + OFFSET(list_head_next), KVADDR, +- &pcilist_data.start, sizeof(void *), "pci devices", +- FAULT_ON_ERROR); ++ get_symbol_data("pci_devices", sizeof(void *), &pcilist_data.start); + pcilist_data.end = symbol_value("pci_devices"); + pcilist_data.list_head_offset = OFFSET(pci_dev_global_list); ++ readmem(symbol_value("pci_devices") + OFFSET(list_head_prev), ++ KVADDR, &prev, sizeof(void *), "list head prev", ++ FAULT_ON_ERROR); ++ /* ++ * Check if this system does not have any PCI devices. ++ */ ++ if ((pcilist_data.start == pcilist_data.end) && ++ (prev == pcilist_data.end)) ++ error(FATAL, "no PCI devices found on this system.\n"); + +- } else { ++ } else if (VALID_MEMBER(pci_dev_next)) { + get_symbol_data("pci_devices", sizeof(void *), + &pcilist_data.start); + pcilist_data.member_offset = OFFSET(pci_dev_next); +- } ++ /* ++ * Check if this system does not have any PCI devices. ++ */ ++ readmem(pcilist_data.start + pcilist_data.member_offset, ++ KVADDR, &next, sizeof(void *), "pci dev next", ++ FAULT_ON_ERROR); ++ if (!next) ++ error(FATAL, "no PCI devices found on this system.\n"); ++ } else ++ option_not_supported('p'); + + hq_open(); + devcnt = do_list(&pcilist_data); +@@ -1987,6 +2000,9 @@ + devcnt = retrieve_list(devlist, devcnt); + hq_close(); + ++ fprintf(fp, "%s BU:SL.FN CLASS: VENDOR-DEVICE\n", ++ mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "PCI_DEV")); ++ + for (i = 0; i < devcnt; i++) { + + /* +--- crash/alpha.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/alpha.c 2006-10-11 09:14:35.000000000 -0400 +@@ -1,8 +1,8 @@ + /* alpha.c - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 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 @@ -186,7 +186,8 @@ "irq_desc", NULL, 0); else @@ -10798,9 +16559,28 @@ fprintf(fp, ")\n"); fprintf(fp, " kvbase: %lx\n", machdep->kvbase); fprintf(fp, " identity_map_base: %lx\n", machdep->identity_map_base); ---- crash/x86.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/x86.c 2006-08-02 10:34:16.000000000 -0400 -@@ -176,6 +176,7 @@ +--- crash/x86.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/x86.c 2007-04-04 14:29:35.000000000 -0400 +@@ -1,8 +1,8 @@ + /* x86.c - core analysis suite + * + * Portions Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 +@@ -51,6 +51,7 @@ + * rights to redistribute these changes. + */ + #include "defs.h" ++#include "xen_hyper_defs.h" + + #ifndef MCLX + +@@ -176,6 +177,7 @@ static void db_symbol_values(db_sym_t, char **, db_expr_t *); static int db_sym_numargs(db_sym_t, int *, char **); static void x86_dump_line_number(ulong); @@ -10808,7 +16588,7 @@ static ulong mach_debug = 0; -@@ -215,7 +216,7 @@ +@@ -215,7 +217,7 @@ argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE, bt); /* @@ -10817,7 +16597,7 @@ * the instruction at the return address in all cases. This * may require better fault handling. */ -@@ -685,6 +686,7 @@ +@@ -685,6 +687,7 @@ bt->debug || (bt->flags & BT_FRAMESIZE_DEBUG) || !(bt->flags & BT_OLD_BACK_TRACE)) { @@ -10825,7 +16605,7 @@ lkcd_x86_back_trace(bt, 0, fp); return; } -@@ -962,8 +964,12 @@ +@@ -962,8 +965,12 @@ */ static int x86_uvtop(struct task_context *, ulong, physaddr_t *, int); static int x86_kvtop(struct task_context *, ulong, physaddr_t *, int); @@ -10840,7 +16620,15 @@ static ulong x86_get_task_pgd(ulong); static ulong x86_processor_speed(void); static ulong x86_get_pc(struct bt_info *); -@@ -983,6 +989,20 @@ +@@ -973,6 +980,7 @@ + static uint64_t x86_memory_size(void); + static ulong x86_vmalloc_start(void); + static ulong *read_idt_table(int); ++static void eframe_init(void); + #define READ_IDT_INIT 1 + #define READ_IDT_RUNTIME 2 + static char *extract_idt_function(ulong *, char *, ulong *); +@@ -983,26 +991,42 @@ static int x86_dis_filter(ulong, char *); static struct line_number_hook x86_line_number_hooks[]; static int x86_is_uvaddr(ulong, struct task_context *); @@ -10858,10 +16646,111 @@ +static char *x86_xendump_load_page_PAE(ulong, char *); +static int x86_xendump_page_index(ulong); +static int x86_xendump_page_index_PAE(ulong); ++static void x86_init_hyper(int); ++static ulong x86_get_stackbase_hyper(ulong); ++static ulong x86_get_stacktop_hyper(ulong); ++ ++static int INT_EFRAME_SS = 14; ++static int INT_EFRAME_ESP = 13; ++static int INT_EFRAME_EFLAGS = 12; /* CS lcall7 */ ++static int INT_EFRAME_CS = 11; /* EIP lcall7 */ ++static int INT_EFRAME_EIP = 10; /* EFLAGS lcall7 */ ++static int INT_EFRAME_ERR = 9; ++static int INT_EFRAME_ES = 8; ++static int INT_EFRAME_DS = 7; ++static int INT_EFRAME_EAX = 6; ++static int INT_EFRAME_EBP = 5; ++static int INT_EFRAME_EDI = 4; ++static int INT_EFRAME_ESI = 3; ++static int INT_EFRAME_EDX = 2; ++static int INT_EFRAME_ECX = 1; ++static int INT_EFRAME_EBX = 0; ++static int INT_EFRAME_GS = -1; +- +-#define INT_EFRAME_SS (14) +-#define INT_EFRAME_ESP (13) +-#define INT_EFRAME_EFLAGS (12) /* CS lcall7 */ +-#define INT_EFRAME_CS (11) /* EIP lcall7 */ +-#define INT_EFRAME_EIP (10) /* EFLAGS lcall7 */ +-#define INT_EFRAME_ERR (9) +- +-#define INT_EFRAME_ES (8) +-#define INT_EFRAME_DS (7) +-#define INT_EFRAME_EAX (6) +-#define INT_EFRAME_EBP (5) +-#define INT_EFRAME_EDI (4) +-#define INT_EFRAME_ESI (3) +-#define INT_EFRAME_EDX (2) +-#define INT_EFRAME_ECX (1) +-#define INT_EFRAME_EBX (0) +- +-#define USER_EFRAME_SIZE (INT_EFRAME_SS+1) ++#define MAX_USER_EFRAME_SIZE (16) + #define KERNEL_EFRAME_SIZE (INT_EFRAME_EFLAGS+1) - #define INT_EFRAME_SS (14) -@@ -1420,6 +1440,17 @@ + #define EFRAME_USER (1) +@@ -1015,7 +1039,7 @@ + { + int i; + char buf[BUFSIZE], *sp; +- ulong int_eframe[USER_EFRAME_SIZE]; ++ ulong int_eframe[MAX_USER_EFRAME_SIZE]; + int eframe_type, args; + ulong value, *argp; + +@@ -1025,11 +1049,11 @@ + return(frame_number); + + GET_STACK_DATA(ep->eframe_addr, (char *)int_eframe, +- USER_EFRAME_SIZE * sizeof(ulong)); ++ SIZE(pt_regs)); + + if (int_eframe[INT_EFRAME_CS] & DPL_BITS) { + if (!INSTACK(ep->eframe_addr + +- (USER_EFRAME_SIZE*sizeof(ulong)) - 1, bt)) ++ SIZE(pt_regs) - 1, bt)) + return(frame_number); + /* error(FATAL, "read of exception frame would go beyond stack\n"); */ + eframe_type = EFRAME_USER; +@@ -1158,17 +1182,24 @@ + int_eframe[INT_EFRAME_EDX]); + + fprintf(fp, +- " DS: %04x ESI: %08lx ES: %04x EDI: %08lx \n", ++ " DS: %04x ESI: %08lx ES: %04x EDI: %08lx", + (short)int_eframe[INT_EFRAME_DS], + int_eframe[INT_EFRAME_ESI], + (short)int_eframe[INT_EFRAME_ES], + int_eframe[INT_EFRAME_EDI]); ++ if (kernel && (INT_EFRAME_GS != -1)) ++ fprintf(fp, " GS: %04x", (short)int_eframe[INT_EFRAME_GS]); ++ fprintf(fp, "\n"); + +- if (!kernel) +- fprintf(fp, " SS: %04x ESP: %08lx EBP: %08lx \n", ++ if (!kernel) { ++ fprintf(fp, " SS: %04x ESP: %08lx EBP: %08lx", + (short)int_eframe[INT_EFRAME_SS], + int_eframe[INT_EFRAME_ESP], + int_eframe[INT_EFRAME_EBP]); ++ if (INT_EFRAME_GS != -1) ++ fprintf(fp, " GS: %04x", (short)int_eframe[INT_EFRAME_GS]); ++ fprintf(fp, "\n"); ++ } + + fprintf(fp, + " CS: %04x EIP: %08lx ERR: %08lx EFLAGS: %08lx \n", +@@ -1355,7 +1386,7 @@ + */ + + struct x86_pt_regs { +- ulong reg_value[USER_EFRAME_SIZE]; ++ ulong reg_value[MAX_USER_EFRAME_SIZE]; + }; + + /* +@@ -1420,6 +1451,17 @@ break; } @@ -10879,7 +16768,7 @@ /* check for user exception frame */ if (((short)pt->reg_value[INT_EFRAME_CS] == 0x23) && -@@ -1441,6 +1472,20 @@ +@@ -1441,6 +1483,20 @@ rv = bt->stackbase + sizeof(ulong) * (first - stack); break; } @@ -10900,7 +16789,7 @@ } return(rv); } -@@ -1536,6 +1581,8 @@ +@@ -1536,6 +1592,8 @@ mode = "USER-MODE"; } else if ((cs == 0x10) || (cs == 0x60)) { mode = "KERNEL-MODE"; @@ -10909,7 +16798,19 @@ } else { mode = "UNKNOWN-MODE"; } -@@ -1639,7 +1686,7 @@ +@@ -1626,6 +1684,11 @@ + { + struct syment *sp, *spn; + ++ if (XEN_HYPER_MODE()) { ++ x86_init_hyper(when); ++ return; ++ } ++ + switch (when) + { + case PRE_SYMTAB: +@@ -1639,7 +1702,7 @@ machdep->stacksize = machdep->pagesize * 2; if ((machdep->pgd = (char *)malloc(PAGESIZE())) == NULL) error(FATAL, "cannot malloc pgd space."); @@ -10918,7 +16819,7 @@ error(FATAL, "cannot malloc pmd space."); if ((machdep->ptbl = (char *)malloc(PAGESIZE())) == NULL) error(FATAL, "cannot malloc ptbl space."); -@@ -1659,8 +1706,8 @@ +@@ -1659,8 +1722,8 @@ PGDIR_SHIFT = PGDIR_SHIFT_3LEVEL; PTRS_PER_PTE = PTRS_PER_PTE_3LEVEL; PTRS_PER_PGD = PTRS_PER_PGD_3LEVEL; @@ -10929,7 +16830,7 @@ } else { PGDIR_SHIFT = PGDIR_SHIFT_2LEVEL; PTRS_PER_PTE = PTRS_PER_PTE_2LEVEL; -@@ -1696,14 +1743,19 @@ +@@ -1696,14 +1759,19 @@ machdep->cmd_mach = x86_cmd_mach; machdep->get_smp_cpus = x86_get_smp_cpus; machdep->line_number_hooks = x86_line_number_hooks; @@ -10952,7 +16853,7 @@ STRUCT_SIZE_INIT(user_regs_struct, "user_regs_struct"); MEMBER_OFFSET_INIT(user_regs_struct_ebp, "user_regs_struct", "ebp"); -@@ -1723,9 +1775,36 @@ +@@ -1723,9 +1791,37 @@ "irq_desc", NULL, 0); else machdep->nr_irqs = 224; /* NR_IRQS */ @@ -10965,7 +16866,7 @@ + machdep->hz = 1000; + } + -+ if (machdep->flags & PAE){ ++ if (machdep->flags & PAE) { + machdep->section_size_bits = _SECTION_SIZE_BITS_PAE; + machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_PAE; + } else { @@ -10989,10 +16890,59 @@ + "cpu_user_regs", "eip"); + } + ++ eframe_init(); break; case POST_INIT: -@@ -1825,7 +1904,7 @@ +@@ -1735,6 +1831,47 @@ + } + + /* ++ * Account for addition of pt_regs.xgs field in 2.6.20+ kernels. ++ */ ++static void ++eframe_init(void) ++{ ++ if (INVALID_SIZE(pt_regs)) { ++ if (THIS_KERNEL_VERSION < LINUX(2,6,20)) ++ ASSIGN_SIZE(pt_regs) = (MAX_USER_EFRAME_SIZE-1)*sizeof(ulong); ++ else { ++ ASSIGN_SIZE(pt_regs) = MAX_USER_EFRAME_SIZE*sizeof(ulong); ++ INT_EFRAME_SS = 15; ++ INT_EFRAME_ESP = 14; ++ INT_EFRAME_EFLAGS = 13; ++ INT_EFRAME_CS = 12; ++ INT_EFRAME_EIP = 11; ++ INT_EFRAME_ERR = 10; ++ INT_EFRAME_GS = 9; ++ } ++ return; ++ } ++ ++ INT_EFRAME_SS = MEMBER_OFFSET("pt_regs", "xss") / 4; ++ INT_EFRAME_ESP = MEMBER_OFFSET("pt_regs", "esp") / 4; ++ INT_EFRAME_EFLAGS = MEMBER_OFFSET("pt_regs", "eflags") / 4; ++ INT_EFRAME_CS = MEMBER_OFFSET("pt_regs", "xcs") / 4; ++ INT_EFRAME_EIP = MEMBER_OFFSET("pt_regs", "eip") / 4; ++ INT_EFRAME_ERR = MEMBER_OFFSET("pt_regs", "orig_eax") / 4; ++ if ((INT_EFRAME_GS = MEMBER_OFFSET("pt_regs", "xgs")) != -1) ++ INT_EFRAME_GS /= 4; ++ INT_EFRAME_ES = MEMBER_OFFSET("pt_regs", "xes") / 4; ++ INT_EFRAME_DS = MEMBER_OFFSET("pt_regs", "xds") / 4; ++ INT_EFRAME_EAX = MEMBER_OFFSET("pt_regs", "eax") / 4; ++ INT_EFRAME_EBP = MEMBER_OFFSET("pt_regs", "ebp") / 4; ++ INT_EFRAME_EDI = MEMBER_OFFSET("pt_regs", "edi") / 4; ++ INT_EFRAME_ESI = MEMBER_OFFSET("pt_regs", "esi") / 4; ++ INT_EFRAME_EDX = MEMBER_OFFSET("pt_regs", "edx") / 4; ++ INT_EFRAME_ECX = MEMBER_OFFSET("pt_regs", "ecx") / 4; ++ INT_EFRAME_EBX = MEMBER_OFFSET("pt_regs", "ebx") / 4; ++} ++ ++/* + * Needs to be done this way because of potential 4G/4G split. + */ + static int +@@ -1825,7 +1962,7 @@ fprintf(fp, " PAGE: %s (4MB)\n\n", mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, MKSTR(NONPAE_PAGEBASE(pgd_pte)))); @@ -11001,7 +16951,7 @@ } *paddr = NONPAE_PAGEBASE(pgd_pte) + (vaddr & ~_4MB_PAGE_MASK); -@@ -1892,7 +1971,170 @@ +@@ -1892,7 +2029,170 @@ } static int @@ -11173,7 +17123,7 @@ { ulong mm, active_mm; ulonglong *pgd; -@@ -1962,7 +2204,7 @@ +@@ -1962,7 +2262,7 @@ page_middle = PAE_PAGEBASE(page_dir_entry); @@ -11182,7 +17132,7 @@ offset = ((vaddr >> PMD_SHIFT) & (PTRS_PER_PMD-1)) * sizeof(ulonglong); -@@ -1998,7 +2240,7 @@ +@@ -1998,7 +2298,7 @@ page_table = PAE_PAGEBASE(page_middle_entry); @@ -11191,7 +17141,7 @@ offset = ((vaddr >> PAGESHIFT()) & (PTRS_PER_PTE-1)) * sizeof(ulonglong); -@@ -2028,9 +2270,10 @@ +@@ -2028,9 +2328,10 @@ *paddr = physpage; if (verbose) { @@ -11205,7 +17155,7 @@ x86_translate_pte(0, 0, page_table_entry); } -@@ -2040,67 +2283,256 @@ +@@ -2040,62 +2341,259 @@ return FALSE; } @@ -11302,34 +17252,27 @@ + fprintf(fp, " PGD: %s => %llx [machine]\n", mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, - MKSTR((ulong)page_dir)), pgd_pte); +- +- if (!pgd_pte) +- goto no_kpage; + MKSTR((ulong)pgd + offset)), + page_dir_entry); -- if (!pgd_pte) -- goto no_kpage; +- if (pgd_pte & _PAGE_4M) { + if (!(page_dir_entry & _PAGE_PRESENT)) { + goto no_upage; + } - -- if (pgd_pte & _PAGE_4M) { -- if (verbose) { -- fprintf(fp, " PAGE: %s (4MB)\n\n", -- mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, -- MKSTR(NONPAE_PAGEBASE(pgd_pte)))); -- x86_translate_pte(0, 0, pgd_pte); -- } ++ + page_middle = PAE_PAGEBASE(page_dir_entry); + pseudo_page_middle = xen_m2p(page_middle); - -- *paddr = NONPAE_PAGEBASE(pgd_pte) + (kvaddr & ~_4MB_PAGE_MASK); ++ + if (verbose) + fprintf(fp, " PGD: %s => %llx\n", + mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, + MKSTR((ulong)pgd + offset)), + pseudo_page_middle | PAGEOFFSET(page_dir_entry) | + (page_dir_entry & _PAGE_NX)); - -- return TRUE; ++ + FILL_PMD_PAE(pseudo_page_middle, PHYSADDR, PAGESIZE()); + + offset = ((vaddr >> PMD_SHIFT) & (PTRS_PER_PMD-1)) * sizeof(ulonglong); @@ -11422,7 +17365,7 @@ + MKSTR(&physpage))); + + pseudo_physpage += (PAGEOFFSET(vaddr) | -+ (page_table_entry & _PAGE_NX)); ++ (page_table_entry & (_PAGE_NX|machdep->pageoffset))); + + fprintf(fp, " PAGE: %s\n\n", + mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX, @@ -11458,22 +17401,30 @@ + if (!IS_KVADDR(kvaddr)) + return FALSE; + -+ if (!vt->vmalloc_start) { -+ *paddr = VTOP(kvaddr); -+ return TRUE; -+ } -+ -+ if (!IS_VMALLOC_ADDR(kvaddr)) { -+ *paddr = VTOP(kvaddr); -+ if (!verbose) ++ if (XEN_HYPER_MODE()) { ++ if (DIRECTMAP_VIRT_ADDR(kvaddr)) { ++ *paddr = kvaddr - DIRECTMAP_VIRT_START; + return TRUE; ++ } ++ pgd = (ulong *)symbol_value("idle_pg_table_l2"); ++ } else { ++ if (!vt->vmalloc_start) { ++ *paddr = VTOP(kvaddr); ++ return TRUE; ++ } ++ ++ if (!IS_VMALLOC_ADDR(kvaddr)) { ++ *paddr = VTOP(kvaddr); ++ if (!verbose) ++ return TRUE; ++ } ++ ++ if (XEN() && (kt->xen_flags & WRITABLE_PAGE_TABLES)) ++ return (x86_kvtop_xen_wpt(tc, kvaddr, paddr, verbose)); ++ ++ pgd = (ulong *)vt->kernel_pgd[0]; + } + -+ if (XEN() && (kt->xen_flags & WRITABLE_PAGE_TABLES)) -+ return (x86_kvtop_xen_wpt(tc, kvaddr, paddr, verbose)); -+ -+ pgd = (ulong *)vt->kernel_pgd[0]; -+ + if (verbose) + fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd); + @@ -11491,20 +17442,16 @@ + goto no_kpage; + + if (pgd_pte & _PAGE_4M) { -+ if (verbose) { -+ fprintf(fp, " PAGE: %s (4MB)\n\n", -+ mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, -+ MKSTR(NONPAE_PAGEBASE(pgd_pte)))); + if (verbose) { + fprintf(fp, " PAGE: %s (4MB)\n\n", + mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, + MKSTR(NONPAE_PAGEBASE(pgd_pte)))); +- x86_translate_pte(0, 0, pgd_pte); + x86_translate_pte(pgd_pte, 0, 0); -+ } -+ -+ *paddr = NONPAE_PAGEBASE(pgd_pte) + (kvaddr & ~_4MB_PAGE_MASK); -+ -+ return TRUE; - } + } - page_middle = page_dir; -@@ -2158,9 +2590,134 @@ + *paddr = NONPAE_PAGEBASE(pgd_pte) + (kvaddr & ~_4MB_PAGE_MASK); +@@ -2158,9 +2656,134 @@ return FALSE; } @@ -11640,17 +17587,47 @@ { ulonglong *pgd; ulonglong page_dir_entry; -@@ -2188,6 +2745,9 @@ - return TRUE; - } +@@ -2177,18 +2800,29 @@ + if (!IS_KVADDR(kvaddr)) + return FALSE; -+ if (XEN() && (kt->xen_flags & WRITABLE_PAGE_TABLES)) -+ return (x86_kvtop_xen_wpt_PAE(tc, kvaddr, paddr, verbose)); +- if (!vt->vmalloc_start) { +- *paddr = VTOP(kvaddr); +- return TRUE; +- } +- +- if (!IS_VMALLOC_ADDR(kvaddr)) { +- *paddr = VTOP(kvaddr); +- if (!verbose) ++ if (XEN_HYPER_MODE()) { ++ if (DIRECTMAP_VIRT_ADDR(kvaddr)) { ++ *paddr = kvaddr - DIRECTMAP_VIRT_START; + return TRUE; +- } ++ } ++ pgd = (ulonglong *)symbol_value("idle_pg_table_l3"); ++ } else { ++ if (!vt->vmalloc_start) { ++ *paddr = VTOP(kvaddr); ++ return TRUE; ++ } + - pgd = (ulonglong *)vt->kernel_pgd[0]; ++ if (!IS_VMALLOC_ADDR(kvaddr)) { ++ *paddr = VTOP(kvaddr); ++ if (!verbose) ++ return TRUE; ++ } + +- pgd = (ulonglong *)vt->kernel_pgd[0]; ++ if (XEN() && (kt->xen_flags & WRITABLE_PAGE_TABLES)) ++ return (x86_kvtop_xen_wpt_PAE(tc, kvaddr, paddr, verbose)); ++ ++ pgd = (ulonglong *)vt->kernel_pgd[0]; ++ } if (verbose) -@@ -2212,7 +2772,7 @@ + fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd); +@@ -2212,7 +2846,7 @@ page_middle = PAE_PAGEBASE(page_dir_entry); @@ -11659,56 +17636,36 @@ offset = ((kvaddr >> PMD_SHIFT) & (PTRS_PER_PMD-1)) * sizeof(ulonglong); -@@ -2247,9 +2807,144 @@ - return TRUE; +@@ -2249,7 +2883,7 @@ + + page_table = PAE_PAGEBASE(page_middle_entry); + +- FILL_PTBL(page_table, PHYSADDR, PAGESIZE()); ++ FILL_PTBL_PAE(page_table, PHYSADDR, PAGESIZE()); + + offset = ((kvaddr >> PAGESHIFT()) & (PTRS_PER_PTE-1)) * + sizeof(ulonglong); +@@ -2277,9 +2911,10 @@ + *paddr = physpage; + + if (verbose) { ++ ull = PAE_PAGEBASE(page_table_entry); + fprintf(fp, " PAGE: %s\n\n", + mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX, +- MKSTR(&physpage))); ++ MKSTR(&ull))); + x86_translate_pte(0, 0, page_table_entry); } -- page_table = PAE_PAGEBASE(page_middle_entry); -- -- FILL_PTBL(page_table, PHYSADDR, PAGESIZE()); -+ page_table = PAE_PAGEBASE(page_middle_entry); -+ -+ FILL_PTBL_PAE(page_table, PHYSADDR, PAGESIZE()); -+ -+ offset = ((kvaddr >> PAGESHIFT()) & (PTRS_PER_PTE-1)) * -+ sizeof(ulonglong); -+ -+ page_table_entry = *((ulonglong *)&machdep->ptbl[offset]); -+ -+ if (verbose) { -+ ull = page_table + offset; -+ fprintf(fp, " PTE: %s => %llx\n", -+ mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX, -+ MKSTR(&ull)), page_table_entry); -+ } -+ -+ if (!(page_table_entry & (_PAGE_PRESENT | _PAGE_PROTNONE))) { -+ if (page_table_entry && verbose) { -+ fprintf(fp, "\n"); -+ x86_translate_pte(0, 0, page_table_entry); -+ } -+ -+ goto no_kpage; -+ } -+ -+ physpage = PAE_PAGEBASE(page_table_entry) + PAGEOFFSET(kvaddr); -+ -+ *paddr = physpage; -+ -+ if (verbose) { -+ ull = PAE_PAGEBASE(page_table_entry); -+ fprintf(fp, " PAGE: %s\n\n", -+ mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX, -+ MKSTR(&ull))); -+ x86_translate_pte(0, 0, page_table_entry); -+ } -+ -+ return TRUE; -+ -+no_kpage: -+ return FALSE; -+} -+ +@@ -2289,11 +2924,170 @@ + return FALSE; + } + +-/* +- * Get the relevant page directory pointer from a task structure. +- */ +-static ulong +-x86_get_task_pgd(ulong task) +static int +x86_kvtop_xen_wpt_PAE(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose) +{ @@ -11804,25 +17761,31 @@ + } + + FILL_PTBL_PAE(pseudo_page_table, PHYSADDR, PAGESIZE()); - - offset = ((kvaddr >> PAGESHIFT()) & (PTRS_PER_PTE-1)) * - sizeof(ulonglong); -@@ -2258,7 +2953,7 @@ - - if (verbose) { - ull = page_table + offset; -- fprintf(fp, " PTE: %s => %llx\n", ++ ++ offset = ((kvaddr >> PAGESHIFT()) & (PTRS_PER_PTE-1)) * ++ sizeof(ulonglong); ++ ++ page_table_entry = *((ulonglong *)&machdep->ptbl[offset]); ++ ++ if (verbose) { ++ ull = page_table + offset; + fprintf(fp, " PTE: %s => %llx [machine]\n", - mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX, - MKSTR(&ull)), page_table_entry); - } -@@ -2273,14 +2968,32 @@ - } - - physpage = PAE_PAGEBASE(page_table_entry) + PAGEOFFSET(kvaddr); ++ mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX, ++ MKSTR(&ull)), page_table_entry); ++ } ++ ++ if (!(page_table_entry & (_PAGE_PRESENT | _PAGE_PROTNONE))) { ++ if (page_table_entry && verbose) { ++ fprintf(fp, "\n"); ++ x86_translate_pte(0, 0, page_table_entry); ++ } ++ ++ goto no_kpage; ++ } ++ ++ physpage = PAE_PAGEBASE(page_table_entry) + PAGEOFFSET(kvaddr); + pseudo_physpage = xen_m2p(physpage); - -- *paddr = physpage; ++ + if (verbose) { + ull = page_table + offset; + fprintf(fp, " PTE: %s => %llx\n", @@ -11833,13 +17796,11 @@ + } + + *paddr = pseudo_physpage + PAGEOFFSET(kvaddr); - - if (verbose) { -- fprintf(fp, " PAGE: %s\n\n", ++ ++ if (verbose) { + fprintf(fp, " PAGE: %s [machine]\n", - mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX, - MKSTR(&physpage))); -- x86_translate_pte(0, 0, page_table_entry); ++ mkstring(buf, VADDR_PRLEN, RJUST|LONGLONG_HEX, ++ MKSTR(&physpage))); + + pseudo_physpage += (PAGEOFFSET(kvaddr) | + (page_table_entry & _PAGE_NX)); @@ -11849,13 +17810,14 @@ + MKSTR(&pseudo_physpage))); + + x86_translate_pte(0, 0, pseudo_physpage); - } - - return TRUE; -@@ -2289,6 +3002,13 @@ - return FALSE; - } - ++ } ++ ++ return TRUE; ++ ++no_kpage: ++ return FALSE; ++} ++ +void +x86_clear_machdep_cache(void) +{ @@ -11863,10 +17825,15 @@ + machdep->machspec->last_ptbl_read_PAE = 0; +} + - /* - * Get the relevant page directory pointer from a task structure. - */ -@@ -2341,6 +3061,7 @@ ++/* ++ * Get the relevant page directory pointer from a task structure. ++ */ ++static ulong ++x86_get_task_pgd(ulong task) + { + long offset; + ulong cr3; +@@ -2341,6 +3135,7 @@ x86_dump_machdep_table(ulong arg) { int others; @@ -11874,7 +17841,7 @@ switch (arg) { default: -@@ -2355,8 +3076,6 @@ +@@ -2355,8 +3150,6 @@ fprintf(fp, "%sPAE", others++ ? "|" : ""); if (machdep->flags & OMIT_FRAME_PTR) fprintf(fp, "%sOMIT_FRAME_PTR", others++ ? "|" : ""); @@ -11883,7 +17850,7 @@ if (machdep->flags & FRAMESIZE_DEBUG) fprintf(fp, "%sFRAMESIZE_DEBUG", others++ ? "|" : ""); fprintf(fp, ")\n"); -@@ -2376,12 +3095,17 @@ +@@ -2376,12 +3169,17 @@ fprintf(fp, " eframe_search: x86_eframe_search()\n"); fprintf(fp, " back_trace: x86_back_trace_cmd()\n"); fprintf(fp, "get_processor_speed: x86_processor_speed()\n"); @@ -11905,7 +17872,7 @@ } fprintf(fp, " get_task_pgd: x86_get_task_pgd()\n"); fprintf(fp, " dump_irq: generic_dump_irq()\n"); -@@ -2399,7 +3123,7 @@ +@@ -2399,7 +3197,7 @@ fprintf(fp, " is_kvaddr: generic_is_kvaddr()\n"); fprintf(fp, " is_uvaddr: generic_is_uvaddr()\n"); fprintf(fp, " verify_paddr: generic_verify_paddr()\n"); @@ -11914,7 +17881,7 @@ fprintf(fp, " value_to_symbol: %s\n", machdep->value_to_symbol == generic_machdep_value_to_symbol ? "generic_machdep_value_to_symbol()" : -@@ -2412,6 +3136,14 @@ +@@ -2412,6 +3210,14 @@ fprintf(fp, " pmd: %lx\n", (ulong)machdep->pmd); fprintf(fp, " ptbl: %lx\n", (ulong)machdep->ptbl); fprintf(fp, " ptrs_per_pgd: %d\n", machdep->ptrs_per_pgd); @@ -11929,7 +17896,7 @@ fprintf(fp, " machspec: x86_machine_specific\n"); fprintf(fp, " idt_table: %lx\n", (ulong)machdep->machspec->idt_table); -@@ -2421,6 +3153,11 @@ +@@ -2421,6 +3227,11 @@ machdep->machspec->entry_tramp_end); fprintf(fp, " entry_tramp_start_phys: %llx\n", machdep->machspec->entry_tramp_start_phys); @@ -11941,7 +17908,7 @@ } /* -@@ -2732,6 +3469,9 @@ +@@ -2732,6 +3543,9 @@ switch (flag) { case READ_IDT_INIT: @@ -11951,7 +17918,7 @@ if (!(idt = (ulong *)malloc(desc_struct_size))) { error(WARNING, "cannot malloc idt_table\n\n"); return NULL; -@@ -2779,6 +3519,10 @@ +@@ -2779,6 +3593,10 @@ break; case READ_IDT_RUNTIME: @@ -11962,7 +17929,20 @@ idt = (ulong *)GETBUF(desc_struct_size); readmem(symbol_value("idt_table"), KVADDR, idt, desc_struct_size, "idt_table", FAULT_ON_ERROR); -@@ -2969,6 +3713,16 @@ +@@ -2942,7 +3760,11 @@ + !strstr(buf2, "+")) + sprintf(p1, buf1); + } +- } ++ } ++ else if (STREQ(argv[2], "ud2a")) ++ pc->curcmd_flags |= UD2A_INSTRUCTION; ++ else if (STREQ(argv[2], "(bad)")) ++ pc->curcmd_flags |= BAD_INSTRUCTION; + + if (CRASHDEBUG(1)) + console(" %s", inbuf); +@@ -2969,6 +3791,16 @@ } } @@ -11979,7 +17959,7 @@ return count; } -@@ -3092,31 +3846,31 @@ +@@ -3092,31 +3924,31 @@ * with the -fomit-frame-pointer flag. */ #define PUSH_BP_MOV_ESP_BP 0xe58955 @@ -12027,7 +18007,7 @@ } /* -@@ -3207,4 +3961,717 @@ +@@ -3207,4 +4039,922 @@ return ((sp = value_search(value, offset))); } @@ -12159,6 +18139,12 @@ + frames -= mfns[i]; + } + ++ if (CRASHDEBUG(2)) { ++ for (i = 0; i < xkd->p2m_frames; i++) ++ fprintf(fp, "%lx ", xkd->p2m_mfn_frame_list[i]); ++ fprintf(fp, "\n"); ++ } ++ + pc->readmem = read_kdump; + return TRUE; + @@ -12412,6 +18398,11 @@ + ulonglong *ulp; + off_t offset; + ++ if (!symbol_exists("phys_to_machine_mapping")) { ++ xd->flags |= XC_CORE_NO_P2M; ++ return TRUE; ++ } ++ + if ((ctrlreg_offset = MEMBER_OFFSET("vcpu_guest_context", "ctrlreg")) == + INVALID_OFFSET) + error(FATAL, @@ -12431,11 +18422,14 @@ + sizeof(ctrlreg)) + error(FATAL, "cannot read vcpu_guest_context ctrlreg[8]\n"); + -+ for (i = 0; CRASHDEBUG(1) && (i < 8); i++) { -+ fprintf(xd->ofp, "ctrlreg[%d]: %lx\n", i, ctrlreg[i]); -+ } ++ mfn = (ctrlreg[3] >> PAGESHIFT()) | (ctrlreg[3] << (BITS()-PAGESHIFT())); + -+ mfn = ctrlreg[3] >> PAGESHIFT(); ++ for (i = 0; CRASHDEBUG(1) && (i < 8); i++) { ++ fprintf(xd->ofp, "ctrlreg[%d]: %lx", i, ctrlreg[i]); ++ if (i == 3) ++ fprintf(xd->ofp, " -> mfn: %lx", mfn); ++ fprintf(xd->ofp, "\n"); ++ } + + if (!xc_core_mfn_to_page(mfn, machdep->pgd)) + error(FATAL, "cannot read/find cr3 page\n"); @@ -12744,10 +18738,211 @@ +generic: + return machdep->get_stack_frame(bt, eip, esp); +} ++ ++/* for Xen Hypervisor analysis */ ++ ++static int ++x86_xenhyper_is_kvaddr(ulong addr) ++{ ++ if (machdep->flags & PAE) { ++ return (addr >= HYPERVISOR_VIRT_START_PAE); ++ } ++ return (addr >= HYPERVISOR_VIRT_START); ++} ++ ++static ulong ++x86_get_stackbase_hyper(ulong task) ++{ ++ struct xen_hyper_vcpu_context *vcc; ++ int pcpu; ++ ulong init_tss; ++ ulong esp, base; ++ char *buf; ++ ++ /* task means vcpu here */ ++ vcc = xen_hyper_vcpu_to_vcpu_context(task); ++ if (!vcc) ++ error(FATAL, "invalid vcpu\n"); ++ ++ pcpu = vcc->processor; ++ if (!xen_hyper_test_pcpu_id(pcpu)) { ++ error(FATAL, "invalid pcpu number\n"); ++ } ++ init_tss = symbol_value("init_tss"); ++ buf = GETBUF(XEN_HYPER_SIZE(tss_struct)); ++ init_tss += XEN_HYPER_SIZE(tss_struct) * pcpu; ++ if (!readmem(init_tss, KVADDR, buf, ++ XEN_HYPER_SIZE(tss_struct), "init_tss", RETURN_ON_ERROR)) { ++ error(FATAL, "cannot read init_tss.\n"); ++ } ++ esp = ULONG(buf + XEN_HYPER_OFFSET(tss_struct_esp0)); ++ FREEBUF(buf); ++ base = esp & (~(STACKSIZE() - 1)); ++ ++ return base; ++} ++ ++static ulong ++x86_get_stacktop_hyper(ulong task) ++{ ++ return x86_get_stackbase_hyper(task) + STACKSIZE(); ++} ++ ++static void ++x86_get_stack_frame_hyper(struct bt_info *bt, ulong *pcp, ulong *spp) ++{ ++ struct xen_hyper_vcpu_context *vcc; ++ int pcpu; ++ ulong *regs; ++ ulong esp, eip; ++ ++ /* task means vcpu here */ ++ vcc = xen_hyper_vcpu_to_vcpu_context(bt->task); ++ if (!vcc) ++ error(FATAL, "invalid vcpu\n"); ++ ++ pcpu = vcc->processor; ++ if (!xen_hyper_test_pcpu_id(pcpu)) { ++ error(FATAL, "invalid pcpu number\n"); ++ } ++ ++ if (bt->flags & BT_TEXT_SYMBOLS_ALL) { ++ if (spp) ++ *spp = x86_get_stackbase_hyper(bt->task); ++ if (pcp) ++ *pcp = 0; ++ bt->flags &= ~BT_TEXT_SYMBOLS_ALL; ++ return; ++ } ++ ++ regs = (ulong *)xen_hyper_id_to_dumpinfo_context(pcpu)->pr_reg_ptr; ++ esp = XEN_HYPER_X86_NOTE_ESP(regs); ++ eip = XEN_HYPER_X86_NOTE_EIP(regs); ++ ++ if (spp) { ++ if (esp < x86_get_stackbase_hyper(bt->task) || ++ esp >= x86_get_stacktop_hyper(bt->task)) ++ *spp = x86_get_stackbase_hyper(bt->task); ++ else ++ *spp = esp; ++ } ++ if (pcp) { ++ if (is_kernel_text(eip)) ++ *pcp = eip; ++ else ++ *pcp = 0; ++ } ++} ++ ++static void ++x86_init_hyper(int when) ++{ ++ switch (when) ++ { ++ case PRE_SYMTAB: ++ machdep->verify_symbol = x86_verify_symbol; ++ if (pc->flags & KERNEL_DEBUG_QUERY) ++ return; ++ machdep->pagesize = memory_page_size(); ++ machdep->pageshift = ffs(machdep->pagesize) - 1; ++ machdep->pageoffset = machdep->pagesize - 1; ++ machdep->pagemask = ~((ulonglong)machdep->pageoffset); ++ machdep->stacksize = machdep->pagesize * 4; /* ODA: magic num */ ++ if ((machdep->pgd = (char *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc pgd space."); ++ if ((machdep->pmd = (char *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc pmd space."); ++ if ((machdep->ptbl = (char *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc ptbl space."); ++ machdep->last_pgd_read = 0; ++ machdep->last_pmd_read = 0; ++ machdep->last_ptbl_read = 0; ++ machdep->machspec = &x86_machine_specific; /* some members used */ ++ break; ++ ++ case PRE_GDB: ++ if (symbol_exists("idle_pg_table_l3")) { ++ machdep->flags |= PAE; ++ PGDIR_SHIFT = PGDIR_SHIFT_3LEVEL; ++ PTRS_PER_PTE = PTRS_PER_PTE_3LEVEL; ++ PTRS_PER_PGD = PTRS_PER_PGD_3LEVEL; ++ machdep->kvtop = x86_kvtop_PAE; ++ machdep->kvbase = HYPERVISOR_VIRT_START_PAE; ++ } else { ++ PGDIR_SHIFT = PGDIR_SHIFT_2LEVEL; ++ PTRS_PER_PTE = PTRS_PER_PTE_2LEVEL; ++ PTRS_PER_PGD = PTRS_PER_PGD_2LEVEL; ++ machdep->kvtop = x86_kvtop; ++ free(machdep->pmd); ++ machdep->pmd = machdep->pgd; ++ machdep->kvbase = HYPERVISOR_VIRT_START; ++ } ++ machdep->ptrs_per_pgd = PTRS_PER_PGD; ++ machdep->identity_map_base = DIRECTMAP_VIRT_START; ++ machdep->is_kvaddr = x86_xenhyper_is_kvaddr; ++ machdep->eframe_search = x86_eframe_search; ++ machdep->back_trace = x86_back_trace_cmd; ++ machdep->processor_speed = x86_processor_speed; /* ODA: check */ ++ machdep->dump_irq = generic_dump_irq; /* ODA: check */ ++ machdep->get_stack_frame = x86_get_stack_frame_hyper; ++ machdep->get_stackbase = x86_get_stackbase_hyper; ++ machdep->get_stacktop = x86_get_stacktop_hyper; ++ machdep->translate_pte = x86_translate_pte; ++ machdep->memory_size = xen_hyper_x86_memory_size; ++ machdep->dis_filter = x86_dis_filter; ++// machdep->cmd_mach = x86_cmd_mach; /* ODA: check */ ++ machdep->get_smp_cpus = xen_hyper_x86_get_smp_cpus; ++// machdep->line_number_hooks = x86_line_number_hooks; /* ODA: check */ ++ machdep->flags |= FRAMESIZE_DEBUG; /* ODA: check */ ++ machdep->value_to_symbol = generic_machdep_value_to_symbol; ++ machdep->clear_machdep_cache = x86_clear_machdep_cache; ++ ++ /* machdep table for Xen Hypervisor */ ++ xhmachdep->pcpu_init = xen_hyper_x86_pcpu_init; ++ break; ++ ++ case POST_GDB: ++#if 0 /* ODA: need this ? */ ++ if (x86_omit_frame_pointer()) { ++ machdep->flags |= OMIT_FRAME_PTR; ++#endif ++ XEN_HYPER_STRUCT_SIZE_INIT(cpu_time, "cpu_time"); ++ XEN_HYPER_STRUCT_SIZE_INIT(cpuinfo_x86, "cpuinfo_x86"); ++ XEN_HYPER_STRUCT_SIZE_INIT(tss_struct, "tss_struct"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(tss_struct_esp0, "tss_struct", "esp0"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(cpu_time_local_tsc_stamp, "cpu_time", "local_tsc_stamp"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(cpu_time_stime_local_stamp, "cpu_time", "stime_local_stamp"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(cpu_time_stime_master_stamp, "cpu_time", "stime_master_stamp"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(cpu_time_tsc_scale, "cpu_time", "tsc_scale"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(cpu_time_calibration_timer, "cpu_time", "calibration_timer"); ++ if (symbol_exists("cpu_data")) { ++ xht->cpu_data_address = symbol_value("cpu_data"); ++ } ++/* KAK Can this be calculated? */ ++ if (!machdep->hz) { ++ machdep->hz = XEN_HYPER_HZ; ++ } ++ break; ++ ++ case POST_INIT: ++ break; ++ } ++} ++ #endif /* X86 */ ---- crash/ppc.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/ppc.c 2006-08-02 10:34:16.000000000 -0400 -@@ -135,9 +135,13 @@ +--- crash/ppc.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/ppc.c 2007-03-19 12:55:31.000000000 -0500 +@@ -51,6 +51,9 @@ + void + ppc_init(int when) + { ++ uint cpu_features; ++ ulong cur_cpu_spec; ++ + switch (when) + { + case PRE_SYMTAB: +@@ -135,9 +138,23 @@ "irq_desc", NULL, 0); else machdep->nr_irqs = 0; @@ -12759,12 +18954,22 @@ + if (THIS_KERNEL_VERSION >= LINUX(2,6,0)) + machdep->hz = 1000; + } ++ if (symbol_exists("cur_cpu_spec")) { ++ get_symbol_data("cur_cpu_spec", sizeof(void *), &cur_cpu_spec); ++ readmem(cur_cpu_spec + MEMBER_OFFSET("cpu_spec", "cpu_user_features"), ++ KVADDR, &cpu_features, sizeof(uint), "cpu user features", ++ FAULT_ON_ERROR); ++ if (cpu_features & CPU_BOOKE) ++ machdep->flags |= CPU_BOOKE; ++ } ++ else ++ machdep->flags |= CPU_BOOKE; + machdep->section_size_bits = _SECTION_SIZE_BITS; + machdep->max_physmem_bits = _MAX_PHYSMEM_BITS; break; case POST_INIT: -@@ -154,8 +158,6 @@ +@@ -154,8 +171,6 @@ fprintf(fp, " flags: %lx (", machdep->flags); if (machdep->flags & KSYMS_START) fprintf(fp, "%sKSYMS_START", others++ ? "|" : ""); @@ -12773,7 +18978,7 @@ fprintf(fp, ")\n"); fprintf(fp, " kvbase: %lx\n", machdep->kvbase); -@@ -205,6 +207,9 @@ +@@ -205,6 +220,9 @@ fprintf(fp, " pmd: %lx\n", (ulong)machdep->pmd); fprintf(fp, " ptbl: %lx\n", (ulong)machdep->ptbl); fprintf(fp, " ptrs_per_pgd: %d\n", machdep->ptrs_per_pgd); @@ -12783,20 +18988,55 @@ fprintf(fp, " machspec: %lx\n", (ulong)machdep->machspec); } ---- crash/ia64.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/ia64.c 2006-08-21 15:08:44.000000000 -0400 +@@ -280,7 +298,11 @@ + + page_middle = (ulong *)pgd_pte; + +- page_table = page_middle + (BTOP(vaddr) & (PTRS_PER_PTE - 1)); ++ if (machdep->flags & CPU_BOOKE) ++ page_table = page_middle + (BTOP(vaddr) & (PTRS_PER_PTE - 1)); ++ else ++ page_table = (ulong *)(((pgd_pte & (ulong)machdep->pagemask) + machdep->kvbase) + ++ ((ulong)BTOP(vaddr) & (PTRS_PER_PTE-1))); + + if (verbose) + fprintf(fp, " PMD: %lx => %lx\n",(ulong)page_middle, +@@ -364,7 +386,11 @@ + + page_middle = (ulong *)pgd_pte; + +- page_table = page_middle + (BTOP(kvaddr) & (PTRS_PER_PTE-1)); ++ if (machdep->flags & CPU_BOOKE) ++ page_table = page_middle + (BTOP(kvaddr) & (PTRS_PER_PTE - 1)); ++ else ++ page_table = (ulong *)(((pgd_pte & (ulong)machdep->pagemask) + machdep->kvbase) + ++ ((ulong)BTOP(kvaddr) & (PTRS_PER_PTE-1))); + + if (verbose) + fprintf(fp, " PMD: %lx => %lx\n", (ulong)page_middle, +--- crash/ia64.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/ia64.c 2007-08-23 17:02:53.000000000 -0400 @@ -1,8 +1,8 @@ /* ia64.c - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002, 2003, 2004, 2005 David Anderson - * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson -+ * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 -@@ -25,6 +25,8 @@ +@@ -16,6 +16,8 @@ + */ + #ifdef IA64 + #include "defs.h" ++#include "xen_hyper_defs.h" ++#include + + static int ia64_verify_symbol(const char *, ulong, char); + static int ia64_eframe_search(struct bt_info *); +@@ -25,6 +27,8 @@ static void try_old_unwind(struct bt_info *); static void ia64_dump_irq(int); static ulong ia64_processor_speed(void); @@ -12805,15 +19045,26 @@ static int ia64_uvtop(struct task_context *, ulong, physaddr_t *, int); static int ia64_kvtop(struct task_context *, ulong, physaddr_t *, int); static ulong ia64_get_task_pgd(ulong); -@@ -62,6 +64,18 @@ +@@ -47,10 +51,12 @@ + static int ia64_verify_paddr(uint64_t); + static int ia64_available_memory(struct efi_memory_desc_t *); + static void ia64_post_init(void); ++static ulong ia64_in_per_cpu_mca_stack(void); + static struct line_number_hook ia64_line_number_hooks[]; + static ulong ia64_get_stackbase(ulong); + static ulong ia64_get_stacktop(ulong); + static void parse_cmdline_arg(void); ++static void ia64_calc_phys_start(void); + + struct unw_frame_info; + static void dump_unw_frame_info(struct unw_frame_info *); +@@ -62,6 +68,17 @@ static ulong rse_read_reg(struct unw_frame_info *, int, int *); static void rse_function_params(struct unw_frame_info *, char *); +static int ia64_vtop_4l_xen_wpt(ulong, physaddr_t *paddr, ulong *pgd, int, int); +static int ia64_vtop_xen_wpt(ulong, physaddr_t *paddr, ulong *pgd, int, int); +static int ia64_xen_kdump_p2m_create(struct xen_kdump_data *); -+static char *ia64_xen_kdump_load_page(ulong, char *); -+static ulong ia64_xen_kdump_page_mfn(ulong); +static int ia64_xendump_p2m_create(struct xendump_data *); +static void ia64_debug_dump_page(FILE *, char *, char *); +static char *ia64_xendump_load_page(ulong, struct xendump_data *); @@ -12821,10 +19072,34 @@ +static ulong ia64_xendump_panic_task(struct xendump_data *); +static void ia64_get_xendump_regs(struct xendump_data *, struct bt_info *, ulong *, ulong *); + ++static void ia64_init_hyper(int); struct machine_specific ia64_machine_specific = { 0 }; -@@ -92,17 +106,23 @@ +@@ -70,8 +87,22 @@ + { + struct syment *sp, *spn; + ++ if (XEN_HYPER_MODE()) { ++ ia64_init_hyper(when); ++ return; ++ } ++ + switch (when) + { ++ case SETUP_ENV: ++#if defined(PR_SET_FPEMU) && defined(PR_FPEMU_NOPRINT) ++ prctl(PR_SET_FPEMU, PR_FPEMU_NOPRINT, 0, 0, 0); ++#endif ++#if defined(PR_SET_UNALIGN) && defined(PR_UNALIGN_NOPRINT) ++ prctl(PR_SET_UNALIGN, PR_UNALIGN_NOPRINT, 0, 0, 0); ++#endif ++ break; ++ + case PRE_SYMTAB: + machdep->verify_symbol = ia64_verify_symbol; + machdep->machspec = &ia64_machine_specific; +@@ -92,17 +123,23 @@ case 16384: machdep->stacksize = (power(2, 1) * PAGESIZE()); break; @@ -12848,7 +19123,7 @@ machdep->last_pmd_read = 0; machdep->last_ptbl_read = 0; machdep->verify_paddr = ia64_verify_paddr; -@@ -115,14 +135,17 @@ +@@ -115,14 +152,17 @@ break; case PRE_GDB: @@ -12866,8 +19141,13 @@ if ((sp = symbol_search("empty_zero_page")) && (spn = next_symbol(NULL, sp)) && -@@ -173,6 +196,11 @@ - DEFAULT_PHYS_START; +@@ -169,10 +209,14 @@ + machdep->machspec->kernel_start + + GIGABYTES((ulong)(4)); + if (machdep->machspec->phys_start == UNKNOWN_PHYS_START) +- machdep->machspec->phys_start = +- DEFAULT_PHYS_START; ++ ia64_calc_phys_start(); } else machdep->machspec->vmalloc_start = KERNEL_VMALLOC_BASE; + @@ -12878,7 +19158,7 @@ break; case POST_GDB: -@@ -202,7 +230,10 @@ +@@ -202,7 +246,10 @@ else if (symbol_exists("_irq_desc")) ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc, "_irq_desc", NULL, 0); @@ -12890,11 +19170,23 @@ ia64_create_memmap(); break; -@@ -284,11 +315,34 @@ +@@ -228,8 +275,10 @@ + char *arglist[MAXARGS]; + ulong value; + struct machine_specific *ms; ++ int vm_flag; + + ms = &ia64_machine_specific; ++ vm_flag = 0; + + if (!strstr(machdep->cmdline_arg, "=")) { + errflag = 0; +@@ -284,11 +333,37 @@ continue; } } + } else if (STRNEQ(arglist[i], "vm=")) { ++ vm_flag++; + p = arglist[i] + strlen("vm="); + if (strlen(p)) { + if (STREQ(p, "4l")) { @@ -12907,25 +19199,86 @@ error(WARNING, "ignoring --machdep option: %s\n", arglist[i]); } -+ switch (machdep->flags & (VM_4_LEVEL)) -+ { -+ case VM_4_LEVEL: -+ error(NOTE, "using 4-level pagetable\n"); -+ c++; -+ break; -+ -+ default: -+ error(WARNING, "Invalid vm= option\n"); -+ c++; -+ machdep->flags &= ~(VM_4_LEVEL); -+ break; -+ } ++ if (vm_flag) { ++ switch (machdep->flags & (VM_4_LEVEL)) ++ { ++ case VM_4_LEVEL: ++ error(NOTE, "using 4-level pagetable\n"); ++ c++; ++ break; ++ ++ default: ++ error(WARNING, "invalid vm= option\n"); ++ c++; ++ machdep->flags &= ~(VM_4_LEVEL); ++ break; ++ } ++ } + + if (c) fprintf(fp, "\n"); } -@@ -401,12 +455,12 @@ +@@ -314,6 +389,58 @@ + return TRUE; + } + ++ ++static ulong ++ia64_in_per_cpu_mca_stack(void) ++{ ++ int plen, i; ++ ulong flag; ++ ulong vaddr, paddr, stackbase, stacktop; ++ ulong *__per_cpu_mca; ++ struct task_context *tc; ++ ++ tc = CURRENT_CONTEXT(); ++ ++ if (STRNEQ(CURRENT_COMM(), "INIT")) ++ flag = INIT; ++ else if (STRNEQ(CURRENT_COMM(), "MCA")) ++ flag = MCA; ++ else ++ return 0; ++ ++ if (!symbol_exists("__per_cpu_mca") || ++ !(plen = get_array_length("__per_cpu_mca", NULL, 0)) || ++ (plen < kt->cpus)) ++ return 0; ++ ++ vaddr = SWITCH_STACK_ADDR(CURRENT_TASK()); ++ if (VADDR_REGION(vaddr) != KERNEL_CACHED_REGION) ++ return 0; ++ paddr = ia64_VTOP(vaddr); ++ ++ __per_cpu_mca = (ulong *)GETBUF(sizeof(ulong) * kt->cpus); ++ ++ if (!readmem(symbol_value("__per_cpu_mca"), KVADDR, __per_cpu_mca, ++ sizeof(ulong) * kt->cpus, "__per_cpu_mca", RETURN_ON_ERROR|QUIET)) ++ return 0; ++ ++ if (CRASHDEBUG(1)) { ++ for (i = 0; i < kt->cpus; i++) { ++ fprintf(fp, "__per_cpu_mca[%d]: %lx\n", ++ i, __per_cpu_mca[i]); ++ } ++ } ++ ++ stackbase = __per_cpu_mca[tc->processor]; ++ stacktop = stackbase + (STACKSIZE() * 2); ++ FREEBUF(__per_cpu_mca); ++ ++ if ((paddr >= stackbase) && (paddr < stacktop)) ++ return flag; ++ else ++ return 0; ++} ++ + void + ia64_dump_machdep_table(ulong arg) + { +@@ -401,12 +528,14 @@ fprintf(fp, "%sUNW_R0", others++ ? "|" : ""); if (machdep->flags & MEM_LIMIT) fprintf(fp, "%sMEM_LIMIT", others++ ? "|" : ""); @@ -12935,12 +19288,14 @@ fprintf(fp, "%sDEVMEMRD", others++ ? "|" : ""); if (machdep->flags & INIT) fprintf(fp, "%sINIT", others++ ? "|" : ""); ++ if (machdep->flags & MCA) ++ fprintf(fp, "%sMCA", others++ ? "|" : ""); + if (machdep->flags & VM_4_LEVEL) + fprintf(fp, "%sVM_4_LEVEL", others++ ? "|" : ""); fprintf(fp, ")\n"); fprintf(fp, " kvbase: %lx\n", machdep->kvbase); fprintf(fp, " identity_map_base: %lx\n", machdep->identity_map_base); -@@ -445,16 +499,25 @@ +@@ -445,16 +574,25 @@ (machdep->verify_paddr == ia64_verify_paddr) ? "ia64_verify_paddr" : "generic_verify_paddr"); fprintf(fp, " init_kernel_pgd: NULL\n"); @@ -12966,7 +19321,20 @@ fprintf(fp, " machspec: ia64_machine_specific\n"); fprintf(fp, " cpu_data_address: %lx\n", machdep->machspec->cpu_data_address); -@@ -665,74 +728,148 @@ +@@ -565,9 +703,9 @@ + if (CRASHDEBUG(8)) + fprintf(fp, "%016lx %s\n", value, name); + +- if (STREQ(name, "phys_start") && type == 'A') +- if (machdep->machspec->phys_start == UNKNOWN_PHYS_START) +- machdep->machspec->phys_start = value; ++// if (STREQ(name, "phys_start") && type == 'A') ++// if (machdep->machspec->phys_start == UNKNOWN_PHYS_START) ++// machdep->machspec->phys_start = value; + + region = VADDR_REGION(value); + +@@ -665,74 +803,148 @@ return (machdep->mhz = mhz); } @@ -13060,16 +19428,16 @@ + + offset = (vaddr >> PAGESHIFT()) & (PTRS_PER_PTE - 1); + page_table = (ulong *)(PTOV(pmd_pte & _PFN_MASK)) + offset; ++ ++ FILL_PTBL(PAGEBASE(page_table), KVADDR, PAGESIZE()); ++ pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table)); - offset = (uvaddr >> PGDIR_SHIFT) & ((PTRS_PER_PGD >> 3) - 1); - offset |= (region << (PAGESHIFT() - 6)); - page_dir = pgd + offset; -+ FILL_PTBL(PAGEBASE(page_table), KVADDR, PAGESIZE()); -+ pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table)); -+ + if (verbose) + fprintf(fp, " PTE: %lx => %lx\n", (ulong)page_table, pte); - ++ + if (!(pte & (_PAGE_P))) { + if (usr) + *paddr = pte; @@ -13106,15 +19474,15 @@ + + if (usr) { + region = VADDR_REGION(vaddr); -+ offset = (vaddr >> PGDIR_SHIFT) & ((PTRS_PER_PGD >> 3) - 1); ++ offset = (vaddr >> PGDIR_SHIFT_3L) & ((PTRS_PER_PGD >> 3) - 1); + offset |= (region << (PAGESHIFT() - 6)); + page_dir = pgd + offset; + } else { + if (!(pgd = (ulong *)vt->kernel_pgd[0])) + error(FATAL, "cannot determine kernel pgd pointer\n"); -+ page_dir = pgd + ((vaddr >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)); ++ page_dir = pgd + ((vaddr >> PGDIR_SHIFT_3L) & (PTRS_PER_PGD - 1)); + } -+ + + if (verbose) + fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd); + @@ -13150,7 +19518,7 @@ page_table = (ulong *)(PTOV(pmd_pte & _PFN_MASK)) + offset; FILL_PTBL(PAGEBASE(page_table), KVADDR, PAGESIZE()); -@@ -742,15 +879,16 @@ +@@ -742,15 +954,16 @@ fprintf(fp, " PTE: %lx => %lx\n", (ulong)page_table, pte); if (!(pte & (_PAGE_P))) { @@ -13170,7 +19538,7 @@ if (verbose) { fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(*paddr)); -@@ -758,10 +896,50 @@ +@@ -758,10 +971,50 @@ } return TRUE; @@ -13223,7 +19591,7 @@ } -@@ -774,13 +952,6 @@ +@@ -774,13 +1027,6 @@ ia64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose) { ulong *pgd; @@ -13237,7 +19605,7 @@ if (!IS_KVADDR(kvaddr)) return FALSE; -@@ -813,66 +984,21 @@ +@@ -813,66 +1059,21 @@ return TRUE; } @@ -13316,28 +19684,89 @@ } /* -@@ -2391,9 +2517,10 @@ +@@ -958,9 +1159,15 @@ + { + ulong ksp; + +- readmem(task + OFFSET(task_struct_thread_ksp), KVADDR, +- &ksp, sizeof(void *), +- "thread_struct ksp", FAULT_ON_ERROR); ++ if (XEN_HYPER_MODE()) { ++ readmem(task + XEN_HYPER_OFFSET(vcpu_thread_ksp), KVADDR, ++ &ksp, sizeof(void *), ++ "vcpu thread ksp", FAULT_ON_ERROR); ++ } else { ++ readmem(task + OFFSET(task_struct_thread_ksp), KVADDR, ++ &ksp, sizeof(void *), ++ "thread_struct ksp", FAULT_ON_ERROR); ++ } + + return ksp; + } +@@ -1315,7 +1522,10 @@ + BZERO(&eframe, sizeof(ulong) * NUM_PT_REGS); + + open_tmpfile(); +- dump_struct("pt_regs", addr, RADIX(16)); ++ if (XEN_HYPER_MODE()) ++ dump_struct("cpu_user_regs", addr, RADIX(16)); ++ else ++ dump_struct("pt_regs", addr, RADIX(16)); + rewind(pc->tmpfile); + + fval = 0; +@@ -1571,6 +1781,12 @@ + + fprintf(fp, " EFRAME: %lx\n", addr); + ++ if (bt->flags & BT_INCOMPLETE_USER_EFRAME) { ++ fprintf(fp, ++ " [exception frame incomplete -- check salinfo for complete context]\n"); ++ bt->flags &= ~BT_INCOMPLETE_USER_EFRAME; ++ } ++ + fprintf(fp, " B0: %016lx CR_IIP: %016lx\n", + eframe[P_b0], eframe[P_cr_iip]); + /** +@@ -2371,9 +2587,10 @@ + !readmem(ia64_boot_param+ + MEMBER_OFFSET("ia64_boot_param", "efi_memmap"), + KVADDR, &efi_memmap, sizeof(uint64_t), "efi_memmap", +- RETURN_ON_ERROR)) { +- error(WARNING, "cannot read ia64_boot_param: " +- "memory verification will not be performed\n\n"); ++ QUIET|RETURN_ON_ERROR)) { ++ if (!XEN() || CRASHDEBUG(1)) ++ error(WARNING, "cannot read ia64_boot_param: " ++ "memory verification will not be performed\n\n"); + return; + } + +@@ -2391,9 +2608,11 @@ if ((ms->mem_limit && (efi_memmap >= ms->mem_limit)) || !readmem(PTOV(efi_memmap), KVADDR, memmap, - ms->efi_memmap_size, "efi_mmap contents", RETURN_ON_ERROR)) { +- error(WARNING, "cannot read efi_mmap: " +- "memory verification will not be performed\n"); + ms->efi_memmap_size, "efi_mmap contents", + QUIET|RETURN_ON_ERROR)) { - error(WARNING, "cannot read efi_mmap: " -- "memory verification will not be performed\n"); -+ "EFI memory verification will not be performed\n\n"); ++ if (!XEN() || (XEN() && CRASHDEBUG(1))) ++ error(WARNING, "cannot read efi_mmap: " ++ "EFI memory verification will not be performed\n\n"); free(memmap); return; } -@@ -2605,6 +2732,7 @@ +@@ -2605,6 +2824,8 @@ ia64_post_init(void) { struct machine_specific *ms; + struct gnu_request req; ++ ulong flag; ms = &ia64_machine_specific; -@@ -2677,9 +2805,10 @@ +@@ -2677,12 +2898,16 @@ } } @@ -13351,7 +19780,13 @@ if (DUMPFILE() && ia64_in_init_stack(SWITCH_STACK_ADDR(CURRENT_TASK()))) machdep->flags |= INIT; -@@ -3326,4 +3455,292 @@ ++ ++ if (DUMPFILE() && (flag = ia64_in_per_cpu_mca_stack())) ++ machdep->flags |= flag; + } + + /* +@@ -3326,4 +3551,766 @@ (vaddr < (ulong)KERNEL_UNCACHED_BASE)); } @@ -13538,35 +19973,216 @@ +#include "netdump.h" + +/* ++ * Determine the relocatable physical address base. ++ */ ++static void ++ia64_calc_phys_start(void) ++{ ++ FILE *iomem; ++ int i, found, errflag; ++ char buf[BUFSIZE]; ++ char *p1; ++ ulong kernel_code_start; ++ struct vmcore_data *vd; ++ Elf64_Phdr *phdr; ++ ulong phys_start, text_start; ++ ++ /* ++ * Default to 64MB. ++ */ ++ machdep->machspec->phys_start = DEFAULT_PHYS_START; ++ ++ text_start = symbol_exists("_text") ? symbol_value("_text") : BADADDR; ++ ++ if (ACTIVE()) { ++ if ((iomem = fopen("/proc/iomem", "r")) == NULL) ++ return; ++ ++ errflag = 1; ++ while (fgets(buf, BUFSIZE, iomem)) { ++ if (strstr(buf, ": Kernel code")) { ++ clean_line(buf); ++ errflag = 0; ++ break; ++ } ++ } ++ fclose(iomem); ++ ++ if (errflag) ++ return; ++ ++ if (!(p1 = strstr(buf, "-"))) ++ return; ++ else ++ *p1 = NULLCHAR; ++ ++ errflag = 0; ++ kernel_code_start = htol(buf, RETURN_ON_ERROR|QUIET, &errflag); ++ if (errflag) ++ return; ++ ++ machdep->machspec->phys_start = kernel_code_start; ++ ++ if (CRASHDEBUG(1)) { ++ if (text_start == BADADDR) ++ fprintf(fp, "_text: (unknown) "); ++ else ++ fprintf(fp, "_text: %lx ", text_start); ++ fprintf(fp, "Kernel code: %lx -> ", kernel_code_start); ++ fprintf(fp, "phys_start: %lx\n\n", ++ machdep->machspec->phys_start); ++ } ++ ++ return; ++ } ++ ++ /* ++ * Get relocation value from whatever dumpfile format is being used. ++ */ ++ ++ if (DISKDUMP_DUMPFILE()) { ++ if (diskdump_phys_base(&phys_start)) { ++ machdep->machspec->phys_start = phys_start; ++ if (CRASHDEBUG(1)) ++ fprintf(fp, ++ "compressed kdump: phys_start: %lx\n", ++ phys_start); ++ } ++ return; ++ } ++ ++ if ((vd = get_kdump_vmcore_data())) { ++ /* ++ * There should be at most one region 5 region, and it ++ * should be equal to "_text". If not, take whatever ++ * region 5 address comes first and hope for the best. ++ */ ++ for (i = found = 0; i < vd->num_pt_load_segments; i++) { ++ phdr = vd->load64 + i; ++ if (phdr->p_vaddr == text_start) { ++ machdep->machspec->phys_start = phdr->p_paddr; ++ found++; ++ break; ++ } ++ } ++ ++ for (i = 0; !found && (i < vd->num_pt_load_segments); i++) { ++ phdr = vd->load64 + i; ++ if (VADDR_REGION(phdr->p_vaddr) == KERNEL_VMALLOC_REGION) { ++ machdep->machspec->phys_start = phdr->p_paddr; ++ found++; ++ break; ++ } ++ } ++ ++ if (found && CRASHDEBUG(1)) { ++ if (text_start == BADADDR) ++ fprintf(fp, "_text: (unknown) "); ++ else ++ fprintf(fp, "_text: %lx ", text_start); ++ fprintf(fp, "p_vaddr: %lx p_paddr: %lx\n", ++ phdr->p_vaddr, phdr->p_paddr); ++ } ++ ++ return; ++ } ++} ++ ++/* + * From the xen vmcore, create an index of mfns for each page that makes + * up the dom0 kernel's complete phys_to_machine_mapping[max_pfn] array. + */ -+ +static int +ia64_xen_kdump_p2m_create(struct xen_kdump_data *xkd) +{ -+ error(FATAL, "ia64_xen_kdump_p2m_create: TBD\n"); ++ /* ++ * Temporarily read physical (machine) addresses from vmcore by ++ * going directly to read_netdump() instead of via read_kdump(). ++ */ ++ pc->readmem = read_netdump; + -+ /* dummy calls for clean "make [wW]arn" */ -+ ia64_xen_kdump_load_page(0, NULL); -+ ia64_xen_kdump_page_mfn(0); -+ ia64_debug_dump_page(NULL, NULL, NULL); ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "ia64_xen_kdump_p2m_create: p2m_mfn: %lx\n", xkd->p2m_mfn); + -+ return FALSE; ++ if ((xkd->p2m_mfn_frame_list = (ulong *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc p2m_frame_list"); ++ ++ if (!readmem(PTOB(xkd->p2m_mfn), PHYSADDR, xkd->p2m_mfn_frame_list, PAGESIZE(), ++ "xen kdump p2m mfn page", RETURN_ON_ERROR)) ++ error(FATAL, "cannot read xen kdump p2m mfn page\n"); ++ ++ xkd->p2m_frames = PAGESIZE()/sizeof(ulong); ++ ++ pc->readmem = read_kdump; ++ ++ return TRUE; +} + -+static char * -+ia64_xen_kdump_load_page(ulong kvaddr, char *pgbuf) ++physaddr_t ++ia64_xen_kdump_p2m(struct xen_kdump_data *xkd, physaddr_t pseudo) +{ -+ error(FATAL, "ia64_xen_kdump_load_page: TBD\n"); -+ return NULL; -+} ++ ulong pgd_idx, pte_idx; ++ ulong pmd, pte; ++ physaddr_t paddr; + -+static ulong -+ia64_xen_kdump_page_mfn(ulong kvaddr) -+{ -+ error(FATAL, "ia64_xen_kdump_page_mfn: TBD\n"); -+ return 0; ++ /* ++ * Temporarily read physical (machine) addresses from vmcore by ++ * going directly to read_netdump() instead of via read_kdump(). ++ */ ++ pc->readmem = read_netdump; ++ ++ xkd->accesses += 2; ++ ++ pgd_idx = (pseudo >> PGDIR_SHIFT_3L) & (PTRS_PER_PGD - 1); ++ pmd = xkd->p2m_mfn_frame_list[pgd_idx] & _PFN_MASK; ++ if (!pmd) { ++ paddr = P2M_FAILURE; ++ goto out; ++ } ++ ++ pmd += ((pseudo >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) * sizeof(ulong); ++ if (pmd != xkd->last_pmd_read) { ++ if (!readmem(pmd, PHYSADDR, &pte, sizeof(ulong), ++ "ia64_xen_kdump_p2m pmd", RETURN_ON_ERROR)) { ++ xkd->last_pmd_read = BADADDR; ++ xkd->last_mfn_read = BADADDR; ++ paddr = P2M_FAILURE; ++ goto out; ++ } ++ xkd->last_pmd_read = pmd; ++ } else { ++ pte = xkd->last_mfn_read; ++ xkd->cache_hits++; ++ } ++ pte = pte & _PFN_MASK; ++ if (!pte) { ++ paddr = P2M_FAILURE; ++ goto out; ++ } ++ ++ if (pte != xkd->last_mfn_read) { ++ if (!readmem(pte, PHYSADDR, xkd->page, PAGESIZE(), ++ "ia64_xen_kdump_p2m pte page", RETURN_ON_ERROR)) { ++ xkd->last_pmd_read = BADADDR; ++ xkd->last_mfn_read = BADADDR; ++ paddr = P2M_FAILURE; ++ goto out; ++ } ++ xkd->last_mfn_read = pte; ++ } else ++ xkd->cache_hits++; ++ ++ pte_idx = (pseudo >> PAGESHIFT()) & (PTRS_PER_PTE - 1); ++ paddr = *(((ulong *)xkd->page) + pte_idx); ++ if (!(paddr & _PAGE_P)) { ++ paddr = P2M_FAILURE; ++ goto out; ++ } ++ paddr = (paddr & _PFN_MASK) | PAGEOFFSET(pseudo); ++ ++out: ++ pc->readmem = read_kdump; ++ return paddr; +} + +#include "xendump.h" @@ -13578,6 +20194,11 @@ +static int +ia64_xendump_p2m_create(struct xendump_data *xd) +{ ++ if (!symbol_exists("phys_to_machine_mapping")) { ++ xd->flags |= XC_CORE_NO_P2M; ++ return TRUE; ++ } ++ + error(FATAL, "ia64_xendump_p2m_create: TBD\n"); + + /* dummy calls for clean "make [wW]arn" */ @@ -13633,7 +20254,8 @@ +static ulong +ia64_xendump_panic_task(struct xendump_data *xd) +{ -+ error(INFO, "ia64_xendump_panic_task: TBD\n"); ++ if (CRASHDEBUG(1)) ++ error(INFO, "ia64_xendump_panic_task: TBD\n"); + + return NO_TASK; +} @@ -13641,11 +20263,311 @@ +static void +ia64_get_xendump_regs(struct xendump_data *xd, struct bt_info *bt, ulong *rip, ulong *rsp) +{ -+ error(FATAL, "ia64_get_xendump_regs: TBD\n"); ++ machdep->get_stack_frame(bt, rip, rsp); ++ ++ if (is_task_active(bt->task) && ++ !(bt->flags & (BT_TEXT_SYMBOLS_ALL|BT_TEXT_SYMBOLS)) && ++ STREQ(closest_symbol(*rip), "schedule")) ++ error(INFO, ++ "xendump: switch_stack possibly not saved -- try \"bt -t\"\n"); ++} ++ ++/* for XEN Hypervisor analysis */ ++ ++static int ++ia64_is_kvaddr_hyper(ulong addr) ++{ ++ return (addr >= HYPERVISOR_VIRT_START && addr < HYPERVISOR_VIRT_END); ++} ++ ++static int ++ia64_kvtop_hyper(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose) ++{ ++ ulong virt_percpu_start, phys_percpu_start; ++ ulong addr, dirp, entry; ++ ++ if (!IS_KVADDR(kvaddr)) ++ return FALSE; ++ ++ if (PERCPU_VIRT_ADDR(kvaddr)) { ++ virt_percpu_start = symbol_value("__phys_per_cpu_start"); ++ phys_percpu_start = virt_percpu_start - DIRECTMAP_VIRT_START; ++ *paddr = kvaddr - PERCPU_ADDR + phys_percpu_start; ++ return TRUE; ++ } else if (DIRECTMAP_VIRT_ADDR(kvaddr)) { ++ *paddr = kvaddr - DIRECTMAP_VIRT_START; ++ return TRUE; ++ } else if (!FRAME_TABLE_VIRT_ADDR(kvaddr)) { ++ return FALSE; ++ } ++ ++ /* frametable virtual address */ ++ addr = kvaddr - xhmachdep->frame_table; ++ ++ dirp = symbol_value("frametable_pg_dir"); ++ dirp += ((addr >> PGDIR_SHIFT_3L) & (PTRS_PER_PGD - 1)) * sizeof(ulong); ++ readmem(dirp, KVADDR, &entry, sizeof(ulong), ++ "frametable_pg_dir", FAULT_ON_ERROR); ++ ++ dirp = entry & _PFN_MASK; ++ if (!dirp) ++ return FALSE; ++ dirp += ((addr >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) * sizeof(ulong); ++ readmem(dirp, PHYSADDR, &entry, sizeof(ulong), ++ "frametable pmd", FAULT_ON_ERROR); ++ ++ dirp = entry & _PFN_MASK; ++ if (!dirp) ++ return FALSE; ++ dirp += ((addr >> PAGESHIFT()) & (PTRS_PER_PTE - 1)) * sizeof(ulong); ++ readmem(dirp, PHYSADDR, &entry, sizeof(ulong), ++ "frametable pte", FAULT_ON_ERROR); ++ ++ if (!(entry & _PAGE_P)) ++ return FALSE; ++ ++ *paddr = (entry & _PFN_MASK) + (kvaddr & (PAGESIZE() - 1)); ++ return TRUE; ++} ++ ++static void ++ia64_post_init_hyper(void) ++{ ++ struct machine_specific *ms; ++ ulong frame_table; ++ ++ ms = &ia64_machine_specific; ++ ++ if (symbol_exists("unw_init_frame_info")) { ++ machdep->flags |= NEW_UNWIND; ++ if (MEMBER_EXISTS("unw_frame_info", "pt")) { ++ if (MEMBER_EXISTS("cpu_user_regs", "ar_csd")) { ++ machdep->flags |= NEW_UNW_V3; ++ ms->unwind_init = unwind_init_v3; ++ ms->unwind = unwind_v3; ++ ms->unwind_debug = unwind_debug_v3; ++ ms->dump_unwind_stats = dump_unwind_stats_v3; ++ } else { ++ machdep->flags |= NEW_UNW_V2; ++ ms->unwind_init = unwind_init_v2; ++ ms->unwind = unwind_v2; ++ ms->unwind_debug = unwind_debug_v2; ++ ms->dump_unwind_stats = dump_unwind_stats_v2; ++ } ++ } else { ++ machdep->flags |= NEW_UNW_V1; ++ ms->unwind_init = unwind_init_v1; ++ ms->unwind = unwind_v1; ++ ms->unwind_debug = unwind_debug_v1; ++ ms->dump_unwind_stats = dump_unwind_stats_v1; ++ } ++ } else { ++ machdep->flags |= OLD_UNWIND; ++ ms->unwind_init = ia64_old_unwind_init; ++ ms->unwind = ia64_old_unwind; ++ } ++ ms->unwind_init(); ++ ++ if (symbol_exists("frame_table")) { ++ frame_table = symbol_value("frame_table"); ++ readmem(frame_table, KVADDR, &xhmachdep->frame_table, sizeof(ulong), ++ "frame_table virtual address", FAULT_ON_ERROR); ++ } else { ++ error(FATAL, "cannot find frame_table virtual address."); ++ } ++} ++ ++int ++ia64_in_mca_stack_hyper(ulong addr, struct bt_info *bt) ++{ ++ int plen, i; ++ ulong paddr, stackbase, stacktop; ++ ulong *__per_cpu_mca; ++ struct xen_hyper_vcpu_context *vcc; ++ ++ vcc = xen_hyper_vcpu_to_vcpu_context(bt->task); ++ if (!vcc) ++ return 0; ++ ++ if (!symbol_exists("__per_cpu_mca") || ++ !(plen = get_array_length("__per_cpu_mca", NULL, 0)) || ++ (plen < xht->pcpus)) ++ return 0; ++ ++ if (!machdep->kvtop(NULL, addr, &paddr, 0)) ++ return 0; ++ ++ __per_cpu_mca = (ulong *)GETBUF(sizeof(ulong) * xht->pcpus); ++ ++ if (!readmem(symbol_value("__per_cpu_mca"), KVADDR, __per_cpu_mca, ++ sizeof(ulong) * xht->pcpus, "__per_cpu_mca", RETURN_ON_ERROR|QUIET)) ++ return 0; ++ ++ if (CRASHDEBUG(1)) { ++ for (i = 0; i < xht->pcpus; i++) { ++ fprintf(fp, "__per_cpu_mca[%d]: %lx\n", ++ i, __per_cpu_mca[i]); ++ } ++ } ++ ++ stackbase = __per_cpu_mca[vcc->processor]; ++ stacktop = stackbase + (STACKSIZE() * 2); ++ FREEBUF(__per_cpu_mca); ++ ++ if ((paddr >= stackbase) && (paddr < stacktop)) ++ return 1; ++ else ++ return 0; ++} ++ ++static void ++ia64_init_hyper(int when) ++{ ++ struct syment *sp; ++ ++ switch (when) ++ { ++ case SETUP_ENV: ++#if defined(PR_SET_FPEMU) && defined(PR_FPEMU_NOPRINT) ++ prctl(PR_SET_FPEMU, PR_FPEMU_NOPRINT, 0, 0, 0); ++#endif ++#if defined(PR_SET_UNALIGN) && defined(PR_UNALIGN_NOPRINT) ++ prctl(PR_SET_UNALIGN, PR_UNALIGN_NOPRINT, 0, 0, 0); ++#endif ++ break; ++ ++ case PRE_SYMTAB: ++ machdep->verify_symbol = ia64_verify_symbol; ++ machdep->machspec = &ia64_machine_specific; ++ if (pc->flags & KERNEL_DEBUG_QUERY) ++ return; ++ machdep->pagesize = memory_page_size(); ++ machdep->pageshift = ffs(machdep->pagesize) - 1; ++ machdep->pageoffset = machdep->pagesize - 1; ++ machdep->pagemask = ~(machdep->pageoffset); ++ switch (machdep->pagesize) ++ { ++ case 4096: ++ machdep->stacksize = (power(2, 3) * PAGESIZE()); ++ break; ++ case 8192: ++ machdep->stacksize = (power(2, 2) * PAGESIZE()); ++ break; ++ case 16384: ++ machdep->stacksize = (power(2, 1) * PAGESIZE()); ++ break; ++ case 65536: ++ machdep->stacksize = (power(2, 0) * PAGESIZE()); ++ break; ++ default: ++ machdep->stacksize = 32*1024; ++ break; ++ } ++ if ((machdep->pgd = (char *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc pgd space."); ++ if ((machdep->pud = (char *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc pud space."); ++ if ((machdep->pmd = (char *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc pmd space."); ++ if ((machdep->ptbl = (char *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc ptbl space."); ++ machdep->last_pgd_read = 0; ++ machdep->last_pud_read = 0; ++ machdep->last_pmd_read = 0; ++ machdep->last_ptbl_read = 0; ++ machdep->verify_paddr = ia64_verify_paddr; ++ machdep->ptrs_per_pgd = PTRS_PER_PGD; ++ machdep->machspec->phys_start = UNKNOWN_PHYS_START; ++ /* ODA: if need make hyper version ++ if (machdep->cmdline_arg) ++ parse_cmdline_arg(); */ ++ break; ++ ++ case PRE_GDB: ++ ++ if (pc->flags & KERNEL_DEBUG_QUERY) ++ return; ++ ++ machdep->kvbase = HYPERVISOR_VIRT_START; ++ machdep->identity_map_base = HYPERVISOR_VIRT_START; ++ machdep->is_kvaddr = ia64_is_kvaddr_hyper; ++ machdep->is_uvaddr = generic_is_uvaddr; ++ machdep->eframe_search = ia64_eframe_search; ++ machdep->back_trace = ia64_back_trace_cmd; ++ machdep->processor_speed = xen_hyper_ia64_processor_speed; ++ machdep->uvtop = ia64_uvtop; ++ machdep->kvtop = ia64_kvtop_hyper; ++ machdep->get_stack_frame = ia64_get_stack_frame; ++ machdep->get_stackbase = ia64_get_stackbase; ++ machdep->get_stacktop = ia64_get_stacktop; ++ machdep->translate_pte = ia64_translate_pte; ++ machdep->memory_size = xen_hyper_ia64_memory_size; ++ machdep->dis_filter = ia64_dis_filter; ++ machdep->cmd_mach = ia64_cmd_mach; ++ machdep->get_smp_cpus = xen_hyper_ia64_get_smp_cpus; ++ machdep->line_number_hooks = ia64_line_number_hooks; ++ machdep->value_to_symbol = generic_machdep_value_to_symbol; ++ machdep->init_kernel_pgd = NULL; ++ ++ if ((sp = symbol_search("_stext"))) { ++ machdep->machspec->kernel_region = ++ VADDR_REGION(sp->value); ++ machdep->machspec->kernel_start = sp->value; ++ } else { ++// machdep->machspec->kernel_region = KERNEL_CACHED_REGION; ++// machdep->machspec->kernel_start = KERNEL_CACHED_BASE; ++ } ++ ++ /* machdep table for Xen Hypervisor */ ++ xhmachdep->pcpu_init = xen_hyper_ia64_pcpu_init; ++ break; ++ ++ case POST_GDB: ++ STRUCT_SIZE_INIT(switch_stack, "switch_stack"); ++ MEMBER_OFFSET_INIT(thread_struct_fph, "thread_struct", "fph"); ++ MEMBER_OFFSET_INIT(switch_stack_b0, "switch_stack", "b0"); ++ MEMBER_OFFSET_INIT(switch_stack_ar_bspstore, ++ "switch_stack", "ar_bspstore"); ++ MEMBER_OFFSET_INIT(switch_stack_ar_pfs, ++ "switch_stack", "ar_pfs"); ++ MEMBER_OFFSET_INIT(switch_stack_ar_rnat, ++ "switch_stack", "ar_rnat"); ++ MEMBER_OFFSET_INIT(switch_stack_pr, ++ "switch_stack", "pr"); ++ ++ XEN_HYPER_STRUCT_SIZE_INIT(cpuinfo_ia64, "cpuinfo_ia64"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(cpuinfo_ia64_proc_freq, "cpuinfo_ia64", "proc_freq"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(cpuinfo_ia64_vendor, "cpuinfo_ia64", "vendor"); ++ if (symbol_exists("per_cpu__cpu_info")) { ++ xht->cpu_data_address = symbol_value("per_cpu__cpu_info"); ++ } ++ /* kakuma Can this be calculated? */ ++ if (!machdep->hz) { ++ machdep->hz = XEN_HYPER_HZ; ++ } ++ break; ++ ++ case POST_INIT: ++ ia64_post_init_hyper(); ++ break; ++ } +} #endif ---- crash/s390.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/s390.c 2006-08-15 09:34:21.000000000 -0400 +--- crash/s390.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/s390.c 2007-04-25 08:58:52.000000000 -0400 +@@ -1,9 +1,9 @@ + /* s390.c - core analysis suite + * + * Copyright (C) 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. +- * Copyright (C) 2005 Michael Holzheu, IBM Corporation ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2005, 2006 Michael Holzheu, IBM Corporation + * + * 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 @@ -86,7 +86,6 @@ static ulong s390_processor_speed(void); static int s390_eframe_search(struct bt_info *); @@ -13720,16 +20642,37 @@ s390_cpu_of_task(unsigned long task) { int cpu; -@@ -551,7 +536,7 @@ +@@ -551,12 +536,13 @@ return FALSE; } else { /* Linux 2.6 */ - unsigned long runqueue_addr, runqueue_offset, per_cpu_offset; + unsigned long runqueue_addr, runqueue_offset; unsigned long cpu_offset, per_cpu_offset_addr, running_task; - char runqueue[4096]; +- char runqueue[4096]; ++ char *runqueue; int cpu; -@@ -700,7 +685,7 @@ + + cpu = s390_cpu_of_task(task); ++ runqueue = GETBUF(SIZE(runqueue)); + + runqueue_offset=symbol_value("per_cpu__runqueues"); + per_cpu_offset_addr=symbol_value("__per_cpu_offset"); +@@ -564,10 +550,10 @@ + &cpu_offset, sizeof(long),"per_cpu_offset", + FAULT_ON_ERROR); + runqueue_addr=runqueue_offset + cpu_offset; +- readmem(runqueue_addr,KVADDR,&runqueue,sizeof(runqueue), ++ readmem(runqueue_addr,KVADDR,runqueue,SIZE(runqueue), + "runqueue", FAULT_ON_ERROR); +- running_task = *((unsigned long*)&runqueue[MEMBER_OFFSET( +- "runqueue", "curr")]); ++ running_task = ULONG(runqueue + OFFSET(runqueue_curr)); ++ FREEBUF(runqueue); + if(running_task == task) + return TRUE; + else +@@ -700,7 +686,7 @@ } else if(skip_first_frame){ skip_first_frame=0; } else { @@ -13738,7 +20681,7 @@ fprintf(fp,"%s at %x\n", closest_symbol(r14), r14); if (bt->flags & BT_LINE_NUMBERS) s390_dump_line_number(r14); -@@ -716,13 +701,15 @@ +@@ -716,13 +702,15 @@ frame_size = stack_base - old_backchain + KERNEL_STACK_SIZE; } else { @@ -13757,7 +20700,7 @@ stack_base + j])); } fprintf(fp,"\n\n"); -@@ -771,10 +758,10 @@ +@@ -771,10 +759,10 @@ return; } fprintf(fp," LOWCORE INFO:\n"); @@ -13770,7 +20713,7 @@ closest_symbol(tmp[1] & S390_ADDR_MASK), tmp[1] & S390_ADDR_MASK); if (bt->flags & BT_LINE_NUMBERS) -@@ -783,12 +770,12 @@ +@@ -783,12 +771,12 @@ ptr = lc + MEMBER_OFFSET("_lowcore","cpu_timer_save_area"); tmp[0]=UINT(ptr); tmp[1]=UINT(ptr + S390_WORD_SIZE); @@ -13785,7 +20728,7 @@ fprintf(fp," -general registers:\n"); ptr = lc + MEMBER_OFFSET("_lowcore","gpregs_save_area"); -@@ -796,25 +783,25 @@ +@@ -796,25 +784,25 @@ tmp[1]=ULONG(ptr + S390_WORD_SIZE); tmp[2]=ULONG(ptr + 2 * S390_WORD_SIZE); tmp[3]=ULONG(ptr + 3 * S390_WORD_SIZE); @@ -13815,7 +20758,7 @@ tmp[0], tmp[1], tmp[2], tmp[3]); fprintf(fp," -access registers:\n"); -@@ -823,25 +810,25 @@ +@@ -823,25 +811,25 @@ tmp[1]=ULONG(ptr + S390_WORD_SIZE); tmp[2]=ULONG(ptr + 2 * S390_WORD_SIZE); tmp[3]=ULONG(ptr + 3 * S390_WORD_SIZE); @@ -13845,7 +20788,7 @@ tmp[0], tmp[1], tmp[2], tmp[3]); fprintf(fp," -control registers:\n"); -@@ -850,26 +837,26 @@ +@@ -850,26 +838,26 @@ tmp[1]=ULONG(ptr + S390_WORD_SIZE); tmp[2]=ULONG(ptr + 2 * S390_WORD_SIZE); tmp[3]=ULONG(ptr + 3 * S390_WORD_SIZE); @@ -13876,7 +20819,7 @@ tmp[0], tmp[1], tmp[2], tmp[3]); ptr = lc + MEMBER_OFFSET("_lowcore","floating_pt_save_area"); -@@ -878,8 +865,8 @@ +@@ -878,8 +866,8 @@ tmp[1]=ULONG(ptr + 2 * S390_WORD_SIZE); tmp[2]=ULONG(ptr + 4 * S390_WORD_SIZE); tmp[3]=ULONG(ptr + 6 * S390_WORD_SIZE); @@ -13887,8 +20830,21 @@ } /* ---- crash/s390x.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/s390x.c 2006-08-15 09:34:21.000000000 -0400 +--- crash/s390x.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/s390x.c 2007-04-25 08:58:52.000000000 -0400 +@@ -1,9 +1,9 @@ + /* s390.c - core analysis suite + * + * Copyright (C) 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. +- * Copyright (C) 2005 Michael Holzheu, IBM Corporation ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2005, 2006 Michael Holzheu, IBM Corporation + * + * 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 @@ -173,7 +173,8 @@ machdep->nr_irqs = 0; /* TBD */ machdep->vmalloc_start = s390x_vmalloc_start; @@ -13965,16 +20921,37 @@ s390x_cpu_of_task(unsigned long task) { unsigned int cpu; -@@ -583,7 +570,7 @@ +@@ -583,12 +570,13 @@ return FALSE; } else { /* Linux 2.6 */ - unsigned long runqueue_addr, runqueue_offset, per_cpu_offset; + unsigned long runqueue_addr, runqueue_offset; unsigned long cpu_offset, per_cpu_offset_addr, running_task; - char runqueue[4096]; +- char runqueue[4096]; ++ char *runqueue; int cpu; -@@ -733,7 +720,7 @@ + + cpu = s390x_cpu_of_task(task); ++ runqueue = GETBUF(SIZE(runqueue)); + + runqueue_offset=symbol_value("per_cpu__runqueues"); + per_cpu_offset_addr=symbol_value("__per_cpu_offset"); +@@ -596,10 +584,10 @@ + &cpu_offset, sizeof(long),"per_cpu_offset", + FAULT_ON_ERROR); + runqueue_addr=runqueue_offset + cpu_offset; +- readmem(runqueue_addr,KVADDR,&runqueue,sizeof(runqueue), ++ readmem(runqueue_addr,KVADDR,runqueue,SIZE(runqueue), + "runqueue", FAULT_ON_ERROR); +- running_task = *((unsigned long*)&runqueue[MEMBER_OFFSET( +- "runqueue", "curr")]); ++ running_task = ULONG(runqueue + OFFSET(runqueue_curr)); ++ FREEBUF(runqueue); + if(running_task == task) + return TRUE; + else +@@ -733,7 +721,7 @@ } else if(skip_first_frame){ skip_first_frame=0; } else { @@ -13983,7 +20960,15 @@ fprintf(fp,"%s at %x\n", closest_symbol(r14), r14); if (bt->flags & BT_LINE_NUMBERS) s390x_dump_line_number(r14); -@@ -749,13 +736,15 @@ +@@ -743,22 +731,25 @@ + backchain = ULONG(&stack[backchain - stack_base + bc_offset]); + + /* print stack content if -f is specified */ +- if((bt->flags & BT_FULL) && !BT_REFERENCE_CHECK(bt)){ ++ if ((bt->flags & BT_FULL) && !BT_REFERENCE_CHECK(bt)) { + int frame_size; +- if(backchain == 0){ ++ if (backchain == 0) { frame_size = stack_base - old_backchain + KERNEL_STACK_SIZE; } else { @@ -13992,17 +20977,24 @@ + (stack_base - old_backchain + + KERNEL_STACK_SIZE)); } - for(j=0; j< frame_size; j+=4){ +- for(j=0; j< frame_size; j+=4){ ++ for (j = 0; j < frame_size; j += 8) { if(j % 16 == 0){ - fprintf(fp,"\n%08x: ",old_backchain+j); -+ fprintf(fp,"\n%08lx: ",old_backchain+j); ++ fprintf(fp, "%s %016lx: ", ++ j ? "\n" : "", old_backchain + j); } - fprintf(fp," %08x",ULONG(&stack[old_backchain - -+ fprintf(fp," %08lx",ULONG(&stack[old_backchain - - stack_base + j])); +- stack_base + j])); ++ fprintf(fp," %016lx", ++ ULONG(&stack[old_backchain - stack_base + j])); } - fprintf(fp,"\n\n"); -@@ -804,26 +793,26 @@ +- fprintf(fp,"\n\n"); ++ fprintf(fp, "\n"); + } + + /* Check for interrupt stackframe */ +@@ -804,26 +795,26 @@ return; } fprintf(fp," LOWCORE INFO:\n"); @@ -14034,7 +21026,7 @@ fprintf(fp," -general registers:\n"); ptr = lc + MEMBER_OFFSET("_lowcore","gpregs_save_area"); -@@ -831,26 +820,26 @@ +@@ -831,26 +822,26 @@ tmp[1]=ULONG(ptr + S390X_WORD_SIZE); tmp[2]=ULONG(ptr + 2 * S390X_WORD_SIZE); tmp[3]=ULONG(ptr + 3 * S390X_WORD_SIZE); @@ -14069,7 +21061,7 @@ fprintf(fp," -access registers:\n"); ptr = lc + MEMBER_OFFSET("_lowcore","access_regs_save_area"); -@@ -858,25 +847,25 @@ +@@ -858,25 +849,25 @@ tmp[1]=ULONG(ptr + 4); tmp[2]=ULONG(ptr + 2 * 4); tmp[3]=ULONG(ptr + 3 * 4); @@ -14099,7 +21091,7 @@ tmp[0], tmp[1], tmp[2], tmp[3]); fprintf(fp," -control registers:\n"); -@@ -885,26 +874,26 @@ +@@ -885,26 +876,26 @@ tmp[1]=ULONG(ptr + S390X_WORD_SIZE); tmp[2]=ULONG(ptr + 2 * S390X_WORD_SIZE); tmp[3]=ULONG(ptr + 3 * S390X_WORD_SIZE); @@ -14134,7 +21126,7 @@ ptr = lc + MEMBER_OFFSET("_lowcore","floating_pt_save_area"); fprintf(fp," -floating point registers 0,2,4,6:\n"); -@@ -912,26 +901,26 @@ +@@ -912,26 +903,26 @@ tmp[1]=ULONG(ptr + S390X_WORD_SIZE); tmp[2]=ULONG(ptr + 2 * S390X_WORD_SIZE); tmp[3]=ULONG(ptr + 3 * S390X_WORD_SIZE); @@ -14169,7 +21161,7 @@ } /* ---- crash/s390dbf.c.orig 2006-09-13 11:10:22.000000000 -0400 +--- crash/s390dbf.c.orig 2007-08-27 15:02:36.000000000 -0400 +++ crash/s390dbf.c 2006-08-14 13:58:56.000000000 -0400 @@ -0,0 +1,1340 @@ +/* @@ -15512,8 +22504,20 @@ + +#endif + ---- crash/ppc64.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/ppc64.c 2006-08-02 10:34:16.000000000 -0400 +--- crash/ppc64.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/ppc64.c 2006-10-11 09:14:35.000000000 -0400 +@@ -1,8 +1,8 @@ + /* ppc64.c -- core analysis suite + * +- * Copyright (C) 2004, 2005 David Anderson +- * Copyright (C) 2004, 2005 Red Hat, Inc. All rights reserved. +- * Copyright (C) 2004 Haren Myneni, IBM Corporation ++ * Copyright (C) 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2004, 2005, 2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2004, 2006 Haren Myneni, IBM Corporation + * + * 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 @@ -47,6 +47,9 @@ static char * ppc64_check_eframe(struct ppc64_pt_regs *); static void ppc64_print_eframe(char *, struct ppc64_pt_regs *, @@ -15524,26 +22528,71 @@ struct machine_specific ppc64_machine_specific = { { 0 }, 0, 0 }; -@@ -75,12 +78,18 @@ - error(FATAL, "cannot malloc pmd space."); - if ((machdep->ptbl = (char *)malloc(PAGESIZE())) == NULL) - error(FATAL, "cannot malloc ptbl space."); -+ if ((machdep->machspec->level4 = (char *)malloc(PAGESIZE())) == NULL) -+ error(FATAL, "cannot malloc level4 space."); - machdep->last_pgd_read = 0; - machdep->last_pmd_read = 0; - machdep->last_ptbl_read = 0; +@@ -64,26 +67,53 @@ + machdep->verify_symbol = ppc64_verify_symbol; + if (pc->flags & KERNEL_DEBUG_QUERY) + return; +- machdep->pagesize = memory_page_size(); ++ machdep->stacksize = PPC64_STACK_SIZE; ++ machdep->last_pgd_read = 0; ++ machdep->last_pmd_read = 0; ++ machdep->last_ptbl_read = 0; + machdep->machspec->last_level4_read = 0; - machdep->verify_paddr = generic_verify_paddr; - machdep->ptrs_per_pgd = PTRS_PER_PGD; - machdep->flags |= MACHDEP_BT_TEXT; ++ machdep->verify_paddr = generic_verify_paddr; ++ machdep->ptrs_per_pgd = PTRS_PER_PGD; ++ machdep->flags |= MACHDEP_BT_TEXT; + if (machdep->cmdline_arg) + parse_cmdline_arg(); + machdep->clear_machdep_cache = ppc64_clear_machdep_cache; - break; ++ break; ++ ++ case PRE_GDB: ++ /* ++ * Recently there were changes made to kexec tools ++ * to support 64K page size. With those changes ++ * vmcore file obtained from a kernel which supports ++ * 64K page size cannot be analyzed using crash on a ++ * machine running with kernel supporting 4K page size ++ * ++ * The following modifications are required in crash ++ * tool to be in sync with kexec tools. ++ * ++ * Look if the following symbol exists. If yes then ++ * the dump was taken with a kernel supporting 64k ++ * page size. So change the page size accordingly. ++ * ++ * Also moved the following code block from ++ * PRE_SYMTAB case here. ++ */ ++ if (symbol_exists("__hash_page_64K")) ++ machdep->pagesize = PPC64_64K_PAGE_SIZE; ++ else ++ machdep->pagesize = memory_page_size(); + machdep->pageshift = ffs(machdep->pagesize) - 1; + machdep->pageoffset = machdep->pagesize - 1; + machdep->pagemask = ~((ulonglong)machdep->pageoffset); +- machdep->stacksize = 4 * machdep->pagesize; + if ((machdep->pgd = (char *)malloc(PAGESIZE())) == NULL) + error(FATAL, "cannot malloc pgd space."); + if ((machdep->pmd = (char *)malloc(PAGESIZE())) == NULL) + error(FATAL, "cannot malloc pmd space."); + if ((machdep->ptbl = (char *)malloc(PAGESIZE())) == NULL) + error(FATAL, "cannot malloc ptbl space."); +- machdep->last_pgd_read = 0; +- machdep->last_pmd_read = 0; +- machdep->last_ptbl_read = 0; +- machdep->verify_paddr = generic_verify_paddr; +- machdep->ptrs_per_pgd = PTRS_PER_PGD; +- machdep->flags |= MACHDEP_BT_TEXT; +- break; ++ if ((machdep->machspec->level4 = (char *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc level4 space."); - case PRE_GDB: -@@ -109,6 +118,56 @@ +- case PRE_GDB: + machdep->kvbase = symbol_value("_stext"); + machdep->identity_map_base = machdep->kvbase; + machdep->is_kvaddr = generic_is_kvaddr; +@@ -109,6 +139,56 @@ break; case POST_GDB: @@ -15600,7 +22649,7 @@ machdep->vmalloc_start = ppc64_vmalloc_start; MEMBER_OFFSET_INIT(thread_struct_pg_tables, "thread_struct", "pg_tables"); -@@ -178,9 +237,11 @@ +@@ -178,9 +258,11 @@ */ BZERO(&machdep->machspec->hwintrstack, NR_CPUS*sizeof(ulong)); @@ -15615,7 +22664,7 @@ /* * IRQ stacks are introduced in 2.6 and also configurable. */ -@@ -229,10 +290,12 @@ +@@ -229,10 +311,12 @@ fprintf(fp, " flags: %lx (", machdep->flags); if (machdep->flags & KSYMS_START) fprintf(fp, "%sKSYMS_START", others++ ? "|" : ""); @@ -15630,7 +22679,7 @@ fprintf(fp, ")\n"); fprintf(fp, " kvbase: %lx\n", machdep->kvbase); -@@ -269,15 +332,25 @@ +@@ -269,15 +353,25 @@ fprintf(fp, " is_kvaddr: generic_is_kvaddr()\n"); fprintf(fp, " is_uvaddr: generic_is_uvaddr()\n"); fprintf(fp, " verify_paddr: generic_verify_paddr()\n"); @@ -15656,7 +22705,7 @@ } /* -@@ -342,7 +415,7 @@ +@@ -342,7 +436,7 @@ if (!(pte & _PAGE_PRESENT)) { if (pte && verbose) { fprintf(fp, "\n"); @@ -15665,7 +22714,7 @@ } return FALSE; } -@@ -354,7 +427,90 @@ +@@ -354,7 +448,90 @@ if (verbose) { fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(*paddr)); @@ -15757,7 +22806,7 @@ } return TRUE; -@@ -411,7 +567,10 @@ +@@ -411,7 +588,10 @@ FAULT_ON_ERROR); } @@ -15769,7 +22818,7 @@ } /* -@@ -436,7 +595,10 @@ +@@ -436,7 +616,10 @@ return TRUE; } @@ -15781,7 +22830,7 @@ } /* -@@ -657,7 +819,7 @@ +@@ -657,7 +840,7 @@ * If a physaddr pointer is passed in, don't print anything. */ static int @@ -15790,7 +22839,7 @@ { int c, len1, len2, len3, others, page_present; char buf[BUFSIZE]; -@@ -668,7 +830,7 @@ +@@ -668,7 +851,7 @@ char *arglist[MAXARGS]; ulong paddr; @@ -15799,7 +22848,7 @@ page_present = (pte & _PAGE_PRESENT); if (physaddr) { -@@ -1034,8 +1196,12 @@ +@@ -1034,8 +1217,12 @@ ms->hwstacksize + STACK_FRAME_OVERHEAD; bt->stackbuf = ms->hwstackbuf; alter_stackbuf(bt); @@ -15814,7 +22863,7 @@ } -@@ -1270,20 +1436,11 @@ +@@ -1270,20 +1457,11 @@ return NULL; } @@ -15836,7 +22885,7 @@ /* print out the gprs... */ for(i=0; i<32; i++) { if(!(i % 3)) -@@ -1315,9 +1472,78 @@ +@@ -1315,9 +1493,78 @@ fprintf(fp, "DAR: %016lx\n", regs->dar); fprintf(fp, " DSISR: %016lx ", regs->dsisr); fprintf(fp, " Syscall Result: %016lx\n", regs->result); @@ -15915,7 +22964,7 @@ /* * Get the starting point for the active cpus in a diskdump/netdump. -@@ -1335,12 +1561,18 @@ +@@ -1335,12 +1582,18 @@ ulong ur_ksp = 0; int check_hardirq, check_softirq; int check_intrstack = TRUE; @@ -15935,7 +22984,7 @@ panic_task = tt->panic_task == bt->task ? TRUE : FALSE; -@@ -1424,6 +1656,7 @@ +@@ -1424,6 +1677,7 @@ if (STREQ(sym, ".netconsole_netdump") || STREQ(sym, ".netpoll_start_netdump") || STREQ(sym, ".start_disk_dump") || @@ -15943,7 +22992,7 @@ STREQ(sym, ".disk_dump")) { *nip = *up; *ksp = bt->stackbase + -@@ -2000,4 +2233,145 @@ +@@ -2000,4 +2254,145 @@ ppc64_dump_line_number(0); } @@ -16089,9 +23138,24 @@ + machdep->machspec->last_level4_read = 0; +} #endif /* PPC64 */ ---- crash/x86_64.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/x86_64.c 2006-08-31 16:02:02.000000000 -0400 -@@ -18,7 +18,10 @@ +--- crash/x86_64.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/x86_64.c 2007-08-23 17:02:54.000000000 -0400 +@@ -1,7 +1,7 @@ + /* x86_64.c -- core analysis suite + * +- * Copyright (C) 2004, 2005 David Anderson +- * Copyright (C) 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2004, 2005, 2006, 2007 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 +@@ -14,11 +14,16 @@ + * GNU General Public License for more details. + */ + #include "defs.h" ++#include "xen_hyper_defs.h" + #ifdef X86_64 static int x86_64_kvtop(struct task_context *, ulong, physaddr_t *, int); @@ -16099,10 +23163,11 @@ static int x86_64_uvtop(struct task_context *, ulong, physaddr_t *, int); +static int x86_64_uvtop_level4(struct task_context *, ulong, physaddr_t *, int); +static int x86_64_uvtop_level4_xen_wpt(struct task_context *, ulong, physaddr_t *, int); ++static int x86_64_uvtop_level4_rhel4_xen_wpt(struct task_context *, ulong, physaddr_t *, int); static ulong x86_64_vmalloc_start(void); static int x86_64_is_task_addr(ulong); static int x86_64_verify_symbol(const char *, ulong, char); -@@ -32,6 +35,7 @@ +@@ -32,14 +37,17 @@ #define EFRAME_VERIFY (0x2) #define EFRAME_CS (0x4) #define EFRAME_SEARCH (0x8) @@ -16110,7 +23175,17 @@ static void x86_64_back_trace_cmd(struct bt_info *); static ulong x86_64_in_exception_stack(struct bt_info *); static ulong x86_64_in_irqstack(struct bt_info *); -@@ -56,6 +60,8 @@ + static void x86_64_low_budget_back_trace_cmd(struct bt_info *); ++static void x86_64_dwarf_back_trace_cmd(struct bt_info *); + static void x86_64_get_dumpfile_stack_frame(struct bt_info *, ulong *, ulong *); + static struct syment *x86_64_function_called_by(ulong); + static int is_direct_call_target(struct bt_info *); + static void get_x86_64_frame(struct bt_info *, ulong *, ulong *); ++static ulong text_lock_function(char *, struct bt_info *, ulong); + static int x86_64_print_stack_entry(struct bt_info *, FILE *, int, int, ulong); + static void x86_64_display_full_frame(struct bt_info *, ulong, FILE *); + static void x86_64_do_bt_reference_check(struct bt_info *, ulong,char *); +@@ -56,6 +64,8 @@ static void x86_64_display_memmap(void); static void x86_64_dump_line_number(ulong); static struct line_number_hook x86_64_line_number_hooks[]; @@ -16119,13 +23194,14 @@ static int x86_64_is_kvaddr(ulong); static int x86_64_is_uvaddr(ulong, struct task_context *); void x86_64_compiler_warning_stub(void); -@@ -63,7 +69,17 @@ +@@ -63,7 +73,25 @@ static void x86_64_cpu_pda_init(void); static void x86_64_ist_init(void); static void x86_64_post_init(void); - +static void parse_cmdline_arg(void); +static void x86_64_clear_machdep_cache(void); ++static void x86_64_irq_eframe_link_init(void); +static int x86_64_xendump_p2m_create(struct xendump_data *); +static char *x86_64_xendump_load_page(ulong, struct xendump_data *); +static int x86_64_xendump_page_index(ulong, struct xendump_data *); @@ -16135,10 +23211,29 @@ +static void x86_64_debug_dump_page(FILE *, char *, char *); +static void x86_64_get_xendump_regs(struct xendump_data *, struct bt_info *, ulong *, ulong *); +static ulong x86_64_xendump_panic_task(struct xendump_data *); ++static void x86_64_init_hyper(int); ++static ulong x86_64_get_stackbase_hyper(ulong); ++static ulong x86_64_get_stacktop_hyper(ulong); ++static int x86_64_framesize_cache_resize(void); ++static int x86_64_framesize_cache_func(int, ulong, int *); ++static int x86_64_get_framesize(struct bt_info *, ulong); ++static void x86_64_framesize_debug(struct bt_info *); struct machine_specific x86_64_machine_specific = { 0 }; -@@ -86,6 +102,8 @@ +@@ -74,6 +102,11 @@ + void + x86_64_init(int when) + { ++ if (XEN_HYPER_MODE()) { ++ x86_64_init_hyper(when); ++ return; ++ } ++ + switch (when) + { + case PRE_SYMTAB: +@@ -86,6 +119,8 @@ machdep->pageoffset = machdep->pagesize - 1; machdep->pagemask = ~((ulonglong)machdep->pageoffset); machdep->stacksize = machdep->pagesize * 2; @@ -16147,7 +23242,7 @@ if ((machdep->pgd = (char *)malloc(PAGESIZE())) == NULL) error(FATAL, "cannot malloc pgd space."); if ((machdep->pmd = (char *)malloc(PAGESIZE())) == NULL) -@@ -93,17 +111,69 @@ +@@ -93,17 +128,85 @@ if ((machdep->ptbl = (char *)malloc(PAGESIZE())) == NULL) error(FATAL, "cannot malloc ptbl space."); if ((machdep->machspec->pml4 = @@ -16162,21 +23257,27 @@ machdep->verify_paddr = generic_verify_paddr; machdep->ptrs_per_pgd = PTRS_PER_PGD; machdep->flags |= MACHDEP_BT_TEXT; ++ machdep->flags |= FRAMESIZE_DEBUG; ++ machdep->machspec->irq_eframe_link = UNINITIALIZED; + if (machdep->cmdline_arg) + parse_cmdline_arg(); break; case PRE_GDB: -+ if (!(machdep->flags & (VM_ORIG|VM_2_6_11|VM_XEN))) { -+ if (symbol_exists("boot_vmalloc_pgt")) ++ if (!(machdep->flags & VM_FLAGS)) { ++ if (symbol_exists("xen_start_info")) { ++ if (symbol_exists("low_pml4") && ++ symbol_exists("swap_low_mappings")) ++ machdep->flags |= VM_XEN_RHEL4; ++ else ++ machdep->flags |= VM_XEN; ++ } else if (symbol_exists("boot_vmalloc_pgt")) + machdep->flags |= VM_ORIG; -+ else if (symbol_exists("xen_start_info")) -+ machdep->flags |= VM_XEN; + else + machdep->flags |= VM_2_6_11; + } + -+ switch (machdep->flags & (VM_ORIG|VM_2_6_11|VM_XEN)) ++ switch (machdep->flags & VM_FLAGS) + { + case VM_ORIG: + /* pre-2.6.11 layout */ @@ -16214,11 +23315,21 @@ + machdep->machspec->modules_vaddr = MODULES_VADDR_XEN; + machdep->machspec->modules_end = MODULES_END_XEN; + break; ++ ++ case VM_XEN_RHEL4: ++ /* RHEL4 Xen layout */ ++ machdep->machspec->userspace_top = USERSPACE_TOP_XEN_RHEL4; ++ machdep->machspec->page_offset = PAGE_OFFSET_XEN_RHEL4; ++ machdep->machspec->vmalloc_start_addr = VMALLOC_START_ADDR_XEN_RHEL4; ++ machdep->machspec->vmalloc_end = VMALLOC_END_XEN_RHEL4; ++ machdep->machspec->modules_vaddr = MODULES_VADDR_XEN_RHEL4; ++ machdep->machspec->modules_end = MODULES_END_XEN_RHEL4; ++ break; + } machdep->kvbase = (ulong)PAGE_OFFSET; machdep->identity_map_base = (ulong)PAGE_OFFSET; machdep->is_kvaddr = x86_64_is_kvaddr; -@@ -111,7 +181,6 @@ +@@ -111,7 +214,6 @@ machdep->eframe_search = x86_64_eframe_search; machdep->back_trace = x86_64_low_budget_back_trace_cmd; machdep->processor_speed = x86_64_processor_speed; @@ -16226,7 +23337,7 @@ machdep->kvtop = x86_64_kvtop; machdep->get_task_pgd = x86_64_get_task_pgd; machdep->get_stack_frame = x86_64_get_stack_frame; -@@ -126,6 +195,12 @@ +@@ -126,6 +228,12 @@ machdep->line_number_hooks = x86_64_line_number_hooks; machdep->value_to_symbol = generic_machdep_value_to_symbol; machdep->init_kernel_pgd = x86_64_init_kernel_pgd; @@ -16239,8 +23350,24 @@ break; case POST_GDB: -@@ -165,9 +240,25 @@ - machdep->nr_irqs = 224; /* NR_IRQS (at least) */ +@@ -158,16 +266,49 @@ + if ((machdep->machspec->irqstack = (char *) + malloc(machdep->machspec->stkinfo.isize)) == NULL) + error(FATAL, "cannot malloc irqstack space."); +- if (symbol_exists("irq_desc")) +- ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc, +- "irq_desc", NULL, 0); +- else +- machdep->nr_irqs = 224; /* NR_IRQS (at least) */ ++ if (symbol_exists("irq_desc")) { ++ if (LKCD_KERNTYPES()) ++ ARRAY_LENGTH_INIT_ALT(machdep->nr_irqs, ++ "irq_desc", "kernel_stat.irqs", NULL, 0); ++ else ++ ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc, ++ "irq_desc", NULL, 0); ++ } else ++ machdep->nr_irqs = 224; /* NR_IRQS (at least) */ machdep->vmalloc_start = x86_64_vmalloc_start; machdep->dump_irq = x86_64_dump_irq; - machdep->hz = HZ; @@ -16254,9 +23381,17 @@ + machdep->section_size_bits = _SECTION_SIZE_BITS; + machdep->max_physmem_bits = _MAX_PHYSMEM_BITS; + if (XEN()) { -+ if (kt->xen_flags & WRITABLE_PAGE_TABLES) -+ machdep->uvtop = x86_64_uvtop_level4_xen_wpt; -+ else ++ if (kt->xen_flags & WRITABLE_PAGE_TABLES) { ++ switch (machdep->flags & VM_FLAGS) ++ { ++ case VM_XEN: ++ machdep->uvtop = x86_64_uvtop_level4_xen_wpt; ++ break; ++ case VM_XEN_RHEL4: ++ machdep->uvtop = x86_64_uvtop_level4_rhel4_xen_wpt; ++ break; ++ } ++ } else + machdep->uvtop = x86_64_uvtop_level4; + MEMBER_OFFSET_INIT(vcpu_guest_context_user_regs, + "vcpu_guest_context", "user_regs"); @@ -16265,10 +23400,15 @@ + ASSIGN_OFFSET(cpu_user_regs_rip) = + MEMBER_OFFSET("cpu_user_regs", "cs") - sizeof(ulong); + } ++ x86_64_irq_eframe_link_init(); ++ break; ++ ++ case POST_VM: ++ init_unwind_table(); break; case POST_INIT: -@@ -191,10 +282,20 @@ +@@ -191,10 +332,24 @@ fprintf(fp, "%sKSYMS_START", others++ ? "|" : ""); if (machdep->flags & PT_REGS_INIT) fprintf(fp, "%sPT_REGS_INIT", others++ ? "|" : ""); @@ -16282,32 +23422,56 @@ + fprintf(fp, "%sVM_2_6_11", others++ ? "|" : ""); + if (machdep->flags & VM_XEN) + fprintf(fp, "%sVM_XEN", others++ ? "|" : ""); ++ if (machdep->flags & VM_XEN_RHEL4) ++ fprintf(fp, "%sVM_XEN_RHEL4", others++ ? "|" : ""); + if (machdep->flags & NO_TSS) + fprintf(fp, "%sNO_TSS", others++ ? "|" : ""); + if (machdep->flags & SCHED_TEXT) + fprintf(fp, "%sSCHED_TEXT", others++ ? "|" : ""); + if (machdep->flags & PHYS_BASE) + fprintf(fp, "%sPHYS_BASE", others++ ? "|" : ""); ++ if (machdep->flags & FRAMESIZE_DEBUG) ++ fprintf(fp, "%sFRAMESIZE_DEBUG", others++ ? "|" : ""); fprintf(fp, ")\n"); fprintf(fp, " kvbase: %lx\n", machdep->kvbase); -@@ -220,7 +321,14 @@ +@@ -215,13 +370,32 @@ + fprintf(fp, " back_trace: x86_64_back_trace_cmd()\n"); + else if (machdep->back_trace == x86_64_low_budget_back_trace_cmd) + fprintf(fp, +- " back_trace: x86_64_low_budget_back_trace_cmd()\n"); ++ " back_trace: x86_64_low_budget_back_trace_cmd() %s\n", ++ kt->flags & DWARF_UNWIND ? ++ "-> x86_64_dwarf_back_trace_cmd()" : ""); ++ else if (machdep->back_trace == x86_64_dwarf_back_trace_cmd) ++ fprintf(fp, ++ " back_trace: x86_64_dwarf_back_trace_cmd() %s\n", ++ kt->flags & DWARF_UNWIND ? ++ "" : "->x86_64_low_budget_back_trace_cmd()"); + else fprintf(fp, " back_trace: %lx\n", (ulong)machdep->back_trace); fprintf(fp, " processor_speed: x86_64_processor_speed()\n"); - fprintf(fp, " uvtop: x86_64_uvtop()\n"); +- fprintf(fp, " kvtop: x86_64_kvtop()\n"); + if (machdep->uvtop == x86_64_uvtop) + fprintf(fp, " uvtop: x86_64_uvtop()\n"); + else if (machdep->uvtop == x86_64_uvtop_level4) + fprintf(fp, " uvtop: x86_64_uvtop_level4()\n"); + else if (machdep->uvtop == x86_64_uvtop_level4_xen_wpt) + fprintf(fp, " uvtop: x86_64_uvtop_level4_xen_wpt()\n"); ++ else if (machdep->uvtop == x86_64_uvtop_level4_rhel4_xen_wpt) ++ fprintf(fp, " uvtop: x86_64_uvtop_level4_rhel4_xen_wpt()\n"); + else + fprintf(fp, " uvtop: %lx\n", (ulong)machdep->uvtop); - fprintf(fp, " kvtop: x86_64_kvtop()\n"); ++ fprintf(fp, " kvtop: x86_64_kvtop()"); ++ if (XEN() && (kt->xen_flags & WRITABLE_PAGE_TABLES)) ++ fprintf(fp, " -> x86_64_kvtop_xen_wpt()"); ++ fprintf(fp, "\n"); fprintf(fp, " get_task_pgd: x86_64_get_task_pgd()\n"); fprintf(fp, " dump_irq: x86_64_dump_irq()\n"); -@@ -239,6 +347,11 @@ + fprintf(fp, " get_stack_frame: x86_64_get_stack_frame()\n"); +@@ -239,6 +413,11 @@ fprintf(fp, " is_uvaddr: x86_64_is_uvaddr()\n"); fprintf(fp, " verify_paddr: generic_verify_paddr()\n"); fprintf(fp, " init_kernel_pgd: x86_64_init_kernel_pgd()\n"); @@ -16319,7 +23483,7 @@ fprintf(fp, " line_number_hooks: x86_64_line_number_hooks\n"); fprintf(fp, " value_to_symbol: generic_machdep_value_to_symbol()\n"); fprintf(fp, " last_pgd_read: %lx\n", machdep->last_pgd_read); -@@ -248,8 +361,27 @@ +@@ -248,9 +427,29 @@ fprintf(fp, " pmd: %lx\n", (ulong)machdep->pmd); fprintf(fp, " ptbl: %lx\n", (ulong)machdep->ptbl); fprintf(fp, " ptrs_per_pgd: %d\n", machdep->ptrs_per_pgd); @@ -16346,9 +23510,11 @@ + fprintf(fp, " last_upml_read: (unused)\n"); + } fprintf(fp, " irqstack: %lx\n", (ulong)ms->irqstack); ++ fprintf(fp, " irq_eframe_link: %ld\n", ms->irq_eframe_link); fprintf(fp, " pto: %s", machdep->flags & PT_REGS_INIT ? "\n" : "(uninitialized)\n"); -@@ -276,8 +408,10 @@ + if (machdep->flags & PT_REGS_INIT) { +@@ -276,8 +475,10 @@ fprintf(fp, " rsp: %ld\n", ms->pto.rsp); fprintf(fp, " ss: %ld\n", ms->pto.ss); } @@ -16361,7 +23527,7 @@ fprintf(fp, " ebase[%s][7]:", arg ? "NR_CPUS" : "cpus"); cpus = arg ? NR_CPUS : kt->cpus; -@@ -306,9 +440,9 @@ +@@ -306,9 +507,9 @@ static void x86_64_cpu_pda_init(void) { @@ -16373,7 +23539,7 @@ struct syment *sp, *nsp; ulong offset, istacksize; -@@ -320,18 +454,36 @@ +@@ -320,18 +521,44 @@ MEMBER_OFFSET_INIT(x8664_pda_irqstackptr, "x8664_pda", "irqstackptr"); MEMBER_OFFSET_INIT(x8664_pda_level4_pgt, "x8664_pda", "level4_pgt"); MEMBER_OFFSET_INIT(x8664_pda_cpunumber, "x8664_pda", "cpunumber"); @@ -16383,14 +23549,22 @@ - if (!(nr_pda = get_array_length("cpu_pda", NULL, 0))) - nr_pda = NR_CPUS; -+ if (symbol_exists("_cpu_pda")) { -+ if (!(nr_pda = get_array_length("_cpu_pda", NULL, 0))) -+ nr_pda = NR_CPUS; -+ _cpu_pda = TRUE; ++ if (LKCD_KERNTYPES()) { ++ if (symbol_exists("_cpu_pda")) ++ _cpu_pda = TRUE; ++ else ++ _cpu_pda = FALSE; ++ nr_pda = get_cpus_possible(); + } else { -+ if (!(nr_pda = get_array_length("cpu_pda", NULL, 0))) -+ nr_pda = NR_CPUS; -+ _cpu_pda = FALSE; ++ if (symbol_exists("_cpu_pda")) { ++ if (!(nr_pda = get_array_length("_cpu_pda", NULL, 0))) ++ nr_pda = NR_CPUS; ++ _cpu_pda = TRUE; ++ } else { ++ if (!(nr_pda = get_array_length("cpu_pda", NULL, 0))) ++ nr_pda = NR_CPUS; ++ _cpu_pda = FALSE; ++ } + } for (i = cpus = 0; i < nr_pda; i++) { @@ -16416,7 +23590,30 @@ break; cpus++; -@@ -448,6 +600,13 @@ +@@ -351,8 +578,8 @@ + i, level4_pgt, data_offset); + } + +- +- if ((i = get_array_length("boot_cpu_stack", NULL, 0))) { ++ if (!LKCD_KERNTYPES() && ++ (i = get_array_length("boot_cpu_stack", NULL, 0))) { + istacksize = i; + } else if ((sp = symbol_search("boot_cpu_stack")) && + (nsp = next_symbol(NULL, sp))) { +@@ -381,8 +608,9 @@ + * the address of &boot_cpu_stack[0]. + */ + sp = value_search(machdep->machspec->stkinfo.ibase[0], &offset); +- if (!sp || offset || !STREQ(sp->name, "boot_cpu_stack")) { +- if (symbol_value("boot_cpu_stack")) { ++ nsp = symbol_search("boot_cpu_stack"); ++ if (!sp || offset || !nsp || (sp->value != nsp->value)) { ++ if (symbol_exists("boot_cpu_stack")) { + error(WARNING, + "cpu 0 IRQ stack: %lx\n boot_cpu_stack: %lx\n\n", + machdep->machspec->stkinfo.ibase[0], +@@ -448,6 +676,13 @@ if (ms->stkinfo.ebase[c][0] == 0) break; } @@ -16430,7 +23627,7 @@ } if (ms->stkinfo.ebase[0][0] && ms->stkinfo.ebase[0][1]) -@@ -535,6 +694,10 @@ +@@ -535,6 +770,10 @@ if (clues >= 2) kt->cpu_flags[c] |= NMI; } @@ -16441,7 +23638,7 @@ } /* -@@ -576,7 +739,7 @@ +@@ -576,7 +815,7 @@ ulong x86_64_VTOP(ulong vaddr) { if (vaddr >= __START_KERNEL_map) @@ -16450,7 +23647,7 @@ else return ((vaddr) - PAGE_OFFSET); } -@@ -584,12 +747,19 @@ +@@ -584,12 +823,19 @@ /* * Include both vmalloc'd and module address space as VMALLOC space. */ @@ -16471,41 +23668,63 @@ /* * Refining this may cause more problems than just doing it this way. */ -@@ -616,6 +786,257 @@ +@@ -616,43 +862,52 @@ */ static int +-x86_64_uvtop(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int verbose) +x86_64_uvtop_level4(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int verbose) -+{ + { +- ulong mm; +- ulong *pgd; + ulong mm; + ulong *pml; + ulong pml_paddr; + ulong pml_pte; + ulong *pgd; -+ ulong pgd_paddr; -+ ulong pgd_pte; -+ ulong *pmd; -+ ulong pmd_paddr; -+ ulong pmd_pte; + ulong pgd_paddr; + ulong pgd_pte; + ulong *pmd; + ulong pmd_paddr; + ulong pmd_pte; +- ulong *ptep; +- ulong pte_paddr; +- ulong pte; +- physaddr_t physpage; + ulong *ptep; + ulong pte_paddr; + ulong pte; + physaddr_t physpage; -+ + +- if (!tc) +- error(FATAL, "current context invalid\n"); + if (!tc) + error(FATAL, "current context invalid\n"); -+ + +- *paddr = 0; + *paddr = 0; -+ + +- if (IS_KVADDR(uvaddr)) +- return x86_64_kvtop(tc, uvaddr, paddr, verbose); + if (IS_KVADDR(uvaddr)) + return x86_64_kvtop(tc, uvaddr, paddr, verbose); -+ + +- /* +- * pgd = pgd_offset(mm, address); +- */ +- if ((mm = task_mm(tc->task, TRUE))) +- pgd = ULONG_PTR(tt->mm_struct + OFFSET(mm_struct_pgd)); +- else +- readmem(tc->mm_struct + OFFSET(mm_struct_pgd), KVADDR, &pgd, +- sizeof(long), "mm_struct pgd", FAULT_ON_ERROR); + if ((mm = task_mm(tc->task, TRUE))) + pml = ULONG_PTR(tt->mm_struct + OFFSET(mm_struct_pgd)); + else + readmem(tc->mm_struct + OFFSET(mm_struct_pgd), KVADDR, &pml, + sizeof(long), "mm_struct pgd", FAULT_ON_ERROR); -+ + +- pgd_paddr = x86_64_VTOP((ulong)pgd); +- FILL_PGD(pgd_paddr, PHYSADDR, PAGESIZE()); + pml_paddr = x86_64_VTOP((ulong)pml); + FILL_UPML(pml_paddr, PHYSADDR, PAGESIZE()); + pml = ((ulong *)pml_paddr) + pml4_index(uvaddr); @@ -16517,41 +23736,35 @@ + + pgd_paddr = pml_pte & PHYSICAL_PAGE_MASK; + FILL_PGD(pgd_paddr, PHYSADDR, PAGESIZE()); -+ pgd = ((ulong *)pgd_paddr) + pgd_index(uvaddr); -+ pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(pgd)); + pgd = ((ulong *)pgd_paddr) + pgd_index(uvaddr); + pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(pgd)); +- if (verbose) +- fprintf(fp, " PGD: %lx => %lx\n", (ulong)pgd, pgd_pte); + if (verbose) + fprintf(fp, " PUD: %lx => %lx\n", (ulong)pgd, pgd_pte); -+ if (!(pgd_pte & _PAGE_PRESENT)) -+ goto no_upage; -+ -+ /* -+ * pmd = pmd_offset(pgd, address); -+ */ -+ pmd_paddr = pgd_pte & PHYSICAL_PAGE_MASK; -+ FILL_PMD(pmd_paddr, PHYSADDR, PAGESIZE()); -+ pmd = ((ulong *)pmd_paddr) + pmd_index(uvaddr); -+ pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(pmd)); -+ if (verbose) -+ fprintf(fp, " PMD: %lx => %lx\n", (ulong)pmd, pmd_pte); -+ if (!(pmd_pte & _PAGE_PRESENT)) -+ goto no_upage; -+ if (pmd_pte & _PAGE_PSE) { -+ if (verbose) { -+ fprintf(fp, " PAGE: %lx (2MB)\n\n", -+ PAGEBASE(pmd_pte) & PHYSICAL_PAGE_MASK); -+ x86_64_translate_pte(pmd_pte, 0, 0); -+ } -+ -+ physpage = (PAGEBASE(pmd_pte) & PHYSICAL_PAGE_MASK) + -+ (uvaddr & ~_2MB_PAGE_MASK); -+ *paddr = physpage; -+ return TRUE; -+ } -+ -+ /* -+ * ptep = pte_offset_map(pmd, address); + if (!(pgd_pte & _PAGE_PRESENT)) + goto no_upage; + +@@ -682,29 +937,31 @@ + + /* + * ptep = pte_offset_map(pmd, address); +- * pte = *ptep; + * pte = *ptep; -+ */ + */ +- pte_paddr = pmd_pte & PHYSICAL_PAGE_MASK; +- FILL_PTBL(pte_paddr, PHYSADDR, PAGESIZE()); +- ptep = ((ulong *)pte_paddr) + pte_index(uvaddr); +- pte = ULONG(machdep->ptbl + PAGEOFFSET(ptep)); +- if (verbose) +- fprintf(fp, " PTE: %lx => %lx\n", (ulong)ptep, pte); +- if (!(pte & (_PAGE_PRESENT))) { +- if (pte && verbose) { +- fprintf(fp, "\n"); +- x86_64_translate_pte(pte, 0, 0); +- } +- goto no_upage; +- } + pte_paddr = pmd_pte & PHYSICAL_PAGE_MASK; + FILL_PTBL(pte_paddr, PHYSADDR, PAGESIZE()); + ptep = ((ulong *)pte_paddr) + pte_index(uvaddr); @@ -16559,54 +23772,93 @@ + if (verbose) + fprintf(fp, " PTE: %lx => %lx\n", (ulong)ptep, pte); + if (!(pte & (_PAGE_PRESENT))) { ++ *paddr = pte; ++ + if (pte && verbose) { + fprintf(fp, "\n"); + x86_64_translate_pte(pte, 0, 0); + } + goto no_upage; + } -+ + +- *paddr = (PAGEBASE(pte) & PHYSICAL_PAGE_MASK) + PAGEOFFSET(uvaddr); + *paddr = (PAGEBASE(pte) & PHYSICAL_PAGE_MASK) + PAGEOFFSET(uvaddr); -+ + +- if (verbose) { +- fprintf(fp, " PAGE: %lx\n\n", + if (verbose) { + fprintf(fp, " PAGE: %lx\n\n", -+ PAGEBASE(*paddr) & PHYSICAL_PAGE_MASK); + PAGEBASE(*paddr) & PHYSICAL_PAGE_MASK); +- x86_64_translate_pte(pte, 0, 0); +- } + x86_64_translate_pte(pte, 0, 0); + } -+ -+ return TRUE; -+ -+no_upage: -+ -+ return FALSE; -+} -+ -+static int + + return TRUE; + +@@ -713,1982 +970,4769 @@ + return FALSE; + } + +- +-/* +- * Translates a kernel virtual address to its physical address. cmd_vtop() +- * sets the verbose flag so that the pte translation gets displayed; all +- * other callers quietly accept the translation. +- */ + static int +-x86_64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose) +x86_64_uvtop_level4_xen_wpt(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int verbose) -+{ + { +- ulong *pml4; +- ulong *pgd; + ulong mm; + ulong *pml; + ulong pml_paddr; + ulong pml_pte; + ulong *pgd; -+ ulong pgd_paddr; -+ ulong pgd_pte; -+ ulong *pmd; -+ ulong pmd_paddr; -+ ulong pmd_pte; + ulong pgd_paddr; + ulong pgd_pte; + ulong *pmd; + ulong pmd_paddr; + ulong pmd_pte; + ulong pseudo_pmd_pte; -+ ulong *ptep; -+ ulong pte_paddr; -+ ulong pte; + ulong *ptep; + ulong pte_paddr; + ulong pte; + ulong pseudo_pte; -+ physaddr_t physpage; + physaddr_t physpage; + char buf[BUFSIZE]; -+ + +- if (!IS_KVADDR(kvaddr)) +- return FALSE; + if (!tc) + error(FATAL, "current context invalid\n"); -+ + +- if (!vt->vmalloc_start) { +- *paddr = x86_64_VTOP(kvaddr); +- return TRUE; +- } + *paddr = 0; -+ + +- if (!IS_VMALLOC_ADDR(kvaddr)) { +- *paddr = x86_64_VTOP(kvaddr); +- if (!verbose) +- return TRUE; +- } +- +- /* +- * pgd = pgd_offset_k(addr); +- */ +- FILL_PML4(); +- pml4 = ((ulong *)machdep->machspec->pml4) + pml4_index(kvaddr); +- if (verbose) { +- fprintf(fp, "PML4 DIRECTORY: %lx\n", vt->kernel_pgd[0]); +- fprintf(fp, "PAGE DIRECTORY: %lx\n", *pml4); +- } +- if (!(*pml4) & _PAGE_PRESENT) +- goto no_kpage; +- pgd_paddr = (*pml4) & PHYSICAL_PAGE_MASK; + if (IS_KVADDR(uvaddr)) + return x86_64_kvtop(tc, uvaddr, paddr, verbose); + @@ -16629,21 +23881,231 @@ + pgd_paddr = xen_m2p(pgd_paddr); + if (verbose) + fprintf(fp, " PML: %lx\n", pgd_paddr); + FILL_PGD(pgd_paddr, PHYSADDR, PAGESIZE()); +- pgd = ((ulong *)pgd_paddr) + pgd_index(kvaddr); ++ pgd = ((ulong *)pgd_paddr) + pgd_index(uvaddr); + pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(pgd)); +- if (verbose) +- fprintf(fp, " PGD: %lx => %lx\n", (ulong)pgd, pgd_pte); ++ if (verbose) ++ fprintf(fp, " PUD: %lx => %lx [machine]\n", (ulong)pgd, pgd_pte); + if (!(pgd_pte & _PAGE_PRESENT)) +- goto no_kpage; ++ goto no_upage; + + /* +- * pmd = pmd_offset(pgd, addr); ++ * pmd = pmd_offset(pgd, address); + */ + pmd_paddr = pgd_pte & PHYSICAL_PAGE_MASK; ++ pmd_paddr = xen_m2p(pmd_paddr); ++ if (verbose) ++ fprintf(fp, " PUD: %lx\n", pmd_paddr); + FILL_PMD(pmd_paddr, PHYSADDR, PAGESIZE()); +- pmd = ((ulong *)pmd_paddr) + pmd_index(kvaddr); ++ pmd = ((ulong *)pmd_paddr) + pmd_index(uvaddr); + pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(pmd)); + if (verbose) +- fprintf(fp, " PMD: %lx => %lx\n", (ulong)pmd, pmd_pte); ++ fprintf(fp, " PMD: %lx => %lx [machine]\n", (ulong)pmd, pmd_pte); + if (!(pmd_pte & _PAGE_PRESENT)) +- goto no_kpage; +- if (pmd_pte & _PAGE_PSE) { +- if (verbose) { +- fprintf(fp, " PAGE: %lx (2MB)\n\n", ++ goto no_upage; ++ if (pmd_pte & _PAGE_PSE) { ++ if (verbose) ++ fprintf(fp, " PAGE: %lx (2MB) [machine]\n", + PAGEBASE(pmd_pte) & PHYSICAL_PAGE_MASK); +- x86_64_translate_pte(pmd_pte, 0, 0); ++ ++ pseudo_pmd_pte = xen_m2p(PAGEBASE(pmd_pte)); ++ ++ if (pseudo_pmd_pte == XEN_MACHADDR_NOT_FOUND) { ++ if (verbose) ++ fprintf(fp, " PAGE: page not available\n"); ++ *paddr = PADDR_NOT_AVAILABLE; ++ return FALSE; + } + +- physpage = (PAGEBASE(pmd_pte) & PHYSICAL_PAGE_MASK) + +- (kvaddr & ~_2MB_PAGE_MASK); ++ pseudo_pmd_pte |= PAGEOFFSET(pmd_pte); ++ ++ if (verbose) { ++ fprintf(fp, " PAGE: %s (2MB)\n\n", ++ mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, ++ MKSTR(PAGEBASE(pseudo_pmd_pte) & ++ PHYSICAL_PAGE_MASK))); ++ ++ x86_64_translate_pte(pseudo_pmd_pte, 0, 0); ++ } ++ ++ physpage = (PAGEBASE(pseudo_pmd_pte) & PHYSICAL_PAGE_MASK) + ++ (uvaddr & ~_2MB_PAGE_MASK); ++ + *paddr = physpage; + return TRUE; +- } ++ } + +- /* +- * ptep = pte_offset_map(pmd, addr); ++ /* ++ * ptep = pte_offset_map(pmd, address); + * pte = *ptep; + */ + pte_paddr = pmd_pte & PHYSICAL_PAGE_MASK; ++ pte_paddr = xen_m2p(pte_paddr); ++ if (verbose) ++ fprintf(fp, " PMD: %lx\n", pte_paddr); + FILL_PTBL(pte_paddr, PHYSADDR, PAGESIZE()); +- ptep = ((ulong *)pte_paddr) + pte_index(kvaddr); ++ ptep = ((ulong *)pte_paddr) + pte_index(uvaddr); + pte = ULONG(machdep->ptbl + PAGEOFFSET(ptep)); +- if (verbose) +- fprintf(fp, " PTE: %lx => %lx\n", (ulong)ptep, pte); +- if (!(pte & (_PAGE_PRESENT))) { +- if (pte && verbose) { +- fprintf(fp, "\n"); +- x86_64_translate_pte(pte, 0, 0); +- } +- goto no_kpage; +- } +- +- *paddr = (PAGEBASE(pte) & PHYSICAL_PAGE_MASK) + PAGEOFFSET(kvaddr); +- +- if (verbose) { +- fprintf(fp, " PAGE: %lx\n\n", ++ if (verbose) ++ fprintf(fp, " PTE: %lx => %lx [machine]\n", (ulong)ptep, pte); ++ if (!(pte & (_PAGE_PRESENT))) { ++ *paddr = pte; ++ ++ if (pte && verbose) { ++ fprintf(fp, "\n"); ++ x86_64_translate_pte(pte, 0, 0); ++ } ++ goto no_upage; ++ } ++ ++ pseudo_pte = xen_m2p(pte & PHYSICAL_PAGE_MASK); ++ if (verbose) ++ fprintf(fp, " PTE: %lx\n", pseudo_pte + PAGEOFFSET(pte)); ++ ++ *paddr = (PAGEBASE(pseudo_pte) & PHYSICAL_PAGE_MASK) + PAGEOFFSET(uvaddr); ++ ++ if (verbose) { ++ fprintf(fp, " PAGE: %lx [machine]\n", ++ PAGEBASE(pte) & PHYSICAL_PAGE_MASK); ++ fprintf(fp, " PAGE: %lx\n\n", + PAGEBASE(*paddr) & PHYSICAL_PAGE_MASK); +- x86_64_translate_pte(pte, 0, 0); +- } ++ x86_64_translate_pte(pseudo_pte + PAGEOFFSET(pte), 0, 0); ++ } + +- return TRUE; ++ return TRUE; + +-no_kpage: +- return FALSE; +-} ++no_upage: + +-/* +- * Determine where vmalloc'd memory starts. +- */ +-static ulong +-x86_64_vmalloc_start(void) +-{ +- return ((ulong)VMALLOC_START); ++ return FALSE; + } + +-/* +- * thread_info implementation makes for less accurate results here. +- */ + static int +-x86_64_is_task_addr(ulong task) ++x86_64_uvtop_level4_rhel4_xen_wpt(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int verbose) + { +- if (tt->flags & THREAD_INFO) +- return IS_KVADDR(task); +- else +- return (IS_KVADDR(task) && (ALIGNED_STACK_OFFSET(task) == 0)); +-} +- ++ ulong mm; ++ ulong *pgd; ++ ulong pgd_paddr; ++ ulong pgd_pte; ++ ulong *pmd; ++ ulong pmd_paddr; ++ ulong pmd_pte; ++ ulong pseudo_pmd_pte; ++ ulong *ptep; ++ ulong pte_paddr; ++ ulong pte; ++ ulong pseudo_pte; ++ physaddr_t physpage; ++ char buf[BUFSIZE]; + +-/* +- * easy enough... +- */ +-static ulong +-x86_64_processor_speed(void) +-{ +- unsigned long cpu_khz; ++ if (!tc) ++ error(FATAL, "current context invalid\n"); + +- if (machdep->mhz) +- return (machdep->mhz); ++ *paddr = 0; + +- if (symbol_exists("cpu_khz")) { +- get_symbol_data("cpu_khz", sizeof(long), &cpu_khz); +- if (cpu_khz) +- return(machdep->mhz = cpu_khz/1000); +- } ++ if (IS_KVADDR(uvaddr)) ++ return x86_64_kvtop(tc, uvaddr, paddr, verbose); + +- return 0; +-} ++ if ((mm = task_mm(tc->task, TRUE))) ++ pgd = ULONG_PTR(tt->mm_struct + OFFSET(mm_struct_pgd)); ++ else ++ readmem(tc->mm_struct + OFFSET(mm_struct_pgd), KVADDR, &pgd, ++ sizeof(long), "mm_struct pgd", FAULT_ON_ERROR); + ++ pgd_paddr = x86_64_VTOP((ulong)pgd); + FILL_PGD(pgd_paddr, PHYSADDR, PAGESIZE()); + pgd = ((ulong *)pgd_paddr) + pgd_index(uvaddr); + pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(pgd)); + if (verbose) -+ fprintf(fp, " PUD: %lx => %lx [machine]\n", (ulong)pgd, pgd_pte); ++ fprintf(fp, " PGD: %lx => %lx [machine]\n", (ulong)pgd, pgd_pte); + if (!(pgd_pte & _PAGE_PRESENT)) + goto no_upage; -+ + +-/* +- * Accept or reject a symbol from the kernel namelist. +- */ +-static int +-x86_64_verify_symbol(const char *name, ulong value, char type) +-{ +- if (STREQ(name, "_text") || STREQ(name, "_stext")) +- machdep->flags |= KSYMS_START; + /* + * pmd = pmd_offset(pgd, address); + */ + pmd_paddr = pgd_pte & PHYSICAL_PAGE_MASK; + pmd_paddr = xen_m2p(pmd_paddr); + if (verbose) -+ fprintf(fp, " PUD: %lx\n", pmd_paddr); ++ fprintf(fp, " PGD: %lx\n", pmd_paddr); + FILL_PMD(pmd_paddr, PHYSADDR, PAGESIZE()); + pmd = ((ulong *)pmd_paddr) + pmd_index(uvaddr); + pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(pmd)); @@ -16655,7 +24117,9 @@ + if (verbose) + fprintf(fp, " PAGE: %lx (2MB) [machine]\n", + PAGEBASE(pmd_pte) & PHYSICAL_PAGE_MASK); -+ + +- if (!name || !strlen(name) || !(machdep->flags & KSYMS_START)) +- return FALSE; + pseudo_pmd_pte = xen_m2p(PAGEBASE(pmd_pte)); + + if (pseudo_pmd_pte == XEN_MACHADDR_NOT_FOUND) { @@ -16697,6 +24161,8 @@ + if (verbose) + fprintf(fp, " PTE: %lx => %lx [machine]\n", (ulong)ptep, pte); + if (!(pte & (_PAGE_PRESENT))) { ++ *paddr = pte; ++ + if (pte && verbose) { + fprintf(fp, "\n"); + x86_64_translate_pte(pte, 0, 0); @@ -16717,62 +24183,405 @@ + PAGEBASE(*paddr) & PHYSICAL_PAGE_MASK); + x86_64_translate_pte(pseudo_pte + PAGEOFFSET(pte), 0, 0); + } -+ + + return TRUE; +-} + ++no_upage: + +-/* +- * Get the relevant page directory pointer from a task structure. +- */ +-static ulong +-x86_64_get_task_pgd(ulong task) +-{ +- return (error(FATAL, "x86_64_get_task_pgd: N/A\n")); ++ return FALSE; + } + +- +-/* +- * Translate a PTE, returning TRUE if the page is present. +- * If a physaddr pointer is passed in, don't print anything. +- */ + static int +-x86_64_translate_pte(ulong pte, void *physaddr, ulonglong unused) ++x86_64_uvtop(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int verbose) + { +- int c, others, len1, len2, len3; +- ulong paddr; +- char buf[BUFSIZE]; +- char buf2[BUFSIZE]; +- char buf3[BUFSIZE]; +- char ptebuf[BUFSIZE]; +- char physbuf[BUFSIZE]; +- char *arglist[MAXARGS]; +- int page_present; ++ ulong mm; ++ ulong *pgd; ++ ulong pgd_paddr; ++ ulong pgd_pte; ++ ulong *pmd; ++ ulong pmd_paddr; ++ ulong pmd_pte; ++ ulong *ptep; ++ ulong pte_paddr; ++ ulong pte; ++ physaddr_t physpage; + +- paddr = pte & PHYSICAL_PAGE_MASK; +- page_present = pte & _PAGE_PRESENT; ++ if (!tc) ++ error(FATAL, "current context invalid\n"); + +- if (physaddr) { +- *((ulong *)physaddr) = paddr; +- return page_present; +- } +- +- sprintf(ptebuf, "%lx", pte); +- len1 = MAX(strlen(ptebuf), strlen("PTE")); +- fprintf(fp, "%s ", mkstring(buf, len1, CENTER|LJUST, "PTE")); ++ *paddr = 0; + +- if (!page_present && pte) { +- swap_location(pte, buf); +- if ((c = parse_line(buf, arglist)) != 3) +- error(FATAL, "cannot determine swap location\n"); ++ if (IS_KVADDR(uvaddr)) ++ return x86_64_kvtop(tc, uvaddr, paddr, verbose); + +- len2 = MAX(strlen(arglist[0]), strlen("SWAP")); +- len3 = MAX(strlen(arglist[2]), strlen("OFFSET")); ++ /* ++ * pgd = pgd_offset(mm, address); ++ */ ++ if ((mm = task_mm(tc->task, TRUE))) ++ pgd = ULONG_PTR(tt->mm_struct + OFFSET(mm_struct_pgd)); ++ else ++ readmem(tc->mm_struct + OFFSET(mm_struct_pgd), KVADDR, &pgd, ++ sizeof(long), "mm_struct pgd", FAULT_ON_ERROR); + +- fprintf(fp, "%s %s\n", +- mkstring(buf2, len2, CENTER|LJUST, "SWAP"), +- mkstring(buf3, len3, CENTER|LJUST, "OFFSET")); ++ pgd_paddr = x86_64_VTOP((ulong)pgd); ++ FILL_PGD(pgd_paddr, PHYSADDR, PAGESIZE()); ++ pgd = ((ulong *)pgd_paddr) + pgd_index(uvaddr); ++ pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(pgd)); ++ if (verbose) ++ fprintf(fp, " PGD: %lx => %lx\n", (ulong)pgd, pgd_pte); ++ if (!(pgd_pte & _PAGE_PRESENT)) ++ goto no_upage; + +- strcpy(buf2, arglist[0]); +- strcpy(buf3, arglist[2]); +- fprintf(fp, "%s %s %s\n", +- mkstring(ptebuf, len1, CENTER|RJUST, NULL), +- mkstring(buf2, len2, CENTER|RJUST, NULL), +- mkstring(buf3, len3, CENTER|RJUST, NULL)); ++ /* ++ * pmd = pmd_offset(pgd, address); ++ */ ++ pmd_paddr = pgd_pte & PHYSICAL_PAGE_MASK; ++ FILL_PMD(pmd_paddr, PHYSADDR, PAGESIZE()); ++ pmd = ((ulong *)pmd_paddr) + pmd_index(uvaddr); ++ pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(pmd)); ++ if (verbose) ++ fprintf(fp, " PMD: %lx => %lx\n", (ulong)pmd, pmd_pte); ++ if (!(pmd_pte & _PAGE_PRESENT)) ++ goto no_upage; ++ if (pmd_pte & _PAGE_PSE) { ++ if (verbose) { ++ fprintf(fp, " PAGE: %lx (2MB)\n\n", ++ PAGEBASE(pmd_pte) & PHYSICAL_PAGE_MASK); ++ x86_64_translate_pte(pmd_pte, 0, 0); ++ } + +- return page_present; ++ physpage = (PAGEBASE(pmd_pte) & PHYSICAL_PAGE_MASK) + ++ (uvaddr & ~_2MB_PAGE_MASK); ++ *paddr = physpage; ++ return TRUE; + } + +- sprintf(physbuf, "%lx", paddr); +- len2 = MAX(strlen(physbuf), strlen("PHYSICAL")); +- fprintf(fp, "%s ", mkstring(buf, len2, CENTER|LJUST, "PHYSICAL")); ++ /* ++ * ptep = pte_offset_map(pmd, address); ++ * pte = *ptep; ++ */ ++ pte_paddr = pmd_pte & PHYSICAL_PAGE_MASK; ++ FILL_PTBL(pte_paddr, PHYSADDR, PAGESIZE()); ++ ptep = ((ulong *)pte_paddr) + pte_index(uvaddr); ++ pte = ULONG(machdep->ptbl + PAGEOFFSET(ptep)); ++ if (verbose) ++ fprintf(fp, " PTE: %lx => %lx\n", (ulong)ptep, pte); ++ if (!(pte & (_PAGE_PRESENT))) { ++ *paddr = pte; + +- fprintf(fp, "FLAGS\n"); ++ if (pte && verbose) { ++ fprintf(fp, "\n"); ++ x86_64_translate_pte(pte, 0, 0); ++ } ++ goto no_upage; ++ } + +- fprintf(fp, "%s %s ", +- mkstring(ptebuf, len1, CENTER|RJUST, NULL), +- mkstring(physbuf, len2, CENTER|RJUST, NULL)); +- fprintf(fp, "("); +- others = 0; ++ *paddr = (PAGEBASE(pte) & PHYSICAL_PAGE_MASK) + PAGEOFFSET(uvaddr); + +- if (pte) { +- if (pte & _PAGE_PRESENT) +- fprintf(fp, "%sPRESENT", others++ ? "|" : ""); +- if (pte & _PAGE_RW) +- fprintf(fp, "%sRW", others++ ? "|" : ""); +- if (pte & _PAGE_USER) +- fprintf(fp, "%sUSER", others++ ? "|" : ""); +- if (pte & _PAGE_PWT) +- fprintf(fp, "%sPWT", others++ ? "|" : ""); +- if (pte & _PAGE_PCD) +- fprintf(fp, "%sPCD", others++ ? "|" : ""); +- if (pte & _PAGE_ACCESSED) +- fprintf(fp, "%sACCESSED", others++ ? "|" : ""); +- if (pte & _PAGE_DIRTY) +- fprintf(fp, "%sDIRTY", others++ ? "|" : ""); +- if ((pte & _PAGE_PSE) && (pte & _PAGE_PRESENT)) +- fprintf(fp, "%sPSE", others++ ? "|" : ""); +- if ((pte & _PAGE_PROTNONE) && !(pte & _PAGE_PRESENT)) +- fprintf(fp, "%sPROTNONE", others++ ? "|" : ""); +- if (pte & _PAGE_GLOBAL) +- fprintf(fp, "%sGLOBAL", others++ ? "|" : ""); +- if (pte & _PAGE_NX) +- fprintf(fp, "%sNX", others++ ? "|" : ""); +- } else { +- fprintf(fp, "no mapping"); ++ if (verbose) { ++ fprintf(fp, " PAGE: %lx\n\n", ++ PAGEBASE(*paddr) & PHYSICAL_PAGE_MASK); ++ x86_64_translate_pte(pte, 0, 0); + } + +- fprintf(fp, ")\n"); + return TRUE; -+ + +- return (page_present); +no_upage: + + return FALSE; -+} -+ -+static int - x86_64_uvtop(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int verbose) - { - ulong mm; -@@ -748,6 +1169,9 @@ - return TRUE; - } - -+ if (XEN() && (kt->xen_flags & WRITABLE_PAGE_TABLES)) -+ return (x86_64_kvtop_xen_wpt(tc, kvaddr, paddr, verbose)); -+ - /* - * pgd = pgd_offset_k(addr); - */ -@@ -764,7 +1188,7 @@ - pgd = ((ulong *)pgd_paddr) + pgd_index(kvaddr); - pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(pgd)); - if (verbose) -- fprintf(fp, " PGD: %lx => %lx\n", (ulong)pgd, pgd_pte); -+ fprintf(fp, " PUD: %lx => %lx\n", (ulong)pgd, pgd_pte); - if (!(pgd_pte & _PAGE_PRESENT)) - goto no_kpage; - -@@ -824,47 +1248,177 @@ - return FALSE; } --/* -- * Determine where vmalloc'd memory starts. -- */ --static ulong --x86_64_vmalloc_start(void) --{ -- return ((ulong)VMALLOC_START); --} +-static char * +-x86_64_exception_stacks[7] = { +- "STACKFAULT", +- "DOUBLEFAULT", +- "NMI", +- "DEBUG", +- "MCE", +- "(unknown)", +- "(unknown)" +-}; --/* -- * thread_info implementation makes for less accurate results here. -- */ - static int --x86_64_is_task_addr(ulong task) -+x86_64_kvtop_xen_wpt(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose) + /* +- * Look for likely exception frames in a stack. ++ * Translates a kernel virtual address to its physical address. cmd_vtop() ++ * sets the verbose flag so that the pte translation gets displayed; all ++ * other callers quietly accept the translation. + */ +-static int +-x86_64_eframe_search(struct bt_info *bt) ++static int ++x86_64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose) { -- if (tt->flags & THREAD_INFO) -- return IS_KVADDR(task); -- else -- return (IS_KVADDR(task) && (ALIGNED_STACK_OFFSET(task) == 0)); --} +- int i, c, cnt; +- ulong estack, irqstack, stacksize; +- ulong *up; +- struct machine_specific *ms; +- struct bt_info bt_local; ++ ulong *pml4; ++ ulong *pgd; ++ ulong pgd_paddr; ++ ulong pgd_pte; ++ ulong *pmd; ++ ulong pmd_paddr; ++ ulong pmd_pte; ++ ulong *ptep; ++ ulong pte_paddr; ++ ulong pte; ++ physaddr_t physpage; + +- if (bt->flags & BT_EFRAME_SEARCH2) { +- BCOPY(bt, &bt_local, sizeof(struct bt_info)); +- bt->flags &= ~(ulonglong)BT_EFRAME_SEARCH2; ++ if (!IS_KVADDR(kvaddr)) ++ return FALSE; + +- ms = machdep->machspec; ++ if (XEN_HYPER_MODE()) { ++ if (DIRECTMAP_VIRT_ADDR(kvaddr)) { ++ *paddr = kvaddr - DIRECTMAP_VIRT_START; ++ return TRUE; ++ } ++ FILL_PML4_HYPER(); ++ pml4 = ((ulong *)machdep->machspec->pml4) + pml4_index(kvaddr); ++ if (verbose) { ++ fprintf(fp, "PML4 DIRECTORY: %lx\n", vt->kernel_pgd[0]); ++ fprintf(fp, "PAGE DIRECTORY: %lx\n", *pml4); ++ } ++ } else { ++ if (!vt->vmalloc_start) { ++ *paddr = x86_64_VTOP(kvaddr); ++ return TRUE; ++ } + +- for (c = 0; c < kt->cpus; c++) { +- if (ms->stkinfo.ibase[c] == 0) +- break; +- bt->hp->esp = ms->stkinfo.ibase[c]; +- fprintf(fp, "CPU %d IRQ STACK:\n", c); +- if ((cnt = x86_64_eframe_search(bt))) +- fprintf(fp, "\n"); +- else +- fprintf(fp, "(none found)\n\n"); ++ if (!IS_VMALLOC_ADDR(kvaddr)) { ++ *paddr = x86_64_VTOP(kvaddr); ++ if (!verbose) ++ return TRUE; ++ } ++ ++ if (XEN() && (kt->xen_flags & WRITABLE_PAGE_TABLES)) ++ return (x86_64_kvtop_xen_wpt(tc, kvaddr, paddr, verbose)); ++ ++ /* ++ * pgd = pgd_offset_k(addr); ++ */ ++ FILL_PML4(); ++ pml4 = ((ulong *)machdep->machspec->pml4) + pml4_index(kvaddr); ++ if (verbose) { ++ fprintf(fp, "PML4 DIRECTORY: %lx\n", vt->kernel_pgd[0]); ++ fprintf(fp, "PAGE DIRECTORY: %lx\n", *pml4); ++ } ++ } ++ if (!(*pml4) & _PAGE_PRESENT) ++ goto no_kpage; ++ pgd_paddr = (*pml4) & PHYSICAL_PAGE_MASK; ++ FILL_PGD(pgd_paddr, PHYSADDR, PAGESIZE()); ++ pgd = ((ulong *)pgd_paddr) + pgd_index(kvaddr); ++ pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(pgd)); ++ if (verbose) ++ fprintf(fp, " PUD: %lx => %lx\n", (ulong)pgd, pgd_pte); ++ if (!(pgd_pte & _PAGE_PRESENT)) ++ goto no_kpage; ++ ++ /* ++ * pmd = pmd_offset(pgd, addr); ++ */ ++ pmd_paddr = pgd_pte & PHYSICAL_PAGE_MASK; ++ FILL_PMD(pmd_paddr, PHYSADDR, PAGESIZE()); ++ pmd = ((ulong *)pmd_paddr) + pmd_index(kvaddr); ++ pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(pmd)); ++ if (verbose) ++ fprintf(fp, " PMD: %lx => %lx\n", (ulong)pmd, pmd_pte); ++ if (!(pmd_pte & _PAGE_PRESENT)) ++ goto no_kpage; ++ if (pmd_pte & _PAGE_PSE) { ++ if (verbose) { ++ fprintf(fp, " PAGE: %lx (2MB)\n\n", ++ PAGEBASE(pmd_pte) & PHYSICAL_PAGE_MASK); ++ x86_64_translate_pte(pmd_pte, 0, 0); + } + +- for (c = 0; c < kt->cpus; c++) { +- for (i = 0; i < 7; i++) { +- if (ms->stkinfo.ebase[c][i] == 0) +- break; +- bt->hp->esp = ms->stkinfo.ebase[c][i]; +- fprintf(fp, "CPU %d %s EXCEPTION STACK:\n", +- c, x86_64_exception_stacks[i]); +- if ((cnt = x86_64_eframe_search(bt))) +- fprintf(fp, "\n"); +- else +- fprintf(fp, "(none found)\n\n"); +- } +- } ++ physpage = (PAGEBASE(pmd_pte) & PHYSICAL_PAGE_MASK) + ++ (kvaddr & ~_2MB_PAGE_MASK); ++ *paddr = physpage; ++ return TRUE; ++ } + +- return 0; ++ /* ++ * ptep = pte_offset_map(pmd, addr); ++ * pte = *ptep; ++ */ ++ pte_paddr = pmd_pte & PHYSICAL_PAGE_MASK; ++ FILL_PTBL(pte_paddr, PHYSADDR, PAGESIZE()); ++ ptep = ((ulong *)pte_paddr) + pte_index(kvaddr); ++ pte = ULONG(machdep->ptbl + PAGEOFFSET(ptep)); ++ if (verbose) ++ fprintf(fp, " PTE: %lx => %lx\n", (ulong)ptep, pte); ++ if (!(pte & (_PAGE_PRESENT))) { ++ if (pte && verbose) { ++ fprintf(fp, "\n"); ++ x86_64_translate_pte(pte, 0, 0); ++ } ++ goto no_kpage; + } + +- if (bt->hp && bt->hp->esp) { +- ms = machdep->machspec; +- bt->stkptr = bt->hp->esp; +- if ((estack = x86_64_in_exception_stack(bt))) { +- stacksize = ms->stkinfo.esize; +- bt->stackbase = estack; +- bt->stacktop = estack + ms->stkinfo.esize; +- bt->stackbuf = ms->irqstack; +- alter_stackbuf(bt); +- } else if ((irqstack = x86_64_in_irqstack(bt))) { +- stacksize = ms->stkinfo.isize; +- bt->stackbase = irqstack; +- bt->stacktop = irqstack + ms->stkinfo.isize; +- bt->stackbuf = ms->irqstack; +- alter_stackbuf(bt); +- } else if (!INSTACK(bt->stkptr, bt)) +- error(FATAL, +- "unrecognized stack address for this task: %lx\n", +- bt->hp->esp); +- } ++ *paddr = (PAGEBASE(pte) & PHYSICAL_PAGE_MASK) + PAGEOFFSET(kvaddr); + +- stacksize = bt->stacktop - bt->stackbase - SIZE(pt_regs); ++ if (verbose) { ++ fprintf(fp, " PAGE: %lx\n\n", ++ PAGEBASE(*paddr) & PHYSICAL_PAGE_MASK); ++ x86_64_translate_pte(pte, 0, 0); ++ } + +- if (bt->stkptr) +- i = (bt->stkptr - bt->stackbase)/sizeof(ulong); +- else +- i = 0; ++ return TRUE; + +- for (cnt = 0; i <= stacksize/sizeof(ulong); i++) { +- up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]); ++no_kpage: ++ return FALSE; ++} + +- if (x86_64_exception_frame(EFRAME_SEARCH|EFRAME_PRINT| +- EFRAME_VERIFY, 0, (char *)up, bt, fp)) +- cnt++; ++ ++static int ++x86_64_kvtop_xen_wpt(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose) ++{ + ulong *pml4; + ulong *pgd; + ulong pgd_paddr; @@ -16787,7 +24596,7 @@ + ulong pseudo_pte; + physaddr_t physpage; + char buf[BUFSIZE]; - ++ + /* + * pgd = pgd_offset_k(addr); + */ @@ -16810,14 +24619,7 @@ + fprintf(fp, " PUD: %lx => %lx [machine]\n", (ulong)pgd, pgd_pte); + if (!(pgd_pte & _PAGE_PRESENT)) + goto no_kpage; - --/* -- * easy enough... -- */ --static ulong --x86_64_processor_speed(void) --{ -- unsigned long cpu_khz; ++ + /* + * pmd = pmd_offset(pgd, addr); + */ @@ -16836,25 +24638,16 @@ + if (verbose) + fprintf(fp, " PAGE: %lx (2MB) [machine]\n", + PAGEBASE(pmd_pte) & PHYSICAL_PAGE_MASK); - -- if (machdep->mhz) -- return (machdep->mhz); ++ + pseudo_pmd_pte = xen_m2p(PAGEBASE(pmd_pte)); - -- if (symbol_exists("cpu_khz")) { -- get_symbol_data("cpu_khz", sizeof(long), &cpu_khz); -- if (cpu_khz) -- return(machdep->mhz = cpu_khz/1000); -- } ++ + if (pseudo_pmd_pte == XEN_MACHADDR_NOT_FOUND) { + if (verbose) + fprintf(fp, " PAGE: page not available\n"); + *paddr = PADDR_NOT_AVAILABLE; + return FALSE; + } - -- return 0; --} ++ + pseudo_pmd_pte |= PAGEOFFSET(pmd_pte); + + if (verbose) { @@ -16871,8 +24664,9 @@ + + *paddr = physpage; + return TRUE; -+ } -+ + } + +- return cnt; + /* + * ptep = pte_offset_map(pmd, addr); + * pte = *ptep; @@ -16956,55 +24750,637 @@ + + return 0; +} - - - /* -@@ -878,7 +1432,6 @@ - - if (!name || !strlen(name) || !(machdep->flags & KSYMS_START)) - return FALSE; -- - return TRUE; - } - -@@ -1091,6 +1644,9 @@ - ulong *up; - ulong words, addr; - ++ ++ ++/* ++ * Accept or reject a symbol from the kernel namelist. ++ */ ++static int ++x86_64_verify_symbol(const char *name, ulong value, char type) ++{ ++ if (STREQ(name, "_text") || STREQ(name, "_stext")) ++ machdep->flags |= KSYMS_START; ++ ++ if (!name || !strlen(name) || !(machdep->flags & KSYMS_START)) ++ return FALSE; ++ return TRUE; ++} ++ ++ ++/* ++ * Get the relevant page directory pointer from a task structure. ++ */ ++static ulong ++x86_64_get_task_pgd(ulong task) ++{ ++ return (error(FATAL, "x86_64_get_task_pgd: N/A\n")); ++} ++ ++ ++/* ++ * Translate a PTE, returning TRUE if the page is present. ++ * If a physaddr pointer is passed in, don't print anything. ++ */ ++static int ++x86_64_translate_pte(ulong pte, void *physaddr, ulonglong unused) ++{ ++ int c, others, len1, len2, len3; ++ ulong paddr; ++ char buf[BUFSIZE]; ++ char buf2[BUFSIZE]; ++ char buf3[BUFSIZE]; ++ char ptebuf[BUFSIZE]; ++ char physbuf[BUFSIZE]; ++ char *arglist[MAXARGS]; ++ int page_present; ++ ++ paddr = pte & PHYSICAL_PAGE_MASK; ++ page_present = pte & _PAGE_PRESENT; ++ ++ if (physaddr) { ++ *((ulong *)physaddr) = paddr; ++ return page_present; ++ } ++ ++ sprintf(ptebuf, "%lx", pte); ++ len1 = MAX(strlen(ptebuf), strlen("PTE")); ++ fprintf(fp, "%s ", mkstring(buf, len1, CENTER|LJUST, "PTE")); ++ ++ if (!page_present && pte) { ++ swap_location(pte, buf); ++ if ((c = parse_line(buf, arglist)) != 3) ++ error(FATAL, "cannot determine swap location\n"); ++ ++ len2 = MAX(strlen(arglist[0]), strlen("SWAP")); ++ len3 = MAX(strlen(arglist[2]), strlen("OFFSET")); ++ ++ fprintf(fp, "%s %s\n", ++ mkstring(buf2, len2, CENTER|LJUST, "SWAP"), ++ mkstring(buf3, len3, CENTER|LJUST, "OFFSET")); ++ ++ strcpy(buf2, arglist[0]); ++ strcpy(buf3, arglist[2]); ++ fprintf(fp, "%s %s %s\n", ++ mkstring(ptebuf, len1, CENTER|RJUST, NULL), ++ mkstring(buf2, len2, CENTER|RJUST, NULL), ++ mkstring(buf3, len3, CENTER|RJUST, NULL)); ++ ++ return page_present; ++ } ++ ++ sprintf(physbuf, "%lx", paddr); ++ len2 = MAX(strlen(physbuf), strlen("PHYSICAL")); ++ fprintf(fp, "%s ", mkstring(buf, len2, CENTER|LJUST, "PHYSICAL")); ++ ++ fprintf(fp, "FLAGS\n"); ++ ++ fprintf(fp, "%s %s ", ++ mkstring(ptebuf, len1, CENTER|RJUST, NULL), ++ mkstring(physbuf, len2, CENTER|RJUST, NULL)); ++ fprintf(fp, "("); ++ others = 0; ++ ++ if (pte) { ++ if (pte & _PAGE_PRESENT) ++ fprintf(fp, "%sPRESENT", others++ ? "|" : ""); ++ if (pte & _PAGE_RW) ++ fprintf(fp, "%sRW", others++ ? "|" : ""); ++ if (pte & _PAGE_USER) ++ fprintf(fp, "%sUSER", others++ ? "|" : ""); ++ if (pte & _PAGE_PWT) ++ fprintf(fp, "%sPWT", others++ ? "|" : ""); ++ if (pte & _PAGE_PCD) ++ fprintf(fp, "%sPCD", others++ ? "|" : ""); ++ if (pte & _PAGE_ACCESSED) ++ fprintf(fp, "%sACCESSED", others++ ? "|" : ""); ++ if (pte & _PAGE_DIRTY) ++ fprintf(fp, "%sDIRTY", others++ ? "|" : ""); ++ if ((pte & _PAGE_PSE) && (pte & _PAGE_PRESENT)) ++ fprintf(fp, "%sPSE", others++ ? "|" : ""); ++ if ((pte & _PAGE_PROTNONE) && !(pte & _PAGE_PRESENT)) ++ fprintf(fp, "%sPROTNONE", others++ ? "|" : ""); ++ if (pte & _PAGE_GLOBAL) ++ fprintf(fp, "%sGLOBAL", others++ ? "|" : ""); ++ if (pte & _PAGE_NX) ++ fprintf(fp, "%sNX", others++ ? "|" : ""); ++ } else { ++ fprintf(fp, "no mapping"); ++ } ++ ++ fprintf(fp, ")\n"); ++ ++ return (page_present); ++} ++ ++static char * ++x86_64_exception_stacks[7] = { ++ "STACKFAULT", ++ "DOUBLEFAULT", ++ "NMI", ++ "DEBUG", ++ "MCE", ++ "(unknown)", ++ "(unknown)" ++}; ++ ++/* ++ * Look for likely exception frames in a stack. ++ */ ++static int ++x86_64_eframe_search(struct bt_info *bt) ++{ ++ int i, c, cnt; ++ ulong estack, irqstack, stacksize; ++ ulong *up; ++ struct machine_specific *ms; ++ struct bt_info bt_local; ++ ++ if (bt->flags & BT_EFRAME_SEARCH2) { ++ BCOPY(bt, &bt_local, sizeof(struct bt_info)); ++ bt->flags &= ~(ulonglong)BT_EFRAME_SEARCH2; ++ ++ ms = machdep->machspec; ++ ++ for (c = 0; c < kt->cpus; c++) { ++ if (ms->stkinfo.ibase[c] == 0) ++ break; ++ bt->hp->esp = ms->stkinfo.ibase[c]; ++ fprintf(fp, "CPU %d IRQ STACK:\n", c); ++ if ((cnt = x86_64_eframe_search(bt))) ++ fprintf(fp, "\n"); ++ else ++ fprintf(fp, "(none found)\n\n"); ++ } ++ ++ for (c = 0; c < kt->cpus; c++) { ++ for (i = 0; i < 7; i++) { ++ if (ms->stkinfo.ebase[c][i] == 0) ++ break; ++ bt->hp->esp = ms->stkinfo.ebase[c][i]; ++ fprintf(fp, "CPU %d %s EXCEPTION STACK:\n", ++ c, x86_64_exception_stacks[i]); ++ if ((cnt = x86_64_eframe_search(bt))) ++ fprintf(fp, "\n"); ++ else ++ fprintf(fp, "(none found)\n\n"); ++ } ++ } ++ ++ return 0; ++ } ++ ++ if (bt->hp && bt->hp->esp) { ++ ms = machdep->machspec; ++ bt->stkptr = bt->hp->esp; ++ if ((estack = x86_64_in_exception_stack(bt))) { ++ stacksize = ms->stkinfo.esize; ++ bt->stackbase = estack; ++ bt->stacktop = estack + ms->stkinfo.esize; ++ bt->stackbuf = ms->irqstack; ++ alter_stackbuf(bt); ++ } else if ((irqstack = x86_64_in_irqstack(bt))) { ++ stacksize = ms->stkinfo.isize; ++ bt->stackbase = irqstack; ++ bt->stacktop = irqstack + ms->stkinfo.isize; ++ bt->stackbuf = ms->irqstack; ++ alter_stackbuf(bt); ++ } else if (!INSTACK(bt->stkptr, bt)) ++ error(FATAL, ++ "unrecognized stack address for this task: %lx\n", ++ bt->hp->esp); ++ } ++ ++ stacksize = bt->stacktop - bt->stackbase - SIZE(pt_regs); ++ ++ if (bt->stkptr) ++ i = (bt->stkptr - bt->stackbase)/sizeof(ulong); ++ else ++ i = 0; ++ ++ for (cnt = 0; i <= stacksize/sizeof(ulong); i++) { ++ up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]); ++ ++ if (x86_64_exception_frame(EFRAME_SEARCH|EFRAME_PRINT| ++ EFRAME_VERIFY, 0, (char *)up, bt, fp)) ++ cnt++; ++ } ++ ++ return cnt; ++} ++ ++static void ++x86_64_display_full_frame(struct bt_info *bt, ulong rsp, FILE *ofp) ++{ ++ int i, u_idx; ++ ulong *up; ++ ulong words, addr; ++ + if (rsp < bt->frameptr) + return; + - words = (rsp - bt->frameptr) / sizeof(ulong) + 1; - - addr = bt->frameptr; -@@ -1308,7 +1864,7 @@ - (rsp < (ms->stkinfo.ebase[c][i] + - ms->stkinfo.esize))) { - estack = ms->stkinfo.ebase[c][i]; -- if (c != bt->tc->processor) ++ words = (rsp - bt->frameptr) / sizeof(ulong) + 1; ++ ++ addr = bt->frameptr; ++ u_idx = (bt->frameptr - bt->stackbase)/sizeof(ulong); ++ for (i = 0; i < words; i++, u_idx++) { ++ if (!(i & 1)) ++ fprintf(ofp, "%s %lx: ", i ? "\n" : "", addr); ++ ++ up = (ulong *)(&bt->stackbuf[u_idx*sizeof(ulong)]); ++ fprintf(ofp, "%016lx ", *up); ++ addr += sizeof(ulong); ++ } ++ fprintf(ofp, "\n"); ++} ++ ++/* ++ * Check a frame for a requested reference. ++ */ ++static void ++x86_64_do_bt_reference_check(struct bt_info *bt, ulong text, char *name) ++{ ++ struct syment *sp; ++ ulong offset; ++ ++ if (!name) ++ sp = value_search(text, &offset); ++ else if (!text) ++ sp = symbol_search(name); ++ ++ switch (bt->ref->cmdflags & (BT_REF_SYMBOL|BT_REF_HEXVAL)) ++ { ++ case BT_REF_SYMBOL: ++ if (name) { ++ if (STREQ(name, bt->ref->str)) ++ bt->ref->cmdflags |= BT_REF_FOUND; ++ } else { ++ if (sp && !offset && STREQ(sp->name, bt->ref->str)) ++ bt->ref->cmdflags |= BT_REF_FOUND; ++ } ++ break; ++ ++ case BT_REF_HEXVAL: ++ if (text) { ++ if (bt->ref->hexval == text) ++ bt->ref->cmdflags |= BT_REF_FOUND; ++ } else if (sp && (bt->ref->hexval == sp->value)) ++ bt->ref->cmdflags |= BT_REF_FOUND; ++ else if (!name && !text && (bt->ref->hexval == 0)) ++ bt->ref->cmdflags |= BT_REF_FOUND; ++ break; ++ } ++} ++ ++/* ++ * Determine the function containing a .text.lock. reference. ++ */ ++static ulong ++text_lock_function(char *name, struct bt_info *bt, ulong locktext) ++{ ++ int c, reterror, instr, arg; ++ char buf[BUFSIZE]; ++ char *arglist[MAXARGS]; ++ char *p1; ++ ulong locking_func; ++ ++ instr = arg = -1; ++ locking_func = 0; ++ ++ open_tmpfile2(); ++ ++ if (STREQ(name, ".text.lock.spinlock")) ++ sprintf(buf, "x/4i 0x%lx", locktext); ++ else ++ sprintf(buf, "x/1i 0x%lx", locktext); ++ ++ if (!gdb_pass_through(buf, pc->tmpfile2, GNU_RETURN_ON_ERROR)) { ++ close_tmpfile2(); ++ bt->flags |= BT_FRAMESIZE_DISABLE; ++ return 0; ++ } ++ ++ rewind(pc->tmpfile2); ++ while (fgets(buf, BUFSIZE, pc->tmpfile2)) { ++ c = parse_line(buf, arglist); ++ ++ if (instr == -1) { ++ /* ++ * Check whether are ++ * in the output string. ++ */ ++ if (LASTCHAR(arglist[0]) == ':') { ++ instr = 1; ++ arg = 2; ++ } else { ++ instr = 2; ++ arg = 3; ++ } ++ } ++ ++ if (c < (arg+1)) ++ break; ++ ++ if (STREQ(arglist[instr], "jmpq") || STREQ(arglist[instr], "jmp")) { ++ p1 = arglist[arg]; ++ reterror = 0; ++ locking_func = htol(p1, RETURN_ON_ERROR, &reterror); ++ if (reterror) ++ locking_func = 0; ++ break; ++ } ++ } ++ close_tmpfile2(); ++ ++ if (!locking_func) ++ bt->flags |= BT_FRAMESIZE_DISABLE; ++ ++ return locking_func; ++ ++} ++ ++ ++/* ++ * print one entry of a stack trace ++ */ ++#define BACKTRACE_COMPLETE (1) ++#define BACKTRACE_ENTRY_IGNORED (2) ++#define BACKTRACE_ENTRY_DISPLAYED (3) ++#define BACKTRACE_ENTRY_AND_EFRAME_DISPLAYED (4) ++ ++static int ++x86_64_print_stack_entry(struct bt_info *bt, FILE *ofp, int level, ++ int stkindex, ulong text) ++{ ++ ulong rsp, offset, locking_func; ++ struct syment *sp, *spl; ++ char *name; ++ int result; ++ long eframe_check; ++ char buf[BUFSIZE]; ++ ++ eframe_check = -1; ++ offset = 0; ++ sp = value_search(text, &offset); ++ if (!sp) ++ return BACKTRACE_ENTRY_IGNORED; ++ ++ name = sp->name; ++ ++ if (bt->flags & BT_TEXT_SYMBOLS) { ++ if (bt->flags & BT_EXCEPTION_FRAME) ++ rsp = bt->stkptr; ++ else ++ rsp = bt->stackbase + (stkindex * sizeof(long)); ++ fprintf(ofp, " [%s] %s at %lx\n", ++ mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, MKSTR(rsp)), ++ name, text); ++ if (BT_REFERENCE_CHECK(bt)) ++ x86_64_do_bt_reference_check(bt, text, name); ++ return BACKTRACE_ENTRY_DISPLAYED; ++ } ++ ++ if (!offset && !(bt->flags & BT_EXCEPTION_FRAME) && ++ !(bt->flags & BT_START)) { ++ if (STREQ(name, "child_rip")) { ++ if (symbol_exists("kernel_thread")) ++ name = "kernel_thread"; ++ else if (symbol_exists("arch_kernel_thread")) ++ name = "arch_kernel_thread"; ++ } ++ else if (!(bt->flags & BT_SCHEDULE)) { ++ if (STREQ(name, "error_exit")) ++ eframe_check = 8; ++ else { ++ if (CRASHDEBUG(2)) ++ fprintf(ofp, ++ "< ignoring text symbol with no offset: %s() >\n", ++ sp->name); ++ return BACKTRACE_ENTRY_IGNORED; ++ } ++ } ++ } ++ ++ if (bt->flags & BT_SCHEDULE) ++ name = "schedule"; ++ ++ if (STREQ(name, "child_rip")) { ++ if (symbol_exists("kernel_thread")) ++ name = "kernel_thread"; ++ else if (symbol_exists("arch_kernel_thread")) ++ name = "arch_kernel_thread"; ++ result = BACKTRACE_COMPLETE; ++ } else if (STREQ(name, "cpu_idle")) ++ result = BACKTRACE_COMPLETE; ++ else ++ result = BACKTRACE_ENTRY_DISPLAYED; ++ ++ if (bt->flags & BT_EXCEPTION_FRAME) ++ rsp = bt->stkptr; ++ else if (bt->flags & BT_START) ++ rsp = bt->stkptr; ++ else ++ rsp = bt->stackbase + (stkindex * sizeof(long)); ++ ++ if ((bt->flags & BT_FULL)) { ++ if (bt->frameptr) ++ x86_64_display_full_frame(bt, rsp, ofp); ++ bt->frameptr = rsp + sizeof(ulong); ++ } ++ ++ fprintf(ofp, "%s#%d [%8lx] %s at %lx", level < 10 ? " " : "", level, ++ rsp, name, text); ++ ++ if (STREQ(name, "tracesys")) ++ fprintf(ofp, " (via system_call)"); ++ else if (STRNEQ(name, ".text.lock.")) { ++ if ((locking_func = text_lock_function(name, bt, text)) && ++ (spl = value_search(locking_func, &offset))) ++ fprintf(ofp, " (via %s)", spl->name); ++ } ++ ++ if (bt->flags & BT_FRAMESIZE_DISABLE) ++ fprintf(ofp, " *"); ++ ++ fprintf(ofp, "\n"); ++ ++ if (bt->flags & BT_LINE_NUMBERS) { ++ get_line_number(text, buf, FALSE); ++ if (strlen(buf)) ++ fprintf(ofp, " %s\n", buf); ++ } ++ ++ if (eframe_check >= 0) { ++ if (x86_64_exception_frame(EFRAME_PRINT|EFRAME_VERIFY, ++ bt->stackbase + (stkindex*sizeof(long)) + eframe_check, ++ NULL, bt, ofp)) ++ result = BACKTRACE_ENTRY_AND_EFRAME_DISPLAYED; ++ } ++ ++ if (BT_REFERENCE_CHECK(bt)) ++ x86_64_do_bt_reference_check(bt, text, name); ++ ++ bt->call_target = name; ++ ++ if (is_direct_call_target(bt)) { ++ if (CRASHDEBUG(2)) ++ fprintf(ofp, "< enable BT_CHECK_CALLER for %s >\n", ++ bt->call_target); ++ bt->flags |= BT_CHECK_CALLER; ++ } else { ++ if (CRASHDEBUG(2) && (bt->flags & BT_CHECK_CALLER)) ++ fprintf(ofp, "< disable BT_CHECK_CALLER for %s >\n", ++ bt->call_target); ++ if (bt->flags & BT_CHECK_CALLER) { ++ if (CRASHDEBUG(2)) ++ fprintf(ofp, "< set BT_NO_CHECK_CALLER >\n"); ++ bt->flags |= BT_NO_CHECK_CALLER; ++ } ++ bt->flags &= ~(ulonglong)BT_CHECK_CALLER; ++ } ++ ++ return result; ++} ++ ++/* ++ * Unroll a kernel stack. ++ */ ++static void ++x86_64_back_trace_cmd(struct bt_info *bt) ++{ ++ error(FATAL, "x86_64_back_trace_cmd: TBD\n"); ++} ++ ++ ++ ++/* ++ * Determine whether the initial stack pointer is located in one of the ++ * exception stacks. ++ */ ++static ulong ++x86_64_in_exception_stack(struct bt_info *bt) ++{ ++ int c, i; ++ ulong rsp; ++ ulong estack; ++ struct machine_specific *ms; ++ ++ rsp = bt->stkptr; ++ ms = machdep->machspec; ++ estack = 0; ++ ++ for (c = 0; !estack && (c < kt->cpus); c++) { ++ for (i = 0; i < 7; i++) { ++ if (ms->stkinfo.ebase[c][i] == 0) ++ break; ++ if ((rsp >= ms->stkinfo.ebase[c][i]) && ++ (rsp < (ms->stkinfo.ebase[c][i] + ++ ms->stkinfo.esize))) { ++ estack = ms->stkinfo.ebase[c][i]; + if (CRASHDEBUG(1) && (c != bt->tc->processor)) - error(INFO, - "task cpu: %d exception stack cpu: %d\n", - bt->tc->processor, c); -@@ -1341,7 +1897,7 @@ - if ((rsp >= ms->stkinfo.ibase[c]) && - (rsp < (ms->stkinfo.ibase[c] + ms->stkinfo.isize))) { - irqstack = ms->stkinfo.ibase[c]; -- if (c != bt->tc->processor) ++ error(INFO, ++ "task cpu: %d exception stack cpu: %d\n", ++ bt->tc->processor, c); ++ break; ++ } ++ } ++ } ++ ++ return estack; ++} ++ ++/* ++ * Determine whether the current stack pointer is in a cpu's irqstack. ++ */ ++static ulong ++x86_64_in_irqstack(struct bt_info *bt) ++{ ++ int c; ++ ulong rsp; ++ ulong irqstack; ++ struct machine_specific *ms; ++ ++ rsp = bt->stkptr; ++ ms = machdep->machspec; ++ irqstack = 0; ++ ++ for (c = 0; !irqstack && (c < kt->cpus); c++) { ++ if (ms->stkinfo.ibase[c] == 0) ++ break; ++ if ((rsp >= ms->stkinfo.ibase[c]) && ++ (rsp < (ms->stkinfo.ibase[c] + ms->stkinfo.isize))) { ++ irqstack = ms->stkinfo.ibase[c]; + if (CRASHDEBUG(1) && (c != bt->tc->processor)) - error(INFO, - "task cpu: %d IRQ stack cpu: %d\n", - bt->tc->processor, c); -@@ -1399,12 +1955,13 @@ - ofp = fp; - - if (bt->flags & BT_TEXT_SYMBOLS) { -- fprintf(ofp, "%sSTART: %s%s at %lx\n", -- space(VADDR_PRLEN > 8 ? 14 : 6), -- closest_symbol(bt->instptr), -- STREQ(closest_symbol(bt->instptr), "thread_return") ? -- " (schedule)" : "", -- bt->instptr); ++ error(INFO, ++ "task cpu: %d IRQ stack cpu: %d\n", ++ bt->tc->processor, c); ++ break; ++ } ++ } ++ ++ return irqstack; ++} ++ ++#define STACK_TRANSITION_ERRMSG_E_I_P \ ++"cannot transition from exception stack to IRQ stack to current process stack:\n exception stack pointer: %lx\n IRQ stack pointer: %lx\n process stack pointer: %lx\n current stack base: %lx\n" ++#define STACK_TRANSITION_ERRMSG_E_P \ ++"cannot transition from exception stack to current process stack:\n exception stack pointer: %lx\n process stack pointer: %lx\n current_stack_base: %lx\n" ++#define STACK_TRANSITION_ERRMSG_I_P \ ++"cannot transition from IRQ stack to current process stack:\n IRQ stack pointer: %lx\n process stack pointer: %lx\n current stack base: %lx" ++ ++/* ++ * Low-budget back tracer -- dump text return addresses, following call chain ++ * when possible, along with any verifiable exception frames. ++ */ ++static void ++x86_64_low_budget_back_trace_cmd(struct bt_info *bt_in) ++{ ++ int i, level, done, framesize; ++ ulong rsp, offset, stacktop; ++ ulong *up; ++ long cs; ++ struct syment *sp, *spt; ++ FILE *ofp; ++ ulong estack, irqstack; ++ ulong irq_eframe; ++ struct bt_info bt_local, *bt; ++ struct machine_specific *ms; ++ ulong last_process_stack_eframe; ++ ulong user_mode_eframe; ++ ++ /* ++ * User may have made a run-time switch. ++ */ ++ if (kt->flags & DWARF_UNWIND) { ++ machdep->back_trace = x86_64_dwarf_back_trace_cmd; ++ x86_64_dwarf_back_trace_cmd(bt_in); ++ return; ++ } ++ ++ bt = &bt_local; ++ BCOPY(bt_in, bt, sizeof(struct bt_info)); ++ ++ if (bt->flags & BT_FRAMESIZE_DEBUG) { ++ x86_64_framesize_debug(bt); ++ return; ++ } ++ ++ level = 0; ++ done = FALSE; ++ irq_eframe = 0; ++ last_process_stack_eframe = 0; ++ bt->call_target = NULL; ++ rsp = bt->stkptr; ++ if (!rsp) { ++ error(INFO, "cannot determine starting stack pointer\n"); ++ return; ++ } ++ ms = machdep->machspec; ++ if (BT_REFERENCE_CHECK(bt)) ++ ofp = pc->nullfp; ++ else ++ ofp = fp; ++ ++ if (bt->flags & BT_TEXT_SYMBOLS) { + if (!(bt->flags & BT_TEXT_SYMBOLS_ALL)) + fprintf(ofp, "%sSTART: %s%s at %lx\n", + space(VADDR_PRLEN > 8 ? 14 : 6), @@ -17012,56 +25388,901 @@ + STREQ(closest_symbol(bt->instptr), "thread_return") ? + " (schedule)" : "", + bt->instptr); - } else if (bt->flags & BT_START) { - x86_64_print_stack_entry(bt, ofp, level, - 0, bt->instptr); -@@ -1647,8 +2204,12 @@ - bt->stackbuf + (irq_eframe - bt->stackbase), bt, ofp); - if (cs & 3) - done = TRUE; /* IRQ from user-mode */ -- else ++ } else if (bt->flags & BT_START) { ++ x86_64_print_stack_entry(bt, ofp, level, ++ 0, bt->instptr); ++ bt->flags &= ~BT_START; ++ level++; ++ } ++ ++ ++ if ((estack = x86_64_in_exception_stack(bt))) { ++in_exception_stack: ++ bt->flags |= BT_EXCEPTION_STACK; ++ /* ++ * The stack buffer will have been loaded with the process ++ * stack, so switch to the indicated exception stack. ++ */ ++ bt->stackbase = estack; ++ bt->stacktop = estack + ms->stkinfo.esize; ++ bt->stackbuf = ms->irqstack; ++ ++ if (!readmem(bt->stackbase, KVADDR, bt->stackbuf, ++ bt->stacktop - bt->stackbase, ++ bt->hp && (bt->hp->esp == bt->stkptr) ? ++ "irqstack contents via hook" : "irqstack contents", ++ RETURN_ON_ERROR)) ++ error(FATAL, "read of exception stack at %lx failed\n", ++ bt->stackbase); ++ ++ /* ++ * If irq_eframe is set, we've jumped back here from the ++ * IRQ stack dump below. Do basically the same thing as if ++ * had come from the processor stack, but presume that we ++ * must have been in kernel mode, i.e., took an exception ++ * while operating on an IRQ stack. (untested) ++ */ ++ if (irq_eframe) { ++ bt->flags |= BT_EXCEPTION_FRAME; ++ i = (irq_eframe - bt->stackbase)/sizeof(ulong); ++ x86_64_print_stack_entry(bt, ofp, level, i, ++ bt->instptr); ++ bt->flags &= ~(ulonglong)BT_EXCEPTION_FRAME; ++ cs = x86_64_exception_frame(EFRAME_PRINT|EFRAME_CS, 0, ++ bt->stackbuf + (irq_eframe - bt->stackbase), ++ bt, ofp); ++ rsp += SIZE(pt_regs); /* guaranteed kernel mode */ ++ level++; ++ irq_eframe = 0; ++ } ++ ++ stacktop = bt->stacktop - SIZE(pt_regs); ++ ++ bt->flags &= ~BT_FRAMESIZE_DISABLE; ++ ++ for (i = (rsp - bt->stackbase)/sizeof(ulong); ++ !done && (rsp < stacktop); i++, rsp += sizeof(ulong)) { ++ ++ up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]); ++ ++ if (!is_kernel_text(*up)) ++ continue; ++ ++ switch (x86_64_print_stack_entry(bt, ofp, level, i,*up)) ++ { ++ case BACKTRACE_ENTRY_AND_EFRAME_DISPLAYED: ++ rsp += SIZE(pt_regs); ++ i += SIZE(pt_regs)/sizeof(ulong); ++ case BACKTRACE_ENTRY_DISPLAYED: ++ level++; ++ if ((framesize = x86_64_get_framesize(bt, *up)) >= 0) { ++ rsp += framesize; ++ i += framesize/sizeof(ulong); ++ } ++ break; ++ case BACKTRACE_ENTRY_IGNORED: ++ break; ++ case BACKTRACE_COMPLETE: ++ done = TRUE; ++ break; ++ } ++ } ++ ++ cs = x86_64_exception_frame(EFRAME_PRINT|EFRAME_CS, 0, ++ bt->stackbuf + (bt->stacktop - bt->stackbase) - ++ SIZE(pt_regs), bt, ofp); ++ ++ if (!BT_REFERENCE_CHECK(bt)) ++ fprintf(fp, "--- ---\n"); ++ ++ /* ++ * stack = (unsigned long *) estack_end[-2]; ++ */ ++ up = (ulong *)(&bt->stackbuf[bt->stacktop - bt->stackbase]); ++ up -= 2; ++ rsp = bt->stkptr = *up; ++ up -= 3; ++ bt->instptr = *up; ++ if (cs & 3) ++ done = TRUE; /* user-mode exception */ ++ else ++ done = FALSE; /* kernel-mode exception */ ++ bt->frameptr = 0; ++ ++ /* ++ * Print the return values from the estack end. ++ */ ++ if (!done) { ++ bt->flags |= BT_START; ++ x86_64_print_stack_entry(bt, ofp, level, ++ 0, bt->instptr); ++ bt->flags &= ~(BT_START|BT_FRAMESIZE_DISABLE); ++ level++; ++ if ((framesize = x86_64_get_framesize(bt, bt->instptr)) >= 0) ++ rsp += framesize; ++ } ++ } ++ ++ /* ++ * IRQ stack entry always comes in via the process stack, regardless ++ * whether it happened while running in user or kernel space. ++ */ ++ if (!done && (irqstack = x86_64_in_irqstack(bt))) { ++ bt->flags |= BT_IRQSTACK; ++ /* ++ * Until coded otherwise, the stackbase will be pointing to ++ * either the exception stack or, more likely, the process ++ * stack base. Switch it to the IRQ stack. ++ */ ++ bt->stackbase = irqstack; ++ bt->stacktop = irqstack + ms->stkinfo.isize; ++ bt->stackbuf = ms->irqstack; ++ ++ if (!readmem(bt->stackbase, KVADDR, ++ bt->stackbuf, bt->stacktop - bt->stackbase, ++ bt->hp && (bt->hp->esp == bt_in->stkptr) ? ++ "irqstack contents via hook" : "irqstack contents", ++ RETURN_ON_ERROR)) ++ error(FATAL, "read of IRQ stack at %lx failed\n", ++ bt->stackbase); ++ ++ stacktop = bt->stacktop - 64; /* from kernel code */ ++ ++ bt->flags &= ~BT_FRAMESIZE_DISABLE; ++ ++ for (i = (rsp - bt->stackbase)/sizeof(ulong); ++ !done && (rsp < stacktop); i++, rsp += sizeof(ulong)) { ++ ++ up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]); ++ ++ if (!is_kernel_text(*up)) ++ continue; ++ ++ switch (x86_64_print_stack_entry(bt, ofp, level, i,*up)) ++ { ++ case BACKTRACE_ENTRY_AND_EFRAME_DISPLAYED: ++ rsp += SIZE(pt_regs); ++ i += SIZE(pt_regs)/sizeof(ulong); ++ case BACKTRACE_ENTRY_DISPLAYED: ++ level++; ++ if ((framesize = x86_64_get_framesize(bt, *up)) >= 0) { ++ rsp += framesize; ++ i += framesize/sizeof(ulong); ++ } ++ break; ++ case BACKTRACE_ENTRY_IGNORED: ++ break; ++ case BACKTRACE_COMPLETE: ++ done = TRUE; ++ break; ++ } ++ } ++ ++ if (!BT_REFERENCE_CHECK(bt)) ++ fprintf(fp, "--- ---\n"); ++ ++ /* ++ * stack = (unsigned long *) (irqstack_end[-1]); ++ * (where irqstack_end is 64 bytes below page end) ++ */ ++ up = (ulong *)(&bt->stackbuf[stacktop - bt->stackbase]); ++ up -= 1; ++ irq_eframe = rsp = bt->stkptr = (*up) - ms->irq_eframe_link; ++ up -= 1; ++ bt->instptr = *up; ++ /* ++ * No exception frame when coming from call_softirq. ++ */ ++ if ((sp = value_search(bt->instptr, &offset)) && ++ STREQ(sp->name, "call_softirq")) ++ irq_eframe = 0; ++ bt->frameptr = 0; ++ done = FALSE; ++ } else ++ irq_eframe = 0; ++ ++ if (!done && (estack = x86_64_in_exception_stack(bt))) ++ goto in_exception_stack; ++ ++ if (!done && (bt->flags & (BT_EXCEPTION_STACK|BT_IRQSTACK))) { ++ /* ++ * Verify that the rsp pointer taken from either the ++ * exception or IRQ stack points into the process stack. ++ */ ++ bt->stackbase = GET_STACKBASE(bt->tc->task); ++ bt->stacktop = GET_STACKTOP(bt->tc->task); ++ ++ if (!INSTACK(rsp, bt)) { ++ switch (bt->flags & (BT_EXCEPTION_STACK|BT_IRQSTACK)) ++ { ++ case (BT_EXCEPTION_STACK|BT_IRQSTACK): ++ error(FATAL, STACK_TRANSITION_ERRMSG_E_I_P, ++ bt_in->stkptr, bt->stkptr, rsp, ++ bt->stackbase); ++ ++ case BT_EXCEPTION_STACK: ++ error(FATAL, STACK_TRANSITION_ERRMSG_E_P, ++ bt_in->stkptr, rsp, bt->stackbase); ++ ++ case BT_IRQSTACK: ++ error(FATAL, STACK_TRANSITION_ERRMSG_I_P, ++ bt_in->stkptr, rsp, bt->stackbase); ++ } ++ } ++ ++ /* ++ * Now fill the local stack buffer from the process stack. ++ */ ++ if (!readmem(bt->stackbase, KVADDR, bt->stackbuf, ++ bt->stacktop - bt->stackbase, ++ "irqstack contents", RETURN_ON_ERROR)) ++ error(FATAL, "read of process stack at %lx failed\n", ++ bt->stackbase); ++ } ++ ++ /* ++ * For a normally blocked task, hand-create the first level. ++ */ ++ if (!done && ++ !(bt->flags & (BT_TEXT_SYMBOLS|BT_EXCEPTION_STACK|BT_IRQSTACK)) && ++ STREQ(closest_symbol(bt->instptr), "thread_return")) { ++ bt->flags |= BT_SCHEDULE; ++ i = (rsp - bt->stackbase)/sizeof(ulong); ++ x86_64_print_stack_entry(bt, ofp, level, ++ i, bt->instptr); ++ bt->flags &= ~(ulonglong)BT_SCHEDULE; ++ rsp += sizeof(ulong); ++ level++; ++ } ++ ++ /* ++ * Dump the IRQ exception frame from the process stack. ++ * If the CS register indicates a user exception frame, ++ * then set done to TRUE to avoid the process stack walk-through. ++ * Otherwise, bump up the rsp past the kernel-mode eframe. ++ */ ++ if (irq_eframe) { ++ bt->flags |= BT_EXCEPTION_FRAME; ++ i = (irq_eframe - bt->stackbase)/sizeof(ulong); ++ x86_64_print_stack_entry(bt, ofp, level, i, bt->instptr); ++ bt->flags &= ~(ulonglong)BT_EXCEPTION_FRAME; ++ cs = x86_64_exception_frame(EFRAME_PRINT|EFRAME_CS, 0, ++ bt->stackbuf + (irq_eframe - bt->stackbase), bt, ofp); ++ if (cs & 3) ++ done = TRUE; /* IRQ from user-mode */ + else { + if (x86_64_print_eframe_location(rsp, level, ofp)) + level++; - rsp += SIZE(pt_regs); ++ rsp += SIZE(pt_regs); + irq_eframe = 0; + } - level++; - } - -@@ -1691,6 +2252,10 @@ - bt->call_target); - continue; - } ++ level++; ++ } ++ ++ /* ++ * Walk the process stack. ++ */ ++ ++ bt->flags &= ~BT_FRAMESIZE_DISABLE; ++ ++ for (i = (rsp - bt->stackbase)/sizeof(ulong); ++ !done && (rsp < bt->stacktop); i++, rsp += sizeof(ulong)) { ++ ++ up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]); ++ ++ if (!is_kernel_text(*up)) ++ continue; ++ ++ if ((bt->flags & BT_CHECK_CALLER)) { ++ /* ++ * A non-zero offset value from the value_search() ++ * lets us know if it's a real text return address. ++ */ ++ spt = value_search(*up, &offset); ++ if (!offset && !(bt->flags & BT_FRAMESIZE_DISABLE)) ++ continue; ++ ++ /* ++ * sp gets the syment of the function that the text ++ * routine above called before leaving its return ++ * address on the stack -- if it can be determined. ++ */ ++ sp = x86_64_function_called_by((*up)-5); ++ ++ if (sp == NULL) { ++ /* ++ * We were unable to get the called function. ++ * If the text address had an offset, then ++ * it must have made an indirect call, and ++ * can't have called our target function. ++ */ ++ if (offset) { ++ if (CRASHDEBUG(1)) ++ fprintf(ofp, ++ "< ignoring %s() -- makes indirect call and NOT %s()>\n", ++ spt->name, ++ bt->call_target); ++ continue; ++ } + } else if ((machdep->flags & SCHED_TEXT) && + STREQ(bt->call_target, "schedule") && + STREQ(sp->name, "__sched_text_start")) { + ; /* bait and switch */ - } else if (!STREQ(sp->name, bt->call_target)) { - /* - * We got function called by the text routine, -@@ -1709,6 +2274,8 @@ - { - case BACKTRACE_ENTRY_AND_EFRAME_DISPLAYED: - last_process_stack_eframe = rsp + 8; ++ } else if (!STREQ(sp->name, bt->call_target)) { ++ /* ++ * We got function called by the text routine, ++ * but it's not our target function. ++ */ ++ if (CRASHDEBUG(2)) ++ fprintf(ofp, ++ "< ignoring %s() -- calls %s() and NOT %s()>\n", ++ spt->name, sp->name, ++ bt->call_target); ++ continue; ++ } ++ } ++ ++ switch (x86_64_print_stack_entry(bt, ofp, level, i,*up)) ++ { ++ case BACKTRACE_ENTRY_AND_EFRAME_DISPLAYED: ++ last_process_stack_eframe = rsp + 8; + if (x86_64_print_eframe_location(last_process_stack_eframe, level, ofp)) + level++; - rsp += SIZE(pt_regs); - i += SIZE(pt_regs)/sizeof(ulong); - case BACKTRACE_ENTRY_DISPLAYED: -@@ -1842,6 +2409,8 @@ - long rax, rbx, rcx, rdx, rsi, rdi; - long r8, r9, r10, r11, r12, r13, r14, r15; - struct machine_specific *ms; ++ rsp += SIZE(pt_regs); ++ i += SIZE(pt_regs)/sizeof(ulong); ++ case BACKTRACE_ENTRY_DISPLAYED: ++ level++; ++ if ((framesize = x86_64_get_framesize(bt, *up)) >= 0) { ++ rsp += framesize; ++ i += framesize/sizeof(ulong); ++ } ++ break; ++ case BACKTRACE_ENTRY_IGNORED: ++ break; ++ case BACKTRACE_COMPLETE: ++ done = TRUE; ++ break; ++ } ++ } ++ ++ if (!irq_eframe && !is_kernel_thread(bt->tc->task) && ++ (GET_STACKBASE(bt->tc->task) == bt->stackbase)) { ++ user_mode_eframe = bt->stacktop - SIZE(pt_regs); ++ if (last_process_stack_eframe < user_mode_eframe) ++ x86_64_exception_frame(EFRAME_PRINT, 0, bt->stackbuf + ++ (bt->stacktop - bt->stackbase) - SIZE(pt_regs), ++ bt, ofp); ++ } ++ ++ if (bt->flags & BT_TEXT_SYMBOLS) { ++ if (BT_REFERENCE_FOUND(bt)) { ++ print_task_header(fp, task_to_context(bt->task), 0); ++ BCOPY(bt_in, bt, sizeof(struct bt_info)); ++ bt->ref = NULL; ++ machdep->back_trace(bt); ++ fprintf(fp, "\n"); ++ } ++ } ++} ++ ++/* ++ * Use dwarf CFI encodings to correctly follow the call chain. ++ */ ++static void ++x86_64_dwarf_back_trace_cmd(struct bt_info *bt_in) ++{ ++ int i, level, done; ++ ulong rsp, offset, stacktop; ++ ulong *up; ++ long cs; ++ struct syment *sp; ++ FILE *ofp; ++ ulong estack, irqstack; ++ ulong irq_eframe; ++ struct bt_info bt_local, *bt; ++ struct machine_specific *ms; ++ ulong last_process_stack_eframe; ++ ulong user_mode_eframe; ++ ++ /* ++ * User may have made a run-time switch. ++ */ ++ if (!(kt->flags & DWARF_UNWIND)) { ++ machdep->back_trace = x86_64_low_budget_back_trace_cmd; ++ x86_64_low_budget_back_trace_cmd(bt_in); ++ return; ++ } ++ ++ bt = &bt_local; ++ BCOPY(bt_in, bt, sizeof(struct bt_info)); ++ ++ if (bt->flags & BT_FRAMESIZE_DEBUG) { ++ dwarf_debug(bt); ++ return; ++ } ++ ++ level = 0; ++ done = FALSE; ++ irq_eframe = 0; ++ last_process_stack_eframe = 0; ++ bt->call_target = NULL; ++ bt->bptr = 0; ++ rsp = bt->stkptr; ++ if (!rsp) { ++ error(INFO, "cannot determine starting stack pointer\n"); ++ return; ++ } ++ ms = machdep->machspec; ++ if (BT_REFERENCE_CHECK(bt)) ++ ofp = pc->nullfp; ++ else ++ ofp = fp; ++ ++ if (bt->flags & BT_TEXT_SYMBOLS) { ++ if (!(bt->flags & BT_TEXT_SYMBOLS_ALL)) ++ fprintf(ofp, "%sSTART: %s%s at %lx\n", ++ space(VADDR_PRLEN > 8 ? 14 : 6), ++ closest_symbol(bt->instptr), ++ STREQ(closest_symbol(bt->instptr), "thread_return") ? ++ " (schedule)" : "", ++ bt->instptr); ++ } else if (bt->flags & BT_START) { ++ x86_64_print_stack_entry(bt, ofp, level, ++ 0, bt->instptr); ++ bt->flags &= ~BT_START; ++ level++; ++ } ++ ++ ++ if ((estack = x86_64_in_exception_stack(bt))) { ++in_exception_stack: ++ bt->flags |= BT_EXCEPTION_STACK; ++ /* ++ * The stack buffer will have been loaded with the process ++ * stack, so switch to the indicated exception stack. ++ */ ++ bt->stackbase = estack; ++ bt->stacktop = estack + ms->stkinfo.esize; ++ bt->stackbuf = ms->irqstack; ++ ++ if (!readmem(bt->stackbase, KVADDR, bt->stackbuf, ++ bt->stacktop - bt->stackbase, ++ bt->hp && (bt->hp->esp == bt->stkptr) ? ++ "irqstack contents via hook" : "irqstack contents", ++ RETURN_ON_ERROR)) ++ error(FATAL, "read of exception stack at %lx failed\n", ++ bt->stackbase); ++ ++ /* ++ * If irq_eframe is set, we've jumped back here from the ++ * IRQ stack dump below. Do basically the same thing as if ++ * had come from the processor stack, but presume that we ++ * must have been in kernel mode, i.e., took an exception ++ * while operating on an IRQ stack. (untested) ++ */ ++ if (irq_eframe) { ++ bt->flags |= BT_EXCEPTION_FRAME; ++ i = (irq_eframe - bt->stackbase)/sizeof(ulong); ++ x86_64_print_stack_entry(bt, ofp, level, i, ++ bt->instptr); ++ bt->flags &= ~(ulonglong)BT_EXCEPTION_FRAME; ++ cs = x86_64_exception_frame(EFRAME_PRINT|EFRAME_CS, 0, ++ bt->stackbuf + (irq_eframe - bt->stackbase), ++ bt, ofp); ++ rsp += SIZE(pt_regs); /* guaranteed kernel mode */ ++ level++; ++ irq_eframe = 0; ++ } ++ ++ stacktop = bt->stacktop - SIZE(pt_regs); ++ ++ if (!done) { ++ level = dwarf_backtrace(bt, level, stacktop); ++ done = TRUE; ++ } ++ ++ cs = x86_64_exception_frame(EFRAME_PRINT|EFRAME_CS, 0, ++ bt->stackbuf + (bt->stacktop - bt->stackbase) - ++ SIZE(pt_regs), bt, ofp); ++ ++ if (!BT_REFERENCE_CHECK(bt)) ++ fprintf(fp, "--- ---\n"); ++ ++ /* ++ * stack = (unsigned long *) estack_end[-2]; ++ */ ++ up = (ulong *)(&bt->stackbuf[bt->stacktop - bt->stackbase]); ++ up -= 2; ++ rsp = bt->stkptr = *up; ++ up -= 3; ++ bt->instptr = *up; ++ if (cs & 3) ++ done = TRUE; /* user-mode exception */ ++ else ++ done = FALSE; /* kernel-mode exception */ ++ bt->frameptr = 0; ++ ++ /* ++ * Print the return values from the estack end. ++ */ ++ if (!done) { ++ bt->flags |= BT_START; ++ x86_64_print_stack_entry(bt, ofp, level, ++ 0, bt->instptr); ++ bt->flags &= ~BT_START; ++ level++; ++ } ++ } ++ ++ /* ++ * IRQ stack entry always comes in via the process stack, regardless ++ * whether it happened while running in user or kernel space. ++ */ ++ if (!done && (irqstack = x86_64_in_irqstack(bt))) { ++ bt->flags |= BT_IRQSTACK; ++ /* ++ * Until coded otherwise, the stackbase will be pointing to ++ * either the exception stack or, more likely, the process ++ * stack base. Switch it to the IRQ stack. ++ */ ++ bt->stackbase = irqstack; ++ bt->stacktop = irqstack + ms->stkinfo.isize; ++ bt->stackbuf = ms->irqstack; ++ ++ if (!readmem(bt->stackbase, KVADDR, ++ bt->stackbuf, bt->stacktop - bt->stackbase, ++ bt->hp && (bt->hp->esp == bt_in->stkptr) ? ++ "irqstack contents via hook" : "irqstack contents", ++ RETURN_ON_ERROR)) ++ error(FATAL, "read of IRQ stack at %lx failed\n", ++ bt->stackbase); ++ ++ stacktop = bt->stacktop - 64; /* from kernel code */ ++ ++ if (!done) { ++ level = dwarf_backtrace(bt, level, stacktop); ++ done = TRUE; ++ } ++ ++ if (!BT_REFERENCE_CHECK(bt)) ++ fprintf(fp, "--- ---\n"); ++ ++ /* ++ * stack = (unsigned long *) (irqstack_end[-1]); ++ * (where irqstack_end is 64 bytes below page end) ++ */ ++ up = (ulong *)(&bt->stackbuf[stacktop - bt->stackbase]); ++ up -= 1; ++ irq_eframe = rsp = bt->stkptr = (*up) - ms->irq_eframe_link; ++ up -= 1; ++ bt->instptr = *up; ++ /* ++ * No exception frame when coming from call_softirq. ++ */ ++ if ((sp = value_search(bt->instptr, &offset)) && ++ STREQ(sp->name, "call_softirq")) ++ irq_eframe = 0; ++ bt->frameptr = 0; ++ done = FALSE; ++ } else ++ irq_eframe = 0; ++ ++ if (!done && (estack = x86_64_in_exception_stack(bt))) ++ goto in_exception_stack; ++ ++ if (!done && (bt->flags & (BT_EXCEPTION_STACK|BT_IRQSTACK))) { ++ /* ++ * Verify that the rsp pointer taken from either the ++ * exception or IRQ stack points into the process stack. ++ */ ++ bt->stackbase = GET_STACKBASE(bt->tc->task); ++ bt->stacktop = GET_STACKTOP(bt->tc->task); ++ ++ if (!INSTACK(rsp, bt)) { ++ switch (bt->flags & (BT_EXCEPTION_STACK|BT_IRQSTACK)) ++ { ++ case (BT_EXCEPTION_STACK|BT_IRQSTACK): ++ error(FATAL, STACK_TRANSITION_ERRMSG_E_I_P, ++ bt_in->stkptr, bt->stkptr, rsp, ++ bt->stackbase); ++ ++ case BT_EXCEPTION_STACK: ++ error(FATAL, STACK_TRANSITION_ERRMSG_E_P, ++ bt_in->stkptr, rsp, bt->stackbase); ++ ++ case BT_IRQSTACK: ++ error(FATAL, STACK_TRANSITION_ERRMSG_I_P, ++ bt_in->stkptr, rsp, bt->stackbase); ++ } ++ } ++ ++ /* ++ * Now fill the local stack buffer from the process stack. ++ */ ++ if (!readmem(bt->stackbase, KVADDR, bt->stackbuf, ++ bt->stacktop - bt->stackbase, ++ "irqstack contents", RETURN_ON_ERROR)) ++ error(FATAL, "read of process stack at %lx failed\n", ++ bt->stackbase); ++ } ++ ++ /* ++ * Dump the IRQ exception frame from the process stack. ++ * If the CS register indicates a user exception frame, ++ * then set done to TRUE to avoid the process stack walk-through. ++ * Otherwise, bump up the rsp past the kernel-mode eframe. ++ */ ++ if (irq_eframe) { ++ bt->flags |= BT_EXCEPTION_FRAME; ++ level = dwarf_print_stack_entry(bt, level); ++ bt->flags &= ~(ulonglong)BT_EXCEPTION_FRAME; ++ cs = x86_64_exception_frame(EFRAME_PRINT|EFRAME_CS, 0, ++ bt->stackbuf + (irq_eframe - bt->stackbase), bt, ofp); ++ if (cs & 3) ++ done = TRUE; /* IRQ from user-mode */ ++ else { ++ if (x86_64_print_eframe_location(rsp, level, ofp)) ++ level++; ++ rsp += SIZE(pt_regs); ++ irq_eframe = 0; ++ } ++ level++; ++ } ++ ++ /* ++ * Walk the process stack. ++ */ ++ if (!done) { ++ level = dwarf_backtrace(bt, level, bt->stacktop); ++ done = TRUE; ++ } ++ ++ if (!irq_eframe && !is_kernel_thread(bt->tc->task) && ++ (GET_STACKBASE(bt->tc->task) == bt->stackbase)) { ++ user_mode_eframe = bt->stacktop - SIZE(pt_regs); ++ if (last_process_stack_eframe < user_mode_eframe) ++ x86_64_exception_frame(EFRAME_PRINT, 0, bt->stackbuf + ++ (bt->stacktop - bt->stackbase) - SIZE(pt_regs), ++ bt, ofp); ++ } ++ ++ if (bt->flags & BT_TEXT_SYMBOLS) { ++ if (BT_REFERENCE_FOUND(bt)) { ++ print_task_header(fp, task_to_context(bt->task), 0); ++ BCOPY(bt_in, bt, sizeof(struct bt_info)); ++ bt->ref = NULL; ++ machdep->back_trace(bt); ++ fprintf(fp, "\n"); ++ } ++ } ++} ++ ++/* ++ * Functions that won't be called indirectly. ++ * Add more to this as they are discovered. ++ */ ++static const char *direct_call_targets[] = { ++ "schedule", ++ "schedule_timeout", ++ NULL ++}; ++ ++static int ++is_direct_call_target(struct bt_info *bt) ++{ ++ int i; ++ ++ if (!bt->call_target || (bt->flags & BT_NO_CHECK_CALLER)) ++ return FALSE; ++ ++ if (strstr(bt->call_target, "schedule") && ++ is_task_active(bt->task)) ++ return FALSE; ++ ++ for (i = 0; direct_call_targets[i]; i++) { ++ if (STREQ(direct_call_targets[i], bt->call_target)) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++static struct syment * ++x86_64_function_called_by(ulong rip) ++{ ++ struct syment *sp; ++ char buf[BUFSIZE], *p1; ++ ulong value, offset; ++ unsigned char byte; ++ ++ value = 0; ++ sp = NULL; ++ ++ if (!readmem(rip, KVADDR, &byte, sizeof(unsigned char), "call byte", ++ RETURN_ON_ERROR)) ++ return sp; ++ ++ if (byte != 0xe8) ++ return sp; ++ ++ sprintf(buf, "x/i 0x%lx", rip); ++ ++ open_tmpfile2(); ++ if (gdb_pass_through(buf, pc->tmpfile2, GNU_RETURN_ON_ERROR)) { ++ rewind(pc->tmpfile2); ++ while (fgets(buf, BUFSIZE, pc->tmpfile2)) { ++ if ((p1 = strstr(buf, "callq")) && ++ whitespace(*(p1-1))) { ++ if (extract_hex(p1, &value, NULLCHAR, TRUE)) ++ break; ++ } ++ } ++ } ++ close_tmpfile2(); ++ ++ if (value) ++ sp = value_search(value, &offset); ++ ++ /* ++ * Functions that jmp to schedule() or schedule_timeout(). ++ */ ++ if (sp) { ++ if ((STREQ(sp->name, "schedule_timeout_interruptible") || ++ STREQ(sp->name, "schedule_timeout_uninterruptible"))) ++ sp = symbol_search("schedule_timeout"); ++ ++ if (STREQ(sp->name, "__cond_resched")) ++ sp = symbol_search("schedule"); ++ } ++ ++ return sp; ++} ++ ++/* ++ * Unroll the kernel stack using a minimal amount of gdb services. ++ */ ++static void ++x86_64_back_trace(struct gnu_request *req, struct bt_info *bt) ++{ ++ error(FATAL, "x86_64_back_trace: unused\n"); ++} ++ ++ ++/* ++ * Print exception frame information for x86_64. ++ * ++ * Pid: 0, comm: swapper Not tainted 2.6.5-1.360phro.rootsmp ++ * RIP: 0010:[] {default_idle+36} ++ * RSP: 0018:ffffffff8048bfd8 EFLAGS: 00000246 ++ * RAX: 0000000000000000 RBX: ffffffff8010f510 RCX: 0000000000000018 ++ * RDX: 0000010001e37280 RSI: ffffffff803ac0a0 RDI: 000001007f43c400 ++ * RBP: 0000000000000000 R08: ffffffff8048a000 R09: 0000000000000000 ++ * R10: ffffffff80482188 R11: 0000000000000001 R12: 0000000000000000 ++ * R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 ++ * FS: 0000002a96e14fc0(0000) GS:ffffffff80481d80(0000) GS:0000000055578aa0 ++ * CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b ++ * CR2: 0000002a9556b000 CR3: 0000000000101000 CR4: 00000000000006e0 ++ * ++ */ ++ ++static long ++x86_64_exception_frame(ulong flags, ulong kvaddr, char *local, ++ struct bt_info *bt, FILE *ofp) ++{ ++ long rip, rsp, cs, ss, rflags, orig_rax, rbp; ++ long rax, rbx, rcx, rdx, rsi, rdi; ++ long r8, r9, r10, r11, r12, r13, r14, r15; ++ struct machine_specific *ms; + struct syment *sp; + ulong offset; - char *pt_regs_buf; - long verified; - int err; -@@ -1950,8 +2519,17 @@ - cs & 3 ? "USER" : "KERNEL", - kvaddr ? kvaddr : - (local - bt->stackbuf) + bt->stackbase); ++ char *pt_regs_buf; ++ long verified; ++ int err; ++ ++ ms = machdep->machspec; ++ ++ if (!(machdep->flags & PT_REGS_INIT)) { ++ err = 0; ++ err |= ((ms->pto.r15 = MEMBER_OFFSET("pt_regs", "r15")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.r14 = MEMBER_OFFSET("pt_regs", "r14")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.r13 = MEMBER_OFFSET("pt_regs", "r13")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.r12 = MEMBER_OFFSET("pt_regs", "r12")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.r11 = MEMBER_OFFSET("pt_regs", "r11")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.r10 = MEMBER_OFFSET("pt_regs", "r10")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.r9 = MEMBER_OFFSET("pt_regs", "r9")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.r8 = MEMBER_OFFSET("pt_regs", "r8")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.rax = MEMBER_OFFSET("pt_regs", "rax")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.rbx = MEMBER_OFFSET("pt_regs", "rbx")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.rcx = MEMBER_OFFSET("pt_regs", "rcx")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.rdx = MEMBER_OFFSET("pt_regs", "rdx")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.rsi = MEMBER_OFFSET("pt_regs", "rsi")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.rdi = MEMBER_OFFSET("pt_regs", "rdi")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.rip = MEMBER_OFFSET("pt_regs", "rip")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.rsp = MEMBER_OFFSET("pt_regs", "rsp")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.cs = MEMBER_OFFSET("pt_regs", "cs")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.ss = MEMBER_OFFSET("pt_regs", "ss")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.eflags = MEMBER_OFFSET("pt_regs", "eflags")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.orig_rax = ++ MEMBER_OFFSET("pt_regs", "orig_rax")) == ++ INVALID_OFFSET); ++ err |= ((ms->pto.rbp = MEMBER_OFFSET("pt_regs", "rbp")) == ++ INVALID_OFFSET); ++ ++ if (err) ++ error(WARNING, "pt_regs structure has changed\n"); ++ ++ machdep->flags |= PT_REGS_INIT; ++ } ++ ++ if (kvaddr) { ++ pt_regs_buf = GETBUF(SIZE(pt_regs)); ++ readmem(kvaddr, KVADDR, pt_regs_buf, ++ SIZE(pt_regs), "pt_regs", FAULT_ON_ERROR); ++ } else ++ pt_regs_buf = local; ++ ++ rip = ULONG(pt_regs_buf + ms->pto.rip); ++ rsp = ULONG(pt_regs_buf + ms->pto.rsp); ++ cs = ULONG(pt_regs_buf + ms->pto.cs); ++ ss = ULONG(pt_regs_buf + ms->pto.ss); ++ rflags = ULONG(pt_regs_buf + ms->pto.eflags); ++ orig_rax = ULONG(pt_regs_buf + ms->pto.orig_rax); ++ rbp = ULONG(pt_regs_buf + ms->pto.rbp); ++ rax = ULONG(pt_regs_buf + ms->pto.rax); ++ rbx = ULONG(pt_regs_buf + ms->pto.rbx); ++ rcx = ULONG(pt_regs_buf + ms->pto.rcx); ++ rdx = ULONG(pt_regs_buf + ms->pto.rdx); ++ rsi = ULONG(pt_regs_buf + ms->pto.rsi); ++ rdi = ULONG(pt_regs_buf + ms->pto.rdi); ++ r8 = ULONG(pt_regs_buf + ms->pto.r8); ++ r9 = ULONG(pt_regs_buf + ms->pto.r9); ++ r10 = ULONG(pt_regs_buf + ms->pto.r10); ++ r11 = ULONG(pt_regs_buf + ms->pto.r11); ++ r12 = ULONG(pt_regs_buf + ms->pto.r12); ++ r13 = ULONG(pt_regs_buf + ms->pto.r13); ++ r14 = ULONG(pt_regs_buf + ms->pto.r14); ++ r15 = ULONG(pt_regs_buf + ms->pto.r15); ++ ++ verified = x86_64_eframe_verify(bt, ++ kvaddr ? kvaddr : (local - bt->stackbuf) + bt->stackbase, ++ cs, ss, rip, rsp, rflags); ++ ++ /* ++ * If it's print-if-verified request, don't print bogus eframes. ++ */ ++ if (!verified && ((flags & (EFRAME_VERIFY|EFRAME_PRINT)) == ++ (EFRAME_VERIFY|EFRAME_PRINT))) ++ flags &= ~EFRAME_PRINT; ++ ++ if (CRASHDEBUG(2)) ++ fprintf(ofp, "< exception frame at: %lx >\n", kvaddr ? kvaddr : ++ (local - bt->stackbuf) + bt->stackbase); ++ ++ if (flags & EFRAME_PRINT) { ++ if (flags & EFRAME_SEARCH) { ++ fprintf(ofp, "\n %s-MODE EXCEPTION FRAME AT: %lx\n", ++ cs & 3 ? "USER" : "KERNEL", ++ kvaddr ? kvaddr : ++ (local - bt->stackbuf) + bt->stackbase); + } else if (!(cs & 3)) { + fprintf(ofp, " [exception RIP: "); + if ((sp = value_search(rip, &offset))) { @@ -17072,15 +26293,68 @@ + } else + fprintf(ofp, "unknown or invalid address"); + fprintf(ofp, "]\n"); - } -- - fprintf(ofp, " RIP: %016lx RSP: %016lx RFLAGS: %08lx\n", - rip, rsp, rflags); - fprintf(ofp, " RAX: %016lx RBX: %016lx RCX: %016lx\n", -@@ -2006,6 +2584,39 @@ - return 0; - } - ++ } ++ fprintf(ofp, " RIP: %016lx RSP: %016lx RFLAGS: %08lx\n", ++ rip, rsp, rflags); ++ fprintf(ofp, " RAX: %016lx RBX: %016lx RCX: %016lx\n", ++ rax, rbx, rcx); ++ fprintf(ofp, " RDX: %016lx RSI: %016lx RDI: %016lx\n", ++ rdx, rsi, rdi); ++ fprintf(ofp, " RBP: %016lx R8: %016lx R9: %016lx\n", ++ rbp, r8, r9); ++ fprintf(ofp, " R10: %016lx R11: %016lx R12: %016lx\n", ++ r10, r11, r12); ++ fprintf(ofp, " R13: %016lx R14: %016lx R15: %016lx\n", ++ r13, r14, r15); ++ fprintf(ofp, " ORIG_RAX: %016lx CS: %04lx SS: %04lx\n", ++ orig_rax, cs, ss); ++ ++ if (!verified && CRASHDEBUG((pc->flags & RUNTIME) ? 0 : 1)) ++ error(WARNING, "possibly bogus exception frame\n"); ++ } ++ ++ if ((flags & EFRAME_PRINT) && BT_REFERENCE_CHECK(bt)) { ++ x86_64_do_bt_reference_check(bt, rip, NULL); ++ x86_64_do_bt_reference_check(bt, rsp, NULL); ++ x86_64_do_bt_reference_check(bt, cs, NULL); ++ x86_64_do_bt_reference_check(bt, ss, NULL); ++ x86_64_do_bt_reference_check(bt, rflags, NULL); ++ x86_64_do_bt_reference_check(bt, orig_rax, NULL); ++ x86_64_do_bt_reference_check(bt, rbp, NULL); ++ x86_64_do_bt_reference_check(bt, rax, NULL); ++ x86_64_do_bt_reference_check(bt, rbx, NULL); ++ x86_64_do_bt_reference_check(bt, rcx, NULL); ++ x86_64_do_bt_reference_check(bt, rdx, NULL); ++ x86_64_do_bt_reference_check(bt, rsi, NULL); ++ x86_64_do_bt_reference_check(bt, rdi, NULL); ++ x86_64_do_bt_reference_check(bt, r8, NULL); ++ x86_64_do_bt_reference_check(bt, r9, NULL); ++ x86_64_do_bt_reference_check(bt, r10, NULL); ++ x86_64_do_bt_reference_check(bt, r11, NULL); ++ x86_64_do_bt_reference_check(bt, r12, NULL); ++ x86_64_do_bt_reference_check(bt, r13, NULL); ++ x86_64_do_bt_reference_check(bt, r14, NULL); ++ x86_64_do_bt_reference_check(bt, r15, NULL); ++ } ++ ++ /* Remember the rip and rsp for unwinding the process stack */ ++ if (kt->flags & DWARF_UNWIND){ ++ bt->instptr = rip; ++ bt->stkptr = rsp; ++ bt->bptr = rbp; ++ } ++ ++ if (kvaddr) ++ FREEBUF(pt_regs_buf); ++ ++ if (flags & EFRAME_CS) ++ return cs; ++ else if (flags & EFRAME_VERIFY) ++ return verified; ++ ++ return 0; ++} ++ +static int +x86_64_print_eframe_location(ulong eframe, int level, FILE *ofp) +{ @@ -17114,25 +26388,51 @@ +#endif +} + - /* - * Check that the verifiable registers contain reasonable data. - */ -@@ -2021,6 +2632,11 @@ - if ((cs == 0x10) && (ss == 0x18)) { - if (is_kernel_text(rip) && IS_KVADDR(rsp)) - return TRUE; ++/* ++ * Check that the verifiable registers contain reasonable data. ++ */ ++#define RAZ_MASK 0xffffffffffc08028 /* return-as-zero bits */ ++ ++static int ++x86_64_eframe_verify(struct bt_info *bt, long kvaddr, long cs, long ss, ++ long rip, long rsp, long rflags) ++{ ++ if ((rflags & RAZ_MASK) || !(rflags & 0x2)) ++ return FALSE; ++ ++ if ((cs == 0x10) && (ss == 0x18)) { ++ if (is_kernel_text(rip) && IS_KVADDR(rsp)) ++ return TRUE; + + if (x86_64_is_module_addr(rip) && + IS_KVADDR(rsp) && + (rsp == (kvaddr + SIZE(pt_regs)))) + return TRUE; - } - - if ((cs == 0x10) && kvaddr) { -@@ -2040,6 +2656,26 @@ - return TRUE; - } - ++ } ++ ++ if ((cs == 0x10) && kvaddr) { ++ if (is_kernel_text(rip) && IS_KVADDR(rsp) && ++ (rsp == (kvaddr + SIZE(pt_regs) + 8))) ++ return TRUE; ++ } ++ ++ if ((cs == 0x10) && kvaddr) { ++ if (is_kernel_text(rip) && IS_KVADDR(rsp) && ++ (rsp == (kvaddr + SIZE(pt_regs)))) ++ return TRUE; ++ } ++ ++ if ((cs == 0x10) && kvaddr) { ++ if (is_kernel_text(rip) && IS_KVADDR(rsp) && ++ x86_64_in_exception_stack(bt)) ++ return TRUE; ++ } ++ ++ if ((cs == 0x33) && (ss == 0x2b)) { ++ if (IS_UVADDR(rip, bt->tc) && IS_UVADDR(rsp, bt->tc)) ++ return TRUE; ++ } ++ + if (XEN() && ((cs == 0x33) || (cs == 0xe033)) && + ((ss == 0x2b) || (ss == 0xe02b))) { + if (IS_UVADDR(rip, bt->tc) && IS_UVADDR(rsp, bt->tc)) @@ -17153,83 +26453,218 @@ + return TRUE; + } + - return FALSE; - } - -@@ -2065,7 +2701,7 @@ - x86_64_get_dumpfile_stack_frame(struct bt_info *bt_in, ulong *rip, ulong *rsp) - { - int panic_task; -- int i, panic, stage; ++ return FALSE; ++} ++ ++/* ++ * Get a stack frame combination of pc and ra from the most relevent spot. ++ */ ++static void ++x86_64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp) ++{ ++ if (bt->flags & BT_DUMPFILE_SEARCH) ++ return x86_64_get_dumpfile_stack_frame(bt, pcp, spp); ++ ++ if (pcp) ++ *pcp = x86_64_get_pc(bt); ++ if (spp) ++ *spp = x86_64_get_sp(bt); ++} ++ ++/* ++ * Get the starting point for the active cpus in a diskdump/netdump. ++ */ ++static void ++x86_64_get_dumpfile_stack_frame(struct bt_info *bt_in, ulong *rip, ulong *rsp) ++{ ++ int panic_task; + int i, estack, panic, stage; - char *sym; - struct syment *sp; - ulong *up; -@@ -2080,6 +2716,7 @@ - ms = machdep->machspec; - ur_rip = ur_rsp = 0; - stage = 0; ++ char *sym; ++ struct syment *sp; ++ ulong *up; ++ struct bt_info bt_local, *bt; ++ struct machine_specific *ms; ++ char *user_regs; ++ ulong ur_rip, ur_rsp; ++ ulong halt_rip, halt_rsp; ++ ulong crash_kexec_rip, crash_kexec_rsp; ++ ++ bt = &bt_local; ++ BCOPY(bt_in, bt, sizeof(struct bt_info)); ++ ms = machdep->machspec; ++ ur_rip = ur_rsp = 0; ++ halt_rip = halt_rsp = 0; ++ crash_kexec_rip = crash_kexec_rsp = 0; ++ stage = 0; + estack = -1; - - panic_task = tt->panic_task == bt->task ? TRUE : FALSE; - -@@ -2119,13 +2756,14 @@ - STREQ(sym, "netpoll_start_netdump") || - STREQ(sym, "start_disk_dump") || - STREQ(sym, "disk_dump") || ++ ++ panic_task = tt->panic_task == bt->task ? TRUE : FALSE; ++ ++ if (panic_task && bt->machdep) { ++ user_regs = bt->machdep; ++ ++ if (x86_64_eframe_verify(bt, ++ 0, ++ ULONG(user_regs + OFFSET(user_regs_struct_cs)), ++ ULONG(user_regs + OFFSET(user_regs_struct_ss)), ++ ULONG(user_regs + OFFSET(user_regs_struct_rip)), ++ ULONG(user_regs + OFFSET(user_regs_struct_rsp)), ++ ULONG(user_regs + OFFSET(user_regs_struct_eflags)))) { ++ bt->stkptr = ULONG(user_regs + ++ OFFSET(user_regs_struct_rsp)); ++ if (x86_64_in_irqstack(bt)) { ++ ur_rip = ULONG(user_regs + ++ OFFSET(user_regs_struct_rip)); ++ ur_rsp = ULONG(user_regs + ++ OFFSET(user_regs_struct_rsp)); ++ goto skip_stage; ++ } ++ } ++ } ++ ++ panic = FALSE; ++ ++ /* ++ * Check the process stack first. ++ */ ++next_stack: ++ for (i = 0, up = (ulong *)bt->stackbuf; ++ i < (bt->stacktop - bt->stackbase)/sizeof(ulong); i++, up++) { ++ sym = closest_symbol(*up); ++ if (XEN_CORE_DUMPFILE()) { ++ if (STREQ(sym, "xen_machine_kexec")) { ++ *rip = *up; ++ *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); ++ return; ++ } ++ } else if (STREQ(sym, "netconsole_netdump") || ++ STREQ(sym, "netpoll_start_netdump") || ++ STREQ(sym, "start_disk_dump") || ++ STREQ(sym, "disk_dump") || + STREQ(sym, "crash_kexec") || - STREQ(sym, "try_crashdump")) { - *rip = *up; - *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); - return; - } - -- if ((stage == 2) && ++ STREQ(sym, "machine_kexec") || ++ STREQ(sym, "try_crashdump")) { ++ /* ++ * Use second instance of crash_kexec if it exists. ++ */ ++ if (!(bt->flags & BT_TEXT_SYMBOLS) && ++ STREQ(sym, "crash_kexec") && !crash_kexec_rip) { ++ crash_kexec_rip = *up; ++ crash_kexec_rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); ++ continue; ++ } ++ *rip = *up; ++ *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); ++ return; ++ } ++ + if ((estack >= 0) && - (STREQ(sym, "nmi_watchdog_tick") || - STREQ(sym, "default_do_nmi"))) { - sp = x86_64_function_called_by((*up)-5); -@@ -2161,7 +2799,7 @@ - next_sysrq: - *rip = *up; - *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); -- machdep->flags |= SYSRQ; ++ (STREQ(sym, "nmi_watchdog_tick") || ++ STREQ(sym, "default_do_nmi"))) { ++ sp = x86_64_function_called_by((*up)-5); ++ if (!sp || !STREQ(sp->name, "die_nmi")) ++ continue; ++ *rip = *up; ++ *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); ++ bt_in->flags |= BT_START; ++ *rip = symbol_value("die_nmi"); ++ *rsp = (*rsp) - (7*sizeof(ulong)); ++ return; ++ } ++ ++ if (STREQ(sym, "panic")) { ++ *rip = *up; ++ *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); ++ panic = TRUE; ++ continue; /* keep looking for die */ ++ } ++ ++ if (STREQ(sym, "die")) { ++ *rip = *up; ++ *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); ++ for (i++, up++; i < LONGS_PER_STACK; i++, up++) { ++ sym = closest_symbol(*up); ++ if (STREQ(sym, "sysrq_handle_crash")) ++ goto next_sysrq; ++ } ++ return; ++ } ++ ++ if (STREQ(sym, "sysrq_handle_crash")) { ++next_sysrq: ++ *rip = *up; ++ *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); + pc->flags |= SYSRQ; - for (i++, up++; i < LONGS_PER_STACK; i++, up++) { - sym = closest_symbol(*up); - if (STREQ(sym, "sysrq_handle_crash")) -@@ -2176,6 +2814,12 @@ - *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); - return; - } ++ for (i++, up++; i < LONGS_PER_STACK; i++, up++) { ++ sym = closest_symbol(*up); ++ if (STREQ(sym, "sysrq_handle_crash")) ++ goto next_sysrq; ++ } ++ return; ++ } ++ ++ if (!panic_task && (stage > 0) && ++ STREQ(sym, "smp_call_function_interrupt")) { ++ *rip = *up; ++ *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); ++ return; ++ } + + if (!panic_task && STREQ(sym, "crash_nmi_callback")) { + *rip = *up; + *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); + return; + } - } - - if (panic) -@@ -2191,25 +2835,30 @@ - bt->stackbase = ms->stkinfo.ibase[bt->tc->processor]; - bt->stacktop = ms->stkinfo.ibase[bt->tc->processor] + - ms->stkinfo.isize; ++ ++ if (XEN_CORE_DUMPFILE() && !panic_task && (bt->tc->pid == 0) && ++ (stage == 0) && STREQ(sym, "safe_halt")) { ++ halt_rip = *up; ++ halt_rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); ++ } ++ ++ if (XEN_CORE_DUMPFILE() && !panic_task && (bt->tc->pid == 0) && ++ !halt_rip && (stage == 0) && STREQ(sym, "xen_idle")) { ++ halt_rip = *up; ++ halt_rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); ++ } ++ ++ if (!XEN_CORE_DUMPFILE() && !panic_task && (bt->tc->pid == 0) && ++ !halt_rip && (stage == 0) && STREQ(sym, "cpu_idle")) { ++ halt_rip = *up; ++ halt_rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); ++ } ++ } ++ ++ if (panic) ++ return; ++ ++ if (crash_kexec_rip) { ++ *rip = crash_kexec_rip; ++ *rsp = crash_kexec_rsp; ++ return; ++ } ++ ++skip_stage: ++ switch (stage) ++ { ++ /* ++ * Now check the processor's interrupt stack. ++ */ ++ case 0: ++ bt->stackbase = ms->stkinfo.ibase[bt->tc->processor]; ++ bt->stacktop = ms->stkinfo.ibase[bt->tc->processor] + ++ ms->stkinfo.isize; + console("x86_64_get_dumpfile_stack_frame: searching IRQ stack at %lx\n", + bt->stackbase); - bt->stackbuf = ms->irqstack; - alter_stackbuf(bt); - stage = 1; - goto next_stack; - - /* -- * Check the NMI exception stack. ++ bt->stackbuf = ms->irqstack; ++ alter_stackbuf(bt); ++ stage = 1; ++ goto next_stack; ++ ++ /* + * Check the exception stacks. - */ - case 1: -- bt->stackbase = ms->stkinfo.ebase[bt->tc->processor][NMI_STACK]; -- bt->stacktop = ms->stkinfo.ebase[bt->tc->processor][NMI_STACK] + -- ms->stkinfo.esize; ++ */ ++ case 1: + if (++estack == 7) + break; + bt->stackbase = ms->stkinfo.ebase[bt->tc->processor][estack]; @@ -17239,56 +26674,413 @@ + x86_64_exception_stacks[estack], bt->stackbase); + if (!(bt->stackbase)) + goto skip_stage; - bt->stackbuf = ms->irqstack; - alter_stackbuf(bt); -- stage = 2; - goto next_stack; ++ bt->stackbuf = ms->irqstack; ++ alter_stackbuf(bt); ++ goto next_stack; ++ ++ } ++ ++ /* ++ * We didn't find what we were looking for, so just use what was ++ * passed in from the ELF header. ++ */ ++ if (ur_rip && ur_rsp) { ++ *rip = ur_rip; ++ *rsp = ur_rsp; ++ return; ++ } ++ ++ if (halt_rip && halt_rsp) { ++ *rip = halt_rip; ++ *rsp = halt_rsp; ++ return; ++ } ++ ++ if (CRASHDEBUG(1)) ++ error(INFO, ++ "x86_64_get_dumpfile_stack_frame: cannot find anything useful (task: %lx)\n", ++ bt->task); ++ ++ bt->flags &= ~(ulonglong)BT_DUMPFILE_SEARCH; ++ ++ machdep->get_stack_frame(bt, rip, rsp); ++} ++ ++/* ++ * Get the saved RSP from the task's thread_struct. ++ */ ++static ulong ++x86_64_get_sp(struct bt_info *bt) ++{ ++ ulong offset, rsp; ++ ++ if (tt->flags & THREAD_INFO) { ++ readmem(bt->task + OFFSET(task_struct_thread) + ++ OFFSET(thread_struct_rsp), KVADDR, ++ &rsp, sizeof(void *), ++ "thread_struct rsp", FAULT_ON_ERROR); ++ return rsp; ++ } ++ ++ offset = OFFSET(task_struct_thread) + OFFSET(thread_struct_rsp); ++ ++ return GET_STACK_ULONG(offset); ++} ++ ++/* ++ * Get the saved PC from the task's thread_struct if it exists; ++ * otherwise just use the "thread_return" label value. ++ */ ++static ulong ++x86_64_get_pc(struct bt_info *bt) ++{ ++ ulong offset, rip; ++ ++ if (INVALID_MEMBER(thread_struct_rip)) ++ return symbol_value("thread_return"); ++ ++ if (tt->flags & THREAD_INFO) { ++ readmem(bt->task + OFFSET(task_struct_thread) + ++ OFFSET(thread_struct_rip), KVADDR, ++ &rip, sizeof(void *), ++ "thread_struct rip", FAULT_ON_ERROR); ++ return rip; ++ } ++ ++ offset = OFFSET(task_struct_thread) + OFFSET(thread_struct_rip); ++ ++ return GET_STACK_ULONG(offset); ++} ++ ++ ++/* ++ * Do the work for x86_64_get_sp() and x86_64_get_pc(). ++ */ ++static void ++get_x86_64_frame(struct bt_info *bt, ulong *getpc, ulong *getsp) ++{ ++ error(FATAL, "get_x86_64_frame: TBD\n"); ++} ++ ++/* ++ * Do the work for cmd_irq(). ++ */ ++static void ++x86_64_dump_irq(int irq) ++{ ++ if (symbol_exists("irq_desc")) { ++ machdep->dump_irq = generic_dump_irq; ++ return(generic_dump_irq(irq)); ++ } ++ ++ error(FATAL, "x86_64_dump_irq: irq_desc[] does not exist?\n"); + } -- case 2: -- break; +-static void +-x86_64_display_full_frame(struct bt_info *bt, ulong rsp, FILE *ofp) ++/* ++ * Do the work for irq -d ++ */ ++void ++x86_64_display_idt_table(void) + { +- int i, u_idx; +- ulong *up; +- ulong words, addr; ++ int i; ++ char *idt_table_buf; ++ char buf[BUFSIZE]; ++ ulong *ip; + +- words = (rsp - bt->frameptr) / sizeof(ulong) + 1; ++ idt_table_buf = GETBUF(SIZE(gate_struct) * 256); ++ readmem(symbol_value("idt_table"), KVADDR, idt_table_buf, ++ SIZE(gate_struct) * 256, "idt_table", FAULT_ON_ERROR); ++ ip = (ulong *)idt_table_buf; + +- addr = bt->frameptr; +- u_idx = (bt->frameptr - bt->stackbase)/sizeof(ulong); +- for (i = 0; i < words; i++, u_idx++) { +- if (!(i & 1)) +- fprintf(ofp, "%s %lx: ", i ? "\n" : "", addr); +- +- up = (ulong *)(&bt->stackbuf[u_idx*sizeof(ulong)]); +- fprintf(ofp, "%016lx ", *up); +- addr += sizeof(ulong); ++ for (i = 0; i < 256; i++, ip += 2) { ++ if (i < 10) ++ fprintf(fp, " "); ++ else if (i < 100) ++ fprintf(fp, " "); ++ fprintf(fp, "[%d] %s\n", ++ i, x86_64_extract_idt_function(ip, buf, NULL)); + } +- fprintf(ofp, "\n"); ++ ++ FREEBUF(idt_table_buf); + } + + /* +- * Check a frame for a requested reference. ++ * Extract the function name out of the IDT entry. + */ +-static void +-x86_64_do_bt_reference_check(struct bt_info *bt, ulong text, char *name) ++static char * ++x86_64_extract_idt_function(ulong *ip, char *buf, ulong *retaddr) + { +- struct syment *sp; +- ulong offset; ++ ulong i1, i2, addr; ++ char locbuf[BUFSIZE]; ++ physaddr_t phys; + +- if (!name) +- sp = value_search(text, &offset); +- else if (!text) +- sp = symbol_search(name); ++ if (buf) ++ BZERO(buf, BUFSIZE); + +- switch (bt->ref->cmdflags & (BT_REF_SYMBOL|BT_REF_HEXVAL)) +- { +- case BT_REF_SYMBOL: +- if (name) { +- if (STREQ(name, bt->ref->str)) +- bt->ref->cmdflags |= BT_REF_FOUND; +- } else { +- if (sp && !offset && STREQ(sp->name, bt->ref->str)) +- bt->ref->cmdflags |= BT_REF_FOUND; ++ i1 = *ip; ++ i2 = *(ip+1); ++ ++ i2 <<= 32; ++ addr = i2 & 0xffffffff00000000; ++ addr |= (i1 & 0xffff); ++ i1 >>= 32; ++ addr |= (i1 & 0xffff0000); ++ ++ if (retaddr) ++ *retaddr = addr; ++ ++ if (!buf) ++ return NULL; ++ ++ value_to_symstr(addr, locbuf, 0); ++ if (strlen(locbuf)) ++ sprintf(buf, locbuf); ++ else { ++ sprintf(buf, "%016lx", addr); ++ if (kvtop(NULL, addr, &phys, 0)) { ++ addr = machdep->kvbase + (ulong)phys; ++ if (value_to_symstr(addr, locbuf, 0)) { ++ strcat(buf, " <"); ++ strcat(buf, locbuf); ++ strcat(buf, ">"); ++ } + } +- break; ++ } + +- case BT_REF_HEXVAL: +- if (text) { +- if (bt->ref->hexval == text) +- bt->ref->cmdflags |= BT_REF_FOUND; +- } else if (sp && (bt->ref->hexval == sp->value)) +- bt->ref->cmdflags |= BT_REF_FOUND; +- else if (!name && !text && (bt->ref->hexval == 0)) +- bt->ref->cmdflags |= BT_REF_FOUND; +- break; +- } ++ return buf; + } + + /* +- * print one entry of a stack trace ++ * Filter disassembly output if the output radix is not gdb's default 10 + */ +-#define BACKTRACE_COMPLETE (1) +-#define BACKTRACE_ENTRY_IGNORED (2) +-#define BACKTRACE_ENTRY_DISPLAYED (3) +-#define BACKTRACE_ENTRY_AND_EFRAME_DISPLAYED (4) +- +-static int +-x86_64_print_stack_entry(struct bt_info *bt, FILE *ofp, int level, +- int stkindex, ulong text) ++static int ++x86_64_dis_filter(ulong vaddr, char *inbuf) + { +- ulong rsp, offset; +- struct syment *sp; +- char *name; +- int result; +- long eframe_check; +- char buf[BUFSIZE]; ++ char buf1[BUFSIZE]; ++ char buf2[BUFSIZE]; ++ char *colon, *p1; ++ int argc; ++ char *argv[MAXARGS]; ++ ulong value; + +- eframe_check = -1; +- offset = 0; +- sp = value_search(text, &offset); +- if (!sp) +- return BACKTRACE_ENTRY_IGNORED; ++ if (!inbuf) ++ return TRUE; ++/* ++ * For some reason gdb can go off into the weeds translating text addresses, ++ * (on alpha -- not necessarily seen on x86_64) so this routine both fixes the ++ * references as well as imposing the current output radix on the translations. ++ */ ++ console("IN: %s", inbuf); + +- name = sp->name; ++ colon = strstr(inbuf, ":"); + +- if (bt->flags & BT_TEXT_SYMBOLS) { +- if (bt->flags & BT_EXCEPTION_FRAME) +- rsp = bt->stkptr; +- else +- rsp = bt->stackbase + (stkindex * sizeof(long)); +- fprintf(ofp, " [%s] %s at %lx\n", +- mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, MKSTR(rsp)), +- name, text); +- if (BT_REFERENCE_CHECK(bt)) +- x86_64_do_bt_reference_check(bt, text, name); +- return BACKTRACE_ENTRY_DISPLAYED; ++ if (colon) { ++ sprintf(buf1, "0x%lx <%s>", vaddr, ++ value_to_symstr(vaddr, buf2, pc->output_radix)); ++ sprintf(buf2, "%s%s", buf1, colon); ++ strcpy(inbuf, buf2); } - /* -@@ -2258,7 +2907,7 @@ - { - ulong offset, rip; +- if (!offset && !(bt->flags & BT_EXCEPTION_FRAME) && +- !(bt->flags & BT_START)) { +- if (STREQ(name, "child_rip")) { +- if (symbol_exists("kernel_thread")) +- name = "kernel_thread"; +- else if (symbol_exists("arch_kernel_thread")) +- name = "arch_kernel_thread"; +- } +- else if (!(bt->flags & BT_SCHEDULE)) { +- if (STREQ(name, "error_exit")) +- eframe_check = 8; +- else { +- if (CRASHDEBUG(2)) +- fprintf(ofp, +- "< ignoring text symbol with no offset: %s() >\n", +- sp->name); +- return BACKTRACE_ENTRY_IGNORED; +- } +- } +- } ++ strcpy(buf1, inbuf); ++ argc = parse_line(buf1, argv); -- if (INVALID_MEMBER(thread_struct_rip)) -+ if (INVALID_MEMBER(thread_struct_rip)) - return symbol_value("thread_return"); +- if (bt->flags & BT_SCHEDULE) +- name = "schedule"; ++ if ((FIRSTCHAR(argv[argc-1]) == '<') && ++ (LASTCHAR(argv[argc-1]) == '>')) { ++ p1 = rindex(inbuf, '<'); ++ while ((p1 > inbuf) && !STRNEQ(p1, " 0x")) ++ p1--; - if (tt->flags & THREAD_INFO) { -@@ -2457,25 +3106,40 @@ - int - x86_64_get_smp_cpus(void) - { -- int i, cpus, nr_pda, cpunumber; +- if (STREQ(name, "child_rip")) { +- if (symbol_exists("kernel_thread")) +- name = "kernel_thread"; +- else if (symbol_exists("arch_kernel_thread")) +- name = "arch_kernel_thread"; +- result = BACKTRACE_COMPLETE; +- } else if (STREQ(name, "cpu_idle")) +- result = BACKTRACE_COMPLETE; +- else +- result = BACKTRACE_ENTRY_DISPLAYED; ++ if (!STRNEQ(p1, " 0x")) ++ return FALSE; ++ p1++; + +- if (bt->flags & BT_EXCEPTION_FRAME) +- rsp = bt->stkptr; +- else if (bt->flags & BT_START) +- rsp = bt->stkptr; +- else +- rsp = bt->stackbase + (stkindex * sizeof(long)); ++ if (!extract_hex(p1, &value, NULLCHAR, TRUE)) ++ return FALSE; ++ ++ sprintf(buf1, "0x%lx <%s>\n", value, ++ value_to_symstr(value, buf2, pc->output_radix)); ++ ++ sprintf(p1, buf1); ++ ++ } else if (STREQ(argv[argc-2], "callq") && ++ hexadecimal(argv[argc-1], 0)) { ++ /* ++ * Update module code of the form: ++ * ++ * callq 0xffffffffa0017aa0 ++ * ++ * to show a bracketed direct call target. ++ */ ++ p1 = &LASTCHAR(inbuf); ++ ++ if (extract_hex(argv[argc-1], &value, NULLCHAR, TRUE)) { ++ sprintf(buf1, " <%s>\n", ++ value_to_symstr(value, buf2, ++ pc->output_radix)); ++ if (IS_MODULE_VADDR(value) && ++ !strstr(buf2, "+")) ++ sprintf(p1, buf1); ++ } ++ } ++ ++ console(" %s", inbuf); ++ ++ return TRUE; ++} ++ ++ ++/* ++ * Override smp_num_cpus if possible and necessary. ++ */ ++int ++x86_64_get_smp_cpus(void) ++{ + int i, cpus, nr_pda, cpunumber, _cpu_pda; - char *cpu_pda_buf; -- ulong level4_pgt; ++ char *cpu_pda_buf; + ulong level4_pgt, cpu_pda_addr; ++ ++ if (!VALID_STRUCT(x8664_pda)) ++ return 1; - if (!VALID_STRUCT(x8664_pda)) - return 1; - - cpu_pda_buf = GETBUF(SIZE(x8664_pda)); - -- if (!(nr_pda = get_array_length("cpu_pda", NULL, 0))) -- nr_pda = NR_CPUS; -- -+ if (symbol_exists("_cpu_pda")) { -+ if (!(nr_pda = get_array_length("_cpu_pda", NULL, 0))) -+ nr_pda = NR_CPUS; -+ _cpu_pda = TRUE; +- if ((bt->flags & BT_FULL)) { +- if (bt->frameptr) +- x86_64_display_full_frame(bt, rsp, ofp); +- bt->frameptr = rsp + sizeof(ulong); ++ cpu_pda_buf = GETBUF(SIZE(x8664_pda)); ++ ++ if (LKCD_KERNTYPES()) { ++ if (symbol_exists("_cpu_pda")) ++ _cpu_pda = TRUE; ++ else ++ _cpu_pda = FALSE; ++ nr_pda = get_cpus_possible(); + } else { -+ if (!(nr_pda = get_array_length("cpu_pda", NULL, 0))) -+ nr_pda = NR_CPUS; -+ _cpu_pda = FALSE; ++ if (symbol_exists("_cpu_pda")) { ++ if (!(nr_pda = get_array_length("_cpu_pda", NULL, 0))) ++ nr_pda = NR_CPUS; ++ _cpu_pda = TRUE; ++ } else { ++ if (!(nr_pda = get_array_length("cpu_pda", NULL, 0))) ++ nr_pda = NR_CPUS; ++ _cpu_pda = FALSE; ++ } + } - for (i = cpus = 0; i < nr_pda; i++) { -- if (!CPU_PDA_READ(i, cpu_pda_buf)) -- break; -- level4_pgt = ULONG(cpu_pda_buf + OFFSET(x8664_pda_level4_pgt)); ++ for (i = cpus = 0; i < nr_pda; i++) { + if (_cpu_pda) { + if (!_CPU_PDA_READ(i, cpu_pda_buf)) + break; @@ -17301,31 +27093,145 @@ + if (!VALID_LEVEL4_PGT_ADDR(level4_pgt)) + break; + } - cpunumber = INT(cpu_pda_buf + OFFSET(x8664_pda_cpunumber)); -- if (!VALID_LEVEL4_PGT_ADDR(level4_pgt) || (cpunumber != cpus)) -- break; ++ cpunumber = INT(cpu_pda_buf + OFFSET(x8664_pda_cpunumber)); + if (cpunumber != cpus) + break; - cpus++; ++ cpus++; } -@@ -2551,9 +3215,9 @@ - static void - x86_64_display_cpu_data(void) +- fprintf(ofp, "%s#%d [%8lx] %s at %lx\n", level < 10 ? " " : "", level, +- rsp, name, text); ++ FREEBUF(cpu_pda_buf); + +- if (bt->flags & BT_LINE_NUMBERS) { +- get_line_number(text, buf, FALSE); +- if (strlen(buf)) +- fprintf(ofp, " %s\n", buf); +- } ++ return cpus; ++} + +- if (eframe_check >= 0) { +- if (x86_64_exception_frame(EFRAME_PRINT|EFRAME_VERIFY, +- bt->stackbase + (stkindex*sizeof(long)) + eframe_check, +- NULL, bt, ofp)) +- result = BACKTRACE_ENTRY_AND_EFRAME_DISPLAYED; +- } ++/* ++ * Machine dependent command. ++ */ ++void ++x86_64_cmd_mach(void) ++{ ++ int c; + +- if (BT_REFERENCE_CHECK(bt)) +- x86_64_do_bt_reference_check(bt, text, name); ++ while ((c = getopt(argcnt, args, "cm")) != EOF) { ++ switch(c) ++ { ++ case 'c': ++ x86_64_display_cpu_data(); ++ return; + +- bt->call_target = name; ++ case 'm': ++ x86_64_display_memmap(); ++ return; + +- if (is_direct_call_target(bt)) { +- if (CRASHDEBUG(2)) +- fprintf(ofp, "< enable BT_CHECK_CALLER for %s >\n", +- bt->call_target); +- bt->flags |= BT_CHECK_CALLER; +- } else { +- if (CRASHDEBUG(2) && (bt->flags & BT_CHECK_CALLER)) +- fprintf(ofp, "< disable BT_CHECK_CALLER for %s >\n", +- bt->call_target); +- if (bt->flags & BT_CHECK_CALLER) { +- if (CRASHDEBUG(2)) +- fprintf(ofp, "< set BT_NO_CHECK_CALLER >\n"); +- bt->flags |= BT_NO_CHECK_CALLER; +- } +- bt->flags &= ~(ulonglong)BT_CHECK_CALLER; +- } ++ default: ++ argerrs++; ++ break; ++ } ++ } + +- return result; ++ if (argerrs) ++ cmd_usage(pc->curcmd, SYNOPSIS); ++ ++ x86_64_display_machine_stats(); + } + + /* +- * Unroll a kernel stack. ++ * "mach" command output. + */ + static void +-x86_64_back_trace_cmd(struct bt_info *bt) ++x86_64_display_machine_stats(void) { -- int cpu, cpus, boot_cpu; +- error(FATAL, "x86_64_back_trace_cmd: TBD\n"); +-} ++ struct new_utsname *uts; ++ char buf[BUFSIZE]; ++ ulong mhz; + ++ uts = &kt->utsname; + ++ fprintf(fp, " MACHINE TYPE: %s\n", uts->machine); ++ fprintf(fp, " MEMORY SIZE: %s\n", get_memory_size(buf)); ++ fprintf(fp, " CPUS: %d\n", kt->cpus); ++ fprintf(fp, " PROCESSOR SPEED: "); ++ if ((mhz = machdep->processor_speed())) ++ fprintf(fp, "%ld Mhz\n", mhz); ++ else ++ fprintf(fp, "(unknown)\n"); ++ fprintf(fp, " HZ: %d\n", machdep->hz); ++ fprintf(fp, " PAGE SIZE: %d\n", PAGESIZE()); ++ fprintf(fp, " L1 CACHE SIZE: %d\n", l1_cache_size()); ++ fprintf(fp, "KERNEL VIRTUAL BASE: %lx\n", machdep->kvbase); ++ fprintf(fp, "KERNEL VMALLOC BASE: %lx\n", vt->vmalloc_start); ++ fprintf(fp, " KERNEL START MAP: %lx\n", __START_KERNEL_map); ++ fprintf(fp, "KERNEL MODULES BASE: %lx\n", MODULES_VADDR); ++ fprintf(fp, " KERNEL STACK SIZE: %ld\n", STACKSIZE()); ++} + + /* +- * Determine whether the initial stack pointer is located in one of the +- * exception stacks. ++ * "mach -c" + */ +-static ulong +-x86_64_in_exception_stack(struct bt_info *bt) ++static void ++x86_64_display_cpu_data(void) + { +- int c, i; +- ulong rsp; +- ulong estack; +- struct machine_specific *ms; + int cpu, cpus, boot_cpu, _cpu_pda; - ulong cpu_data; -- ulong cpu_pda; ++ ulong cpu_data; + ulong cpu_pda, cpu_pda_addr; - if (symbol_exists("cpu_data")) { - cpu_data = symbol_value("cpu_data"); -@@ -2564,7 +3228,13 @@ - boot_cpu = TRUE; - cpus = 1; - } -- cpu_pda = symbol_value("cpu_pda"); +- rsp = bt->stkptr; +- ms = machdep->machspec; +- estack = 0; ++ if (symbol_exists("cpu_data")) { ++ cpu_data = symbol_value("cpu_data"); ++ cpus = kt->cpus; ++ boot_cpu = FALSE; ++ } else if (symbol_exists("boot_cpu_data")) { ++ cpu_data = symbol_value("boot_cpu_data"); ++ boot_cpu = TRUE; ++ cpus = 1; ++ } + if (symbol_exists("_cpu_pda")) { + cpu_pda = symbol_value("_cpu_pda"); + _cpu_pda = TRUE; @@ -17334,14 +27240,29 @@ + _cpu_pda = FALSE; + } - for (cpu = 0; cpu < cpus; cpu++) { - if (boot_cpu) -@@ -2574,10 +3244,17 @@ - - dump_struct("cpuinfo_x86", cpu_data, 0); - fprintf(fp, "\n"); -- dump_struct("x8664_pda", cpu_pda, 0); - +- for (c = 0; !estack && (c < kt->cpus); c++) { +- for (i = 0; i < 7; i++) { +- if (ms->stkinfo.ebase[c][i] == 0) +- break; +- if ((rsp >= ms->stkinfo.ebase[c][i]) && +- (rsp < (ms->stkinfo.ebase[c][i] + +- ms->stkinfo.esize))) { +- estack = ms->stkinfo.ebase[c][i]; +- if (c != bt->tc->processor) +- error(INFO, +- "task cpu: %d exception stack cpu: %d\n", +- bt->tc->processor, c); +- break; +- } ++ for (cpu = 0; cpu < cpus; cpu++) { ++ if (boot_cpu) ++ fprintf(fp, "BOOT CPU:\n"); ++ else ++ fprintf(fp, "%sCPU %d:\n", cpu ? "\n" : "", cpu); ++ ++ dump_struct("cpuinfo_x86", cpu_data, 0); ++ fprintf(fp, "\n"); ++ + if (_cpu_pda) { + readmem(cpu_pda, KVADDR, &cpu_pda_addr, + sizeof(unsigned long), "_cpu_pda addr", FAULT_ON_ERROR); @@ -17350,17 +27271,155 @@ + } else { + dump_struct("x8664_pda", cpu_pda, 0); + cpu_pda += SIZE(x8664_pda); -+ } - cpu_data += SIZE(cpuinfo_x86); -- cpu_pda += SIZE(x8664_pda); + } ++ cpu_data += SIZE(cpuinfo_x86); } +- +- return estack; } -@@ -2691,4 +3368,824 @@ - x86_64_dump_line_number(0); + /* +- * Determine whether the current stack pointer is in a cpu's irqstack. ++ * "mach -m" + */ +-static ulong +-x86_64_in_irqstack(struct bt_info *bt) ++static char *e820type[] = { ++ "(invalid type)", ++ "E820_RAM", ++ "E820_RESERVED", ++ "E820_ACPI", ++ "E820_NVS", ++}; ++ ++static void ++x86_64_display_memmap(void) + { +- int c; +- ulong rsp; +- ulong irqstack; +- struct machine_specific *ms; ++ ulong e820; ++ int nr_map, i; ++ char *buf, *e820entry_ptr; ++ ulonglong addr, size; ++ uint type; + +- rsp = bt->stkptr; +- ms = machdep->machspec; +- irqstack = 0; ++ e820 = symbol_value("e820"); ++ if (CRASHDEBUG(1)) ++ dump_struct("e820map", e820, RADIX(16)); ++ buf = (char *)GETBUF(SIZE(e820map)); + +- for (c = 0; !irqstack && (c < kt->cpus); c++) { +- if (ms->stkinfo.ibase[c] == 0) +- break; +- if ((rsp >= ms->stkinfo.ibase[c]) && +- (rsp < (ms->stkinfo.ibase[c] + ms->stkinfo.isize))) { +- irqstack = ms->stkinfo.ibase[c]; +- if (c != bt->tc->processor) +- error(INFO, +- "task cpu: %d IRQ stack cpu: %d\n", +- bt->tc->processor, c); +- break; +- } ++ readmem(e820, KVADDR, &buf[0], SIZE(e820map), ++ "e820map", FAULT_ON_ERROR); ++ ++ nr_map = INT(buf + OFFSET(e820map_nr_map)); ++ ++ fprintf(fp, " PHYSICAL ADDRESS RANGE TYPE\n"); ++ ++ for (i = 0; i < nr_map; i++) { ++ e820entry_ptr = buf + sizeof(int) + (SIZE(e820entry) * i); ++ addr = ULONGLONG(e820entry_ptr + OFFSET(e820entry_addr)); ++ size = ULONGLONG(e820entry_ptr + OFFSET(e820entry_size)); ++ type = UINT(e820entry_ptr + OFFSET(e820entry_type)); ++ fprintf(fp, "%016llx - %016llx %s\n", addr, addr+size, ++ e820type[type]); + } ++} ++ ++ ++static const char *hook_files[] = { ++ "arch/x86_64/kernel/entry.S", ++ "arch/x86_64/kernel/head.S", ++ "arch/x86_64/kernel/semaphore.c" ++}; ++ ++#define ENTRY_S ((char **)&hook_files[0]) ++#define HEAD_S ((char **)&hook_files[1]) ++#define SEMAPHORE_C ((char **)&hook_files[2]) ++ ++static struct line_number_hook x86_64_line_number_hooks[] = { ++ {"ret_from_fork", ENTRY_S}, ++ {"system_call", ENTRY_S}, ++ {"int_ret_from_sys_call", ENTRY_S}, ++ {"ptregscall_common", ENTRY_S}, ++ {"stub_execve", ENTRY_S}, ++ {"stub_rt_sigreturn", ENTRY_S}, ++ {"common_interrupt", ENTRY_S}, ++ {"ret_from_intr", ENTRY_S}, ++ {"load_gs_index", ENTRY_S}, ++ {"arch_kernel_thread", ENTRY_S}, ++ {"execve", ENTRY_S}, ++ {"page_fault", ENTRY_S}, ++ {"coprocessor_error", ENTRY_S}, ++ {"simd_coprocessor_error", ENTRY_S}, ++ {"device_not_available", ENTRY_S}, ++ {"debug", ENTRY_S}, ++ {"nmi", ENTRY_S}, ++ {"int3", ENTRY_S}, ++ {"overflow", ENTRY_S}, ++ {"bounds", ENTRY_S}, ++ {"invalid_op", ENTRY_S}, ++ {"coprocessor_segment_overrun", ENTRY_S}, ++ {"reserved", ENTRY_S}, ++ {"double_fault", ENTRY_S}, ++ {"invalid_TSS", ENTRY_S}, ++ {"segment_not_present", ENTRY_S}, ++ {"stack_segment", ENTRY_S}, ++ {"general_protection", ENTRY_S}, ++ {"alignment_check", ENTRY_S}, ++ {"divide_error", ENTRY_S}, ++ {"spurious_interrupt_bug", ENTRY_S}, ++ {"machine_check", ENTRY_S}, ++ {"call_debug", ENTRY_S}, + +- return irqstack; ++ {NULL, NULL} /* list must be NULL-terminated */ ++}; ++ ++static void ++x86_64_dump_line_number(ulong callpc) ++{ ++ error(FATAL, "x86_64_dump_line_number: TBD\n"); } -+/* +-#define STACK_TRANSITION_ERRMSG_E_I_P \ +-"cannot transition from exception stack to IRQ stack to current process stack:\n exception stack pointer: %lx\n IRQ stack pointer: %lx\n process stack pointer: %lx\n current stack base: %lx\n" +-#define STACK_TRANSITION_ERRMSG_E_P \ +-"cannot transition from exception stack to current process stack:\n exception stack pointer: %lx\n process stack pointer: %lx\n current_stack_base: %lx\n" +-#define STACK_TRANSITION_ERRMSG_I_P \ +-"cannot transition from IRQ stack to current process stack:\n IRQ stack pointer: %lx\n process stack pointer: %lx\n current stack base: %lx" ++void ++x86_64_compiler_warning_stub(void) ++{ ++ struct line_number_hook *lhp; ++ char **p; ++ ++ lhp = &x86_64_line_number_hooks[0]; lhp++; ++ p = ENTRY_S; ++ x86_64_back_trace(NULL, NULL); ++ get_x86_64_frame(NULL, NULL, NULL); ++ x86_64_dump_line_number(0); ++} + + /* +- * Low-budget back tracer -- dump text return addresses, following call chain +- * when possible, along with any verifiable exception frames. + * Force the VM address-range selection via: + * + * --machdep vm=orig @@ -17369,8 +27428,38 @@ + * Force the phys_base address via: + * + * --machdep phys_base=
-+ */ -+ ++ * ++ * Force the IRQ stack back-link via: ++ * ++ * --machdep irq_eframe_link= + */ +-static void +-x86_64_low_budget_back_trace_cmd(struct bt_info *bt_in) +-{ +- int i, level, done; +- ulong rsp, offset, stacktop; +- ulong *up; +- long cs; +- struct syment *sp, *spt; +- FILE *ofp; +- ulong estack, irqstack; +- ulong irq_eframe; +- struct bt_info bt_local, *bt; +- struct machine_specific *ms; +- ulong last_process_stack_eframe; +- ulong user_mode_eframe; +- +- bt = &bt_local; +- BCOPY(bt_in, bt, sizeof(struct bt_info)); + +- level = 0; +- done = FALSE; +- irq_eframe = 0; +- last_process_stack_eframe = 0; +- bt->call_target = NULL; +- rsp = bt->stkptr; +- if (!rsp) { +- error(INFO, "cannot determine starting stack pointer\n"); +void +parse_cmdline_arg(void) +{ @@ -17380,27 +27469,85 @@ + char *arglist[MAXARGS]; + int megabytes; + int lines = 0; ++ int vm_flag; + ulong value; + + if (!strstr(machdep->cmdline_arg, "=")) { + error(WARNING, "ignoring --machdep option: %s\n\n", + machdep->cmdline_arg); -+ return; + return; +- } +- ms = machdep->machspec; +- if (BT_REFERENCE_CHECK(bt)) +- ofp = pc->nullfp; +- else +- ofp = fp; + } -+ + +- if (bt->flags & BT_TEXT_SYMBOLS) { +- fprintf(ofp, "%sSTART: %s%s at %lx\n", +- space(VADDR_PRLEN > 8 ? 14 : 6), +- closest_symbol(bt->instptr), +- STREQ(closest_symbol(bt->instptr), "thread_return") ? +- " (schedule)" : "", +- bt->instptr); +- } else if (bt->flags & BT_START) { +- x86_64_print_stack_entry(bt, ofp, level, +- 0, bt->instptr); +- bt->flags &= ~BT_START; +- level++; +- } + strcpy(buf, machdep->cmdline_arg); -+ + + for (p = buf; *p; p++) { + if (*p == ',') + *p = ' '; + } -+ + +- if ((estack = x86_64_in_exception_stack(bt))) { +-in_exception_stack: +- bt->flags |= BT_EXCEPTION_STACK; +- /* +- * The stack buffer will have been loaded with the process +- * stack, so switch to the indicated exception stack. +- */ +- bt->stackbase = estack; +- bt->stacktop = estack + ms->stkinfo.esize; +- bt->stackbuf = ms->irqstack; + c = parse_line(buf, arglist); -+ -+ for (i = 0; i < c; i++) { + +- if (!readmem(bt->stackbase, KVADDR, bt->stackbuf, +- bt->stacktop - bt->stackbase, +- bt->hp && (bt->hp->esp == bt->stkptr) ? +- "irqstack contents via hook" : "irqstack contents", +- RETURN_ON_ERROR)) +- error(FATAL, "read of exception stack at %lx failed\n", +- bt->stackbase); ++ for (i = vm_flag = 0; i < c; i++) { + errflag = 0; -+ + +- /* +- * If irq_eframe is set, we've jumped back here from the +- * IRQ stack dump below. Do basically the same thing as if +- * had come from the processor stack, but presume that we +- * must have been in kernel mode, i.e., took an exception +- * while operating on an IRQ stack. (untested) +- */ +- if (irq_eframe) { +- bt->flags |= BT_EXCEPTION_FRAME; +- i = (irq_eframe - bt->stackbase)/sizeof(ulong); +- x86_64_print_stack_entry(bt, ofp, level, i, +- bt->instptr); +- bt->flags &= ~(ulonglong)BT_EXCEPTION_FRAME; +- cs = x86_64_exception_frame(EFRAME_PRINT|EFRAME_CS, 0, +- bt->stackbuf + (irq_eframe - bt->stackbase), +- bt, ofp); +- rsp += SIZE(pt_regs); /* guaranteed kernel mode */ +- level++; +- irq_eframe = 0; +- } + if (STRNEQ(arglist[i], "vm=")) { ++ vm_flag++; + p = arglist[i] + strlen("vm="); + if (strlen(p)) { + if (STREQ(p, "orig")) { @@ -17412,6 +27559,9 @@ + } else if (STREQ(p, "xen")) { + machdep->flags |= VM_XEN; + continue; ++ } else if (STREQ(p, "xen-rhel4")) { ++ machdep->flags |= VM_XEN_RHEL4; ++ continue; + } + } + } else if (STRNEQ(arglist[i], "phys_base=")) { @@ -17440,51 +27590,229 @@ + continue; + } + } -+ } -+ ++ } else if (STRNEQ(arglist[i], "irq_eframe_link=")) { ++ p = arglist[i] + strlen("irq_eframe_link="); ++ if (strlen(p)) { ++ value = stol(p, RETURN_ON_ERROR|QUIET, &errflag); ++ if (!errflag) { ++ machdep->machspec->irq_eframe_link = value; ++ continue; ++ } ++ } ++ } + +- stacktop = bt->stacktop - SIZE(pt_regs); + error(WARNING, "ignoring --machdep option: %s\n", arglist[i]); + lines++; + } -+ -+ switch (machdep->flags & (VM_ORIG|VM_2_6_11|VM_XEN)) -+ { -+ case 0: -+ break; -+ -+ case VM_ORIG: -+ error(NOTE, "using original x86_64 VM address ranges\n"); -+ lines++; -+ break; -+ -+ case VM_2_6_11: -+ error(NOTE, "using 2.6.11 x86_64 VM address ranges\n"); -+ lines++; -+ break; -+ -+ case VM_XEN: -+ error(NOTE, "using xen x86_64 VM address ranges\n"); -+ lines++; -+ break; -+ -+ default: -+ error(WARNING, "cannot set multiple vm values\n"); -+ lines++; -+ machdep->flags &= ~(VM_ORIG|VM_2_6_11|VM_XEN); -+ break; -+ } -+ + +- for (i = (rsp - bt->stackbase)/sizeof(ulong); +- !done && (rsp < stacktop); i++, rsp += sizeof(ulong)) { ++ if (vm_flag) { ++ switch (machdep->flags & VM_FLAGS) ++ { ++ case 0: ++ break; ++ ++ case VM_ORIG: ++ error(NOTE, "using original x86_64 VM address ranges\n"); ++ lines++; ++ break; ++ ++ case VM_2_6_11: ++ error(NOTE, "using 2.6.11 x86_64 VM address ranges\n"); ++ lines++; ++ break; ++ ++ case VM_XEN: ++ error(NOTE, "using xen x86_64 VM address ranges\n"); ++ lines++; ++ break; + +- up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]); ++ case VM_XEN_RHEL4: ++ error(NOTE, "using RHEL4 xen x86_64 VM address ranges\n"); ++ lines++; ++ break; ++ ++ default: ++ error(WARNING, "cannot set multiple vm values\n"); ++ lines++; ++ machdep->flags &= ~VM_FLAGS; ++ break; ++ } ++ } + +- if (!is_kernel_text(*up)) +- continue; + if (lines) + fprintf(fp, "\n"); +} -+ + +- switch (x86_64_print_stack_entry(bt, ofp, level, i,*up)) +- { +- case BACKTRACE_ENTRY_AND_EFRAME_DISPLAYED: +- rsp += SIZE(pt_regs); +- i += SIZE(pt_regs)/sizeof(ulong); +- case BACKTRACE_ENTRY_DISPLAYED: +- level++; +- break; +- case BACKTRACE_ENTRY_IGNORED: +- break; +- case BACKTRACE_COMPLETE: +- done = TRUE; +- break; +- } +- } +void +x86_64_clear_machdep_cache(void) +{ + machdep->machspec->last_upml_read = 0; +} + +- cs = x86_64_exception_frame(EFRAME_PRINT|EFRAME_CS, 0, +- bt->stackbuf + (bt->stacktop - bt->stackbase) - +- SIZE(pt_regs), bt, ofp); ++static void ++x86_64_irq_eframe_link_init(void) ++{ ++ int c; ++ struct syment *sp, *spn; ++ char buf[BUFSIZE]; ++ char link_register[BUFSIZE]; ++ char *arglist[MAXARGS]; ++ ulong max_instructions; + +- if (!BT_REFERENCE_CHECK(bt)) +- fprintf(fp, "--- ---\n"); ++ if (machdep->machspec->irq_eframe_link == UNINITIALIZED) ++ machdep->machspec->irq_eframe_link = 0; ++ else ++ return; + +- /* +- * stack = (unsigned long *) estack_end[-2]; +- */ +- up = (ulong *)(&bt->stackbuf[bt->stacktop - bt->stackbase]); +- up -= 2; +- rsp = bt->stkptr = *up; +- up -= 3; +- bt->instptr = *up; +- if (cs & 3) +- done = TRUE; /* user-mode exception */ +- else +- done = FALSE; /* kernel-mode exception */ +- bt->frameptr = 0; ++ if (THIS_KERNEL_VERSION < LINUX(2,6,9)) ++ return; + +- /* +- * Print the return values from the estack end. +- */ +- if (!done) { +- bt->flags |= BT_START; +- x86_64_print_stack_entry(bt, ofp, level, +- 0, bt->instptr); +- bt->flags &= ~BT_START; +- level++; +- } ++ if (!(sp = symbol_search("common_interrupt")) || ++ !(spn = next_symbol(NULL, sp))) { ++ return; + } + +- /* +- * IRQ stack entry always comes in via the process stack, regardless +- * whether it happened while running in user or kernel space. +- */ +- if (!done && (irqstack = x86_64_in_irqstack(bt))) { +- bt->flags |= BT_IRQSTACK; +- /* +- * Until coded otherwise, the stackbase will be pointing to +- * either the exception stack or, more likely, the process +- * stack base. Switch it to the IRQ stack. +- */ +- bt->stackbase = irqstack; +- bt->stacktop = irqstack + ms->stkinfo.isize; +- bt->stackbuf = ms->irqstack; ++ max_instructions = spn->value - sp->value; + +- if (!readmem(bt->stackbase, KVADDR, +- bt->stackbuf, bt->stacktop - bt->stackbase, +- bt->hp && (bt->hp->esp == bt_in->stkptr) ? +- "irqstack contents via hook" : "irqstack contents", +- RETURN_ON_ERROR)) +- error(FATAL, "read of IRQ stack at %lx failed\n", +- bt->stackbase); ++ open_tmpfile(); + +- stacktop = bt->stacktop - 64; /* from kernel code */ ++ sprintf(buf, "x/%ldi 0x%lx", ++ max_instructions, sp->value); + +- for (i = (rsp - bt->stackbase)/sizeof(ulong); +- !done && (rsp < stacktop); i++, rsp += sizeof(ulong)) { ++ if (!gdb_pass_through(buf, pc->tmpfile, GNU_RETURN_ON_ERROR)) ++ return; + +- up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]); ++ link_register[0] = NULLCHAR; + +- if (!is_kernel_text(*up)) +- continue; ++ rewind(pc->tmpfile); ++ while (fgets(buf, BUFSIZE, pc->tmpfile)) { ++ if (!strstr(buf, sp->name)) ++ break; ++ if ((c = parse_line(buf, arglist)) < 4) ++ continue; ++ if (strstr(arglist[2], "push")) ++ strcpy(link_register, arglist[3]); ++ } ++ close_tmpfile(); + +- switch (x86_64_print_stack_entry(bt, ofp, level, i,*up)) +- { +- case BACKTRACE_ENTRY_AND_EFRAME_DISPLAYED: +- rsp += SIZE(pt_regs); +- i += SIZE(pt_regs)/sizeof(ulong); +- case BACKTRACE_ENTRY_DISPLAYED: +- level++; +- break; +- case BACKTRACE_ENTRY_IGNORED: +- break; +- case BACKTRACE_COMPLETE: +- done = TRUE; +- break; +- } +- } ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "IRQ stack link register: %s\n", ++ strlen(link_register) ? ++ link_register : "undetermined"); + +- if (!BT_REFERENCE_CHECK(bt)) +- fprintf(fp, "--- ---\n"); ++ if (STREQ(link_register, "%rbp")) ++ machdep->machspec->irq_eframe_link = 40; ++ ++} + +#include "netdump.h" -+ + +- /* +- * stack = (unsigned long *) (irqstack_end[-1]); +- * (where irqstack_end is 64 bytes below page end) +- */ +- up = (ulong *)(&bt->stackbuf[stacktop - bt->stackbase]); +- up -= 1; +- irq_eframe = rsp = bt->stkptr = *up; +- up -= 1; +- bt->instptr = *up; +- bt->frameptr = 0; +- done = FALSE; +- } else +- irq_eframe = 0; +/* + * Determine the physical address base for relocatable kernels. + */ @@ -17495,24 +27823,46 @@ + FILE *iomem; + char buf[BUFSIZE]; + char *p1; -+ ulong text_start, kernel_code_start; ++ ulong phys_base, text_start, kernel_code_start; + int errflag; + struct vmcore_data *vd; + Elf64_Phdr *phdr; -+ + +- if (!done && (estack = x86_64_in_exception_stack(bt))) +- goto in_exception_stack; + if (machdep->flags & PHYS_BASE) /* --machdep override */ + return; -+ + +- if (!done && (bt->flags & (BT_EXCEPTION_STACK|BT_IRQSTACK))) { +- /* +- * Verify that the rsp pointer taken from either the +- * exception or IRQ stack points into the process stack. +- */ +- bt->stackbase = GET_STACKBASE(bt->tc->task); +- bt->stacktop = GET_STACKTOP(bt->tc->task); + machdep->machspec->phys_base = 0; /* default/traditional */ -+ -+ if (!symbol_exists("phys_base")) + +- if (!INSTACK(rsp, bt)) { +- switch (bt->flags & (BT_EXCEPTION_STACK|BT_IRQSTACK)) +- { +- case (BT_EXCEPTION_STACK|BT_IRQSTACK): +- error(FATAL, STACK_TRANSITION_ERRMSG_E_I_P, +- bt_in->stkptr, bt->stkptr, rsp, +- bt->stackbase); ++ if (!kernel_symbol_exists("phys_base")) + return; -+ + +- case BT_EXCEPTION_STACK: +- error(FATAL, STACK_TRANSITION_ERRMSG_E_P, +- bt_in->stkptr, rsp, bt->stackbase); + if (!symbol_exists("_text")) + return; + else + text_start = symbol_value("_text"); -+ + +- case BT_IRQSTACK: +- error(FATAL, STACK_TRANSITION_ERRMSG_I_P, +- bt_in->stkptr, rsp, bt->stackbase); + if (ACTIVE()) { + if ((iomem = fopen("/proc/iomem", "r")) == NULL) + return; @@ -17523,8 +27873,8 @@ + clean_line(buf); + errflag = 0; + break; -+ } -+ } + } + } + fclose(iomem); + + if (errflag) @@ -17549,13 +27899,101 @@ + fprintf(fp, "phys_base: %lx\n\n", + machdep->machspec->phys_base); + } -+ + +- /* +- * Now fill the local stack buffer from the process stack. +- */ +- if (!readmem(bt->stackbase, KVADDR, bt->stackbuf, +- bt->stacktop - bt->stackbase, +- "irqstack contents", RETURN_ON_ERROR)) +- error(FATAL, "read of process stack at %lx failed\n", +- bt->stackbase); +- } +- +- /* +- * For a normally blocked task, hand-create the first level. +- */ +- if (!done && +- !(bt->flags & (BT_TEXT_SYMBOLS|BT_EXCEPTION_STACK|BT_IRQSTACK)) && +- STREQ(closest_symbol(bt->instptr), "thread_return")) { +- bt->flags |= BT_SCHEDULE; +- i = (rsp - bt->stackbase)/sizeof(ulong); +- x86_64_print_stack_entry(bt, ofp, level, +- i, bt->instptr); +- bt->flags &= ~(ulonglong)BT_SCHEDULE; +- rsp += sizeof(ulong); +- level++; ++ return; + } + + /* +- * Dump the IRQ exception frame from the process stack. +- * If the CS register indicates a user exception frame, +- * then set done to TRUE to avoid the process stack walk-through. +- * Otherwise, bump up the rsp past the kernel-mode eframe. +- */ +- if (irq_eframe) { +- bt->flags |= BT_EXCEPTION_FRAME; +- i = (irq_eframe - bt->stackbase)/sizeof(ulong); +- x86_64_print_stack_entry(bt, ofp, level, i, bt->instptr); +- bt->flags &= ~(ulonglong)BT_EXCEPTION_FRAME; +- cs = x86_64_exception_frame(EFRAME_PRINT|EFRAME_CS, 0, +- bt->stackbuf + (irq_eframe - bt->stackbase), bt, ofp); +- if (cs & 3) +- done = TRUE; /* IRQ from user-mode */ +- else +- rsp += SIZE(pt_regs); +- level++; +- } +- +- /* +- * Walk the process stack. ++ * Get relocation value from whatever dumpfile format is being used. + */ +- for (i = (rsp - bt->stackbase)/sizeof(ulong); +- !done && (rsp < bt->stacktop); i++, rsp += sizeof(ulong)) { +- +- up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]); +- +- if (!is_kernel_text(*up)) +- continue; + +- if ((bt->flags & BT_CHECK_CALLER)) { +- /* +- * A non-zero offset value from the value_search() +- * lets us know if it's a real text return address. +- */ +- spt = value_search(*up, &offset); +- /* +- * sp gets the syment of the function that the text +- * routine above called before leaving its return +- * address on the stack -- if it can be determined. +- */ +- sp = x86_64_function_called_by((*up)-5); ++ if (DISKDUMP_DUMPFILE()) { ++ if (diskdump_phys_base(&phys_base)) { ++ machdep->machspec->phys_base = phys_base; ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "compressed kdump: phys_base: %lx\n", ++ phys_base); ++ } + return; + } -+ -+ /* -+ * Get relocation value from whatever dumpfile format is being used. -+ */ + +- if (sp == NULL) { +- /* +- * We were unable to get the called function. +- * If the text address had an offset, then +- * it must have made an indirect call, and +- * can't have called our target function. +- */ +- if (offset) { +- if (CRASHDEBUG(1)) +- fprintf(ofp, +- "< ignoring %s() -- makes indirect call and NOT %s()>\n", +- spt->name, +- bt->call_target); +- continue; + if ((vd = get_kdump_vmcore_data())) { + for (i = 0; i < vd->num_pt_load_segments; i++) { + phdr = vd->load64 + i; @@ -17570,39 +28008,111 @@ + phdr->p_vaddr, phdr->p_paddr); + fprintf(fp, "phys_base: %lx\n\n", + machdep->machspec->phys_base); -+ } + } +- } else if (!STREQ(sp->name, bt->call_target)) { +- /* +- * We got function called by the text routine, +- * but it's not our target function. +- */ +- if (CRASHDEBUG(2)) +- fprintf(ofp, +- "< ignoring %s() -- calls %s() and NOT %s()>\n", +- spt->name, sp->name, +- bt->call_target); +- continue; + break; -+ } -+ } -+ + } + } + +- switch (x86_64_print_stack_entry(bt, ofp, level, i,*up)) +- { +- case BACKTRACE_ENTRY_AND_EFRAME_DISPLAYED: +- last_process_stack_eframe = rsp + 8; +- rsp += SIZE(pt_regs); +- i += SIZE(pt_regs)/sizeof(ulong); +- case BACKTRACE_ENTRY_DISPLAYED: +- level++; +- break; +- case BACKTRACE_ENTRY_IGNORED: +- break; +- case BACKTRACE_COMPLETE: +- done = TRUE; +- break; +- } +- } +- +- if (!irq_eframe && !is_kernel_thread(bt->tc->task) && +- (GET_STACKBASE(bt->tc->task) == bt->stackbase)) { +- user_mode_eframe = bt->stacktop - SIZE(pt_regs); +- if (last_process_stack_eframe < user_mode_eframe) +- x86_64_exception_frame(EFRAME_PRINT, 0, bt->stackbuf + +- (bt->stacktop - bt->stackbase) - SIZE(pt_regs), +- bt, ofp); + return; -+ } -+} -+ -+/* + } + +- if (bt->flags & BT_TEXT_SYMBOLS) { +- if (BT_REFERENCE_FOUND(bt)) { +- print_task_header(fp, task_to_context(bt->task), 0); +- BCOPY(bt_in, bt, sizeof(struct bt_info)); +- bt->ref = NULL; +- machdep->back_trace(bt); +- fprintf(fp, "\n"); +- } ++ if (XENDUMP_DUMPFILE() && (text_start == __START_KERNEL_map)) { ++ /* ++ * Xen kernels are not relocable (yet) and don't have the ++ * "phys_base" entry point, so this must be a xendump of a ++ * fully-virtualized relocatable kernel. No clues exist in ++ * the xendump header, so hardwire phys_base to 2MB and hope ++ * for the best. ++ */ ++ machdep->machspec->phys_base = 0x200000; ++ if (CRASHDEBUG(1)) ++ fprintf(fp, ++ "default relocatable default phys_base: %lx\n", ++ machdep->machspec->phys_base); + } + } + + /* +- * Functions that won't be called indirectly. +- * Add more to this as they are discovered. + * From the xen vmcore, create an index of mfns for each page that makes + * up the dom0 kernel's complete phys_to_machine_mapping[max_pfn] array. -+ */ + */ +-static const char *direct_call_targets[] = { +- "schedule", +- "schedule_timeout", +- NULL +-}; + +#define MAX_X86_64_FRAMES (512) +#define MFNS_PER_FRAME (PAGESIZE()/sizeof(ulong)) -+ -+static int + + static int +-is_direct_call_target(struct bt_info *bt) +x86_64_xen_kdump_p2m_create(struct xen_kdump_data *xkd) -+{ + { +- int i; + int i, j; + ulong kvaddr; + ulong *up; + ulong frames; + ulong frame_mfn[MAX_X86_64_FRAMES] = { 0 }; + int mfns[MAX_X86_64_FRAMES] = { 0 }; -+ + +- if (!bt->call_target || (bt->flags & BT_NO_CHECK_CALLER)) +- return FALSE; + /* + * Temporarily read physical (machine) addresses from vmcore by + * going directly to read_netdump() instead of via read_kdump(). + */ + pc->readmem = read_netdump; -+ + +- for (i = 0; direct_call_targets[i]; i++) { +- if (STREQ(direct_call_targets[i], bt->call_target)) +- return TRUE; + if (xkd->flags & KDUMP_CR3) + goto use_cr3; + @@ -17614,7 +28124,7 @@ + "xen kdump p2m mfn page", RETURN_ON_ERROR)) + error(FATAL, "cannot read xen kdump p2m mfn page\n"); + -+ if (CRASHDEBUG(1)) ++ if (CRASHDEBUG(2)) + x86_64_debug_dump_page(fp, xkd->page, "pfn_to_mfn_frame_list"); + + for (i = 0, up = (ulong *)xkd->page; i < MAX_X86_64_FRAMES; i++, up++) @@ -17636,8 +28146,9 @@ + + if (CRASHDEBUG(7)) + x86_64_debug_dump_page(fp, xkd->page, "pfn_to_mfn_frame_list page"); -+ } -+ + } + +- return FALSE; + if (CRASHDEBUG(1)) + fprintf(fp, "p2m_frames: %d\n", xkd->p2m_frames); + @@ -17655,8 +28166,14 @@ + frames -= mfns[i]; + } + ++ if (CRASHDEBUG(2)) { ++ for (i = 0; i < xkd->p2m_frames; i++) ++ fprintf(fp, "%lx ", xkd->p2m_mfn_frame_list[i]); ++ fprintf(fp, "\n"); ++ } ++ + pc->readmem = read_kdump; -+ return FALSE; ++ return TRUE; + +use_cr3: + @@ -17716,14 +28233,22 @@ + pc->readmem = read_kdump; + + return TRUE; -+} -+ + } + +-static struct syment * +-x86_64_function_called_by(ulong rip) +static char * +x86_64_xen_kdump_load_page(ulong kvaddr, char *pgbuf) -+{ + { +- struct syment *sp; +- char buf[BUFSIZE], *p1; +- ulong value, offset; +- unsigned char byte; + ulong mfn; + ulong *pml4, *pgd, *pmd, *ptep; -+ + +- value = 0; +- sp = NULL; + pml4 = ((ulong *)machdep->machspec->pml4) + pml4_index(kvaddr); + mfn = ((*pml4) & PHYSICAL_PAGE_MASK) >> PAGESHIFT(); + @@ -17767,33 +28292,60 @@ + if (!readmem(PTOB(mfn), PHYSADDR, machdep->ptbl, PAGESIZE(), + "xen kdump page table page", RETURN_ON_ERROR)) + error(FATAL, "cannot read/find page table page\n"); -+ + +- if (!readmem(rip, KVADDR, &byte, sizeof(unsigned char), "call byte", +- RETURN_ON_ERROR)) +- return sp; + if (CRASHDEBUG(7)) + x86_64_debug_dump_page(fp, machdep->ptbl, + "contents of page table page:"); -+ + +- if (byte != 0xe8) +- return sp; + ptep = ((ulong *)machdep->ptbl) + pte_index(kvaddr); + mfn = ((*ptep) & PHYSICAL_PAGE_MASK) >> PAGESHIFT(); -+ + +- sprintf(buf, "x/i 0x%lx", rip); + if (CRASHDEBUG(3)) + fprintf(fp, + "[%lx] ptep: %lx mfn: %lx pte_index: %lx\n", + kvaddr, *ptep, mfn, pte_index(kvaddr)); -+ + +- open_tmpfile2(); +- if (gdb_pass_through(buf, pc->tmpfile2, GNU_RETURN_ON_ERROR)) { +- rewind(pc->tmpfile2); +- while (fgets(buf, BUFSIZE, pc->tmpfile2)) { +- if ((p1 = strstr(buf, "callq")) && +- whitespace(*(p1-1))) { +- if (extract_hex(p1, &value, NULLCHAR, TRUE)) +- break; +- } +- } +- } +- close_tmpfile2(); + if (!readmem(PTOB(mfn), PHYSADDR, pgbuf, PAGESIZE(), + "xen kdump page table page", RETURN_ON_ERROR)) + error(FATAL, "cannot read/find pte page\n"); -+ + +- if (value) +- sp = value_search(value, &offset); + if (CRASHDEBUG(7)) + x86_64_debug_dump_page(fp, pgbuf, + "contents of page:"); -+ + +- return sp; + return pgbuf; -+} -+ + } + +-/* +- * Unroll the kernel stack using a minimal amount of gdb services. +- */ +-static void +-x86_64_back_trace(struct gnu_request *req, struct bt_info *bt) +static ulong +x86_64_xen_kdump_page_mfn(ulong kvaddr) -+{ + { +- error(FATAL, "x86_64_back_trace: unused\n"); + ulong mfn; + ulong *pml4, *pgd, *pmd, *ptep; + @@ -17828,22 +28380,104 @@ + mfn = ((*ptep) & PHYSICAL_PAGE_MASK) >> PAGESHIFT(); + + return mfn; -+} -+ + } + +#include "xendump.h" -+ -+/* + + /* +- * Print exception frame information for x86_64. +- * +- * Pid: 0, comm: swapper Not tainted 2.6.5-1.360phro.rootsmp +- * RIP: 0010:[] {default_idle+36} +- * RSP: 0018:ffffffff8048bfd8 EFLAGS: 00000246 +- * RAX: 0000000000000000 RBX: ffffffff8010f510 RCX: 0000000000000018 +- * RDX: 0000010001e37280 RSI: ffffffff803ac0a0 RDI: 000001007f43c400 +- * RBP: 0000000000000000 R08: ffffffff8048a000 R09: 0000000000000000 +- * R10: ffffffff80482188 R11: 0000000000000001 R12: 0000000000000000 +- * R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 +- * FS: 0000002a96e14fc0(0000) GS:ffffffff80481d80(0000) GS:0000000055578aa0 +- * CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b +- * CR2: 0000002a9556b000 CR3: 0000000000101000 CR4: 00000000000006e0 +- * + * Create an index of mfns for each page that makes up the + * kernel's complete phys_to_machine_mapping[max_pfn] array. -+ */ + */ +- +-static long +-x86_64_exception_frame(ulong flags, ulong kvaddr, char *local, +- struct bt_info *bt, FILE *ofp) +static int +x86_64_xendump_p2m_create(struct xendump_data *xd) -+{ + { +- long rip, rsp, cs, ss, rflags, orig_rax, rbp; +- long rax, rbx, rcx, rdx, rsi, rdi; +- long r8, r9, r10, r11, r12, r13, r14, r15; +- struct machine_specific *ms; +- char *pt_regs_buf; +- long verified; +- int err; +- +- ms = machdep->machspec; +- +- if (!(machdep->flags & PT_REGS_INIT)) { +- err = 0; +- err |= ((ms->pto.r15 = MEMBER_OFFSET("pt_regs", "r15")) == +- INVALID_OFFSET); +- err |= ((ms->pto.r14 = MEMBER_OFFSET("pt_regs", "r14")) == +- INVALID_OFFSET); +- err |= ((ms->pto.r13 = MEMBER_OFFSET("pt_regs", "r13")) == +- INVALID_OFFSET); +- err |= ((ms->pto.r12 = MEMBER_OFFSET("pt_regs", "r12")) == +- INVALID_OFFSET); +- err |= ((ms->pto.r11 = MEMBER_OFFSET("pt_regs", "r11")) == +- INVALID_OFFSET); +- err |= ((ms->pto.r10 = MEMBER_OFFSET("pt_regs", "r10")) == +- INVALID_OFFSET); +- err |= ((ms->pto.r9 = MEMBER_OFFSET("pt_regs", "r9")) == +- INVALID_OFFSET); +- err |= ((ms->pto.r8 = MEMBER_OFFSET("pt_regs", "r8")) == +- INVALID_OFFSET); +- err |= ((ms->pto.rax = MEMBER_OFFSET("pt_regs", "rax")) == +- INVALID_OFFSET); +- err |= ((ms->pto.rbx = MEMBER_OFFSET("pt_regs", "rbx")) == +- INVALID_OFFSET); +- err |= ((ms->pto.rcx = MEMBER_OFFSET("pt_regs", "rcx")) == +- INVALID_OFFSET); +- err |= ((ms->pto.rdx = MEMBER_OFFSET("pt_regs", "rdx")) == +- INVALID_OFFSET); +- err |= ((ms->pto.rsi = MEMBER_OFFSET("pt_regs", "rsi")) == +- INVALID_OFFSET); +- err |= ((ms->pto.rdi = MEMBER_OFFSET("pt_regs", "rdi")) == +- INVALID_OFFSET); +- err |= ((ms->pto.rip = MEMBER_OFFSET("pt_regs", "rip")) == +- INVALID_OFFSET); +- err |= ((ms->pto.rsp = MEMBER_OFFSET("pt_regs", "rsp")) == +- INVALID_OFFSET); +- err |= ((ms->pto.cs = MEMBER_OFFSET("pt_regs", "cs")) == +- INVALID_OFFSET); +- err |= ((ms->pto.ss = MEMBER_OFFSET("pt_regs", "ss")) == +- INVALID_OFFSET); +- err |= ((ms->pto.eflags = MEMBER_OFFSET("pt_regs", "eflags")) == +- INVALID_OFFSET); +- err |= ((ms->pto.orig_rax = +- MEMBER_OFFSET("pt_regs", "orig_rax")) == +- INVALID_OFFSET); +- err |= ((ms->pto.rbp = MEMBER_OFFSET("pt_regs", "rbp")) == +- INVALID_OFFSET); + int i, idx; + ulong mfn, kvaddr, ctrlreg[8], ctrlreg_offset; + ulong *up; + off_t offset; -+ + +- if (err) +- error(WARNING, "pt_regs structure has changed\n"); ++ if (!symbol_exists("phys_to_machine_mapping")) { ++ xd->flags |= XC_CORE_NO_P2M; ++ return TRUE; ++ } + +- machdep->flags |= PT_REGS_INIT; +- } + if ((ctrlreg_offset = MEMBER_OFFSET("vcpu_guest_context", "ctrlreg")) == + INVALID_OFFSET) + error(FATAL, @@ -17874,51 +28508,143 @@ + if (CRASHDEBUG(7)) + x86_64_debug_dump_page(xd->ofp, machdep->machspec->pml4, + "contents of PML4 page:"); -+ + +- if (kvaddr) { +- pt_regs_buf = GETBUF(SIZE(pt_regs)); +- readmem(kvaddr, KVADDR, pt_regs_buf, +- SIZE(pt_regs), "pt_regs", FAULT_ON_ERROR); +- } else +- pt_regs_buf = local; + kvaddr = symbol_value("end_pfn"); + if (!x86_64_xendump_load_page(kvaddr, xd)) + return FALSE; -+ + +- rip = ULONG(pt_regs_buf + ms->pto.rip); +- rsp = ULONG(pt_regs_buf + ms->pto.rsp); +- cs = ULONG(pt_regs_buf + ms->pto.cs); +- ss = ULONG(pt_regs_buf + ms->pto.ss); +- rflags = ULONG(pt_regs_buf + ms->pto.eflags); +- orig_rax = ULONG(pt_regs_buf + ms->pto.orig_rax); +- rbp = ULONG(pt_regs_buf + ms->pto.rbp); +- rax = ULONG(pt_regs_buf + ms->pto.rax); +- rbx = ULONG(pt_regs_buf + ms->pto.rbx); +- rcx = ULONG(pt_regs_buf + ms->pto.rcx); +- rdx = ULONG(pt_regs_buf + ms->pto.rdx); +- rsi = ULONG(pt_regs_buf + ms->pto.rsi); +- rdi = ULONG(pt_regs_buf + ms->pto.rdi); +- r8 = ULONG(pt_regs_buf + ms->pto.r8); +- r9 = ULONG(pt_regs_buf + ms->pto.r9); +- r10 = ULONG(pt_regs_buf + ms->pto.r10); +- r11 = ULONG(pt_regs_buf + ms->pto.r11); +- r12 = ULONG(pt_regs_buf + ms->pto.r12); +- r13 = ULONG(pt_regs_buf + ms->pto.r13); +- r14 = ULONG(pt_regs_buf + ms->pto.r14); +- r15 = ULONG(pt_regs_buf + ms->pto.r15); + up = (ulong *)(xd->page + PAGEOFFSET(kvaddr)); + if (CRASHDEBUG(1)) + fprintf(xd->ofp, "end_pfn: %lx\n", *up); -+ + +- verified = x86_64_eframe_verify(bt, +- kvaddr ? kvaddr : (local - bt->stackbuf) + bt->stackbase, +- cs, ss, rip, rsp, rflags); + xd->xc_core.p2m_frames = (*up/(PAGESIZE()/sizeof(ulong))) + + ((*up%(PAGESIZE()/sizeof(ulong))) ? 1 : 0); -+ + +- /* +- * If it's print-if-verified request, don't print bogus eframes. +- */ +- if (!verified && ((flags & (EFRAME_VERIFY|EFRAME_PRINT)) == +- (EFRAME_VERIFY|EFRAME_PRINT))) +- flags &= ~EFRAME_PRINT; + if ((xd->xc_core.p2m_frame_index_list = (ulong *) + malloc(xd->xc_core.p2m_frames * sizeof(ulong))) == NULL) + error(FATAL, "cannot malloc p2m_frame_list"); -+ + +- if (CRASHDEBUG(2)) +- fprintf(ofp, "< exception frame at: %lx >\n", kvaddr ? kvaddr : +- (local - bt->stackbuf) + bt->stackbase); + kvaddr = symbol_value("phys_to_machine_mapping"); + if (!x86_64_xendump_load_page(kvaddr, xd)) + return FALSE; -+ + +- if (flags & EFRAME_PRINT) { +- if (flags & EFRAME_SEARCH) { +- fprintf(ofp, "\n %s-MODE EXCEPTION FRAME AT: %lx\n", +- cs & 3 ? "USER" : "KERNEL", +- kvaddr ? kvaddr : +- (local - bt->stackbuf) + bt->stackbase); +- } + up = (ulong *)(xd->page + PAGEOFFSET(kvaddr)); + if (CRASHDEBUG(1)) + fprintf(fp, "phys_to_machine_mapping: %lx\n", *up); -+ + +- fprintf(ofp, " RIP: %016lx RSP: %016lx RFLAGS: %08lx\n", +- rip, rsp, rflags); +- fprintf(ofp, " RAX: %016lx RBX: %016lx RCX: %016lx\n", +- rax, rbx, rcx); +- fprintf(ofp, " RDX: %016lx RSI: %016lx RDI: %016lx\n", +- rdx, rsi, rdi); +- fprintf(ofp, " RBP: %016lx R8: %016lx R9: %016lx\n", +- rbp, r8, r9); +- fprintf(ofp, " R10: %016lx R11: %016lx R12: %016lx\n", +- r10, r11, r12); +- fprintf(ofp, " R13: %016lx R14: %016lx R15: %016lx\n", +- r13, r14, r15); +- fprintf(ofp, " ORIG_RAX: %016lx CS: %04lx SS: %04lx\n", +- orig_rax, cs, ss); + kvaddr = *up; + machdep->last_ptbl_read = BADADDR; -+ + +- if (!verified) +- error(WARNING, "possibly bogus exception frame\n"); + for (i = 0; i < xd->xc_core.p2m_frames; i++) { + if ((idx = x86_64_xendump_page_index(kvaddr, xd)) == MFN_NOT_FOUND) + return FALSE; + xd->xc_core.p2m_frame_index_list[i] = idx; + kvaddr += PAGESIZE(); -+ } -+ + } + +- if ((flags & EFRAME_PRINT) && BT_REFERENCE_CHECK(bt)) { +- x86_64_do_bt_reference_check(bt, rip, NULL); +- x86_64_do_bt_reference_check(bt, rsp, NULL); +- x86_64_do_bt_reference_check(bt, cs, NULL); +- x86_64_do_bt_reference_check(bt, ss, NULL); +- x86_64_do_bt_reference_check(bt, rflags, NULL); +- x86_64_do_bt_reference_check(bt, orig_rax, NULL); +- x86_64_do_bt_reference_check(bt, rbp, NULL); +- x86_64_do_bt_reference_check(bt, rax, NULL); +- x86_64_do_bt_reference_check(bt, rbx, NULL); +- x86_64_do_bt_reference_check(bt, rcx, NULL); +- x86_64_do_bt_reference_check(bt, rdx, NULL); +- x86_64_do_bt_reference_check(bt, rsi, NULL); +- x86_64_do_bt_reference_check(bt, rdi, NULL); +- x86_64_do_bt_reference_check(bt, r8, NULL); +- x86_64_do_bt_reference_check(bt, r9, NULL); +- x86_64_do_bt_reference_check(bt, r10, NULL); +- x86_64_do_bt_reference_check(bt, r11, NULL); +- x86_64_do_bt_reference_check(bt, r12, NULL); +- x86_64_do_bt_reference_check(bt, r13, NULL); +- x86_64_do_bt_reference_check(bt, r14, NULL); +- x86_64_do_bt_reference_check(bt, r15, NULL); +- } + machdep->last_ptbl_read = 0; -+ + +- if (kvaddr) +- FREEBUF(pt_regs_buf); + return TRUE; +} -+ + +- if (flags & EFRAME_CS) +- return cs; +- else if (flags & EFRAME_VERIFY) +- return verified; +static void +x86_64_debug_dump_page(FILE *ofp, char *page, char *name) +{ + int i; + ulong *up; -+ + +- return 0; + fprintf(ofp, "%s\n", name); + + up = (ulong *)page; @@ -17928,29 +28654,55 @@ + *up, *(up+1)); + up += 2; + } -+} -+ -+/* + } + + /* +- * Check that the verifiable registers contain reasonable data. + * Find the page associate with the kvaddr, and read its contents + * into the passed-in buffer. -+ */ + */ +-#define RAZ_MASK 0xffffffffffc08028 /* return-as-zero bits */ +- +-static int +-x86_64_eframe_verify(struct bt_info *bt, long kvaddr, long cs, long ss, +- long rip, long rsp, long rflags) +static char * +x86_64_xendump_load_page(ulong kvaddr, struct xendump_data *xd) -+{ + { +- if ((rflags & RAZ_MASK) || !(rflags & 0x2)) +- return FALSE; + ulong mfn; + ulong *pml4, *pgd, *pmd, *ptep; -+ + +- if ((cs == 0x10) && (ss == 0x18)) { +- if (is_kernel_text(rip) && IS_KVADDR(rsp)) +- return TRUE; +- } + pml4 = ((ulong *)machdep->machspec->pml4) + pml4_index(kvaddr); + mfn = ((*pml4) & PHYSICAL_PAGE_MASK) >> PAGESHIFT(); -+ + +- if ((cs == 0x10) && kvaddr) { +- if (is_kernel_text(rip) && IS_KVADDR(rsp) && +- (rsp == (kvaddr + SIZE(pt_regs) + 8))) +- return TRUE; +- } + if (CRASHDEBUG(3)) + fprintf(xd->ofp, + "[%lx] pml4: %lx mfn: %lx pml4_index: %lx\n", + kvaddr, *pml4, mfn, pml4_index(kvaddr)); -+ + +- if ((cs == 0x10) && kvaddr) { +- if (is_kernel_text(rip) && IS_KVADDR(rsp) && +- (rsp == (kvaddr + SIZE(pt_regs)))) +- return TRUE; +- } + if (!xc_core_mfn_to_page(mfn, machdep->pgd)) + error(FATAL, "cannot read/find pud page\n"); -+ + +- if ((cs == 0x33) && (ss == 0x2b)) { +- if (IS_UVADDR(rip, bt->tc) && IS_UVADDR(rsp, bt->tc)) +- return TRUE; +- } + if (CRASHDEBUG(7)) + x86_64_debug_dump_page(xd->ofp, machdep->pgd, + "contents of page upper directory page:"); @@ -17987,67 +28739,178 @@ + + ptep = ((ulong *)machdep->ptbl) + pte_index(kvaddr); + mfn = ((*ptep) & PHYSICAL_PAGE_MASK) >> PAGESHIFT(); -+ + +- return FALSE; +-} + if (CRASHDEBUG(3)) + fprintf(xd->ofp, + "[%lx] ptep: %lx mfn: %lx pte_index: %lx\n", + kvaddr, *ptep, mfn, pte_index(kvaddr)); -+ + +-/* +- * Get a stack frame combination of pc and ra from the most relevent spot. +- */ +-static void +-x86_64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp) +-{ +- if (bt->flags & BT_DUMPFILE_SEARCH) +- return x86_64_get_dumpfile_stack_frame(bt, pcp, spp); + if (!xc_core_mfn_to_page(mfn, xd->page)) + error(FATAL, "cannot read/find pte page\n"); -+ + +- if (pcp) +- *pcp = x86_64_get_pc(bt); +- if (spp) +- *spp = x86_64_get_sp(bt); + if (CRASHDEBUG(7)) + x86_64_debug_dump_page(xd->ofp, xd->page, + "contents of page:"); + + return xd->page; -+} -+ -+/* + } + + /* +- * Get the starting point for the active cpus in a diskdump/netdump. + * Find the dumpfile page index associated with the kvaddr. -+ */ + */ +-static void +-x86_64_get_dumpfile_stack_frame(struct bt_info *bt_in, ulong *rip, ulong *rsp) +static int +x86_64_xendump_page_index(ulong kvaddr, struct xendump_data *xd) -+{ + { +- int panic_task; +- int i, panic, stage; +- char *sym; +- struct syment *sp; +- ulong *up; +- struct bt_info bt_local, *bt; +- struct machine_specific *ms; +- char *user_regs; +- ulong ur_rip; +- ulong ur_rsp; + int idx; + ulong mfn; + ulong *pml4, *pgd, *pmd, *ptep; -+ + +- bt = &bt_local; +- BCOPY(bt_in, bt, sizeof(struct bt_info)); +- ms = machdep->machspec; +- ur_rip = ur_rsp = 0; +- stage = 0; + pml4 = ((ulong *)machdep->machspec->pml4) + pml4_index(kvaddr); + mfn = ((*pml4) & PHYSICAL_PAGE_MASK) >> PAGESHIFT(); -+ + +- panic_task = tt->panic_task == bt->task ? TRUE : FALSE; + if ((mfn != machdep->last_pgd_read) && + !xc_core_mfn_to_page(mfn, machdep->pgd)) + error(FATAL, "cannot read/find pud page\n"); + machdep->last_pgd_read = mfn; -+ + +- if (panic_task && bt->machdep) { +- user_regs = bt->machdep; + pgd = ((ulong *)machdep->pgd) + pgd_index(kvaddr); + mfn = ((*pgd) & PHYSICAL_PAGE_MASK) >> PAGESHIFT(); -+ + +- if (x86_64_eframe_verify(bt, +- 0, +- ULONG(user_regs + OFFSET(user_regs_struct_cs)), +- ULONG(user_regs + OFFSET(user_regs_struct_ss)), +- ULONG(user_regs + OFFSET(user_regs_struct_rip)), +- ULONG(user_regs + OFFSET(user_regs_struct_rsp)), +- ULONG(user_regs + OFFSET(user_regs_struct_eflags)))) { +- bt->stkptr = ULONG(user_regs + +- OFFSET(user_regs_struct_rsp)); +- if (x86_64_in_irqstack(bt)) { +- ur_rip = ULONG(user_regs + +- OFFSET(user_regs_struct_rip)); +- ur_rsp = ULONG(user_regs + +- OFFSET(user_regs_struct_rsp)); +- goto skip_stage; +- } +- } +- } + if ((mfn != machdep->last_pmd_read) && + !xc_core_mfn_to_page(mfn, machdep->pmd)) + error(FATAL, "cannot read/find pmd page\n"); -+ + +- panic = FALSE; + machdep->last_pmd_read = mfn; -+ + +- /* +- * Check the process stack first. +- */ +-next_stack: +- for (i = 0, up = (ulong *)bt->stackbuf; +- i < (bt->stacktop - bt->stackbase)/sizeof(ulong); i++, up++) { +- sym = closest_symbol(*up); + pmd = ((ulong *)machdep->pmd) + pmd_index(kvaddr); + mfn = ((*pmd) & PHYSICAL_PAGE_MASK) >> PAGESHIFT(); -+ + +- if (STREQ(sym, "netconsole_netdump") || +- STREQ(sym, "netpoll_start_netdump") || +- STREQ(sym, "start_disk_dump") || +- STREQ(sym, "disk_dump") || +- STREQ(sym, "try_crashdump")) { +- *rip = *up; +- *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); +- return; +- } + if ((mfn != machdep->last_ptbl_read) && + !xc_core_mfn_to_page(mfn, machdep->ptbl)) + error(FATAL, "cannot read/find page table page\n"); + machdep->last_ptbl_read = mfn; -+ + +- if ((stage == 2) && +- (STREQ(sym, "nmi_watchdog_tick") || +- STREQ(sym, "default_do_nmi"))) { +- sp = x86_64_function_called_by((*up)-5); +- if (!sp || !STREQ(sp->name, "die_nmi")) +- continue; +- *rip = *up; +- *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); +- bt_in->flags |= BT_START; +- *rip = symbol_value("die_nmi"); +- *rsp = (*rsp) - (7*sizeof(ulong)); +- return; +- } + ptep = ((ulong *)machdep->ptbl) + pte_index(kvaddr); + mfn = ((*ptep) & PHYSICAL_PAGE_MASK) >> PAGESHIFT(); -+ + +- if (STREQ(sym, "panic")) { +- *rip = *up; +- *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); +- panic = TRUE; +- continue; /* keep looking for die */ +- } + if ((idx = xc_core_mfn_to_page_index(mfn)) == MFN_NOT_FOUND) + error(INFO, "cannot determine page index for %lx\n", + kvaddr); -+ + +- if (STREQ(sym, "die")) { +- *rip = *up; +- *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); +- for (i++, up++; i < LONGS_PER_STACK; i++, up++) { +- sym = closest_symbol(*up); +- if (STREQ(sym, "sysrq_handle_crash")) +- goto next_sysrq; +- } +- return; +- } + return idx; +} -+ + +- if (STREQ(sym, "sysrq_handle_crash")) { +-next_sysrq: +- *rip = *up; +- *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); +- machdep->flags |= SYSRQ; +- for (i++, up++; i < LONGS_PER_STACK; i++, up++) { +- sym = closest_symbol(*up); +- if (STREQ(sym, "sysrq_handle_crash")) +- goto next_sysrq; +- } +- return; +- } +/* + * Pull the rsp from the cpu_user_regs struct in the header + * turn it into a task, and match it with the active_set. @@ -18062,7 +28925,14 @@ + ulong rsp; + off_t offset; + ulong task; -+ + +- if (!panic_task && (stage > 0) && +- STREQ(sym, "smp_call_function_interrupt")) { +- *rip = *up; +- *rsp = bt->stackbase + ((char *)(up) - bt->stackbuf); +- return; +- } +- } + if (INVALID_MEMBER(vcpu_guest_context_user_regs) || + INVALID_MEMBER(cpu_user_regs_esp)) + return NO_TASK; @@ -18088,15 +28958,42 @@ + return task; + } + } -+ + +- if (panic) +- return; + error(WARNING, + "x86_64_xendump_panic_task: rsp: %lx -> task: %lx (not active)\n", + rsp); + } -+ + +-skip_stage: +- switch (stage) +- { +- /* +- * Now check the processor's interrupt stack. +- */ +- case 0: +- bt->stackbase = ms->stkinfo.ibase[bt->tc->processor]; +- bt->stacktop = ms->stkinfo.ibase[bt->tc->processor] + +- ms->stkinfo.isize; +- bt->stackbuf = ms->irqstack; +- alter_stackbuf(bt); +- stage = 1; +- goto next_stack; + return NO_TASK; +} -+ + +- /* +- * Check the NMI exception stack. +- */ +- case 1: +- bt->stackbase = ms->stkinfo.ebase[bt->tc->processor][NMI_STACK]; +- bt->stacktop = ms->stkinfo.ebase[bt->tc->processor][NMI_STACK] + +- ms->stkinfo.esize; +- bt->stackbuf = ms->irqstack; +- alter_stackbuf(bt); +- stage = 2; +- goto next_stack; +/* + * Because of an off-by-one vcpu bug in early xc_domain_dumpcore() + * instantiations, the registers in the vcpu_guest_context are not @@ -18112,7 +29009,9 @@ + off_t offset; + struct syment *sp; + int cpu; -+ + +- case 2: +- break; + if (INVALID_MEMBER(vcpu_guest_context_user_regs) || + INVALID_MEMBER(cpu_user_regs_rip) || + INVALID_MEMBER(cpu_user_regs_rsp)) @@ -18147,17 +29046,22 @@ + *rip = xrip; + *rsp = xrsp; + return; -+ } -+ + } + +generic: + + machdep->get_stack_frame(bt, rip, rsp); + -+ /* + /* +- * We didn't find what we were looking for, so just use what was +- * passed in from the ELF header. + * If this is an active task showing itself in schedule(), + * then the thread_struct rsp is stale. It has to be coming + * from a callback via the interrupt stack. -+ */ + */ +- if (ur_rip && ur_rsp) { +- *rip = ur_rip; +- *rsp = ur_rsp; + if (is_task_active(bt->task) && (symbol_value("thread_return") == *rip)) { + cpu = bt->tc->processor; + xrsp = machdep->machspec->stkinfo.ibase[cpu] + @@ -18178,11 +29082,1084 @@ + if (xrsp <= machdep->machspec->stkinfo.ibase[cpu]) + break; + } + } ++} + +- console("x86_64_get_dumpfile_stack_frame: cannot find anything useful\n"); ++/* for XEN Hypervisor analysis */ + +- bt->flags &= ~(ulonglong)BT_DUMPFILE_SEARCH; ++static int ++x86_64_is_kvaddr_hyper(ulong addr) ++{ ++ return (addr >= HYPERVISOR_VIRT_START && addr < HYPERVISOR_VIRT_END); ++} + +- machdep->get_stack_frame(bt, rip, rsp); ++static ulong ++x86_64_get_stackbase_hyper(ulong task) ++{ ++ struct xen_hyper_vcpu_context *vcc; ++ struct xen_hyper_pcpu_context *pcc; ++ ulong rsp0, base; ++ ++ /* task means vcpu here */ ++ vcc = xen_hyper_vcpu_to_vcpu_context(task); ++ if (!vcc) ++ error(FATAL, "invalid vcpu\n"); ++ ++ pcc = xen_hyper_id_to_pcpu_context(vcc->processor); ++ if (!pcc) ++ error(FATAL, "invalid pcpu number\n"); ++ ++ rsp0 = pcc->sp.rsp0; ++ base = rsp0 & (~(STACKSIZE() - 1)); ++ return base; + } + +-/* +- * Get the saved RSP from the task's thread_struct. +- */ + static ulong +-x86_64_get_sp(struct bt_info *bt) ++x86_64_get_stacktop_hyper(ulong task) + { +- ulong offset, rsp; ++ return x86_64_get_stackbase_hyper(task) + STACKSIZE(); ++} + +- if (tt->flags & THREAD_INFO) { +- readmem(bt->task + OFFSET(task_struct_thread) + +- OFFSET(thread_struct_rsp), KVADDR, +- &rsp, sizeof(void *), +- "thread_struct rsp", FAULT_ON_ERROR); +- return rsp; +- } ++#define EXCEPTION_STACKSIZE_HYPER (1024UL) + +- offset = OFFSET(task_struct_thread) + OFFSET(thread_struct_rsp); ++static ulong ++x86_64_in_exception_stack_hyper(ulong vcpu, ulong rsp) ++{ ++ struct xen_hyper_vcpu_context *vcc; ++ struct xen_hyper_pcpu_context *pcc; ++ int i; ++ ulong stackbase; + +- return GET_STACK_ULONG(offset); ++ vcc = xen_hyper_vcpu_to_vcpu_context(vcpu); ++ if (!vcc) ++ error(FATAL, "invalid vcpu\n"); ++ ++ pcc = xen_hyper_id_to_pcpu_context(vcc->processor); ++ if (!pcc) ++ error(FATAL, "invalid pcpu number\n"); ++ ++ for (i = 0; i < XEN_HYPER_TSS_IST_MAX; i++) { ++ if (pcc->ist[i] == 0) { ++ continue; ++ } ++ stackbase = pcc->ist[i] - EXCEPTION_STACKSIZE_HYPER; ++ if ((rsp & ~(EXCEPTION_STACKSIZE_HYPER - 1)) == stackbase) { ++ return stackbase; ++ } ++ } ++ ++ return 0; + } + +-/* +- * Get the saved PC from the task's thread_struct if it exists; +- * otherwise just use the "thread_return" label value. +- */ +-static ulong +-x86_64_get_pc(struct bt_info *bt) ++static void ++x86_64_get_stack_frame_hyper(struct bt_info *bt, ulong *pcp, ulong *spp) + { +- ulong offset, rip; ++ struct xen_hyper_vcpu_context *vcc; ++ int pcpu; ++ ulong *regs; ++ ulong rsp, rip; ++ ++ /* task means vcpu here */ ++ vcc = xen_hyper_vcpu_to_vcpu_context(bt->task); ++ if (!vcc) ++ error(FATAL, "invalid vcpu\n"); ++ ++ pcpu = vcc->processor; ++ if (!xen_hyper_test_pcpu_id(pcpu)) { ++ error(FATAL, "invalid pcpu number\n"); ++ } ++ ++ if (bt->flags & BT_TEXT_SYMBOLS_ALL) { ++ if (spp) ++ *spp = x86_64_get_stackbase_hyper(bt->task); ++ if (pcp) ++ *pcp = 0; ++ bt->flags &= ~BT_TEXT_SYMBOLS_ALL; ++ return; ++ } + +- if (INVALID_MEMBER(thread_struct_rip)) +- return symbol_value("thread_return"); ++ regs = (ulong *)xen_hyper_id_to_dumpinfo_context(pcpu)->pr_reg_ptr; ++ rsp = XEN_HYPER_X86_64_NOTE_RSP(regs); ++ rip = XEN_HYPER_X86_64_NOTE_RIP(regs); ++ ++ if (spp) { ++ if (x86_64_in_exception_stack_hyper(bt->task, rsp)) ++ *spp = rsp; ++ else if (rsp < x86_64_get_stackbase_hyper(bt->task) || ++ rsp >= x86_64_get_stacktop_hyper(bt->task)) ++ *spp = x86_64_get_stackbase_hyper(bt->task); ++ else ++ *spp = rsp; ++ } ++ if (pcp) { ++ if (is_kernel_text(rip)) ++ *pcp = rip; ++ else ++ *pcp = 0; ++ } ++} + +- if (tt->flags & THREAD_INFO) { +- readmem(bt->task + OFFSET(task_struct_thread) + +- OFFSET(thread_struct_rip), KVADDR, +- &rip, sizeof(void *), +- "thread_struct rip", FAULT_ON_ERROR); +- return rip; +- } ++static int ++x86_64_print_stack_entry_hyper(struct bt_info *bt, FILE *ofp, int level, ++ int stkindex, ulong text) ++{ ++ ulong rsp, offset; ++ struct syment *sp; ++ char *name; ++ int result; ++ char buf[BUFSIZE]; + +- offset = OFFSET(task_struct_thread) + OFFSET(thread_struct_rip); ++ offset = 0; ++ sp = value_search(text, &offset); ++ if (!sp) ++ return BACKTRACE_ENTRY_IGNORED; + +- return GET_STACK_ULONG(offset); +-} ++ name = sp->name; ++ ++ if (STREQ(name, "syscall_enter")) ++ result = BACKTRACE_COMPLETE; ++ else ++ result = BACKTRACE_ENTRY_DISPLAYED; ++ ++ rsp = bt->stackbase + (stkindex * sizeof(long)); ++ ++ if ((bt->flags & BT_FULL)) { ++ if (bt->frameptr) ++ x86_64_display_full_frame(bt, rsp, ofp); ++ bt->frameptr = rsp + sizeof(ulong); ++ } ++ ++ fprintf(ofp, "%s#%d [%8lx] %s at %lx\n", level < 10 ? " " : "", level, ++ rsp, name, text); ++ ++ if (bt->flags & BT_LINE_NUMBERS) { ++ get_line_number(text, buf, FALSE); ++ if (strlen(buf)) ++ fprintf(ofp, " %s\n", buf); ++ } + ++ if (BT_REFERENCE_CHECK(bt)) ++ x86_64_do_bt_reference_check(bt, text, name); + +-/* +- * Do the work for x86_64_get_sp() and x86_64_get_pc(). +- */ +-static void +-get_x86_64_frame(struct bt_info *bt, ulong *getpc, ulong *getsp) +-{ +- error(FATAL, "get_x86_64_frame: TBD\n"); ++ return result; + } + +-/* +- * Do the work for cmd_irq(). +- */ +-static void +-x86_64_dump_irq(int irq) ++static void ++x86_64_print_eframe_regs_hyper(struct bt_info *bt) + { +- if (symbol_exists("irq_desc")) { +- machdep->dump_irq = generic_dump_irq; +- return(generic_dump_irq(irq)); +- } ++ ulong *up; ++ ulong offset; ++ struct syment *sp; + +- error(FATAL, "ia64_dump_irq: irq_desc[] does not exist?\n"); +-} + +-/* +- * Do the work for irq -d +- */ +-void +-x86_64_display_idt_table(void) +-{ +- int i; +- char *idt_table_buf; +- char buf[BUFSIZE]; +- ulong *ip; ++ up = (ulong *)(&bt->stackbuf[bt->stacktop - bt->stackbase]); ++ up -= 21; + +- idt_table_buf = GETBUF(SIZE(gate_struct) * 256); +- readmem(symbol_value("idt_table"), KVADDR, idt_table_buf, +- SIZE(gate_struct) * 256, "idt_table", FAULT_ON_ERROR); +- ip = (ulong *)idt_table_buf; ++ fprintf(fp, " [exception RIP: "); ++ if ((sp = value_search(up[16], &offset))) { ++ fprintf(fp, "%s", sp->name); ++ if (offset) ++ fprintf(fp, (output_radix == 16) ? ++ "+0x%lx" : "+%ld", offset); ++ } else ++ fprintf(fp, "unknown or invalid address"); ++ fprintf(fp, "]\n"); + +- for (i = 0; i < 256; i++, ip += 2) { +- if (i < 10) +- fprintf(fp, " "); +- else if (i < 100) +- fprintf(fp, " "); +- fprintf(fp, "[%d] %s\n", +- i, x86_64_extract_idt_function(ip, buf, NULL)); +- } ++ fprintf(fp, " RIP: %016lx RSP: %016lx RFLAGS: %08lx\n", ++ up[16], up[19], up[18]); ++ fprintf(fp, " RAX: %016lx RBX: %016lx RCX: %016lx\n", ++ up[10], up[5], up[11]); ++ fprintf(fp, " RDX: %016lx RSI: %016lx RDI: %016lx\n", ++ up[11], up[13], up[14]); ++ fprintf(fp, " RBP: %016lx R8: %016lx R9: %016lx\n", ++ up[4], up[9], up[8]); ++ fprintf(fp, " R10: %016lx R11: %016lx R12: %016lx\n", ++ up[7], up[6], up[3]); ++ fprintf(fp, " R13: %016lx R14: %016lx R15: %016lx\n", ++ up[2], up[1], up[0]); ++ fprintf(fp, " ORIG_RAX: %016lx CS: %04lx SS: %04lx\n", ++ up[15], up[17], up[20]); + +- FREEBUF(idt_table_buf); ++ fprintf(fp, "--- ---\n"); + } + + /* +- * Extract the function name out of the IDT entry. ++ * simple back tracer for xen hypervisor ++ * irq stack does not exist. so relative easy. + */ +-static char * +-x86_64_extract_idt_function(ulong *ip, char *buf, ulong *retaddr) ++static void ++x86_64_simple_back_trace_cmd_hyper(struct bt_info *bt_in) + { +- ulong i1, i2, addr; +- char locbuf[BUFSIZE]; +- physaddr_t phys; ++ int i, level, done; ++ ulong rsp, estack, stacktop; ++ ulong *up; ++ FILE *ofp; ++ struct bt_info bt_local, *bt; ++ char ebuf[EXCEPTION_STACKSIZE_HYPER]; + +- if (buf) +- BZERO(buf, BUFSIZE); ++ bt = &bt_local; ++ BCOPY(bt_in, bt, sizeof(struct bt_info)); + +- i1 = *ip; +- i2 = *(ip+1); ++ if (bt->flags & BT_FRAMESIZE_DEBUG) { ++ error(INFO, "-F not support\n"); ++ return; ++ } + +- i2 <<= 32; +- addr = i2 & 0xffffffff00000000; +- addr |= (i1 & 0xffff); +- i1 >>= 32; +- addr |= (i1 & 0xffff0000); ++ level = 0; ++ done = FALSE; ++ bt->call_target = NULL; ++ rsp = bt->stkptr; ++ if (!rsp) { ++ error(INFO, "cannot determine starting stack pointer\n"); ++ return; ++ } ++ if (BT_REFERENCE_CHECK(bt)) ++ ofp = pc->nullfp; ++ else ++ ofp = fp; + +- if (retaddr) +- *retaddr = addr; ++ while ((estack = x86_64_in_exception_stack_hyper(bt->task, rsp))) { ++ bt->flags |= BT_EXCEPTION_STACK; ++ bt->stackbase = estack; ++ bt->stacktop = estack + EXCEPTION_STACKSIZE_HYPER; ++ bt->stackbuf = ebuf; + +- if (!buf) +- return NULL; ++ if (!readmem(bt->stackbase, KVADDR, bt->stackbuf, ++ bt->stacktop - bt->stackbase, "exception stack contents", ++ RETURN_ON_ERROR)) ++ error(FATAL, "read of exception stack at %lx failed\n", ++ bt->stackbase); + +- value_to_symstr(addr, locbuf, 0); +- if (strlen(locbuf)) +- sprintf(buf, locbuf); +- else { +- sprintf(buf, "%016lx", addr); +- if (kvtop(NULL, addr, &phys, 0)) { +- addr = machdep->kvbase + (ulong)phys; +- if (value_to_symstr(addr, locbuf, 0)) { +- strcat(buf, " <"); +- strcat(buf, locbuf); +- strcat(buf, ">"); +- } +- } +- } ++ stacktop = bt->stacktop - 168; + +- return buf; +-} ++ for (i = (rsp - bt->stackbase)/sizeof(ulong); ++ !done && (rsp < stacktop); i++, rsp += sizeof(ulong)) { ++ ++ up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]); + +-/* +- * Filter disassembly output if the output radix is not gdb's default 10 +- */ +-static int +-x86_64_dis_filter(ulong vaddr, char *inbuf) +-{ +- char buf1[BUFSIZE]; +- char buf2[BUFSIZE]; +- char *colon, *p1; +- int argc; +- char *argv[MAXARGS]; +- ulong value; ++ if (!is_kernel_text(*up)) ++ continue; + +- if (!inbuf) +- return TRUE; +-/* +- * For some reason gdb can go off into the weeds translating text addresses, +- * (on alpha -- not necessarily seen on x86_64) so this routine both fixes the +- * references as well as imposing the current output radix on the translations. +- */ +- console("IN: %s", inbuf); ++ switch (x86_64_print_stack_entry_hyper(bt, ofp, level, i,*up)) ++ { ++ case BACKTRACE_ENTRY_DISPLAYED: ++ level++; ++ break; ++ case BACKTRACE_ENTRY_IGNORED: ++ break; ++ case BACKTRACE_COMPLETE: ++ done = TRUE; ++ break; ++ } ++ } + +- colon = strstr(inbuf, ":"); ++ if (!BT_REFERENCE_CHECK(bt)) ++ x86_64_print_eframe_regs_hyper(bt); + +- if (colon) { +- sprintf(buf1, "0x%lx <%s>", vaddr, +- value_to_symstr(vaddr, buf2, pc->output_radix)); +- sprintf(buf2, "%s%s", buf1, colon); +- strcpy(inbuf, buf2); ++ up = (ulong *)(&bt->stackbuf[bt->stacktop - bt->stackbase]); ++ up -= 2; ++ rsp = bt->stkptr = *up; ++ up -= 3; ++ bt->instptr = *up; ++ done = FALSE; ++ bt->frameptr = 0; + } + +- strcpy(buf1, inbuf); +- argc = parse_line(buf1, argv); ++ if (bt->flags & BT_EXCEPTION_STACK) { ++ bt->flags &= ~BT_EXCEPTION_STACK; ++ bt->stackbase = bt_in->stackbase; ++ bt->stacktop = bt_in->stacktop; ++ bt->stackbuf = bt_in->stackbuf; ++ } + +- if ((FIRSTCHAR(argv[argc-1]) == '<') && +- (LASTCHAR(argv[argc-1]) == '>')) { +- p1 = rindex(inbuf, '<'); +- while ((p1 > inbuf) && !STRNEQ(p1, " 0x")) +- p1--; ++ for (i = (rsp - bt->stackbase)/sizeof(ulong); ++ !done && (rsp < bt->stacktop); i++, rsp += sizeof(ulong)) { + +- if (!STRNEQ(p1, " 0x")) +- return FALSE; +- p1++; ++ up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]); + +- if (!extract_hex(p1, &value, NULLCHAR, TRUE)) +- return FALSE; ++ if (!is_kernel_text(*up)) ++ continue; + +- sprintf(buf1, "0x%lx <%s>\n", value, +- value_to_symstr(value, buf2, pc->output_radix)); ++ switch (x86_64_print_stack_entry_hyper(bt, ofp, level, i,*up)) ++ { ++ case BACKTRACE_ENTRY_DISPLAYED: ++ level++; ++ break; ++ case BACKTRACE_ENTRY_IGNORED: ++ break; ++ case BACKTRACE_COMPLETE: ++ done = TRUE; ++ break; ++ } ++ } ++} + +- sprintf(p1, buf1); +- +- } else if (STREQ(argv[argc-2], "callq") && +- hexadecimal(argv[argc-1], 0)) { +- /* +- * Update module code of the form: +- * +- * callq 0xffffffffa0017aa0 +- * +- * to show a bracketed direct call target. +- */ +- p1 = &LASTCHAR(inbuf); ++static void ++x86_64_init_hyper(int when) ++{ ++ switch (when) ++ { ++ case PRE_SYMTAB: ++ machdep->verify_symbol = x86_64_verify_symbol; ++ machdep->machspec = &x86_64_machine_specific; ++ if (pc->flags & KERNEL_DEBUG_QUERY) ++ return; ++ machdep->pagesize = memory_page_size(); ++ machdep->pageshift = ffs(machdep->pagesize) - 1; ++ machdep->pageoffset = machdep->pagesize - 1; ++ machdep->pagemask = ~((ulonglong)machdep->pageoffset); ++ machdep->stacksize = machdep->pagesize * 2; ++ if ((machdep->machspec->upml = (char *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc upml space."); ++ if ((machdep->pgd = (char *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc pgd space."); ++ if ((machdep->pmd = (char *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc pmd space."); ++ if ((machdep->ptbl = (char *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc ptbl space."); ++ if ((machdep->machspec->pml4 = ++ (char *)malloc(PAGESIZE()*2)) == NULL) ++ error(FATAL, "cannot malloc pml4 space."); ++ machdep->machspec->last_upml_read = 0; ++ machdep->machspec->last_pml4_read = 0; ++ machdep->last_pgd_read = 0; ++ machdep->last_pmd_read = 0; ++ machdep->last_ptbl_read = 0; ++ machdep->verify_paddr = generic_verify_paddr; ++ machdep->ptrs_per_pgd = PTRS_PER_PGD; ++ if (machdep->cmdline_arg) ++ parse_cmdline_arg(); ++ break; + +- if (extract_hex(argv[argc-1], &value, NULLCHAR, TRUE)) { +- sprintf(buf1, " <%s>\n", +- value_to_symstr(value, buf2, +- pc->output_radix)); +- if (IS_MODULE_VADDR(value) && +- !strstr(buf2, "+")) +- sprintf(p1, buf1); +- } +- } ++ case PRE_GDB: ++ machdep->machspec->page_offset = PAGE_OFFSET_XEN_HYPER; ++ machdep->kvbase = (ulong)HYPERVISOR_VIRT_START; ++ machdep->identity_map_base = (ulong)PAGE_OFFSET_XEN_HYPER; ++ machdep->is_kvaddr = x86_64_is_kvaddr_hyper; ++ machdep->is_uvaddr = x86_64_is_uvaddr; ++ machdep->eframe_search = x86_64_eframe_search; ++ machdep->back_trace = x86_64_simple_back_trace_cmd_hyper; ++ machdep->processor_speed = x86_64_processor_speed; ++ machdep->kvtop = x86_64_kvtop; ++ machdep->get_task_pgd = x86_64_get_task_pgd; ++ machdep->get_stack_frame = x86_64_get_stack_frame_hyper; ++ machdep->get_stackbase = x86_64_get_stackbase_hyper; ++ machdep->get_stacktop = x86_64_get_stacktop_hyper; ++ machdep->translate_pte = x86_64_translate_pte; ++ machdep->memory_size = xen_hyper_x86_memory_size; /* KAK add */ ++ machdep->is_task_addr = x86_64_is_task_addr; ++ machdep->dis_filter = x86_64_dis_filter; ++ machdep->cmd_mach = x86_64_cmd_mach; ++ machdep->get_smp_cpus = xen_hyper_x86_get_smp_cpus; /* KAK add */ ++ machdep->line_number_hooks = x86_64_line_number_hooks; ++ machdep->value_to_symbol = generic_machdep_value_to_symbol; ++ machdep->init_kernel_pgd = x86_64_init_kernel_pgd; ++ machdep->clear_machdep_cache = x86_64_clear_machdep_cache; ++ ++ /* machdep table for Xen Hypervisor */ ++ xhmachdep->pcpu_init = xen_hyper_x86_pcpu_init; ++ break; ++ ++ case POST_GDB: ++ XEN_HYPER_STRUCT_SIZE_INIT(cpuinfo_x86, "cpuinfo_x86"); ++ XEN_HYPER_STRUCT_SIZE_INIT(tss_struct, "tss_struct"); ++ XEN_HYPER_ASSIGN_OFFSET(tss_struct_rsp0) = MEMBER_OFFSET("tss_struct", "__blh") + sizeof(short unsigned int); ++ XEN_HYPER_MEMBER_OFFSET_INIT(tss_struct_ist, "tss_struct", "ist"); ++ if (symbol_exists("cpu_data")) { ++ xht->cpu_data_address = symbol_value("cpu_data"); ++ } ++/* KAK Can this be calculated? */ ++ if (!machdep->hz) { ++ machdep->hz = XEN_HYPER_HZ; ++ } ++ break; ++ ++ case POST_INIT: ++ break; ++ } ++} + +- console(" %s", inbuf); + +- return TRUE; +-} ++struct framesize_cache { ++ ulong textaddr; ++ int framesize; ++}; + ++static struct framesize_cache *x86_64_framesize_cache = NULL; ++static int framesize_cache_entries = 0; + +-/* +- * Override smp_num_cpus if possible and necessary. +- */ +-int +-x86_64_get_smp_cpus(void) +-{ +- int i, cpus, nr_pda, cpunumber; +- char *cpu_pda_buf; +- ulong level4_pgt; ++#define FRAMESIZE_QUERY (1) ++#define FRAMESIZE_ENTER (2) ++#define FRAMESIZE_DUMP (3) + +- if (!VALID_STRUCT(x8664_pda)) +- return 1; ++#define FRAMESIZE_CACHE_INCR (50) + +- cpu_pda_buf = GETBUF(SIZE(x8664_pda)); ++static int ++x86_64_framesize_cache_resize(void) ++{ ++ int i; ++ struct framesize_cache *new_fc, *fc; + +- if (!(nr_pda = get_array_length("cpu_pda", NULL, 0))) +- nr_pda = NR_CPUS; ++ if ((new_fc = realloc(x86_64_framesize_cache, ++ (framesize_cache_entries+FRAMESIZE_CACHE_INCR) * ++ sizeof(struct framesize_cache))) == NULL) { ++ error(INFO, "cannot realloc x86_64_framesize_cache space!\n"); ++ return FALSE; ++ } + +- for (i = cpus = 0; i < nr_pda; i++) { +- if (!CPU_PDA_READ(i, cpu_pda_buf)) +- break; +- level4_pgt = ULONG(cpu_pda_buf + OFFSET(x8664_pda_level4_pgt)); +- cpunumber = INT(cpu_pda_buf + OFFSET(x8664_pda_cpunumber)); +- if (!VALID_LEVEL4_PGT_ADDR(level4_pgt) || (cpunumber != cpus)) +- break; +- cpus++; +- } ++ fc = new_fc + framesize_cache_entries; ++ for (i = framesize_cache_entries; ++ i < (framesize_cache_entries+FRAMESIZE_CACHE_INCR); ++ fc++, i++) { ++ fc->textaddr = 0; ++ fc->framesize = 0; ++ } + +- FREEBUF(cpu_pda_buf); ++ x86_64_framesize_cache = new_fc; ++ framesize_cache_entries += FRAMESIZE_CACHE_INCR; + +- return cpus; ++ return TRUE; + } + +-/* +- * Machine dependent command. +- */ +-void +-x86_64_cmd_mach(void) ++static int ++x86_64_framesize_cache_func(int cmd, ulong textaddr, int *framesize) + { +- int c; ++ int i; ++ struct framesize_cache *fc; ++ char buf[BUFSIZE]; + +- while ((c = getopt(argcnt, args, "cm")) != EOF) { +- switch(c) +- { +- case 'c': +- x86_64_display_cpu_data(); +- return; ++ if (!x86_64_framesize_cache) { ++ framesize_cache_entries = FRAMESIZE_CACHE_INCR; ++ if ((x86_64_framesize_cache = calloc(framesize_cache_entries, ++ sizeof(struct framesize_cache))) == NULL) ++ error(FATAL, ++ "cannot calloc x86_64_framesize_cache space!\n"); ++ } + +- case 'm': +- x86_64_display_memmap(); +- return; ++ switch (cmd) ++ { ++ case FRAMESIZE_QUERY: ++ fc = &x86_64_framesize_cache[0]; ++ for (i = 0; i < framesize_cache_entries; i++, fc++) { ++ if (fc->textaddr == textaddr) { ++ *framesize = fc->framesize; ++ return TRUE; ++ } ++ } ++ return FALSE; + +- default: +- argerrs++; +- break; +- } +- } ++ case FRAMESIZE_ENTER: ++retry: ++ fc = &x86_64_framesize_cache[0]; ++ for (i = 0; i < framesize_cache_entries; i++, fc++) { ++ if ((fc->textaddr == 0) || ++ (fc->textaddr == textaddr)) { ++ fc->textaddr = textaddr; ++ fc->framesize = *framesize; ++ return fc->framesize; ++ } ++ } + +- if (argerrs) +- cmd_usage(pc->curcmd, SYNOPSIS); ++ if (x86_64_framesize_cache_resize()) ++ goto retry; + +- x86_64_display_machine_stats(); +-} ++ return *framesize; + +-/* +- * "mach" command output. +- */ +-static void +-x86_64_display_machine_stats(void) +-{ +- struct new_utsname *uts; +- char buf[BUFSIZE]; +- ulong mhz; ++ case FRAMESIZE_DUMP: ++ fc = &x86_64_framesize_cache[0]; ++ for (i = 0; i < framesize_cache_entries; i++, fc++) { ++ if (fc->textaddr == 0) { ++ if (i < (framesize_cache_entries-1)) { ++ fprintf(fp, "[%d-%d]: (unused)\n", ++ i, framesize_cache_entries-1); ++ } ++ break; ++ } + +- uts = &kt->utsname; ++ fprintf(fp, "[%3d]: %lx %3d (%s)\n", i, ++ fc->textaddr, fc->framesize, ++ value_to_symstr(fc->textaddr, buf, 0)); ++ } ++ break; ++ } + +- fprintf(fp, " MACHINE TYPE: %s\n", uts->machine); +- fprintf(fp, " MEMORY SIZE: %s\n", get_memory_size(buf)); +- fprintf(fp, " CPUS: %d\n", kt->cpus); +- fprintf(fp, " PROCESSOR SPEED: "); +- if ((mhz = machdep->processor_speed())) +- fprintf(fp, "%ld Mhz\n", mhz); +- else +- fprintf(fp, "(unknown)\n"); +- fprintf(fp, " HZ: %d\n", machdep->hz); +- fprintf(fp, " PAGE SIZE: %d\n", PAGESIZE()); +- fprintf(fp, " L1 CACHE SIZE: %d\n", l1_cache_size()); +- fprintf(fp, "KERNEL VIRTUAL BASE: %lx\n", machdep->kvbase); +- fprintf(fp, "KERNEL VMALLOC BASE: %lx\n", vt->vmalloc_start); +- fprintf(fp, " KERNEL START MAP: %lx\n", __START_KERNEL_map); +- fprintf(fp, "KERNEL MODULES BASE: %lx\n", MODULES_VADDR); +- fprintf(fp, " KERNEL STACK SIZE: %ld\n", STACKSIZE()); ++ return TRUE; + } + +-/* +- * "mach -c" +- */ +-static void +-x86_64_display_cpu_data(void) ++#define BT_FRAMESIZE_IGNORE_MASK \ ++ (BT_OLD_BACK_TRACE|BT_TEXT_SYMBOLS|BT_TEXT_SYMBOLS_ALL|BT_FRAMESIZE_DISABLE) ++ ++static int ++x86_64_get_framesize(struct bt_info *bt, ulong textaddr) + { +- int cpu, cpus, boot_cpu; +- ulong cpu_data; +- ulong cpu_pda; +- +- if (symbol_exists("cpu_data")) { +- cpu_data = symbol_value("cpu_data"); +- cpus = kt->cpus; +- boot_cpu = FALSE; +- } else if (symbol_exists("boot_cpu_data")) { +- cpu_data = symbol_value("boot_cpu_data"); +- boot_cpu = TRUE; +- cpus = 1; ++ int c, framesize, instr, arg; ++ struct syment *sp; ++ long max_instructions; ++ ulong offset; ++ char buf[BUFSIZE]; ++ char buf2[BUFSIZE]; ++ char *arglist[MAXARGS]; ++ ulong locking_func, textaddr_save, current; ++ char *p1, *p2; ++ int reterror; ++ ++ if (!(bt->flags & BT_FRAMESIZE_DEBUG)) { ++ if ((bt->flags & BT_FRAMESIZE_IGNORE_MASK) || ++ (kt->flags & USE_OLD_BT)) ++ return 0; ++ } ++ ++ if (!(sp = value_search(textaddr, &offset))) { ++ if (!(bt->flags & BT_FRAMESIZE_DEBUG)) ++ bt->flags |= BT_FRAMESIZE_DISABLE; ++ return 0; ++ } ++ ++ if (!(bt->flags & BT_FRAMESIZE_DEBUG) && ++ x86_64_framesize_cache_func(FRAMESIZE_QUERY, textaddr, &framesize)) { ++ if (framesize == -1) ++ bt->flags |= BT_FRAMESIZE_DISABLE; ++ return framesize; + } +- cpu_pda = symbol_value("cpu_pda"); +- +- for (cpu = 0; cpu < cpus; cpu++) { +- if (boot_cpu) +- fprintf(fp, "BOOT CPU:\n"); +- else +- fprintf(fp, "%sCPU %d:\n", cpu ? "\n" : "", cpu); + +- dump_struct("cpuinfo_x86", cpu_data, 0); +- fprintf(fp, "\n"); +- dump_struct("x8664_pda", cpu_pda, 0); +- +- cpu_data += SIZE(cpuinfo_x86); +- cpu_pda += SIZE(x8664_pda); +- } +-} ++ /* ++ * Bait and switch an incoming .text.lock address ++ * with the containing function's address. ++ */ ++ if (STRNEQ(sp->name, ".text.lock.") && ++ (locking_func = text_lock_function(sp->name, bt, textaddr))) { ++ if (!(sp = value_search(locking_func, &offset))) { ++ bt->flags |= BT_FRAMESIZE_DISABLE; ++ return 0; ++ } ++ textaddr_save = textaddr; ++ textaddr = locking_func; ++ } else ++ textaddr_save = 0; + +-/* +- * "mach -m" +- */ +-static char *e820type[] = { +- "(invalid type)", +- "E820_RAM", +- "E820_RESERVED", +- "E820_ACPI", +- "E820_NVS", +-}; ++ framesize = 0; ++ max_instructions = textaddr - sp->value; ++ instr = arg = -1; + +-static void +-x86_64_display_memmap(void) +-{ +- ulong e820; +- int nr_map, i; +- char *buf, *e820entry_ptr; +- ulonglong addr, size; +- uint type; ++ open_tmpfile2(); + +- e820 = symbol_value("e820"); +- if (CRASHDEBUG(1)) +- dump_struct("e820map", e820, RADIX(16)); +- buf = (char *)GETBUF(SIZE(e820map)); ++ sprintf(buf, "x/%ldi 0x%lx", ++ max_instructions, sp->value); + +- readmem(e820, KVADDR, &buf[0], SIZE(e820map), +- "e820map", FAULT_ON_ERROR); ++ if (!gdb_pass_through(buf, pc->tmpfile2, GNU_RETURN_ON_ERROR)) { ++ close_tmpfile2(); ++ bt->flags |= BT_FRAMESIZE_DISABLE; ++ return 0; ++ } + +- nr_map = INT(buf + OFFSET(e820map_nr_map)); ++ rewind(pc->tmpfile2); ++ while (fgets(buf, BUFSIZE, pc->tmpfile2)) { ++ strcpy(buf2, buf); + +- fprintf(fp, " PHYSICAL ADDRESS RANGE TYPE\n"); ++ if (CRASHDEBUG(3)) ++ fprintf(pc->saved_fp, buf2); + +- for (i = 0; i < nr_map; i++) { +- e820entry_ptr = buf + sizeof(int) + (SIZE(e820entry) * i); +- addr = ULONGLONG(e820entry_ptr + OFFSET(e820entry_addr)); +- size = ULONGLONG(e820entry_ptr + OFFSET(e820entry_size)); +- type = UINT(e820entry_ptr + OFFSET(e820entry_type)); +- fprintf(fp, "%016llx - %016llx %s\n", addr, addr+size, +- e820type[type]); +- } +-} ++ c = parse_line(buf, arglist); + ++ if (instr == -1) { ++ /* ++ * Check whether are ++ * in the output string. ++ */ ++ if (LASTCHAR(arglist[0]) == ':') { ++ instr = 1; ++ arg = 2; ++ } else { ++ instr = 2; ++ arg = 3; ++ } ++ } + +-static const char *hook_files[] = { +- "arch/x86_64/kernel/entry.S", +- "arch/x86_64/kernel/head.S", +- "arch/x86_64/kernel/semaphore.c" +-}; ++ if (c < (arg+1)) ++ continue; + +-#define ENTRY_S ((char **)&hook_files[0]) +-#define HEAD_S ((char **)&hook_files[1]) +-#define SEMAPHORE_C ((char **)&hook_files[2]) ++ reterror = 0; ++ current = htol(strip_ending_char(arglist[0], ':'), ++ RETURN_ON_ERROR, &reterror); ++ if (reterror) ++ continue; ++ if (current >= textaddr) ++ break; + +-static struct line_number_hook x86_64_line_number_hooks[] = { +- {"ret_from_fork", ENTRY_S}, +- {"system_call", ENTRY_S}, +- {"int_ret_from_sys_call", ENTRY_S}, +- {"ptregscall_common", ENTRY_S}, +- {"stub_execve", ENTRY_S}, +- {"stub_rt_sigreturn", ENTRY_S}, +- {"common_interrupt", ENTRY_S}, +- {"ret_from_intr", ENTRY_S}, +- {"load_gs_index", ENTRY_S}, +- {"arch_kernel_thread", ENTRY_S}, +- {"execve", ENTRY_S}, +- {"page_fault", ENTRY_S}, +- {"coprocessor_error", ENTRY_S}, +- {"simd_coprocessor_error", ENTRY_S}, +- {"device_not_available", ENTRY_S}, +- {"debug", ENTRY_S}, +- {"nmi", ENTRY_S}, +- {"int3", ENTRY_S}, +- {"overflow", ENTRY_S}, +- {"bounds", ENTRY_S}, +- {"invalid_op", ENTRY_S}, +- {"coprocessor_segment_overrun", ENTRY_S}, +- {"reserved", ENTRY_S}, +- {"double_fault", ENTRY_S}, +- {"invalid_TSS", ENTRY_S}, +- {"segment_not_present", ENTRY_S}, +- {"stack_segment", ENTRY_S}, +- {"general_protection", ENTRY_S}, +- {"alignment_check", ENTRY_S}, +- {"divide_error", ENTRY_S}, +- {"spurious_interrupt_bug", ENTRY_S}, +- {"machine_check", ENTRY_S}, +- {"call_debug", ENTRY_S}, ++ if (STRNEQ(arglist[instr], "push")) { ++ framesize += 8; ++ if (CRASHDEBUG(2) || (bt->flags & BT_FRAMESIZE_DEBUG)) ++ fprintf(pc->saved_fp, "%s\t[framesize: %d]\n", ++ strip_linefeeds(buf2), framesize); ++ } else if (STRNEQ(arglist[instr], "pop")) { ++ framesize -= 8; ++ if (CRASHDEBUG(2) || (bt->flags & BT_FRAMESIZE_DEBUG)) ++ fprintf(pc->saved_fp, "%s\t[framesize: %d]\n", ++ strip_linefeeds(buf2), framesize); ++ } else if (STRNEQ(arglist[instr], "add") && ++ (p1 = strstr(arglist[arg], ",%rsp"))) { ++ *p1 = NULLCHAR; ++ p2 = arglist[arg]; ++ reterror = 0; ++ offset = htol(p2+1, RETURN_ON_ERROR, &reterror); ++ if (reterror) ++ continue; ++ framesize -= offset; ++ if (CRASHDEBUG(2) || (bt->flags & BT_FRAMESIZE_DEBUG)) ++ fprintf(pc->saved_fp, "%s\t[framesize: %d]\n", ++ strip_linefeeds(buf2), framesize); ++ } else if (STRNEQ(arglist[instr], "sub") && ++ (p1 = strstr(arglist[arg], ",%rsp"))) { ++ *p1 = NULLCHAR; ++ p2 = arglist[arg]; ++ reterror = 0; ++ offset = htol(p2+1, RETURN_ON_ERROR, &reterror); ++ if (reterror) ++ continue; ++ framesize += offset; ++ if (CRASHDEBUG(2) || (bt->flags & BT_FRAMESIZE_DEBUG)) ++ fprintf(pc->saved_fp, "%s\t[framesize: %d]\n", ++ strip_linefeeds(buf2), framesize); ++ } else if (STRNEQ(arglist[instr], "retq")) { ++ bt->flags |= BT_FRAMESIZE_DISABLE; ++ framesize = -1; ++ if (CRASHDEBUG(2) || (bt->flags & BT_FRAMESIZE_DEBUG)) ++ fprintf(pc->saved_fp, "%s\t[framesize: DISABLED]\n", ++ strip_linefeeds(buf2)); ++ break; ++ } ++ } ++ close_tmpfile2(); + +- {NULL, NULL} /* list must be NULL-terminated */ +-}; ++ if (textaddr_save) ++ textaddr = textaddr_save; + +-static void +-x86_64_dump_line_number(ulong callpc) +-{ +- error(FATAL, "x86_64_dump_line_number: TBD\n"); ++ return (x86_64_framesize_cache_func(FRAMESIZE_ENTER, textaddr, &framesize)); + } + +-void +-x86_64_compiler_warning_stub(void) ++static void ++x86_64_framesize_debug(struct bt_info *bt) + { +- struct line_number_hook *lhp; +- char **p; ++ int framesize; + +- lhp = &x86_64_line_number_hooks[0]; lhp++; +- p = ENTRY_S; +- x86_64_back_trace(NULL, NULL); +- get_x86_64_frame(NULL, NULL, NULL); +- x86_64_dump_line_number(0); +-} ++ switch (bt->hp->esp) ++ { ++ case 1: /* "dump" */ ++ if (bt->hp->eip) { ++ framesize = 1; ++ x86_64_framesize_cache_func(FRAMESIZE_ENTER, bt->hp->eip, ++ &framesize); ++ } else ++ x86_64_framesize_cache_func(FRAMESIZE_DUMP, 0, NULL); ++ break; ++ ++ case 0: ++ if (bt->hp->eip) { ++ framesize = 0; ++ x86_64_framesize_cache_func(FRAMESIZE_ENTER, bt->hp->eip, ++ &framesize); ++ } else /* "clear" */ ++ BZERO(&x86_64_framesize_cache[0], ++ sizeof(struct framesize_cache)*framesize_cache_entries); ++ break; ++ ++ case -1: ++ if (!bt->hp->eip) ++ error(INFO, "x86_64_framesize_debug: ignoring command\n"); ++ else ++ x86_64_get_framesize(bt, bt->hp->eip); ++ break; + ++ default: ++ if (bt->hp->esp > 1) { ++ framesize = bt->hp->esp; ++ if (bt->hp->eip) ++ x86_64_framesize_cache_func(FRAMESIZE_ENTER, bt->hp->eip, ++ &framesize); ++ } else ++ error(INFO, "x86_64_framesize_debug: ignoring command\n"); ++ break; + } +} #endif /* X86_64 */ ---- crash/extensions.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/extensions.c 2005-11-10 10:12:44.000000000 -0500 +--- crash/extensions.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/extensions.c 2007-05-24 16:26:41.000000000 -0400 @@ -18,9 +18,6 @@ #include "defs.h" #include @@ -18193,7 +30170,65 @@ #define DUMP_EXTENSIONS (0) #define LOAD_EXTENSION (1) #define UNLOAD_EXTENSION (2) -@@ -171,7 +168,7 @@ +@@ -110,6 +107,7 @@ + void + dump_extension_table(int verbose) + { ++ int i; + struct extension_table *ext; + struct command_table_entry *cp; + char buf[BUFSIZE]; +@@ -120,23 +118,37 @@ + + if (verbose) { + for (ext = extension_table; ext; ext = ext->next) { +- fprintf(fp, " filename: %s\n", ext->filename); +- fprintf(fp, " handle: %lx\n", (ulong)ext->handle); +- fprintf(fp, "command_table: %lx (", +- (ulong)ext->command_table); +- for (others = 0, cp = ext->command_table; cp->name;cp++) +- fprintf(fp, "%s%s%s", others++ ? " " : "", +- cp->name, cp->help_data ? "*" : ""); +- fprintf(fp, ")\n"); +- fprintf(fp, " flags: %lx (", ext->flags); ++ fprintf(fp, " filename: %s\n", ext->filename); ++ fprintf(fp, " handle: %lx\n", (ulong)ext->handle); ++ ++ ++ fprintf(fp, " flags: %lx (", ext->flags); + others = 0; + if (ext->flags & REGISTERED) + fprintf(fp, "%sREGISTERED", others++ ? + "|" : ""); + fprintf(fp, ")\n"); +- fprintf(fp, " next: %lx\n", (ulong)ext->next); +- fprintf(fp, " prev: %lx\n%s", +- (ulong)ext->prev, ext->next ? "\n" : ""); ++ fprintf(fp, " next: %lx\n", (ulong)ext->next); ++ fprintf(fp, " prev: %lx\n", (ulong)ext->prev); ++ ++ for (i = 0, cp = ext->command_table; cp->name; cp++, i++) { ++ fprintf(fp, "command_table[%d]: %lx\n", i, (ulong)cp); ++ fprintf(fp, " name: %s\n", cp->name); ++ fprintf(fp, " func: %lx\n", (ulong)cp->func); ++ fprintf(fp, " help_data: %lx\n", (ulong)cp->help_data); ++ fprintf(fp, " flags: %lx (", cp->flags); ++ others = 0; ++ if (cp->flags & CLEANUP) ++ fprintf(fp, "%sCLEANUP", others++ ? "|" : ""); ++ if (cp->flags & REFRESH_TASK_TABLE) ++ fprintf(fp, "%sREFRESH_TASK_TABLE", others++ ? "|" : ""); ++ if (cp->flags & HIDDEN_COMMAND) ++ fprintf(fp, "%sHIDDEN_COMMAND", others++ ? "|" : ""); ++ fprintf(fp, ")\n"); ++ } ++ ++ if (ext->next) ++ fprintf(fp, "\n"); + } + return; + } +@@ -171,7 +183,7 @@ /* * Load an extension library. */ @@ -18202,7 +30237,16 @@ load_extension(char *lib) { struct extension_table *ext; -@@ -252,7 +249,7 @@ +@@ -208,7 +220,7 @@ + * _init() function before dlopen() returns below. + */ + pc->curext = ext; +- ext->handle = dlopen(ext->filename, RTLD_NOW); ++ ext->handle = dlopen(ext->filename, RTLD_NOW|RTLD_GLOBAL); + + if (!ext->handle) { + strcpy(buf, dlerror()); +@@ -252,7 +264,7 @@ /* * Unload all, or as specified, extension libraries. */ @@ -18211,8 +30255,19 @@ unload_extension(char *lib) { struct extension_table *ext; ---- crash/va_server.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/va_server.c 2006-03-22 09:11:38.000000000 -0500 +--- crash/va_server.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/va_server.c 2006-10-11 09:14:36.000000000 -0400 +@@ -1,8 +1,8 @@ + /* va_server.c - kernel crash dump file translation library + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 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 @@ -57,13 +57,15 @@ extern int monitor_memory(long *, long *, long *, long *); @@ -18230,20 +30285,275 @@ if(read_map(crash_file)) { if(va_server_init_v1(crash_file, start, end, stride)) return -1; ---- crash/symbols.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/symbols.c 2006-08-22 12:06:27.000000000 -0400 +--- crash/symbols.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/symbols.c 2007-07-31 16:05:08.000000000 -0400 @@ -1,8 +1,8 @@ /* symbols.c - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002, 2003, 2004, 2005 David Anderson - * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson -+ * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 -@@ -1159,7 +1159,7 @@ +@@ -21,6 +21,8 @@ + + static void store_symbols(bfd *, int, void *, long, unsigned int); + static void store_sysmap_symbols(void); ++static ulong relocate(ulong, char *, int); ++static int relocate_force(ulong, char *); + static void strip_module_symbol_end(char *s); + static int compare_syms(const void *, const void *); + static int compare_mods(const void *, const void *); +@@ -36,7 +38,9 @@ + static int load_module_index(struct syment *); + static void section_header_info(bfd *, asection *, void *); + static void store_section_data(struct load_module *, bfd *, asection *); +-static void calculate_load_order(struct load_module *, bfd *); ++static void calculate_load_order_v1(struct load_module *, bfd *); ++static void calculate_load_order_v2(struct load_module *, bfd *, int, ++ void *, long, unsigned int); + static void check_insmod_builtin(struct load_module *, int, ulong *); + static int is_insmod_builtin(struct load_module *, struct syment *); + struct load_module; +@@ -61,12 +65,16 @@ + struct elf_common; + static void Elf32_Sym_to_common(Elf32_Sym *, struct elf_common *); + static void Elf64_Sym_to_common(Elf64_Sym *, struct elf_common *); ++static void cmd_datatype_common(ulong); ++static int display_per_cpu_info(struct syment *); + + + #define KERNEL_SECTIONS (void *)(1) + #define MODULE_SECTIONS (void *)(2) + #define VERIFY_SECTIONS (void *)(3) + ++#define EV_DWARFEXTRACT 101010101 ++ + #define PARSE_FOR_DATA (1) + #define PARSE_FOR_DECLARATION (2) + static void parse_for_member(struct datatype_member *, ulong); +@@ -96,6 +104,7 @@ + #define SHOW_OFFSET (0x10000) + #define IN_UNION (0x20000) + #define IN_STRUCT (0x40000) ++#define DATATYPE_QUERY (0x80000) + + #define INTEGER_TYPE (UINT8|INT8|UINT16|INT16|UINT32|INT32|UINT64|INT64) + +@@ -139,6 +148,12 @@ + if (!bfd_check_format_matches(st->bfd, bfd_object, &matching)) + error(FATAL, "cannot determine object file format: %s\n", + pc->namelist); ++ /* ++ * Check whether the namelist is a kerntypes file built by ++ * dwarfextract, which places a magic number in e_version. ++ */ ++ if (file_elf_version(pc->namelist) == EV_DWARFEXTRACT) ++ pc->flags |= KERNTYPES; + + if (pc->flags & SYSMAP) { + bfd_map_over_sections(st->bfd, section_header_info, +@@ -153,13 +168,16 @@ + } + store_sysmap_symbols(); + return; +- } ++ } else if (LKCD_KERNTYPES()) ++ error(FATAL, "%s: use of kerntypes requires a system map\n", ++ pc->namelist); + + /* + * Pull a bait-and-switch on st->bfd if we've got a separate +- * .gnu_debuglink file that matches the CRC. ++ * .gnu_debuglink file that matches the CRC. Not done for kerntypes. + */ +- if (!(bfd_get_file_flags(st->bfd) & HAS_SYMS)) { ++ if (!(LKCD_KERNTYPES()) && ++ !(bfd_get_file_flags(st->bfd) & HAS_SYMS)) { + if (!check_gnu_debuglink(st->bfd)) + no_debugging_data(FATAL); + } +@@ -471,6 +489,11 @@ + kt->stext_init = (ulong)bfd_get_section_vma(st->bfd, section); + kt->etext_init = kt->stext_init + + (ulong)bfd_section_size(st->bfd, section); ++ ++ if (kt->relocate) { ++ kt->stext_init -= kt->relocate; ++ kt->etext_init -= kt->relocate; ++ } + } + + /* +@@ -486,6 +509,7 @@ + bfd_byte *from, *fromend; + symbol_info syminfo; + struct syment *sp; ++ int first; + + if ((store = bfd_make_empty_symbol(abfd)) == NULL) + error(FATAL, "bfd_make_empty_symbol() failed\n"); +@@ -505,6 +529,13 @@ + st->symcnt = 0; + sp = st->symtable; + ++ if (machine_type("X86")) { ++ if (!(kt->flags & RELOC_SET)) ++ kt->flags |= RELOC_FORCE; ++ } else ++ kt->flags &= ~RELOC_SET; ++ ++ first = 0; + from = (bfd_byte *) minisyms; + fromend = from + symcount * size; + for (; from < fromend; from += size) +@@ -516,7 +547,11 @@ + bfd_get_symbol_info(abfd, sym, &syminfo); + if (machdep->verify_symbol(syminfo.name, syminfo.value, + syminfo.type)) { +- sp->value = syminfo.value; ++ if (kt->flags & (RELOC_SET|RELOC_FORCE)) ++ sp->value = relocate(syminfo.value, ++ (char *)syminfo.name, !(first++)); ++ else ++ sp->value = syminfo.value; + sp->type = syminfo.type; + namespace_ctl(NAMESPACE_INSTALL, &st->namespace, + sp, (char *)syminfo.name); +@@ -540,7 +575,7 @@ + static void + store_sysmap_symbols(void) + { +- int c; ++ int c, first; + long symcount; + char buf[BUFSIZE]; + FILE *map; +@@ -564,6 +599,10 @@ + error(FATAL, "symbol table namespace malloc: %s\n", + strerror(errno)); + ++ if (!machine_type("X86")) ++ kt->flags &= ~RELOC_SET; ++ ++ first = 0; + st->syment_size = symcount * sizeof(struct syment); + st->symcnt = 0; + sp = st->symtable; +@@ -580,7 +619,11 @@ + + if (machdep->verify_symbol(syment.name, syment.value, + syment.type)) { +- sp->value = syment.value; ++ if (kt->flags & RELOC_SET) ++ sp->value = relocate(syment.value, ++ syment.name, !(first++)); ++ else ++ sp->value = syment.value; + sp->type = syment.type; + namespace_ctl(NAMESPACE_INSTALL, &st->namespace, + sp, syment.name); +@@ -603,6 +646,96 @@ + } + + /* ++ * Handle x86 kernels configured such that the vmlinux symbols ++ * are not as loaded into the kernel (not unity-mapped). ++ */ ++static ulong ++relocate(ulong symval, char *symname, int first_symbol) ++{ ++ switch (kt->flags & (RELOC_SET|RELOC_FORCE)) ++ { ++ case RELOC_SET: ++ break; ++ ++ case RELOC_FORCE: ++ if (first_symbol && !relocate_force(symval, symname)) ++ kt->flags &= ~RELOC_FORCE; ++ break; ++ } ++ ++ return (symval - kt->relocate); ++} ++ ++/* ++ * If no --reloc argument was passed, try to figure it out ++ * by comparing the first vmlinux kernel symbol with the ++ * first /proc/kallsyms symbol. (should be "_text") ++ * ++ * Live system only (at least for now). ++ */ ++static int ++relocate_force(ulong symval, char *symname) ++{ ++ FILE *kp; ++ char buf[BUFSIZE]; ++ char *kallsyms[MAXARGS]; ++ ulong first; ++ ++ if (!ACTIVE() || !file_exists("/proc/kallsyms", NULL)) { ++ if (CRASHDEBUG(1)) ++ fprintf(fp, ++ "cannot determine relocation value: %s\n", ++ !ACTIVE() ? "not a live system" : ++ "/proc/kallsyms does not exist"); ++ return FALSE; ++ } ++ ++ if ((kp = fopen("/proc/kallsyms", "r")) == NULL) { ++ if (CRASHDEBUG(1)) ++ fprintf(fp, ++ "cannot open /proc/kallsyms to determine relocation\n"); ++ return FALSE; ++ } ++ ++ if (!fgets(buf, BUFSIZE, kp) || ++ (parse_line(buf, kallsyms) != 3) || ++ !hexadecimal(kallsyms[0], 0)) { ++ fclose(kp); ++ if (CRASHDEBUG(1)) ++ fprintf(fp, ++ "malformed /proc/kallsyms: cannot determine relocation value\n"); ++ return FALSE; ++ } ++ fclose(kp); ++ ++ first = htol(kallsyms[0], RETURN_ON_ERROR, NULL); ++ ++ if (CRASHDEBUG(1)) ++ fprintf(fp, ++ "RELOCATE: %s @ %lx %s\n" ++ " %s @ %lx /proc/kallsyms\n", ++ symname, symval, pc->namelist, ++ kallsyms[2], first); ++ ++ /* ++ * If the symbols match and have different values, ++ * force the relocation. ++ */ ++ if (STREQ(symname, kallsyms[2])) { ++ if (symval > first) { ++ kt->relocate = symval - first; ++ return TRUE; ++ } ++ } ++ ++ if (CRASHDEBUG(1)) ++ fprintf(fp, ++ "cannot determine relocation value from first symbol\n"); ++ ++ return FALSE; ++} ++ ++/* + * Install all static kernel symbol values into the symval_hash. + */ + static void +@@ -1159,7 +1292,7 @@ mod_name); strncpy(lm->mod_name, mod_name, MAX_MOD_NAME-1); } @@ -18252,16 +30562,68 @@ fprintf(fp, "%lx (%lx): %s syms: %d gplsyms: %d ksyms: %ld\n", mod, lm->mod_base, lm->mod_name, nsyms, -@@ -2121,6 +2121,8 @@ +@@ -2121,22 +2254,13 @@ fprintf(fp, "%sFORCE_DEBUGINFO", others++ ? "|" : ""); if (st->flags & CRC_MATCHES) fprintf(fp, "%sCRC_MATCHES", others++ ? "|" : ""); + if (st->flags & ADD_SYMBOL_FILE) + fprintf(fp, "%sADD_SYMBOL_FILE", others++ ? "|" : ""); ++ if (st->flags & USE_OLD_ADD_SYM) ++ fprintf(fp, "%sUSE_OLD_ADD_SYM", others++ ? "|" : ""); fprintf(fp, ")\n"); fprintf(fp, " bfd: %lx\n", (ulong)st->bfd); -@@ -3463,6 +3465,22 @@ +- +- sec = (asection **)st->sections; +- fprintf(fp, " sections: %s\n", sec ? "" : "(not in use)"); +- for (i = 0; sec && (i < st->bfd->section_count); i++, sec++) { +- asection *section; +- +- section = *sec; +- fprintf(fp, "%25s vma: %.*lx size: %ld\n", +- section->name, VADDR_PRLEN, +- (ulong)bfd_get_section_vma(st->bfd, section), +- (ulong)bfd_section_size(st->bfd, section)); +- } +- + fprintf(fp, " symtable: %lx\n", (ulong)st->symtable); + fprintf(fp, " symend: %lx\n", (ulong)st->symend); + fprintf(fp, " symcnt: %ld\n", st->symcnt); +@@ -2320,6 +2444,24 @@ + } + } + } ++ ++ fprintf(fp, "\n"); ++ fprintf(fp, "dwarf_eh_frame_file_offset: %llx\n", ++ (unsigned long long)st->dwarf_eh_frame_file_offset); ++ fprintf(fp, " dwarf_eh_frame_size: %ld\n", st->dwarf_eh_frame_size); ++ fprintf(fp, "\n"); ++ ++ sec = (asection **)st->sections; ++ fprintf(fp, " sections: %s\n", sec ? "" : "(not in use)"); ++ for (i = 0; sec && (i < st->bfd->section_count); i++, sec++) { ++ asection *section; ++ ++ section = *sec; ++ fprintf(fp, "%25s vma: %.*lx size: %ld\n", ++ section->name, VADDR_PRLEN, ++ (ulong)bfd_get_section_vma(st->bfd, section), ++ (ulong)bfd_section_size(st->bfd, section)); ++ } + } + + +@@ -2427,7 +2569,7 @@ + goto not_system_map; + if (parse_line(buf, mapitems) != 3) + goto not_system_map; +- if ((strlen(mapitems[0]) != MAX_HEXADDR_STRLEN) || ++ if ((strlen(mapitems[0]) > MAX_HEXADDR_STRLEN) || + !hexadecimal(mapitems[0], 0) || (strlen(mapitems[1]) > 1)) + goto not_system_map; + } +@@ -3463,6 +3605,22 @@ } /* @@ -18284,7 +30646,715 @@ * Return the value of a given symbol. */ ulong -@@ -5079,7 +5097,8 @@ +@@ -3477,6 +3635,34 @@ + } + + /* ++ * Return the value of a symbol from a specific module. ++ */ ++ulong ++symbol_value_module(char *symbol, char *module) ++{ ++ int i; ++ struct syment *sp, *sp_end; ++ struct load_module *lm; ++ ++ for (i = 0; i < st->mods_installed; i++) { ++ lm = &st->load_modules[i]; ++ ++ if (!STREQ(module, lm->mod_name)) ++ continue; ++ ++ sp = lm->mod_symtable; ++ sp_end = lm->mod_symend; ++ ++ for ( ; sp < sp_end; sp++) { ++ if (STREQ(symbol, sp->name)) ++ return(sp->value); ++ } ++ } ++ ++ return 0; ++} ++ ++/* + * Return the symbol name of a given value, with no allowance for offsets. + * Returns NULL on failure to allow for testing of a value. + */ +@@ -3748,6 +3934,7 @@ + dm->size = size; + dm->member_size = member_size; + dm->member_typecode = member_typecode; ++ dm->member_offset = offset; + if (req->is_typedef) { + dm->flags |= TYPEDEF; + } +@@ -3928,25 +4115,59 @@ + void + cmd_struct(void) + { +- int c; ++ cmd_datatype_common(STRUCT_REQUEST); ++} ++/* ++ * This command displays either a union definition, or a formatted display ++ * of the contents of a union at a specified address. If no address is ++ * specified, the union size and the file in which the union is defined ++ * are also displayed. A union member may be appended to the union ++ * name (in a "union.member" format) in order to limit the scope of the data ++ * displayed to that particular member. Structure data is shown in hexadecimal ++ * format. The raw data in a union may be dumped with the -r flag. ++ */ ++void ++cmd_union(void) ++{ ++ cmd_datatype_common(UNION_REQUEST); ++} ++ ++/* ++ * After determining what type of data type follows the *, this routine ++ * has the identical functionality as cmd_struct() or cmd_union(). ++ */ ++void ++cmd_pointer(void) ++{ ++ cmd_datatype_common(0); ++} ++ ++static void ++cmd_datatype_common(ulong flags) ++{ ++ int i, c; + ulong addr, aflag; + struct syment *sp; + int rawdata; + long len; +- ulong flags; + ulong list_head_offset; + int count; +- struct datatype_member struct_member, *sm; ++ int argc_members; ++ int optind_save; ++ struct datatype_member datatype_member, *dm; ++ char *separator; ++ char *structname, *members; ++ char *memberlist[MAXARGS]; + +- sm = &struct_member; +- count = 1; ++ dm = &datatype_member; ++ count = 0xdeadbeef; + rawdata = 0; + aflag = 0; +- list_head_offset = 0; +- flags = STRUCT_REQUEST; ++ list_head_offset = 0; ++ argc_members = 0; + +- while ((c = getopt(argcnt, args, "c:rvol:")) != EOF) { +- switch(c) ++ while ((c = getopt(argcnt, args, "fuc:rvol:")) != EOF) { ++ switch (c) + { + case 'c': + count = atoi(optarg); +@@ -3969,8 +4190,22 @@ + list_head_offset = stol(optarg, + FAULT_ON_ERROR, NULL); + else if (arg_to_datatype(optarg, +- sm, RETURN_ON_ERROR) > 1) +- list_head_offset = sm->member_offset; ++ dm, RETURN_ON_ERROR) > 1) ++ list_head_offset = dm->member_offset; ++ else ++ error(FATAL, "invalid -l option: %s\n", ++ optarg); ++ break; ++ ++ case 'f': ++ if (!pc->dumpfile) ++ error(FATAL, ++ "-f option requires a dumpfile\n"); ++ pc->curcmd_flags |= MEMTYPE_FILEADDR; ++ break; ++ ++ case 'u': ++ pc->curcmd_flags |= MEMTYPE_UVADDR; + break; + + default: +@@ -3982,35 +4217,42 @@ + if (argerrs || !args[optind]) + cmd_usage(pc->curcmd, SYNOPSIS); + +- if ((arg_to_datatype(args[optind++], sm, FAULT_ON_ERROR) > 1) && +- rawdata) +- error(FATAL, "member-specific output not allowed with -r\n"); +- +- if ((len = sm->size) < 0) { +- error(INFO, "structure not found: %s\n", sm->name); +- cmd_usage(pc->curcmd, SYNOPSIS); +- } +- +- if (!args[optind]) { +- do_datatype_declaration(sm, flags | (sm->flags & TYPEDEF)); +- return; +- } ++ if ((count_chars(args[optind], ',')+1) > MAXARGS) ++ error(FATAL, "too many members in comma-separated list!\n"); ++ ++ if ((count_chars(args[optind], '.') > 1) || ++ (LASTCHAR(args[optind]) == ',') || ++ (LASTCHAR(args[optind]) == '.')) ++ error(FATAL, "invalid format: %s\n", args[optind]); ++ ++ optind_save = optind; ++ ++ /* ++ * Take care of address and count (array). ++ */ ++ while (args[++optind]) { ++ if (aflag && (count != 0xdeadbeef)) ++ error(FATAL, "too many arguments!\n"); + +- while (args[optind]) { + if (clean_arg() && IS_A_NUMBER(args[optind])) { + if (aflag) + count = stol(args[optind], + FAULT_ON_ERROR, NULL); + else { +- if (!IS_KVADDR(addr = htol(args[optind], ++ if (pc->curcmd_flags & MEMTYPE_FILEADDR) ++ pc->curcmd_private = stoll(args[optind], ++ FAULT_ON_ERROR, NULL); ++ else if (pc->curcmd_flags & MEMTYPE_UVADDR) { ++ addr = htol(args[optind], FAULT_ON_ERROR, ++ NULL); ++ } else if (!IS_KVADDR(addr = htol(args[optind], + FAULT_ON_ERROR, NULL))) + error(FATAL, + "invalid kernel virtual address: %s\n", + args[optind]); + aflag++; + } +- } +- else if ((sp = symbol_search(args[optind]))) { ++ } else if ((sp = symbol_search(args[optind]))) { + addr = sp->value; + aflag++; + } else { +@@ -4018,298 +4260,134 @@ + fprintf(fp, "possible aternatives:\n"); + if (!symbol_query(args[optind], " ", NULL)) + fprintf(fp, " (none found)\n"); +- return; +- } +- optind++; +- } +- +- if (!aflag) +- error(FATAL, "no kernel virtual address argument entered\n"); +- +- if (list_head_offset) +- addr -= list_head_offset; +- +- if (count < 0) { +- addr -= len * abs(count); +- addr += len; +- } +- +- for (c = 0; c < abs(count); c++, addr += len) { +- if (rawdata) +- raw_data_dump(addr, len, flags & STRUCT_VERBOSE); +- else { +- if (sm->member) +- open_tmpfile(); +- +- print_struct(sm->name, addr); +- +- if (sm->member) { +- parse_for_member(sm, PARSE_FOR_DATA); +- close_tmpfile(); +- } +- } +- } +-} +- +-/* +- * After determining what type of data type follows the *, this routine +- * has the identical functionality as cmd_struct() or cmd_union(). +- */ +-void +-cmd_pointer(void) +-{ +- int c; +- ulong addr, aflag; +- struct syment *sp; +- int rawdata; +- long len; +- ulong flags; +- int count; +- struct datatype_member datatype_member, *dm; +- +- dm = &datatype_member; +- rawdata = 0; +- flags = 0; +- aflag = 0; +- count = 1; +- +- while ((c = getopt(argcnt, args, "c:rvo")) != EOF) { +- switch(c) +- { +- case 'c': +- count = atoi(optarg); +- break; +- +- case 'r': +- rawdata = 1; +- break; +- +- case 'v': +- flags |= STRUCT_VERBOSE; +- break; +- +- case 'o': +- flags |= SHOW_OFFSET; +- break; +- +- default: +- argerrs++; +- break; ++ goto freebuf; + } + } + +- if (argerrs || !args[optind]) +- cmd_usage(pc->curcmd, SYNOPSIS); ++ optind = optind_save; + +- if ((arg_to_datatype(args[optind++], dm, FAULT_ON_ERROR) > 1) && +- rawdata) +- error(FATAL, "member-specific output not allowed with -r\n"); ++ if (count == 0xdeadbeef) ++ count = 1; ++ else if (!aflag) ++ error(FATAL, "no kernel virtual address argument entered\n"); + +- if ((len = dm->size) < 0) { +- error(INFO, "structure or union not found: %s\n", dm->name); +- cmd_usage(pc->curcmd, SYNOPSIS); ++ if ((flags & SHOW_OFFSET) && aflag) { ++ error(INFO, "-o option not valid with an address argument\n"); ++ flags &= ~SHOW_OFFSET; + } + +- flags |= dm->type; +- +- if (!args[optind]) { +- do_datatype_declaration(dm, flags | (dm->flags & TYPEDEF)); +- return; +- } ++ if (list_head_offset) ++ addr -= list_head_offset; + +- while (args[optind]) { +- if (clean_arg() && IS_A_NUMBER(args[optind])) { +- if (aflag) +- count = stol(args[optind], +- FAULT_ON_ERROR, NULL); +- else { +- if (!IS_KVADDR(addr = htol(args[optind], +- FAULT_ON_ERROR, NULL))) +- error(FATAL, +- "invalid kernel virtual address: %s\n", +- args[optind]); +- aflag++; +- } +- } +- else if ((sp = symbol_search(args[optind]))) { +- addr = sp->value; +- aflag++; +- } else { +- fprintf(fp, "symbol not found: %s\n", args[optind]); +- fprintf(fp, "possible aternatives:\n"); +- if (!symbol_query(args[optind], " ", NULL)) +- fprintf(fp, " (none found)\n"); +- return; +- } +- optind++; ++ /* ++ * Handle struct.member[,member] argument format. ++ */ ++ if (strstr(args[optind], ".")) { ++ structname = GETBUF(strlen(args[optind])+1); ++ strcpy(structname, args[optind]); ++ separator = strstr(structname, "."); ++ ++ members = GETBUF(strlen(args[optind])+1); ++ strcpy(members, separator+1); ++ replace_string(members, ",", ' '); ++ argc_members = parse_line(members, memberlist); ++ } else ++ structname = args[optind]; ++ ++ if ((arg_to_datatype(structname, dm, DATATYPE_QUERY|RETURN_ON_ERROR) < 1)) ++ error(FATAL, "invalid data structure reference: %s\n", structname); ++ ++ if ((argc_members > 1) && !aflag) { ++ error(INFO, flags & SHOW_OFFSET ? ++ "-o option not valid with multiple member format\n" : ++ "multiple member format not supported in this syntax\n"); ++ *separator = NULLCHAR; ++ argc_members = 0; ++ flags |= SHOW_OFFSET; + } + +- if (!(flags & (UNION_REQUEST|STRUCT_REQUEST))) +- error(FATAL, "invalid argument!"); +- +- if (!aflag) +- error(FATAL, "no kernel virtual address argument entered\n"); ++ len = dm->size; + + if (count < 0) { + addr -= len * abs(count); + addr += len; + } + +- for (c = 0; c < abs(count); c++, addr += len) { +- if (rawdata) +- raw_data_dump(addr, len, flags & STRUCT_VERBOSE); +- else { +- if (dm->member) +- open_tmpfile(); +- +- if (flags & UNION_REQUEST) +- print_union(dm->name, addr); +- else if (flags & STRUCT_REQUEST) +- print_struct(dm->name, addr); +- +- if (dm->member) { +- parse_for_member(dm, PARSE_FOR_DATA); +- close_tmpfile(); +- } +- } +- } +-} +- +-/* +- * This command displays either a union definition, or a formatted display +- * of the contents of a union at a specified address. If no address is +- * specified, the union size and the file in which the union is defined +- * are also displayed. A union member may be appended to the union +- * name (in a "union.member" format) in order to limit the scope of the data +- * displayed to that particular member. Structure data is shown in hexadecimal +- * format. The raw data in a union may be dumped with the -r flag. +- */ +-void +-cmd_union(void) +-{ +- int c; +- ulong addr, aflag; +- struct syment *sp; +- int rawdata; +- long len; +- ulong flags; +- int count; +- struct datatype_member union_member, *um; +- ulong list_head_offset; +- +- um = &union_member; +- count = 1; +- rawdata = 0; +- aflag = 0; +- list_head_offset = 0; +- flags = UNION_REQUEST; +- +- while ((c = getopt(argcnt, args, "c:rvol:")) != EOF) { +- switch(c) +- { +- case 'c': +- count = atoi(optarg); +- break; +- +- case 'r': +- rawdata = 1; +- break; +- +- case 'v': +- flags |= STRUCT_VERBOSE; +- break; ++ if (pc->curcmd_flags & MEMTYPE_FILEADDR) ++ addr = 0; /* unused, but parsed by gdb */ + +- case 'o': +- flags |= SHOW_OFFSET; +- break; +- +- case 'l': +- if (IS_A_NUMBER(optarg)) +- list_head_offset = stol(optarg, +- FAULT_ON_ERROR, NULL); +- else if (arg_to_datatype(optarg, +- um, RETURN_ON_ERROR) > 1) +- list_head_offset = um->member_offset; +- break; ++ for (c = 0; c < abs(count); c++, addr += len, pc->curcmd_private += len) { ++ if (c) ++ fprintf(fp,"\n"); + +- default: +- argerrs++; +- break; +- } +- } ++ i = 0; ++ do { ++ if (argc_members) { ++ *separator = '.'; ++ strcpy(separator+1, memberlist[i]); ++ } + +- if (argerrs || !args[optind]) +- cmd_usage(pc->curcmd, SYNOPSIS); ++ switch (arg_to_datatype(structname, dm, RETURN_ON_ERROR)) ++ { ++ case 0: error(FATAL, "invalid data structure reference: %s\n", ++ structname); ++ break; ++ case 1: break; ++ case 2: if (rawdata) ++ error(FATAL, ++ "member-specific output not allowed with -r\n"); ++ break; ++ } + +- if ((arg_to_datatype(args[optind++], um, FAULT_ON_ERROR) > 1) && +- rawdata) +- error(FATAL, "member-specific output not allowed with -r\n"); ++ if (!(dm->flags & TYPEDEF)) { ++ if (flags &(STRUCT_REQUEST|UNION_REQUEST) ) { ++ if ((flags & (STRUCT_REQUEST|UNION_REQUEST)) != dm->type) ++ goto freebuf; ++ } else ++ flags |= dm->type; ++ } + +- if ((len = um->size) < 0) { +- error(INFO, "union not found: %s\n", um->name); +- cmd_usage(pc->curcmd, SYNOPSIS); +- } ++ /* ++ * No address was passed -- dump the structure/member declaration. ++ */ ++ if (!aflag) { ++ do_datatype_declaration(dm, flags | (dm->flags & TYPEDEF)); ++ goto freebuf; ++ } ++ ++ if (!(flags & (UNION_REQUEST|STRUCT_REQUEST))) ++ error(FATAL, "invalid argument"); ++ ++ /* ++ * Display data. ++ */ ++ if (rawdata) ++ raw_data_dump(addr, len, flags & STRUCT_VERBOSE); ++ else { ++ if (dm->member) ++ open_tmpfile(); + +- if (!args[optind]) { +- do_datatype_declaration(um, flags | (um->flags & TYPEDEF)); +- return; +- } +- +- while (args[optind]) { +- if (clean_arg() && IS_A_NUMBER(args[optind])) { +- if (aflag) +- count = stol(args[optind], +- FAULT_ON_ERROR, NULL); +- else { +- if (!IS_KVADDR(addr = htol(args[optind], +- FAULT_ON_ERROR, NULL))) +- error(FATAL, +- "invalid kernel virtual address: %s\n", +- args[optind]); +- aflag++; +- } +- } +- else if ((sp = symbol_search(args[optind]))) { +- addr = sp->value; +- aflag++; +- } else { +- fprintf(fp, "symbol not found: %s\n", args[optind]); +- fprintf(fp, "possible aternatives:\n"); +- if (!symbol_query(args[optind], " ", NULL)) +- fprintf(fp, " (none found)\n"); +- return; +- } +- optind++; +- } +- +- if (!aflag) +- error(FATAL, "no kernel virtual address argument entered\n"); +- +- if (list_head_offset) +- addr -= list_head_offset; +- +- if (count < 0) { +- addr -= len * abs(count); +- addr += len; +- } ++ if (flags & UNION_REQUEST) ++ print_union(dm->name, addr); ++ else if (flags & STRUCT_REQUEST) ++ print_struct(dm->name, addr); ++ ++ if (dm->member) { ++ parse_for_member(dm, PARSE_FOR_DATA); ++ close_tmpfile(); ++ } ++ } ++ } while (++i < argc_members); ++ } + +- for (c = 0; c < abs(count); c++, addr += len) { +- if (rawdata) +- raw_data_dump(addr, len, flags & STRUCT_VERBOSE); +- else { +- if (um->member) +- open_tmpfile(); +- +- print_union(um->name, addr); +- +- if (um->member) { +- parse_for_member(um, PARSE_FOR_DATA); +- close_tmpfile(); +- } +- } ++freebuf: ++ if (argc_members) { ++ FREEBUF(structname); ++ FREEBUF(members); + } + } + ++ + /* + * Generic function for dumping data structure declarations, with a small + * fixup for typedefs, sizes and member offsets. +@@ -4405,7 +4483,10 @@ + + if (!(p1 = strstr(s, "."))) + both = FALSE; +- else { ++ else if (flags & DATATYPE_QUERY) { ++ *p1 = NULLCHAR; ++ both = FALSE; ++ } else { + if ((p1 == s) || !strlen(p1+1)) + goto datatype_member_fatal; + *p1 = NULLCHAR; +@@ -4634,6 +4715,27 @@ + } + + /* ++ * Given the name of an enum, return its value. ++ */ ++int ++enumerator_value(char *e, long *value) ++{ ++ struct datatype_member datatype_member, *dm; ++ ++ dm = &datatype_member; ++ ++ if (arg_to_datatype(e, dm, RETURN_ON_ERROR)) { ++ if ((dm->size >= 0) && ++ (dm->type == ENUM) && dm->tagname) { ++ *value = dm->value; ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ ++/* + * Verify that a datatype exists, but return on error. + */ + int +@@ -4705,6 +4807,8 @@ + cmd_usage(pc->curcmd, SYNOPSIS); + + if ((sp = symbol_search(args[optind])) && !args[optind+1]) { ++ if (STRNEQ(sp->name, "per_cpu__") && display_per_cpu_info(sp)) ++ return; + sprintf(buf2, "%s = ", args[optind]); + leader = strlen(buf2); + if (module_symbol(sp->value, NULL, NULL, NULL, output_radix)) +@@ -4758,6 +4862,39 @@ + } + + /* ++ * Display the datatype of the per_cpu__xxx symbol and ++ * the addresses of each its per-cpu instances. ++ */ ++static int ++display_per_cpu_info(struct syment *sp) ++{ ++ int c; ++ ulong addr; ++ char buf[BUFSIZE]; ++ ++ if (((kt->flags & (SMP|PER_CPU_OFF)) != (SMP|PER_CPU_OFF)) || ++ (sp->value < symbol_value("__per_cpu_start")) || ++ (sp->value >= symbol_value("__per_cpu_end")) || ++ !((sp->type == 'd') || (sp->type == 'D'))) ++ return FALSE; ++ ++ fprintf(fp, "PER-CPU DATA TYPE:\n "); ++ sprintf(buf, "whatis %s", sp->name); ++ if (!gdb_pass_through(buf, pc->nullfp, GNU_RETURN_ON_ERROR)) ++ fprintf(fp, "[undetermined type] %s;\n", sp->name); ++ else ++ whatis_variable(sp); ++ ++ fprintf(fp, "PER-CPU ADDRESSES:\n"); ++ for (c = 0; c < kt->cpus; c++) { ++ addr = sp->value + kt->__per_cpu_offset[c]; ++ fprintf(fp, " [%d]: %lx\n", c, addr); ++ } ++ ++ return TRUE; ++} ++ ++/* + * As a latch ditch effort before a command is thrown away by exec_command(), + * args[0] is checked to see whether it's the name of a variable, structure, + * union, or typedef. If so, args[0] is changed to the appropriate command, +@@ -4793,9 +4930,9 @@ + command = "whatis"; + else if (!datatype_exists(args[0])) + return FALSE; +- else if (!arg_to_datatype(buf, dm, RETURN_ON_ERROR)) { ++ else if (!arg_to_datatype(buf, dm, RETURN_ON_ERROR|DATATYPE_QUERY)) + return FALSE; +- } else { ++ else { + if (is_gdb_command(FALSE, RETURN_ON_ERROR)) { + pc->curcmd = pc->program_name; + error(FATAL, +@@ -5056,6 +5193,8 @@ + fprintf(ofp, "%sSTRUCT_VERBOSE", others++ ? "|" : ""); + if (flags & SHOW_OFFSET) + fprintf(ofp, "%sSHOW_OFFSET", others++ ? "|" : ""); ++ if (flags & DATATYPE_QUERY) ++ fprintf(ofp, "%sDATATYPE_QUERY", others++ ? "|" : ""); + fprintf(ofp, ")\n"); + } + +@@ -5079,7 +5218,8 @@ s = dm->member; indent = 0; @@ -18294,7 +31364,7 @@ rewind(pc->tmpfile); switch (flag) -@@ -5090,7 +5109,7 @@ +@@ -5090,7 +5230,7 @@ next_item: while (fgets(buf, BUFSIZE, pc->tmpfile)) { if (STRNEQ(buf, lookfor1) || STRNEQ(buf, lookfor2)) { @@ -18303,7 +31373,7 @@ if (strstr(buf, "= {")) indent = count_leading_spaces(buf); if (strstr(buf, "[")) -@@ -5098,16 +5117,22 @@ +@@ -5098,16 +5238,22 @@ } if (on) { @@ -18326,7 +31396,84 @@ goto next_item; } break; -@@ -5433,6 +5458,8 @@ +@@ -5174,7 +5320,7 @@ + { + int i, c, len; + long offset; +- char *target; ++ char *t1, *target; + char *arglist[MAXARGS]; + char buf1[BUFSIZE]; + char fmt[BUFSIZE]; +@@ -5186,6 +5332,9 @@ + return FALSE; + } + ++ if (STRNEQ(inbuf, " ")) ++ goto do_empty_offset; ++ + if (STRNEQ(inbuf, " union {")) + dm->flags |= IN_UNION; + if (STRNEQ(inbuf, " struct {")) +@@ -5215,9 +5364,20 @@ + } + } + } else if (c) { +- target = arglist[c-1]; +- if (!strstr(target, ";")) +- target = NULL; ++ for (i = 0; i < c; i++) { ++ if (STRNEQ(arglist[i], "(*")) { ++ target = arglist[i]+2; ++ if (!(t1 = strstr(target, ")"))) ++ continue; ++ *t1 = NULLCHAR; ++ break; ++ } ++ } ++ if (i == c) { ++ target = arglist[c-1]; ++ if (!strstr(target, ";")) ++ target = NULL; ++ } + } + + if (!target) +@@ -5307,7 +5467,8 @@ + if ((retval = builtin_array_length(s, 0, two_dim))) + return retval; + +- if (symbol_search(s)) { ++ /* symbol_search cannot be done with just kernel type information */ ++ if (!(LKCD_KERNTYPES()) && symbol_search(s)) { + if (!two_dim) { + req = &gnu_request; + if ((get_symbol_type(copy, NULL, req) == +@@ -5417,6 +5578,23 @@ + } + + /* ++ * Get and store the size of a "known" array. ++ * A wrapper for get_array_length(), for cases in which ++ * the name of the result to be stored is different from the ++ * structure.member to be evaluated. ++ */ ++int ++get_array_length_alt(char *name, char *s, int *two_dim, long entry_size) ++{ ++ int retval; ++ ++ retval = get_array_length(s, two_dim, entry_size); ++ if (retval) ++ retval = builtin_array_length(name, retval, two_dim); ++ return retval; ++} ++ ++/* + * Designed for use by non-debug kernels, but used by all. + */ + int +@@ -5433,6 +5611,8 @@ lenptr = &array_table.kmem_cache_s_c_name; else if (STREQ(s, "kmem_cache_s.array")) lenptr = &array_table.kmem_cache_s_array; @@ -18335,7 +31482,53 @@ else if (STREQ(s, "kmem_cache_s.cpudata")) lenptr = &array_table.kmem_cache_s_cpudata; else if (STREQ(s, "log_buf")) -@@ -5766,6 +5793,8 @@ +@@ -5469,6 +5649,8 @@ + lenptr = &array_table.prio_array_queue; + else if (STREQ(s, "height_to_maxindex")) + lenptr = &array_table.height_to_maxindex; ++ else if (STREQ(s, "pid_hash")) ++ lenptr = &array_table.pid_hash; + else if (STREQ(s, "free_area")) { + lenptr = &array_table.free_area; + if (two_dim) +@@ -5608,6 +5790,10 @@ + OFFSET(task_struct_timestamp)); + fprintf(fp, " task_struct_thread_info: %ld\n", + OFFSET(task_struct_thread_info)); ++ fprintf(fp, " task_struct_nsproxy: %ld\n", ++ OFFSET(task_struct_nsproxy)); ++ fprintf(fp, " task_struct_rlim: %ld\n", ++ OFFSET(task_struct_rlim)); + + fprintf(fp, " thread_info_task: %ld\n", + OFFSET(thread_info_task)); +@@ -5618,6 +5804,13 @@ + fprintf(fp, " thread_info_previous_esp: %ld\n", + OFFSET(thread_info_previous_esp)); + ++ fprintf(fp, " nsproxy_mnt_ns: %ld\n", ++ OFFSET(nsproxy_mnt_ns)); ++ fprintf(fp, " mnt_namespace_root: %ld\n", ++ OFFSET(mnt_namespace_root)); ++ fprintf(fp, " mnt_namespace_list: %ld\n", ++ OFFSET(mnt_namespace_list)); ++ + fprintf(fp, " pid_link_pid: %ld\n", + OFFSET(pid_link_pid)); + fprintf(fp, " pid_hash_chain: %ld\n", +@@ -5647,6 +5840,11 @@ + OFFSET(signal_struct_count)); + fprintf(fp, " signal_struct_action: %ld\n", + OFFSET(signal_struct_action)); ++ fprintf(fp, " signal_struct_shared_pending: %ld\n", ++ OFFSET(signal_struct_shared_pending)); ++ fprintf(fp, " signal_struct_rlim: %ld\n", ++ OFFSET(signal_struct_rlim)); ++ + fprintf(fp, " task_struct_start_time: %ld\n", + OFFSET(task_struct_start_time)); + fprintf(fp, " task_struct_times: %ld\n", +@@ -5766,10 +5964,20 @@ OFFSET(mm_struct_pgd)); fprintf(fp, " mm_struct_rss: %ld\n", OFFSET(mm_struct_rss)); @@ -18344,7 +31537,64 @@ fprintf(fp, " mm_struct_total_vm: %ld\n", OFFSET(mm_struct_total_vm)); fprintf(fp, " mm_struct_start_code: %ld\n", -@@ -5972,6 +6001,16 @@ + OFFSET(mm_struct_start_code)); ++ fprintf(fp, " mm_struct_arg_start: %ld\n", ++ OFFSET(mm_struct_arg_start)); ++ fprintf(fp, " mm_struct_arg_end: %ld\n", ++ OFFSET(mm_struct_arg_end)); ++ fprintf(fp, " mm_struct_env_start: %ld\n", ++ OFFSET(mm_struct_env_start)); ++ fprintf(fp, " mm_struct_env_end: %ld\n", ++ OFFSET(mm_struct_env_end)); + + fprintf(fp, " vm_area_struct_vm_mm: %ld\n", + OFFSET(vm_area_struct_vm_mm)); +@@ -5922,6 +6130,8 @@ + OFFSET(irq_desc_t_status)); + fprintf(fp, " irq_desc_t_handler: %ld\n", + OFFSET(irq_desc_t_handler)); ++ fprintf(fp, " irq_desc_t_chip: %ld\n", ++ OFFSET(irq_desc_t_chip)); + fprintf(fp, " irq_desc_t_action: %ld\n", + OFFSET(irq_desc_t_action)); + fprintf(fp, " irq_desc_t_depth: %ld\n", +@@ -5967,11 +6177,52 @@ + fprintf(fp, "hw_interrupt_type_set_affinity: %ld\n", + OFFSET(hw_interrupt_type_set_affinity)); + ++ fprintf(fp, " irq_chip_typename: %ld\n", ++ OFFSET(irq_chip_typename)); ++ fprintf(fp, " irq_chip_startup: %ld\n", ++ OFFSET(irq_chip_startup)); ++ fprintf(fp, " irq_chip_shutdown: %ld\n", ++ OFFSET(irq_chip_shutdown)); ++ fprintf(fp, " irq_chip_enable: %ld\n", ++ OFFSET(irq_chip_enable)); ++ fprintf(fp, " irq_chip_disable: %ld\n", ++ OFFSET(irq_chip_disable)); ++ fprintf(fp, " irq_chip_ack: %ld\n", ++ OFFSET(irq_chip_ack)); ++ fprintf(fp, " irq_chip_mask: %ld\n", ++ OFFSET(irq_chip_mask)); ++ fprintf(fp, " irq_chip_mask_ack: %ld\n", ++ OFFSET(irq_chip_mask_ack)); ++ fprintf(fp, " irq_chip_unmask: %ld\n", ++ OFFSET(irq_chip_unmask)); ++ fprintf(fp, " irq_chip_eoi: %ld\n", ++ OFFSET(irq_chip_eoi)); ++ fprintf(fp, " irq_chip_end: %ld\n", ++ OFFSET(irq_chip_end)); ++ fprintf(fp, " irq_chip_set_affinity: %ld\n", ++ OFFSET(irq_chip_set_affinity)); ++ fprintf(fp, " irq_chip_retrigger: %ld\n", ++ OFFSET(irq_chip_retrigger)); ++ fprintf(fp, " irq_chip_set_type: %ld\n", ++ OFFSET(irq_chip_set_type)); ++ fprintf(fp, " irq_chip_set_wake: %ld\n", ++ OFFSET(irq_chip_set_wake)); ++ + fprintf(fp, "irq_cpustat_t___softirq_active: %ld\n", + OFFSET(irq_cpustat_t___softirq_active)); fprintf(fp, " irq_cpustat_t___softirq_mask: %ld\n", OFFSET(irq_cpustat_t___softirq_mask)); @@ -18361,7 +31611,20 @@ fprintf(fp, " files_struct_max_fds: %ld\n", OFFSET(files_struct_max_fds)); fprintf(fp, " files_struct_max_fdset: %ld\n", -@@ -6217,6 +6256,11 @@ +@@ -5988,6 +6239,12 @@ + OFFSET(file_f_vfsmnt)); + fprintf(fp, " file_f_count: %ld\n", + OFFSET(file_f_count)); ++ fprintf(fp, " file_f_path: %ld\n", ++ OFFSET(file_f_path)); ++ fprintf(fp, " path_mnt: %ld\n", ++ OFFSET(path_mnt)); ++ fprintf(fp, " path_dentry: %ld\n", ++ OFFSET(path_dentry)); + fprintf(fp, " fs_struct_root: %ld\n", + OFFSET(fs_struct_root)); + fprintf(fp, " fs_struct_pwd: %ld\n", +@@ -6217,6 +6474,11 @@ fprintf(fp, " inet_opt_num: %ld\n", OFFSET(inet_opt_num)); @@ -18373,7 +31636,7 @@ fprintf(fp, " timer_list_list: %ld\n", OFFSET(timer_list_list)); fprintf(fp, " timer_list_next: %ld\n", -@@ -6291,6 +6335,8 @@ +@@ -6291,6 +6553,8 @@ OFFSET(zone_struct_size)); fprintf(fp, " zone_struct_memsize: %ld\n", OFFSET(zone_struct_memsize)); @@ -18382,7 +31645,16 @@ fprintf(fp, " zone_struct_zone_start_paddr: %ld\n", OFFSET(zone_struct_zone_start_paddr)); fprintf(fp, " zone_struct_zone_start_mapnr: %ld\n", -@@ -6471,10 +6517,25 @@ +@@ -6332,6 +6596,8 @@ + OFFSET(zone_pages_low)); + fprintf(fp, " zone_pages_high: %ld\n", + OFFSET(zone_pages_high)); ++ fprintf(fp, " zone_vm_stat: %ld\n", ++ OFFSET(zone_vm_stat)); + + fprintf(fp, " neighbour_next: %ld\n", + OFFSET(neighbour_next)); +@@ -6471,10 +6737,55 @@ OFFSET(x8664_pda_irqstackptr)); fprintf(fp, " x8664_pda_level4_pgt: %ld\n", OFFSET(x8664_pda_level4_pgt)); @@ -18404,11 +31676,41 @@ + OFFSET(cpu_user_regs_rip)); + fprintf(fp, " cpu_user_regs_rsp: %ld\n", + OFFSET(cpu_user_regs_rsp)); -+ ++ fprintf(fp, " unwind_table_core: %ld\n", ++ OFFSET(unwind_table_core)); ++ fprintf(fp, " unwind_table_init: %ld\n", ++ OFFSET(unwind_table_init)); ++ fprintf(fp, " unwind_table_address: %ld\n", ++ OFFSET(unwind_table_address)); ++ fprintf(fp, " unwind_table_size: %ld\n", ++ OFFSET(unwind_table_size)); ++ fprintf(fp, " unwind_table_link: %ld\n", ++ OFFSET(unwind_table_link)); ++ fprintf(fp, " unwind_table_name: %ld\n", ++ OFFSET(unwind_table_name)); ++ ++ fprintf(fp, " rq_cfs: %ld\n", ++ OFFSET(rq_cfs)); ++ fprintf(fp, " rq_rt: %ld\n", ++ OFFSET(rq_rt)); ++ fprintf(fp, " rq_nr_running: %ld\n", ++ OFFSET(rq_nr_running)); ++ fprintf(fp, " task_struct_se: %ld\n", ++ OFFSET(task_struct_se)); ++ fprintf(fp, " sched_entity_run_node: %ld\n", ++ OFFSET(sched_entity_run_node)); ++ fprintf(fp, " cfs_rq_nr_running: %ld\n", ++ OFFSET(cfs_rq_nr_running)); ++ fprintf(fp, " cfs_rq_rb_leftmost: %ld\n", ++ OFFSET(cfs_rq_rb_leftmost)); ++ fprintf(fp, " cfs_rq_tasks_timeline: %ld\n", ++ OFFSET(cfs_rq_tasks_timeline)); ++ fprintf(fp, " rt_rq_active: %ld\n", ++ OFFSET(rt_rq_active)); fprintf(fp, "\n size_table:\n"); fprintf(fp, " page: %ld\n", SIZE(page)); -@@ -6512,6 +6573,7 @@ +@@ -6512,6 +6823,7 @@ fprintf(fp, " fs_struct: %ld\n", SIZE(fs_struct)); fprintf(fp, " files_struct: %ld\n", SIZE(files_struct)); @@ -18416,15 +31718,19 @@ fprintf(fp, " file: %ld\n", SIZE(file)); fprintf(fp, " inode: %ld\n", SIZE(inode)); fprintf(fp, " vfsmount: %ld\n", SIZE(vfsmount)); -@@ -6546,6 +6608,7 @@ +@@ -6546,8 +6858,11 @@ fprintf(fp, " sock: %ld\n", SIZE(sock)); fprintf(fp, " inet_sock: %ld\n", SIZE(inet_sock)); fprintf(fp, " socket: %ld\n", SIZE(socket)); + fprintf(fp, " in6_addr: %ld\n", SIZE(in6_addr)); fprintf(fp, " signal_struct: %ld\n", SIZE(signal_struct)); ++ fprintf(fp, " sigpending_signal: %ld\n", ++ SIZE(sigpending_signal)); fprintf(fp, " signal_queue: %ld\n", -@@ -6601,6 +6664,8 @@ + SIZE(signal_queue)); + fprintf(fp, " sigqueue: %ld\n", SIZE(sigqueue)); +@@ -6601,6 +6916,8 @@ fprintf(fp, " x8664_pda: %ld\n", SIZE(x8664_pda)); @@ -18433,7 +31739,7 @@ fprintf(fp, " gate_struct: %ld\n", SIZE(gate_struct)); fprintf(fp, " tss_struct: %ld\n", -@@ -6609,7 +6674,10 @@ +@@ -6609,7 +6926,14 @@ SIZE(task_struct_start_time)); fprintf(fp, " cputime_t: %ld\n", SIZE(cputime_t)); @@ -18442,10 +31748,229 @@ + SIZE(mem_section)); + fprintf(fp, " pid_link: %ld\n", + SIZE(pid_link)); ++ fprintf(fp, " unwind_table: %ld\n", ++ SIZE(unwind_table)); ++ fprintf(fp, " rlimit: %ld\n", ++ SIZE(rlimit)); fprintf(fp, "\n array_table:\n"); /* -@@ -7261,7 +7329,9 @@ +@@ -6663,6 +6987,8 @@ + get_array_length("prio_array.queue", NULL, SIZE(list_head))); + fprintf(fp, " height_to_maxindex: %d\n", + ARRAY_LENGTH(height_to_maxindex)); ++ fprintf(fp, " pid_hash: %d\n", ++ ARRAY_LENGTH(pid_hash)); + + if (spec) { + int in_size_table, in_array_table, arrays, offsets, sizes; +@@ -6890,6 +7216,10 @@ + SEC_HAS_CONTENTS)) + st->flags |= NO_SEC_CONTENTS; + } ++ if (STREQ(bfd_get_section_name(bfd, section), ".eh_frame")) { ++ st->dwarf_eh_frame_file_offset = (off_t)section->filepos; ++ st->dwarf_eh_frame_size = (ulong)bfd_section_size(bfd, section); ++ } + break; + + case (uint)MODULE_SECTIONS: +@@ -6906,6 +7236,10 @@ + SEC_HAS_CONTENTS)) + st->flags |= NO_SEC_CONTENTS; + } ++ if (STREQ(bfd_get_section_name(bfd, section), ".eh_frame")) { ++ st->dwarf_eh_frame_file_offset = (off_t)section->filepos; ++ st->dwarf_eh_frame_size = (ulong)bfd_section_size(bfd, section); ++ } + break; + + default: +@@ -6960,8 +7294,9 @@ + i = lm->mod_sections; + lm->mod_section_data[i].section = section; + lm->mod_section_data[i].priority = prio; +- lm->mod_section_data[i].flags = section->flags; ++ lm->mod_section_data[i].flags = section->flags & ~SEC_FOUND; + lm->mod_section_data[i].size = bfd_section_size(bfd, section); ++ lm->mod_section_data[i].offset = 0; + if (strlen(name) < MAX_MOD_SEC_NAME) + strcpy(lm->mod_section_data[i].name, name); + else +@@ -7013,7 +7348,7 @@ + */ + + static void +-calculate_load_order(struct load_module *lm, bfd *bfd) ++calculate_load_order_v1(struct load_module *lm, bfd *bfd) + { + int i; + asection *section; +@@ -7073,6 +7408,131 @@ + } + + /* ++ * Later versions of kmod no longer get the help from insmod, ++ * and while the heuristics might work, it's relatively ++ * straightforward to just try to match the sections in the object file ++ * with exported symbols. ++ * ++ * This works well if kallsyms is set, but may not work so well in other ++ * instances. ++ */ ++static void ++calculate_load_order_v2(struct load_module *lm, bfd *bfd, int dynamic, ++ void *minisyms, long symcount, unsigned int size) ++{ ++ struct syment *s1, *s2; ++ ulong sec_start, sec_end; ++ bfd_byte *from, *fromend; ++ asymbol *store; ++ asymbol *sym; ++ symbol_info syminfo; ++ char *secname; ++ int i; ++ ++ s1 = lm->mod_symtable; ++ s2 = lm->mod_symend; ++ while (s1 < s2) { ++ ulong sym_offset = s1->value - lm->mod_base; ++ if (MODULE_PSEUDO_SYMBOL(s1)) { ++ s1++; ++ continue; ++ } ++ ++ /* Skip over symbols whose sections have been identified. */ ++ for (i = 0; i < lm->mod_sections; i++) { ++ if ((lm->mod_section_data[i].flags & SEC_FOUND) == 0) ++ continue; ++ if (sym_offset >= lm->mod_section_data[i].offset ++ && sym_offset < lm->mod_section_data[i].offset ++ + lm->mod_section_data[i].size) { ++ break; ++ } ++ } ++ ++ /* Matched one of the sections. Skip symbol. */ ++ if (i < lm->mod_sections) { ++ if (CRASHDEBUG(2)) { ++ fprintf(fp, "skip %lx %s %s\n", s1->value, s1->name, ++ lm->mod_section_data[i].name); ++ } ++ s1++; ++ continue; ++ } ++ ++ /* Find the symbol in the object file. */ ++ from = (bfd_byte *) minisyms; ++ fromend = from + symcount * size; ++ secname = NULL; ++ for (; from < fromend; from += size) { ++ if ((sym = bfd_minisymbol_to_symbol(bfd, dynamic, from, ++ store)) == NULL) ++ error(FATAL, ++ "bfd_minisymbol_to_symbol() failed\n"); ++ ++ bfd_get_symbol_info(bfd, sym, &syminfo); ++ if (CRASHDEBUG(3)) { ++ fprintf(fp,"matching sym %s %lx against bfd %s %lx\n", ++ s1->name, (long) s1->value, syminfo.name, ++ (long) syminfo.value); ++ } ++ if (strcmp(syminfo.name, s1->name) == 0) { ++ secname = (char *)bfd_get_section_name(bfd, sym->section); ++ break; ++ } ++ ++ } ++ if (secname == NULL) { ++ if (CRASHDEBUG(1)) { ++ fprintf(fp, "symbol %s not found in module\n", s1->name); ++ } ++ s1++; ++ continue; ++ } ++ ++ /* Match the section it came in. */ ++ for (i = 0; i < lm->mod_sections; i++) { ++ if (STREQ(lm->mod_section_data[i].name, secname)) { ++ break; ++ } ++ } ++ ++ if (i == lm->mod_sections) { ++ fprintf(fp, "?? Section %s not found for symbol %s\n", ++ secname, s1->name); ++ s1++; ++ continue; ++ } ++ ++ /* Update the offset information for the section */ ++ sec_start = s1->value - syminfo.value; ++ sec_end = sec_start + lm->mod_section_data[i].size; ++ lm->mod_section_data[i].offset = sec_start - lm->mod_base; ++ lm->mod_section_data[i].flags |= SEC_FOUND; ++ ++ if (CRASHDEBUG(1)) { ++ fprintf(fp, "update sec offset sym %s @ %lx val %lx section %s\n", ++ s1->name, s1->value, syminfo.value, secname); ++ } ++ ++ if (strcmp(secname, ".text") == 0) ++ lm->mod_text_start = sec_start; ++ ++ if (strcmp(secname, ".bss") == 0) ++ lm->mod_bss_start = sec_start; ++ ++ if (strcmp(secname, ".data") == 0) ++ lm->mod_data_start = sec_start; ++ ++ if (strcmp(secname, ".data") == 0) ++ lm->mod_data_start = sec_start; ++ ++ if (strcmp(secname, ".rodata") == 0) ++ lm->mod_rodata_start = sec_start; ++ s1++; ++ } ++} ++ ++/* + * Later versons of insmod store basic address information of each + * module in a format that looks like the following example of the + * nfsd module: +@@ -7185,8 +7645,8 @@ + } + + if (CRASHDEBUG(1)) +- fprintf(fp, "load_module_symbols: %s %s %lx\n", +- modref, namelist, base_addr); ++ fprintf(fp, "load_module_symbols: %s %s %lx %lx\n", ++ modref, namelist, base_addr, kt->flags); + + switch (kt->flags & (KMOD_V1|KMOD_V2)) + { +@@ -7199,7 +7659,8 @@ + strcpy(lm->mod_namelist, namelist); + else + strncpy(lm->mod_namelist, namelist, MAX_MOD_NAMELIST-1); +- goto add_symbols; ++ if (st->flags & USE_OLD_ADD_SYM) ++ goto add_symbols; + } + + if ((mbfd = bfd_openr(namelist, NULL)) == NULL) +@@ -7219,6 +7680,10 @@ + else if (symcount == 0) + error(FATAL, "no symbols in object file: %s\n", namelist); + ++ if (CRASHDEBUG(1)) { ++ fprintf(fp, "%ld symbols found in obj file %s\n", symcount, ++ namelist); ++ } + sort_x = bfd_make_empty_symbol(mbfd); + sort_y = bfd_make_empty_symbol(mbfd); + if (sort_x == NULL || sort_y == NULL) +@@ -7261,7 +7726,9 @@ if (!CRASHDEBUG(1)) req->fp = pc->nullfp; @@ -18455,14 +31980,278 @@ sprintf(buf, "set complaints 0"); gdb_pass_through(buf, NULL, 0); ---- crash/cmdline.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/cmdline.c 2006-08-21 12:06:39.000000000 -0400 -@@ -71,14 +71,17 @@ +@@ -7382,7 +7849,12 @@ + + bfd_map_over_sections(bfd, section_header_info, MODULE_SECTIONS); + +- calculate_load_order(lm, bfd); ++ if (kt->flags & KMOD_V1) ++ calculate_load_order_v1(lm, bfd); ++ else ++ calculate_load_order_v2(lm, bfd, dynamic, minisyms, ++ symcount, size); ++ + + from = (bfd_byte *) minisyms; + fromend = from + symcount * size; +@@ -7395,104 +7867,112 @@ + bfd_get_symbol_info(bfd, sym, &syminfo); + + secname = (char *)bfd_get_section_name(bfd, sym->section); ++ found = 0; + +- switch (syminfo.type) +- { +- case 'b': +- case 'B': +- if (CRASHDEBUG(2)) +- fprintf(fp, "%08lx (%c) [%s] %s\n", +- (ulong)syminfo.value, +- syminfo.type, secname, syminfo.name); ++ if (kt->flags & KMOD_V1) { ++ switch (syminfo.type) ++ { ++ case 'b': ++ case 'B': ++ if (CRASHDEBUG(2)) ++ fprintf(fp, "%08lx (%c) [%s] %s\n", ++ (ulong)syminfo.value, ++ syminfo.type, secname, syminfo.name); + +- syminfo.value += lm->mod_bss_start; +- strcpy(name, syminfo.name); +- strip_module_symbol_end(name); ++ if (!lm->mod_bss_start) ++ break; + +- if (machdep->verify_symbol(name, syminfo.value, +- syminfo.type)) { +- sp->value = syminfo.value; +- sp->type = syminfo.type; +- +- namespace_ctl(NAMESPACE_INSTALL, +- &lm->mod_load_namespace, sp, name); ++ syminfo.value += lm->mod_bss_start; ++ found = 1; ++ break; + +- if (CRASHDEBUG(1)) +- fprintf(fp, "%08lx %s\n", sp->value, +- name); ++ case 'd': ++ case 'D': ++ if (CRASHDEBUG(2)) ++ fprintf(fp, "%08lx (%c) [%s] %s\n", ++ (ulong)syminfo.value, ++ syminfo.type, secname, syminfo.name); ++ ++ if (STREQ(secname, ".rodata")) { ++ if (!lm->mod_rodata_start) ++ break; ++ syminfo.value += lm->mod_rodata_start; ++ } else { ++ if (!lm->mod_data_start) ++ break; ++ syminfo.value += lm->mod_data_start; ++ } ++ found = 1; ++ break; + +- sp++; +- lm->mod_load_symcnt++; +- } +- break; ++ case 't': ++ case 'T': ++ if (CRASHDEBUG(2)) ++ fprintf(fp, "%08lx (%c) [%s] %s\n", ++ (ulong)syminfo.value, ++ syminfo.type, secname, syminfo.name); + +- case 'd': +- case 'D': +- if (CRASHDEBUG(2)) +- fprintf(fp, "%08lx (%c) [%s] %s\n", +- (ulong)syminfo.value, +- syminfo.type, secname, syminfo.name); ++ if (! lm->mod_text_start) { ++ break; ++ } + +- if (STREQ(secname, ".rodata")) +- syminfo.value += lm->mod_rodata_start; +- else +- syminfo.value += lm->mod_data_start; ++ if ((st->flags & INSMOD_BUILTIN) && ++ (STREQ(name, "init_module") || ++ STREQ(name, "cleanup_module"))) ++ break; + ++ syminfo.value += lm->mod_text_start; ++ found = 1; ++ break; ++ ++ default: ++ break; ++ } ++ ++ } else { ++ /* Match the section it came in. */ ++ for (i = 0; i < lm->mod_sections; i++) { ++ if (STREQ(lm->mod_section_data[i].name, secname) ++ && (lm->mod_section_data[i].flags & SEC_FOUND)) { ++ break; ++ } ++ } ++ if (i < lm->mod_sections) { ++ if (CRASHDEBUG(2)) ++ fprintf(fp, "%08lx (%c) [%s] %s\n", ++ (ulong)syminfo.value, ++ syminfo.type, secname, syminfo.name); ++ ++ if ((st->flags & INSMOD_BUILTIN) && ++ (STREQ(name, "init_module") || ++ STREQ(name, "cleanup_module"))) { ++ found = 0; ++ } else { ++ syminfo.value += lm->mod_section_data[i].offset + lm->mod_base; ++ found = 1; ++ } ++ } ++ } ++ ++ if (found) { + strcpy(name, syminfo.name); + strip_module_symbol_end(name); + +- if (machdep->verify_symbol(name, syminfo.value, +- syminfo.type)) { ++ if (machdep->verify_symbol(name, syminfo.value, ++ syminfo.type)) { + sp->value = syminfo.value; +- sp->type = syminfo.type; ++ sp->type = syminfo.type; + namespace_ctl(NAMESPACE_INSTALL, +- &lm->mod_load_namespace, sp, name); ++ &lm->mod_load_namespace, sp, name); + + if (CRASHDEBUG(1)) +- fprintf(fp, "%08lx %s\n", sp->value, ++ fprintf(fp, "installing %c %08lx %s\n", syminfo.type, sp->value, + name); + + sp++; + lm->mod_load_symcnt++; + } +- break; +- +- case 't': +- case 'T': +- if (CRASHDEBUG(2)) +- fprintf(fp, "%08lx (%c) [%s] %s\n", +- (ulong)syminfo.value, +- syminfo.type, secname, syminfo.name); +- +- syminfo.value += lm->mod_text_start; +- strcpy(name, syminfo.name); +- strip_module_symbol_end(name); +- +- if ((st->flags & INSMOD_BUILTIN) && +- (STREQ(name, "init_module") || +- STREQ(name, "cleanup_module"))) +- break; +- +- if (machdep->verify_symbol(name, syminfo.value, +- syminfo.type)) { +- sp->value = syminfo.value; +- sp->type = syminfo.type; +- namespace_ctl(NAMESPACE_INSTALL, +- &lm->mod_load_namespace, sp, name); +- +- if (CRASHDEBUG(1)) +- fprintf(fp, "%08lx %s\n", sp->value, +- name); +- +- sp++; +- lm->mod_load_symcnt++; +- } +- +- break; +- +- default: +- break; +- } ++ } + } + + lm->mod_load_symend = &lm->mod_load_symtable[lm->mod_load_symcnt]; +@@ -7713,7 +8193,7 @@ + ulong start, end; + char *modbuf; + ulong maxchunk, alloc; +- long offset; ++ long offset = 0; + + start = roundup(lm->mod_size_of_struct, sizeof(long)) + lm->mod_base; + end = lm->mod_base + lm->mod_size; +@@ -8089,6 +8569,10 @@ + struct syment *sp_array[200], *sp; + + if (req->name == PATCH_KERNEL_SYMBOLS_START) { ++ if (kt->flags & RELOC_FORCE) ++ error(WARNING, ++ "\nkernel relocated [%ldMB]: patching %ld gdb minimal_symbol values\n", ++ kt->relocate >> 20, st->symcnt); + fprintf(fp, (pc->flags & SILENT) || !(pc->flags & TTY) ? "" : + "\nplease wait... (patching %ld gdb minimal_symbol values) ", + st->symcnt); +--- crash/cmdline.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/cmdline.c 2007-07-18 14:41:55.000000000 -0400 +@@ -1,8 +1,8 @@ + /* cmdline.c - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 +@@ -70,15 +70,45 @@ + * program invocation. * 4. from a terminal. * 5. from a pipe, if stdin is a pipe rather than a terminal. ++ * ++ * But first, handle the interruption of an input file caused ++ * by a FATAL error in one of its commands. ++ * */ - if (pc->flags & RCHOME_IFILE) -+ if (pc->flags & RCHOME_IFILE) { ++ if (pc->ifile_in_progress) { ++ switch (pc->ifile_in_progress) ++ { ++ case RCHOME_IFILE: ++ pc->flags |= INIT_IFILE|RCHOME_IFILE; ++ sprintf(pc->command_line, "< %s/.%src", ++ pc->home, pc->program_name); ++ break; ++ case RCLOCAL_IFILE: ++ sprintf(pc->command_line, "< .%src", pc->program_name); ++ pc->flags |= INIT_IFILE|RCLOCAL_IFILE; ++ break; ++ case CMDLINE_IFILE: ++ sprintf(pc->command_line, "< %s", pc->input_file); ++ pc->flags |= INIT_IFILE|CMDLINE_IFILE; ++ break; ++ case RUNTIME_IFILE: ++ sprintf(pc->command_line, "%s", pc->runtime_ifile_cmd); ++ pc->flags |= IFILE_ERROR; ++ break; ++ default: ++ error(FATAL, "invalid input file\n"); ++ } ++ } else if (pc->flags & RCHOME_IFILE) { sprintf(pc->command_line, "< %s/.%src", pc->home, pc->program_name); - else if (pc->flags & RCLOCAL_IFILE) @@ -18479,23 +32268,300 @@ if (!(pc->readline = readline(pc->prompt))) { args[0] = NULL; fprintf(fp, "\n"); -@@ -918,13 +921,14 @@ +@@ -276,6 +306,106 @@ + } + + /* ++ * Pager arguments. ++ */ ++ ++static char *less_argv[5] = { ++ "/usr/bin/less", ++ "-E", ++ "-X", ++ "-Ps -- MORE -- forward\\: , or j backward\\: b or k quit\\: q", ++ NULL ++}; ++ ++static char *more_argv[2] = { ++ "/bin/more", ++ NULL ++}; ++ ++static char **CRASHPAGER_argv = NULL; ++ ++int ++CRASHPAGER_valid(void) ++{ ++ int i, c; ++ char *env, *CRASHPAGER_buf; ++ char *arglist[MAXARGS]; ++ ++ if (CRASHPAGER_argv) ++ return TRUE; ++ ++ if (!(env = getenv("CRASHPAGER"))) ++ return FALSE; ++ ++ if (strstr(env, "|") || strstr(env, "<") || strstr(env, ">")) { ++ error(INFO, ++ "CRASHPAGER ignored: contains invalid character: \"%s\"\n", ++ env); ++ return FALSE; ++ } ++ ++ if ((CRASHPAGER_buf = (char *)malloc(strlen(env)+1)) == NULL) ++ return FALSE; ++ ++ strcpy(CRASHPAGER_buf, env); ++ ++ if (!(c = parse_line(CRASHPAGER_buf, arglist)) || ++ !file_exists(arglist[0], NULL) || access(arglist[0], X_OK) || ++ !(CRASHPAGER_argv = (char **)malloc(sizeof(char *) * (c+1)))) { ++ free(CRASHPAGER_buf); ++ if (strlen(env)) ++ error(INFO, ++ "CRASHPAGER ignored: \"%s\"\n", env); ++ return FALSE; ++ } ++ ++ for (i = 0; i < c; i++) ++ CRASHPAGER_argv[i] = arglist[i]; ++ CRASHPAGER_argv[i] = NULL; ++ ++ return TRUE; ++} ++ ++/* ++ * Set up a command string buffer for error/help output. ++ */ ++char * ++setup_scroll_command(void) ++{ ++ char *buf; ++ long i, len; ++ ++ if (!(pc->flags & SCROLL)) ++ return NULL; ++ ++ switch (pc->scroll_command) ++ { ++ case SCROLL_LESS: ++ buf = GETBUF(strlen(less_argv[0])+1); ++ strcpy(buf, less_argv[0]); ++ break; ++ case SCROLL_MORE: ++ buf = GETBUF(strlen(more_argv[0])+1); ++ strcpy(buf, more_argv[0]); ++ break; ++ case SCROLL_CRASHPAGER: ++ for (i = len = 0; CRASHPAGER_argv[i]; i++) ++ len += strlen(CRASHPAGER_argv[i])+1; ++ ++ buf = GETBUF(len); ++ ++ for (i = 0; CRASHPAGER_argv[i]; i++) { ++ sprintf(&buf[strlen(buf)], "%s%s", ++ i ? " " : "", ++ CRASHPAGER_argv[i]); ++ } ++ break; ++ } ++ ++ return buf; ++} ++ ++/* + * Parse the command line for pipe or redirect characters: + * + * 1. if a "|" character is found, popen() what comes after it, and +@@ -415,6 +545,9 @@ + return REDIRECT_FAILURE; + } + ++ if (pc->flags & IFILE_ERROR) ++ append = TRUE; ++ + if ((ofile = + fopen(p, append ? "a+" : "w+")) == NULL) { + error(INFO, "unable to open %s\n", p); +@@ -464,10 +597,13 @@ + switch (pc->scroll_command) + { + case SCROLL_LESS: +- strcpy(pc->pipe_command, "/usr/bin/less"); ++ strcpy(pc->pipe_command, less_argv[0]); + break; + case SCROLL_MORE: +- strcpy(pc->pipe_command, "/bin/more"); ++ strcpy(pc->pipe_command, more_argv[0]); ++ break; ++ case SCROLL_CRASHPAGER: ++ strcpy(pc->pipe_command, CRASHPAGER_argv[0]); + break; + } + +@@ -839,13 +975,15 @@ + restore_sanity(void) + { + int fd, waitstatus; ++ struct extension_table *ext; ++ struct command_table_entry *cp; + + if (pc->stdpipe) { + close(fileno(pc->stdpipe)); + pc->stdpipe = NULL; + if (pc->stdpipe_pid && PID_ALIVE(pc->stdpipe_pid)) { + while (!waitpid(pc->stdpipe_pid, &waitstatus, WNOHANG)) +- ; ++ stall(1000); + } + pc->stdpipe_pid = 0; + } +@@ -855,12 +993,16 @@ + console("wait for redirect %d->%d to finish...\n", + pc->pipe_shell_pid, pc->pipe_pid); + if (pc->pipe_pid) +- while (PID_ALIVE(pc->pipe_pid)) ++ while (PID_ALIVE(pc->pipe_pid)) { + waitpid(pc->pipe_pid, &waitstatus, WNOHANG); ++ stall(1000); ++ } + if (pc->pipe_shell_pid) +- while (PID_ALIVE(pc->pipe_shell_pid)) ++ while (PID_ALIVE(pc->pipe_shell_pid)) { + waitpid(pc->pipe_shell_pid, + &waitstatus, WNOHANG); ++ stall(1000); ++ } + pc->pipe_pid = 0; + } + if (pc->ifile_pipe) { +@@ -872,12 +1014,16 @@ + (FROM_INPUT_FILE|REDIRECT_TO_PIPE|REDIRECT_PID_KNOWN))) { + console("wait for redirect %d->%d to finish...\n", + pc->pipe_shell_pid, pc->pipe_pid); +- while (PID_ALIVE(pc->pipe_pid)) ++ while (PID_ALIVE(pc->pipe_pid)) { + waitpid(pc->pipe_pid, &waitstatus, WNOHANG); ++ stall(1000); ++ } + if (pc->pipe_shell_pid) +- while (PID_ALIVE(pc->pipe_shell_pid)) ++ while (PID_ALIVE(pc->pipe_shell_pid)) { + waitpid(pc->pipe_shell_pid, + &waitstatus, WNOHANG); ++ stall(1000); ++ } + if (pc->redirect & (REDIRECT_MULTI_PIPE)) + wait_for_children(ALL_CHILDREN); + } +@@ -918,13 +1064,20 @@ wait_for_children(ZOMBIES_ONLY); - pc->flags &= ~(RUNTIME_IFILE|_SIGINT_); -+ pc->flags &= ~(INIT_IFILE|RUNTIME_IFILE|_SIGINT_); ++ pc->flags &= ~(INIT_IFILE|RUNTIME_IFILE|IFILE_ERROR|_SIGINT_|PLEASE_WAIT); pc->sigint_cnt = 0; pc->redirect = 0; pc->pipe_command[0] = NULLCHAR; pc->pipe_pid = 0; pc->pipe_shell_pid = 0; pc->sbrk = sbrk(0); ++ if ((pc->curcmd_flags & (UD2A_INSTRUCTION|BAD_INSTRUCTION)) == ++ (UD2A_INSTRUCTION|BAD_INSTRUCTION)) ++ error(WARNING, "A (bad) instruction was noted in last disassembly.\n" ++ " Use \"dis -b [number]\" to set/restore the number of\n" ++ " encoded bytes to skip after a ud2a (BUG) instruction.\n"); + pc->curcmd_flags = 0; ++ pc->curcmd_private = 0; restore_gdb_sanity(); -@@ -1706,15 +1710,20 @@ +@@ -942,6 +1095,16 @@ + clear_vma_cache(); + clear_active_set(); + ++ /* ++ * Call the cleanup() function of any extension. ++ */ ++ for (ext = extension_table; ext; ext = ext->next) { ++ for (cp = ext->command_table; cp->name; cp++) { ++ if (cp->flags & CLEANUP) ++ (*cp->func)(); ++ } ++ } ++ + if (CRASHDEBUG(4)) { + dump_filesys_table(0); + dump_vma_cache(0); +@@ -961,6 +1124,8 @@ + { + int fd; + ++ pc->flags &= ~IFILE_ERROR; ++ + if (pc->ifile_pipe) { + close(fileno(pc->ifile_pipe)); + pc->ifile_pipe = NULL; +@@ -1076,7 +1241,6 @@ + } else + this = 0; + +- + if (pc->flags & RUNTIME_IFILE) { + error(INFO, "embedded input files not allowed!\n"); + return; +@@ -1111,6 +1275,28 @@ + pc->flags |= RUNTIME_IFILE; + incoming_fp = fp; + ++ /* ++ * Handle runtime commands that use input files. ++ */ ++ if ((pc->ifile_in_progress = this) == 0) { ++ if (!pc->runtime_ifile_cmd) { ++ if (!(pc->runtime_ifile_cmd = (char *)malloc(BUFSIZE))) { ++ error(INFO, ++ "cannot malloc input file command line buffer\n"); ++ return; ++ } ++ } ++ strcpy(pc->runtime_ifile_cmd, pc->orig_line); ++ pc->ifile_in_progress = RUNTIME_IFILE; ++ } ++ ++ /* ++ * If there's an offset, then there was a FATAL error caused ++ * by the last command executed from the input file. ++ */ ++ if (pc->ifile_offset) ++ fseek(pc->ifile, (long)pc->ifile_offset, SEEK_SET); ++ + while (fgets(buf, BUFSIZE-1, pc->ifile)) { + /* + * Restore normal environment. +@@ -1120,6 +1306,8 @@ + BZERO(pc->command_line, BUFSIZE); + BZERO(pc->orig_line, BUFSIZE); + ++ pc->ifile_offset = ftell(pc->ifile); ++ + if (STRNEQ(buf, "#") || STREQ(buf, "\n")) + continue; + +@@ -1168,6 +1356,10 @@ + fclose(pc->ifile); + pc->ifile = NULL; + pc->flags &= ~RUNTIME_IFILE; ++ pc->ifile_offset = 0; ++ if (pc->runtime_ifile_cmd) ++ BZERO(pc->runtime_ifile_cmd, BUFSIZE); ++ pc->ifile_in_progress = 0; + } + + /* +@@ -1706,15 +1898,20 @@ error(FATAL, "scrolling must be turned off when repeating an input file\n"); @@ -18517,8 +32583,75 @@ if (delay) sleep(delay); ---- crash/lkcd_common.c.orig 2006-09-13 11:10:22.000000000 -0400 -+++ crash/lkcd_common.c 2006-06-15 10:36:08.000000000 -0400 +@@ -1829,19 +2026,6 @@ + * Set up the standard output pipe using whichever was selected during init. + */ + +-static char *less_argv[5] = { +- "/usr/bin/less", +- "-E", +- "-X", +- "-Ps -- MORE -- forward\\: , or j backward\\: b or k quit\\: q", +- NULL +-}; +- +-static char *more_argv[2] = { +- "/bin/more", +- NULL +-}; +- + static int + setup_stdpipe(void) + { +@@ -1877,6 +2061,9 @@ + case SCROLL_MORE: + strcpy(pc->pipe_command, more_argv[0]); + break; ++ case SCROLL_CRASHPAGER: ++ strcpy(pc->pipe_command, CRASHPAGER_argv[0]); ++ break; + } + + if (CRASHDEBUG(2)) +@@ -1905,10 +2092,16 @@ + path = more_argv[0]; + execv(path, more_argv); + break; ++ ++ case SCROLL_CRASHPAGER: ++ path = CRASHPAGER_argv[0]; ++ execv(path, CRASHPAGER_argv); ++ break; + } + +- perror("child execv failed"); +- return(clean_exit(1)); ++ perror(path); ++ fprintf(stderr, "execv of scroll command failed\n"); ++ exit(1); + } + } + +@@ -1939,5 +2132,6 @@ + fprintf(fp, "wait_for_children: reaped %d\n", pid); + break; + } ++ stall(1000); + } + } +--- crash/lkcd_common.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/lkcd_common.c 2007-01-17 10:14:26.000000000 -0500 +@@ -3,8 +3,8 @@ + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. + * Copyright (C) 2002 Silicon Graphics, Inc. + * Copyright (C) 2002 Free Software Foundation, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2007 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 @@ -53,6 +53,8 @@ struct lkcd_environment lkcd_environment = { 0 }; @@ -18536,7 +32669,18 @@ lkcd->version = LKCD_DUMP_V8; return TRUE; -@@ -667,6 +670,8 @@ +@@ -623,6 +626,10 @@ + { + static int i = 0; + ++ if (pc->flags & SILENT) { ++ return; ++ } ++ + switch (++i%4) { + case 0: + lkcd_print("|\b"); +@@ -667,6 +674,8 @@ { uint64_t zone, page; int ii, ret; @@ -18545,7 +32689,7 @@ zone = paddr & lkcd->zone_mask; -@@ -693,6 +698,7 @@ +@@ -693,6 +702,7 @@ lkcd->num_zones++; } @@ -18553,7 +32697,7 @@ /* find the zone */ for (ii=0; ii < lkcd->num_zones; ii++) { if (lkcd->zones[ii].start == zone) { -@@ -734,8 +740,20 @@ +@@ -734,8 +744,20 @@ ret = 1; lkcd->num_zones++; } else { @@ -18576,7 +32720,25 @@ } } -@@ -1164,40 +1182,103 @@ +@@ -769,7 +791,7 @@ + int + lkcd_lseek(physaddr_t paddr) + { +- long i; ++ long i = 0; + int err; + int eof; + void *dp; +@@ -814,7 +836,7 @@ + lseek(lkcd->fd, lkcd->page_offset_max, SEEK_SET); + eof = FALSE; + while (!eof) { +- if( (i%2048) == 0) { ++ if( (i++%2048) == 0) { + lkcd_speedo(); + } + +@@ -1164,40 +1186,103 @@ return 1; } @@ -18686,7 +32848,7 @@ } -@@ -1252,8 +1333,9 @@ +@@ -1252,8 +1337,9 @@ dp_flags = lkcd->get_dp_flags(); dp_address = lkcd->get_dp_address(); @@ -18697,7 +32859,7 @@ if ((lkcd->flags & LKCD_VALID) && (page > lkcd->total_pages)) lkcd->total_pages = page; ---- crash/lkcd_v7.c.orig 2006-09-13 11:10:22.000000000 -0400 +--- crash/lkcd_v7.c.orig 2007-08-27 15:02:36.000000000 -0400 +++ crash/lkcd_v7.c 2005-11-10 15:25:45.000000000 -0500 @@ -89,7 +89,11 @@ ifd = 0; @@ -18712,7 +32874,7 @@ dump_index_size = (lkcd->memory_pages * sizeof(off_t)); lkcd->page_offsets = 0; strcpy(dumpfile_index_name, dumpfile); ---- crash/lkcd_v8.c.orig 2006-09-13 11:10:22.000000000 -0400 +--- crash/lkcd_v8.c.orig 2007-08-27 15:02:36.000000000 -0400 +++ crash/lkcd_v8.c 2005-12-15 15:19:21.000000000 -0500 @@ -26,6 +26,7 @@ // static dump_header_asm_t dump_header_asm_v8 = { 0 }; @@ -18773,8 +32935,19 @@ set_mb_benchmark((granularity * (i+1))/lkcd->page_size); } } ---- crash/s390_dump.c.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/s390_dump.c 2006-05-15 17:21:03.000000000 -0400 +--- crash/s390_dump.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/s390_dump.c 2006-10-11 09:14:35.000000000 -0400 +@@ -1,8 +1,8 @@ + /* s390_dump.c - core analysis suite + * + * Copyright (C) 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2005 Michael Holzheu, IBM Corporation + * + * This program is free software; you can redistribute it and/or modify @@ -16,7 +16,7 @@ * GNU General Public License for more details. */ @@ -18799,9 +32972,30 @@ } int ---- crash/lkcd_x86_trace.c.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/lkcd_x86_trace.c 2006-05-15 16:26:15.000000000 -0400 -@@ -47,11 +47,13 @@ +--- crash/lkcd_x86_trace.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/lkcd_x86_trace.c 2007-08-23 17:02:54.000000000 -0400 +@@ -5,8 +5,8 @@ + /* + * lkcd_x86_trace.c + * +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. + * + * Adapted as noted from the following LKCD files: + * +@@ -21,6 +21,9 @@ + + #include "lkcd_x86_trace.h" + ++#undef XEN_HYPER_MODE ++static int XEN_HYPER_MODE(void) { return (pc->flags & XEN_HYPER) != 0; } ++ + static void *kl_alloc_block(int, int); + static void kl_free_block(void *); + static void GET_BLOCK(kaddr_t, unsigned, void *); +@@ -47,11 +50,13 @@ static int setup_trace_rec(kaddr_t, kaddr_t, int, trace_t *); static int valid_ra(kaddr_t); static int valid_ra_function(kaddr_t, char *); @@ -18815,7 +33009,7 @@ static void print_eframe(FILE *, struct pt_regs *); static void trace_banner(FILE *); static void print_kaddr(kaddr_t, FILE *, int); -@@ -505,7 +507,7 @@ +@@ -505,7 +510,7 @@ { "receive_chars", NULL, COMPILER_VERSION_EQUAL, GCC(2,96,0), 0, 0, 48 }, { "default_idle", NULL, @@ -18824,7 +33018,7 @@ { NULL, NULL, 0, 0, 0, 0, 0 }, }; -@@ -1118,7 +1120,9 @@ +@@ -1118,7 +1123,9 @@ } #include @@ -18834,7 +33028,7 @@ #define KERNEL_EFRAME 0 #define USER_EFRAME 1 #define KERNEL_EFRAME_SZ 13 /* no ss and esp */ -@@ -1153,6 +1157,9 @@ +@@ -1153,6 +1160,9 @@ else if (((regs->xcs & 0xffff) == 0x60) && ((regs->xds & 0xffff) == 0x7b)) return KERNEL_EFRAME; @@ -18844,7 +33038,7 @@ #endif else if (((regs->xcs & 0xffff) == __USER_CS) && ((regs->xds & 0xffff) == __USER_DS)) -@@ -1206,6 +1213,93 @@ +@@ -1206,6 +1216,93 @@ } \ } #endif @@ -18938,7 +33132,7 @@ /* * find_trace() * -@@ -1253,6 +1347,7 @@ +@@ -1253,6 +1350,7 @@ int flag; int interrupted_system_call = FALSE; struct bt_info *bt = trace->bt; @@ -18946,7 +33140,35 @@ #endif sbp = trace->stack[curstkidx].ptr; sbase = trace->stack[curstkidx].addr; -@@ -1503,12 +1598,13 @@ +@@ -1322,7 +1420,17 @@ + } + } + asp = (uaddr_t*)((uaddr_t)sbp + (STACK_SIZE - (saddr - sp))); ++ + #ifdef REDHAT ++ if (XEN_HYPER_MODE()) { ++ func_name = kl_funcname(pc); ++ if (STREQ(func_name, "idle_loop") || STREQ(func_name, "hypercall") ++ || STREQ(func_name, "handle_exception")) { ++ UPDATE_FRAME(func_name, pc, 0, sp, bp, asp, 0, 0, bp - sp, 0); ++ return(trace->nframes); ++ } ++ } ++ + ra = GET_STACK_ULONG(bp + 4); + /* + * HACK: The get_framesize() function can return the proper +@@ -1447,7 +1555,8 @@ + bp = curframe->fp + frame_size; + } + #endif +- if ((func_name = kl_funcname(pc))) { ++ func_name = kl_funcname(pc); ++ if (func_name && !XEN_HYPER_MODE()) { + if (strstr(func_name, "kernel_thread")) { + ra = 0; + bp = saddr - 4; +@@ -1503,12 +1612,13 @@ return(trace->nframes); #ifdef REDHAT } else if (strstr(func_name, "error_code") @@ -18961,10 +33183,35 @@ bp = sp + (KERNEL_EFRAME_SZ-1)*4; asp = (uaddr_t*)((uaddr_t)sbp + (STACK_SIZE - -@@ -1572,6 +1668,22 @@ +@@ -1571,6 +1681,46 @@ + } } } - ++ if (func_name && XEN_HYPER_MODE()) { ++ if (STREQ(func_name, "continue_nmi") || ++ STREQ(func_name, "vmx_asm_vmexit_handler") || ++ STREQ(func_name, "deferred_nmi")) { ++ /* Interrupt frame */ ++ sp = curframe->fp + 4; ++ asp = (uaddr_t*)((uaddr_t)sbp + (STACK_SIZE - ++ (saddr - sp))); ++ bp = curframe->fp + (12 * 4); ++ curframe = alloc_sframe(trace, flags); ++ ra = *(asp + 9); ++ UPDATE_FRAME(func_name, pc, ra, sp, bp + 4, asp, ++ 0, 0, curframe->fp - curframe->sp+4, 12 * 4); ++ ++ /* contunue next frame */ ++ pc = ra; ++ sp = curframe->fp + 4; ++ bp = sp + get_framesize(pc, bt); ++ func_name = kl_funcname(pc); ++ if (!func_name) ++ return trace->nframes; ++ continue; ++ } ++ } ++ + /* + * Check for hypervisor_callback from user-space. + */ @@ -18980,11 +33227,10 @@ + return(trace->nframes); + } + } -+ + /* Make sure our next frame pointer is valid (in the stack). */ - if ((bp < sbase) || (bp >= saddr)) { -@@ -1684,8 +1796,15 @@ +@@ -1684,8 +1834,15 @@ (bt->flags & (BT_HARDIRQ|BT_SOFTIRQ))) return; @@ -19002,7 +33248,7 @@ frmp->level + 1 : frmp->level, fp ? (ulong)fp : trace->bt->stkptr, (ulong)frmp->pc, frmp->funcname, frmp, ofp); -@@ -1708,6 +1827,10 @@ +@@ -1708,6 +1865,10 @@ #endif if (frmp->flag & EX_FRAME) { pt = (struct pt_regs *)frmp->asp; @@ -19013,11 +33259,11 @@ print_eframe(ofp, pt); } #ifdef REDHAT -@@ -1789,6 +1912,114 @@ +@@ -1789,6 +1950,114 @@ if (kt->flags & RA_SEEK) bt->flags |= BT_SPECULATE; -+ if (XENDUMP_DUMPFILE() && is_task_active(bt->task) && ++ if (XENDUMP_DUMPFILE() && XEN() && is_task_active(bt->task) && + STREQ(kl_funcname(bt->instptr), "stop_this_cpu")) { + /* + * bt->instptr of "stop_this_cpu" is not a return @@ -19033,7 +33279,7 @@ + kl_funcname(bt->instptr)); + } + -+ if (XENDUMP_DUMPFILE() && is_idle_thread(bt->task) && ++ if (XENDUMP_DUMPFILE() && XEN() && is_idle_thread(bt->task) && + is_task_active(bt->task) && + !(kt->xen_flags & XEN_SUSPEND) && + STREQ(kl_funcname(bt->instptr), "schedule")) { @@ -19061,7 +33307,7 @@ + } + } + -+ if (XENDUMP_DUMPFILE() && is_idle_thread(bt->task) && ++ if (XENDUMP_DUMPFILE() && XEN() && is_idle_thread(bt->task) && + is_task_active(bt->task) && + (kt->xen_flags & XEN_SUSPEND) && + STREQ(kl_funcname(bt->instptr), "schedule")) { @@ -19098,7 +33344,7 @@ + } + } + -+ if (XENDUMP_DUMPFILE() && !is_idle_thread(bt->task) && ++ if (XENDUMP_DUMPFILE() && XEN() && !is_idle_thread(bt->task) && + is_task_active(bt->task) && + STREQ(kl_funcname(bt->instptr), "schedule")) { + /* @@ -19128,7 +33374,73 @@ if (!verify_back_trace(bt) && !recoverable(bt, ofp) && !BT_REFERENCE_CHECK(bt)) error(INFO, "cannot resolve stack trace:\n"); -@@ -2192,11 +2423,12 @@ +@@ -1797,12 +2066,14 @@ + return(0); + #endif + +- if (!(tsp = kl_alloc_block(TASK_STRUCT_SZ, K_TEMP))) { +- return(1); +- } +- if (kl_get_task_struct(task, 2, tsp)) { +- kl_free_block(tsp); +- return(1); ++ if (!XEN_HYPER_MODE()) { ++ if (!(tsp = kl_alloc_block(TASK_STRUCT_SZ, K_TEMP))) { ++ return(1); ++ } ++ if (kl_get_task_struct(task, 2, tsp)) { ++ kl_free_block(tsp); ++ return(1); ++ } + } + trace = (trace_t *)alloc_trace_rec(C_TEMP); + if (!trace) { +@@ -1874,7 +2145,9 @@ + #endif + print_trace(trace, flags, ofp); + } +- kl_free_block(tsp); ++ if (!XEN_HYPER_MODE()) ++ kl_free_block(tsp); ++ + free_trace_rec(trace); + #ifdef REDHAT + if (KL_ERROR == KLE_PRINT_TRACE_ERROR) { +@@ -1901,13 +2174,15 @@ + errcnt = 0; + KL_ERROR = 0; + +- if (!(tsp = kl_alloc_block(TASK_STRUCT_SZ, K_TEMP))) +- return FALSE; +- +- if (kl_get_task_struct(bt->task, 2, tsp)) { +- kl_free_block(tsp); +- return FALSE; +- } ++ if (!XEN_HYPER_MODE()) { ++ if (!(tsp = kl_alloc_block(TASK_STRUCT_SZ, K_TEMP))) ++ return FALSE; ++ ++ if (kl_get_task_struct(bt->task, 2, tsp)) { ++ kl_free_block(tsp); ++ return FALSE; ++ } ++ } + + trace = (trace_t *)alloc_trace_rec(C_TEMP); + if (!trace) +@@ -1952,7 +2227,9 @@ + } while (frmp != trace->frame); + } + +- kl_free_block(tsp); ++ if (!XEN_HYPER_MODE()) ++ kl_free_block(tsp); ++ + free_trace_rec(trace); + return (errcnt ? FALSE : TRUE); + } +@@ -2192,11 +2469,12 @@ else buf[0] = NULLCHAR; @@ -19143,7 +33455,17 @@ strlen(buf) ? buf : "", eip); if (bt->flags & BT_LINE_NUMBERS) { -@@ -2325,6 +2557,25 @@ +@@ -2236,6 +2514,9 @@ + struct eframe_labels *efp; + struct syment *sp; + ++ if (XEN_HYPER_MODE()) ++ return NULL; /* ODA: need support ? */ ++ + efp = &eframe_labels; + + if (!efp->init) { +@@ -2325,6 +2606,25 @@ } /* @@ -19169,8 +33491,27 @@ * Cache 2k starting from the passed-in text address. This sits on top * of the instrbuf 256-byte cache, but we don't want to extend its size * because we can run off the end of a module segment -- if this routine ---- crash/netdump.c.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/netdump.c 2006-08-31 15:59:44.000000000 -0400 +@@ -4858,6 +5158,8 @@ + } else { + codeptr++; + } ++ if (STREQ(op->name, "ud2a")) ++ codeptr += kt->BUG_bytes; + } else { + opcode = *codeptr; + op = &op_386[*codeptr]; +--- crash/netdump.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/netdump.c 2007-07-20 11:50:42.000000000 -0400 +@@ -1,7 +1,7 @@ + /* netdump.c + * +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. + * + * This software may be freely redistributed under the terms of the + * GNU General Public License. @@ -16,35 +16,9 @@ #include "defs.h" #include "netdump.h" @@ -19414,7 +33755,57 @@ return nd->header_size; bailout: -@@ -243,7 +280,7 @@ +@@ -238,12 +275,57 @@ + } + + /* ++ * Return the e_version number of an ELF file ++ * (or -1 if its not readable ELF file) ++ */ ++int ++file_elf_version(char *file) ++{ ++ int fd, size; ++ Elf32_Ehdr *elf32; ++ Elf64_Ehdr *elf64; ++ char header[MIN_NETDUMP_ELF_HEADER_SIZE]; ++ char buf[BUFSIZE]; ++ ++ if ((fd = open(file, O_RDONLY)) < 0) { ++ sprintf(buf, "%s: open", file); ++ perror(buf); ++ return -1; ++ } ++ ++ size = MIN_NETDUMP_ELF_HEADER_SIZE; ++ if (read(fd, header, size) != size) { ++ sprintf(buf, "%s: read", file); ++ perror(buf); ++ close(fd); ++ return -1; ++ } ++ close(fd); ++ ++ elf32 = (Elf32_Ehdr *)&header[0]; ++ elf64 = (Elf64_Ehdr *)&header[0]; ++ ++ if (STRNEQ(elf32->e_ident, ELFMAG) && ++ (elf32->e_ident[EI_CLASS] == ELFCLASS32) && ++ (elf32->e_ident[EI_DATA] == ELFDATA2LSB) && ++ (elf32->e_ident[EI_VERSION] == EV_CURRENT)) { ++ return (elf32->e_version); ++ } else if (STRNEQ(elf64->e_ident, ELFMAG) && ++ (elf64->e_ident[EI_CLASS] == ELFCLASS64) && ++ (elf64->e_ident[EI_VERSION] == EV_CURRENT)) { ++ return (elf64->e_version); ++ } ++ ++ return -1; ++} ++ ++/* + * Perform any post-dumpfile determination stuff here. + */ int netdump_init(char *unused, FILE *fptr) { @@ -19423,7 +33814,7 @@ return FALSE; nd->ofp = fptr; -@@ -263,19 +300,19 @@ +@@ -263,19 +345,19 @@ /* * The Elf32_Phdr has 32-bit fields for p_paddr, p_filesz and * p_memsz, so for now, multiple PT_LOAD segment support is @@ -19449,7 +33840,19 @@ if (nd->num_pt_load_segments == 1) { offset = (off_t)paddr + (off_t)nd->header_size; break; -@@ -302,24 +339,57 @@ +@@ -289,6 +371,11 @@ + pls->file_offset; + break; + } ++ if (pls->zero_fill && (paddr >= pls->phys_end) && ++ (paddr < pls->zero_fill)) { ++ memset(bufptr, 0, cnt); ++ return cnt; ++ } + } + + if (!offset) +@@ -302,24 +389,57 @@ if (read(nd->ndfd, bufptr, cnt) != cnt) return READ_ERROR; @@ -19469,7 +33872,8 @@ off_t offset; + struct pt_load_segment *pls; + int i; -+ + +- offset = (off_t)paddr + (off_t)nd->header_size; + switch (DUMPFILE_FORMAT(nd->flags)) + { + case NETDUMP_ELF32: @@ -19484,7 +33888,7 @@ + break; + } -- offset = (off_t)paddr + (off_t)nd->header_size; +- if (lseek(nd->ndfd, offset, SEEK_SET) != offset) + for (i = offset = 0; i < nd->num_pt_load_segments; i++) { + pls = &nd->pt_load_segments[i]; + if ((paddr >= pls->phys_start) && @@ -19500,8 +33904,7 @@ + + break; + } - -- if (lseek(nd->ndfd, offset, SEEK_SET) != offset) ++ + if (lseek(nd->ndfd, offset, SEEK_SET) == -1) return SEEK_ERROR; @@ -19511,7 +33914,7 @@ return cnt; } -@@ -330,7 +400,7 @@ +@@ -330,7 +450,7 @@ FILE * set_netdump_fp(FILE *fp) { @@ -19520,7 +33923,7 @@ return NULL; nd->ofp = fp; -@@ -346,7 +416,7 @@ +@@ -346,7 +466,7 @@ char buf[BUFSIZE]; va_list ap; @@ -19529,7 +33932,7 @@ return; va_start(ap, fmt); -@@ -362,33 +432,21 @@ +@@ -362,33 +482,21 @@ uint netdump_page_size(void) { @@ -19567,7 +33970,7 @@ } /* -@@ -414,21 +472,57 @@ +@@ -414,21 +522,57 @@ #ifdef DAEMON return nd->task_struct; #else @@ -19633,7 +34036,7 @@ len = sizeof(Elf32_Nhdr); len = roundup(len + note32->n_namesz, 4); len = roundup(len + note32->n_descsz, 4); -@@ -437,14 +531,15 @@ +@@ -437,14 +581,15 @@ - SIZE(user_regs_struct) - sizeof(int); ebp = ULONG(user_regs + OFFSET(user_regs_struct_ebp)); esp = ULONG(user_regs + OFFSET(user_regs_struct_esp)); @@ -19652,7 +34055,7 @@ "get_netdump_panic_task: esp: %lx -> task: %lx\n", esp, task); for (i = 0; task && (i < NR_CPUS); i++) { -@@ -455,7 +550,7 @@ +@@ -455,7 +600,7 @@ if (IS_KVADDR(ebp)) { task = stkptr_to_task(ebp); if (CRASHDEBUG(1)) @@ -19661,7 +34064,7 @@ "get_netdump_panic_task: ebp: %lx -> task: %lx\n", ebp, task); for (i = 0; task && (i < NR_CPUS); i++) { -@@ -464,25 +559,37 @@ +@@ -464,25 +609,37 @@ } } } else if (nd->elf64) { @@ -19705,7 +34108,7 @@ "get_netdump_panic_task: esp: %lx -> task: %lx\n", esp, task); for (i = 0; task && (i < NR_CPUS); i++) { -@@ -493,8 +600,10 @@ +@@ -493,8 +650,10 @@ } } @@ -19717,7 +34120,7 @@ return NO_TASK; #endif -@@ -512,7 +621,7 @@ +@@ -512,7 +671,7 @@ return nd->switch_stack; return 0; #else @@ -19726,7 +34129,7 @@ return 0; if (nd->task_struct == task) -@@ -525,32 +634,40 @@ +@@ -525,33 +684,75 @@ int netdump_memory_dump(FILE *fp) { @@ -19765,21 +34168,59 @@ + netdump_print("%sKDUMP_ELF64", others++ ? "|" : ""); if (nd->flags & PARTIAL_DUMP) netdump_print("%sPARTIAL_DUMP", others++ ? "|" : ""); -+ if (nd->flags & KDUMP_XEN_HV) -+ netdump_print("%sKDUMP_XEN_HV", others++ ? "|" : ""); netdump_print(")\n"); ++ if ((pc->flags & RUNTIME) && symbol_exists("dump_level")) { ++ int dump_level; ++ if (readmem(symbol_value("dump_level"), KVADDR, &dump_level, ++ sizeof(dump_level), "dump_level", QUIET|RETURN_ON_ERROR)) { ++ netdump_print(" dump_level: %d (0x%x) %s", ++ dump_level, dump_level, ++ dump_level > 0 ? "(" : ""); ++ ++#define DUMP_EXCLUDE_CACHE 0x00000001 /* Exclude LRU & SwapCache pages*/ ++#define DUMP_EXCLUDE_CLEAN 0x00000002 /* Exclude all-zero pages */ ++#define DUMP_EXCLUDE_FREE 0x00000004 /* Exclude free pages */ ++#define DUMP_EXCLUDE_ANON 0x00000008 /* Exclude Anon pages */ ++#define DUMP_SAVE_PRIVATE 0x00000010 /* Save private pages */ ++ ++ others = 0; ++ if (dump_level & DUMP_EXCLUDE_CACHE) ++ netdump_print("%sDUMP_EXCLUDE_CACHE", ++ others++ ? "|" : ""); ++ if (dump_level & DUMP_EXCLUDE_CLEAN) ++ netdump_print("%sDUMP_EXCLUDE_CLEAN", ++ others++ ? "|" : ""); ++ if (dump_level & DUMP_EXCLUDE_FREE) ++ netdump_print("%sDUMP_EXCLUDE_FREE", ++ others++ ? "|" : ""); ++ if (dump_level & DUMP_EXCLUDE_ANON) ++ netdump_print("%sDUMP_EXCLUDE_ANON", ++ others++ ? "|" : ""); ++ if (dump_level & DUMP_SAVE_PRIVATE) ++ netdump_print("%sDUMP_SAVE_PRIVATE", ++ others++ ? "|" : ""); ++ netdump_print("%s\n", dump_level > 0 ? ")" : ""); ++ } else ++ netdump_print(" dump_level: (unknown)\n"); ++ } else if (!(pc->flags & RUNTIME) && symbol_exists("dump_level")) ++ netdump_print(" dump_level: (undetermined)\n"); ++ netdump_print(" ndfd: %d\n", nd->ndfd); netdump_print(" ofp: %lx\n", nd->ofp); -@@ -566,7 +683,7 @@ + netdump_print(" header_size: %d\n", nd->header_size); +@@ -565,8 +766,10 @@ + pls->phys_start); netdump_print(" phys_end: %llx\n", pls->phys_end); ++ netdump_print(" zero_fill: %llx\n", ++ pls->zero_fill); } - netdump_print(" netdump_header: %lx\n", nd->netdump_header); + netdump_print(" elf_header: %lx\n", nd->elf_header); netdump_print(" elf32: %lx\n", nd->elf32); netdump_print(" notes32: %lx\n", nd->notes32); netdump_print(" load32: %lx\n", nd->load32); -@@ -577,11 +694,64 @@ +@@ -577,11 +780,66 @@ netdump_print(" nt_prpsinfo: %lx\n", nd->nt_prpsinfo); netdump_print(" nt_taskstruct: %lx\n", nd->nt_taskstruct); netdump_print(" task_struct: %lx\n", nd->task_struct); @@ -19787,8 +34228,8 @@ + netdump_print(" page_size: %d\n", nd->page_size); + netdump_print(" switch_stack: %lx\n", nd->switch_stack); + netdump_print(" xen_kdump_data: %s\n", -+ nd->flags & KDUMP_XEN_HV ? " " : "(unused)"); -+ if (nd->flags & KDUMP_XEN_HV) { ++ XEN_CORE_DUMPFILE() ? " " : "(unused)"); ++ if (XEN_CORE_DUMPFILE()) { + netdump_print(" flags: %lx (", nd->xen_kdump_data->flags); + others = 0; + if (nd->xen_kdump_data->flags & KDUMP_P2M_INIT) @@ -19804,11 +34245,13 @@ + nd->xen_kdump_data->cr3); + netdump_print(" last_mfn_read: %lx\n", + nd->xen_kdump_data->last_mfn_read); ++ netdump_print(" last_pmd_read: %lx\n", ++ nd->xen_kdump_data->last_pmd_read); + netdump_print(" page: %lx\n", + nd->xen_kdump_data->page); -+ netdump_print(" accesses: %lx\n", ++ netdump_print(" accesses: %ld\n", + nd->xen_kdump_data->accesses); -+ netdump_print(" cache_hits: %lx ", ++ netdump_print(" cache_hits: %ld ", + nd->xen_kdump_data->cache_hits); + if (nd->xen_kdump_data->accesses) + netdump_print("(%ld%%)", @@ -19822,8 +34265,8 @@ + nd->xen_kdump_data->p2m_mfn_frame_list[i]); + if (i) netdump_print("\n"); + } -+ netdump_print(" num_prstatus_notes: %d\n", nd->num_prstatus_notes); -+ netdump_print(" nt_prstatus_percpu: "); ++ netdump_print(" num_prstatus_notes: %d\n", nd->num_prstatus_notes); ++ netdump_print(" nt_prstatus_percpu: "); + wrap = sizeof(void *) == SIZEOF_32BIT ? 8 : 4; + flen = sizeof(void *) == SIZEOF_32BIT ? 8 : 16; + if (nd->num_prstatus_notes == 1) @@ -19846,7 +34289,7 @@ dump_Elf32_Ehdr(nd->elf32); dump_Elf32_Phdr(nd->notes32, ELFREAD); for (i = 0; i < nd->num_pt_load_segments; i++) -@@ -594,6 +764,7 @@ +@@ -594,6 +852,7 @@ break; case NETDUMP_ELF64: @@ -19854,7 +34297,7 @@ dump_Elf64_Ehdr(nd->elf64); dump_Elf64_Phdr(nd->notes64, ELFREAD); for (i = 0; i < nd->num_pt_load_segments; i++) -@@ -865,6 +1036,9 @@ +@@ -865,6 +1124,9 @@ netdump_print(" e_machine: %d ", elf->e_machine); switch (elf->e_machine) { @@ -19864,16 +34307,58 @@ case EM_IA_64: netdump_print("(EM_IA_64)\n"); break; -@@ -1061,7 +1235,7 @@ +@@ -961,8 +1223,11 @@ + pls->phys_start = prog->p_paddr; + netdump_print(" p_filesz: %lu (%lx)\n", prog->p_filesz, + prog->p_filesz); +- if (store_pt_load_data) ++ if (store_pt_load_data) { + pls->phys_end = pls->phys_start + prog->p_filesz; ++ pls->zero_fill = (prog->p_filesz == prog->p_memsz) ? ++ 0 : pls->phys_start + prog->p_memsz; ++ } + netdump_print(" p_memsz: %lu (%lx)\n", prog->p_memsz, + prog->p_memsz); + netdump_print(" p_flags: %lx (", prog->p_flags); +@@ -1040,8 +1305,11 @@ + pls->phys_start = prog->p_paddr; + netdump_print(" p_filesz: %lu (%lx)\n", prog->p_filesz, + prog->p_filesz); +- if (store_pt_load_data) ++ if (store_pt_load_data) { + pls->phys_end = pls->phys_start + prog->p_filesz; ++ pls->zero_fill = (prog->p_filesz == prog->p_memsz) ? ++ 0 : pls->phys_start + prog->p_memsz; ++ } + netdump_print(" p_memsz: %lu (%lx)\n", prog->p_memsz, + prog->p_memsz); + netdump_print(" p_flags: %lx (", prog->p_flags); +@@ -1061,20 +1329,22 @@ */ static size_t -dump_Elf32_Nhdr(Elf32_Off offset, int store_addresses) +dump_Elf32_Nhdr(Elf32_Off offset, int store) { - int i, lf; +- int i, lf; ++ int i, lf, words; Elf32_Nhdr *note; -@@ -1085,17 +1259,26 @@ + size_t len; + char buf[BUFSIZE]; + char *ptr; + ulong *uptr; ++ int xen_core; + + note = (Elf32_Nhdr *)((char *)nd->elf32 + offset); + + netdump_print("Elf32_Nhdr:\n"); + netdump_print(" n_namesz: %ld ", note->n_namesz); + BZERO(buf, BUFSIZE); ++ xen_core = FALSE; + ptr = (char *)note + sizeof(Elf32_Nhdr); + BCOPY(ptr, buf, note->n_namesz); + netdump_print("(\"%s\")\n", buf); +@@ -1085,17 +1355,26 @@ { case NT_PRSTATUS: netdump_print("(NT_PRSTATUS)\n"); @@ -19904,7 +34389,7 @@ nd->nt_taskstruct = (void *)note; nd->task_struct = *((ulong *)(ptr + note->n_namesz)); nd->switch_stack = *((ulong *) -@@ -1105,14 +1288,59 @@ +@@ -1105,14 +1384,103 @@ case NT_DISKDUMP: netdump_print("(NT_DISKDUMP)\n"); uptr = (ulong *)(ptr + note->n_namesz); @@ -19929,26 +34414,71 @@ + } + break; +#endif -+ case NT_XEN_KDUMP_CR3: -+ netdump_print("(NT_XEN_KDUMP_CR3)\n"); + default: +- netdump_print("(?)\n"); ++ xen_core = STRNEQ(buf, "XEN CORE") || STRNEQ(buf, "Xen"); ++ if (xen_core) { ++ netdump_print("(unknown Xen n_type)\n"); ++ if (store) ++ error(WARNING, "unknown Xen n_type: %lx\n\n", ++ note->n_type); ++ } else ++ netdump_print("(?)\n"); ++ break; ++ ++ case NT_XEN_KDUMP_CR3: ++ netdump_print("(NT_XEN_KDUMP_CR3) [obsolete]\n"); ++ if (store) ++ error(WARNING, ++ "obsolete Xen n_type: %lx (NT_XEN_KDUMP_CR3)\n\n", ++ note->n_type); ++ /* FALL THROUGH */ ++ ++ case XEN_ELFNOTE_CRASH_INFO: ++ /* ++ * x86 and x86_64: p2m mfn appended to crash_xen_info_t structure ++ */ ++ if (note->n_type == XEN_ELFNOTE_CRASH_INFO) ++ netdump_print("(XEN_ELFNOTE_CRASH_INFO)\n"); ++ xen_core = TRUE; + if (store) { -+ nd->flags |= KDUMP_XEN_HV; ++ pc->flags |= XEN_CORE; + nd->xen_kdump_data = &xen_kdump_data; -+ nd->xen_kdump_data->last_mfn_read = BADVAL; -+ nd->xen_kdump_data->flags |= KDUMP_CR3; -+ /* -+ * Use the first cr3 found. -+ */ -+ if (!nd->xen_kdump_data->cr3) { ++ nd->xen_kdump_data->last_mfn_read = UNINITIALIZED; ++ nd->xen_kdump_data->last_pmd_read = UNINITIALIZED; ++ ++ if ((note->n_type == NT_XEN_KDUMP_CR3) && ++ ((note->n_descsz/sizeof(ulong)) == 1)) { ++ nd->xen_kdump_data->flags |= KDUMP_CR3; ++ /* ++ * Use the first cr3 found. ++ */ ++ if (!nd->xen_kdump_data->cr3) { ++ uptr = (ulong *)(ptr + note->n_namesz); ++ uptr = (ulong *)roundup((ulong)uptr, 4); ++ nd->xen_kdump_data->cr3 = *uptr; ++ } ++ } else { ++ nd->xen_kdump_data->flags |= KDUMP_MFN_LIST; + uptr = (ulong *)(ptr + note->n_namesz); + uptr = (ulong *)roundup((ulong)uptr, 4); -+ nd->xen_kdump_data->cr3 = *uptr; ++ words = note->n_descsz/sizeof(ulong); ++ /* ++ * If already set, overridden with --pfm_mfn ++ */ ++ if (!nd->xen_kdump_data->p2m_mfn) ++ nd->xen_kdump_data->p2m_mfn = *(uptr+(words-1)); + } + } + break; + - default: - netdump_print("(?)\n"); ++ case XEN_ELFNOTE_CRASH_REGS: ++ /* ++ * x86 and x86_64: cr0, cr2, cr3, cr4 ++ */ ++ xen_core = TRUE; ++ netdump_print("(XEN_ELFNOTE_CRASH_REGS)\n"); ++ break; } uptr = (ulong *)(ptr + note->n_namesz); @@ -19959,40 +34489,50 @@ + if ((nd->flags & KDUMP_ELF32) && (note->n_namesz == 5)) + uptr = (ulong *)(ptr + ((note->n_namesz + 3) & ~3)); + -+ if (note->n_type == NT_XEN_KDUMP_CR3) ++ if (xen_core) + uptr = (ulong *)roundup((ulong)uptr, 4); + for (i = lf = 0; i < note->n_descsz/sizeof(ulong); i++) { if (((i%4)==0)) { netdump_print("%s ", -@@ -1123,7 +1351,8 @@ +@@ -1123,7 +1491,7 @@ netdump_print("%08lx ", *uptr++); } if (!lf || (note->n_type == NT_TASKSTRUCT) || - (note->n_type == NT_DISKDUMP)) -+ (note->n_type == NT_DISKDUMP) || -+ (note->n_type == NT_XEN_KDUMP_CR3)) ++ (note->n_type == NT_DISKDUMP) || xen_core) netdump_print("\n"); len = sizeof(Elf32_Nhdr); -@@ -1135,7 +1364,7 @@ +@@ -1135,15 +1503,17 @@ static size_t -dump_Elf64_Nhdr(Elf64_Off offset, int store_addresses) +dump_Elf64_Nhdr(Elf64_Off offset, int store) { - int i, lf; +- int i, lf; ++ int i, lf, words; Elf64_Nhdr *note; -@@ -1144,6 +1373,7 @@ + size_t len; + char buf[BUFSIZE]; char *ptr; ulonglong *uptr; int *iptr; + ulong *up; ++ int xen_core; note = (Elf64_Nhdr *)((char *)nd->elf64 + offset); -@@ -1160,17 +1390,26 @@ +@@ -1151,6 +1521,7 @@ + netdump_print(" n_namesz: %ld ", note->n_namesz); + BZERO(buf, BUFSIZE); + ptr = (char *)note + sizeof(Elf64_Nhdr); ++ xen_core = FALSE; + BCOPY(ptr, buf, note->n_namesz); + netdump_print("(\"%s\")\n", buf); + +@@ -1160,17 +1531,26 @@ { case NT_PRSTATUS: netdump_print("(NT_PRSTATUS)\n"); @@ -20023,7 +34563,7 @@ nd->nt_taskstruct = (void *)note; nd->task_struct = *((ulong *)(ptr + note->n_namesz)); nd->switch_stack = *((ulong *) -@@ -1180,16 +1419,72 @@ +@@ -1180,24 +1560,137 @@ case NT_DISKDUMP: netdump_print("(NT_DISKDUMP)\n"); iptr = (int *)(ptr + note->n_namesz); @@ -20061,29 +34601,82 @@ + } + break; +#endif -+ case NT_XEN_KDUMP_CR3: -+ netdump_print("(NT_XEN_KDUMP_CR3)\n"); + default: +- netdump_print("(?)\n"); ++ xen_core = STRNEQ(buf, "XEN CORE") || STRNEQ(buf, "Xen"); ++ if (xen_core) { ++ netdump_print("(unknown Xen n_type)\n"); ++ if (store) ++ error(WARNING, ++ "unknown Xen n_type: %lx\n\n", note->n_type); ++ } else ++ netdump_print("(?)\n"); ++ break; ++ ++ case NT_XEN_KDUMP_CR3: ++ netdump_print("(NT_XEN_KDUMP_CR3) [obsolete]\n"); ++ if (store) ++ error(WARNING, ++ "obsolete Xen n_type: %lx (NT_XEN_KDUMP_CR3)\n\n", ++ note->n_type); ++ /* FALL THROUGH */ ++ ++ case XEN_ELFNOTE_CRASH_INFO: ++ /* ++ * x86 and x86_64: p2m mfn appended to crash_xen_info_t structure ++ */ ++ if (note->n_type == XEN_ELFNOTE_CRASH_INFO) ++ netdump_print("(XEN_ELFNOTE_CRASH_INFO)\n"); ++ xen_core = TRUE; + if (store) { -+ nd->flags |= KDUMP_XEN_HV; ++ pc->flags |= XEN_CORE; + nd->xen_kdump_data = &xen_kdump_data; -+ nd->xen_kdump_data->last_mfn_read = BADVAL; -+ nd->xen_kdump_data->flags |= KDUMP_CR3; -+ /* -+ * Use the first cr3 found. -+ */ -+ if (!nd->xen_kdump_data->cr3) { ++ nd->xen_kdump_data->last_mfn_read = UNINITIALIZED; ++ nd->xen_kdump_data->last_pmd_read = UNINITIALIZED; ++ ++ if ((note->n_type == NT_XEN_KDUMP_CR3) && ++ ((note->n_descsz/sizeof(ulong)) == 1)) { ++ nd->xen_kdump_data->flags |= KDUMP_CR3; ++ /* ++ * Use the first cr3 found. ++ */ ++ if (!nd->xen_kdump_data->cr3) { ++ up = (ulong *)(ptr + note->n_namesz); ++ up = (ulong *)roundup((ulong)up, 4); ++ nd->xen_kdump_data->cr3 = *up; ++ } ++ } else { ++ nd->xen_kdump_data->flags |= KDUMP_MFN_LIST; + up = (ulong *)(ptr + note->n_namesz); -+ up = (ulong *)roundup((ulong)up, 4); -+ nd->xen_kdump_data->cr3 = *up; -+ } ++ up = (ulong *)roundup((ulong)up, 4); ++ words = note->n_descsz/sizeof(ulong); ++ /* ++ * If already set, overridden with --p2m_mfn ++ */ ++ if (!nd->xen_kdump_data->p2m_mfn) ++ nd->xen_kdump_data->p2m_mfn = *(up+(words-1)); ++ } + } + break; + - default: - netdump_print("(?)\n"); ++ case XEN_ELFNOTE_CRASH_REGS: ++ /* ++ * x86 and x86_64: cr0, cr2, cr3, cr4 ++ */ ++ xen_core = TRUE; ++ netdump_print("(XEN_ELFNOTE_CRASH_REGS)\n"); ++ break; } uptr = (ulonglong *)(ptr + note->n_namesz); +- for (i = lf = 0; i < note->n_descsz/sizeof(ulonglong); i++) { +- if (((i%2)==0)) { +- netdump_print("%s ", +- i ? "\n" : ""); +- lf++; +- } else +- lf = 0; +- netdump_print("%016llx ", *uptr++); + + /* + * kdumps are off-by-1, because their n_namesz is 5 for "CORE". @@ -20091,13 +34684,34 @@ + if ((nd->flags & KDUMP_ELF64) && (note->n_namesz == 5)) + uptr = (ulonglong *)(ptr + ((note->n_namesz + 3) & ~3)); + -+ if (note->n_type == NT_XEN_KDUMP_CR3) ++ if (xen_core) + uptr = (ulonglong *)roundup((ulong)uptr, 4); + - for (i = lf = 0; i < note->n_descsz/sizeof(ulonglong); i++) { - if (((i%2)==0)) { - netdump_print("%s ", -@@ -1251,12 +1546,12 @@ ++ if (BITS32() && (xen_core || (note->n_type == NT_PRSTATUS))) { ++ iptr = (int *)uptr; ++ for (i = lf = 0; i < note->n_descsz/sizeof(ulong); i++) { ++ if (((i%4)==0)) { ++ netdump_print("%s ", ++ i ? "\n" : ""); ++ lf++; ++ } else ++ lf = 0; ++ netdump_print("%08lx ", *iptr++); ++ } ++ } else { ++ for (i = lf = 0; i < note->n_descsz/sizeof(ulonglong); i++) { ++ if (((i%2)==0)) { ++ netdump_print("%s ", ++ i ? "\n" : ""); ++ lf++; ++ } else ++ lf = 0; ++ netdump_print("%016llx ", *uptr++); ++ } + } + if (!lf) + netdump_print("\n"); +@@ -1251,39 +1744,71 @@ default: error(FATAL, @@ -20108,18 +34722,34 @@ } -static void ++struct x86_64_user_regs_struct { ++ unsigned long r15,r14,r13,r12,rbp,rbx,r11,r10; ++ unsigned long r9,r8,rax,rcx,rdx,rsi,rdi,orig_rax; ++ unsigned long rip,cs,eflags; ++ unsigned long rsp,ss; ++ unsigned long fs_base, gs_base; ++ unsigned long ds,es,fs,gs; ++}; ++#define offsetof(TYPE, MEMBER) ((ulong)&((TYPE *)0)->MEMBER) ++ +void get_netdump_regs_x86_64(struct bt_info *bt, ulong *ripp, ulong *rspp) { Elf64_Nhdr *note; -@@ -1267,8 +1562,13 @@ + size_t len; + char *user_regs; +- ulong rsp, rip; ++ ulong regs_size, rsp_offset, rip_offset; + if (is_task_active(bt->task)) bt->flags |= BT_DUMPFILE_SEARCH; - if (VALID_STRUCT(user_regs_struct) && (bt->task == tt->panic_task)) { - note = (Elf64_Nhdr *)nd->nt_prstatus; -+ if ((NETDUMP_DUMPFILE() || KDUMP_DUMPFILE()) && -+ VALID_STRUCT(user_regs_struct) && (bt->task == tt->panic_task)) { ++ if (((NETDUMP_DUMPFILE() || KDUMP_DUMPFILE()) && ++ VALID_STRUCT(user_regs_struct) && (bt->task == tt->panic_task)) || ++ (KDUMP_DUMPFILE() && (kt->flags & DWARF_UNWIND) && ++ (bt->flags & BT_DUMPFILE_SEARCH))) { + if (nd->num_prstatus_notes > 1) + note = (Elf64_Nhdr *) + nd->nt_prstatus_percpu[bt->tc->processor]; @@ -20128,7 +34758,44 @@ len = sizeof(Elf64_Nhdr); len = roundup(len + note->n_namesz, 4); -@@ -1295,7 +1595,7 @@ + len = roundup(len + note->n_descsz, 4); + +- user_regs = ((char *)note + len) +- - SIZE(user_regs_struct) - sizeof(long); ++ regs_size = VALID_STRUCT(user_regs_struct) ? ++ SIZE(user_regs_struct) : ++ sizeof(struct x86_64_user_regs_struct); ++ rsp_offset = VALID_MEMBER(user_regs_struct_rsp) ? ++ OFFSET(user_regs_struct_rsp) : ++ offsetof(struct x86_64_user_regs_struct, rsp); ++ rip_offset = VALID_MEMBER(user_regs_struct_rip) ? ++ OFFSET(user_regs_struct_rip) : ++ offsetof(struct x86_64_user_regs_struct, rip); ++ ++ user_regs = ((char *)note + len) - regs_size - sizeof(long); + +- if (CRASHDEBUG(1)) { +- rsp = ULONG(user_regs + OFFSET(user_regs_struct_rsp)); +- rip = ULONG(user_regs + OFFSET(user_regs_struct_rip)); ++ if (CRASHDEBUG(1)) + netdump_print("ELF prstatus rsp: %lx rip: %lx\n", +- rsp, rip); +- } ++ ULONG(user_regs + rsp_offset), ++ ULONG(user_regs + rip_offset)); ++ ++ if (KDUMP_DUMPFILE()) { ++ *rspp = ULONG(user_regs + rsp_offset); ++ *ripp = ULONG(user_regs + rip_offset); + ++ if (*ripp && *rspp) ++ return; ++ } ++ + bt->machdep = (void *)user_regs; + } + +@@ -1295,13 +1820,14 @@ * the raw stack for some reasonable hooks. */ @@ -20136,16 +34803,50 @@ +void get_netdump_regs_x86(struct bt_info *bt, ulong *eip, ulong *esp) { - int i, search, panic; -@@ -1320,6 +1620,7 @@ - if (STREQ(sym, "netconsole_netdump") || +- int i, search, panic; ++ int i, search, panic, panic_task; + char *sym; + ulong *up; + ulong ipintr_eip, ipintr_esp, ipintr_func; ++ ulong halt_eip, halt_esp; + int check_hardirq, check_softirq; + + if (!is_task_active(bt->task)) { +@@ -1309,17 +1835,31 @@ + return; + } + ++ panic_task = tt->panic_task == bt->task ? TRUE : FALSE; ++ + ipintr_eip = ipintr_esp = ipintr_func = panic = 0; ++ halt_eip = halt_esp = 0; + check_hardirq = check_softirq = tt->flags & IRQSTACKS ? TRUE : FALSE; + search = ((bt->flags & BT_TEXT_SYMBOLS) && (tt->flags & TASK_INIT_DONE)) + || (machdep->flags & OMIT_FRAME_PTR); +- + retry: + for (i = 0, up = (ulong *)bt->stackbuf; i < LONGS_PER_STACK; i++, up++){ + sym = closest_symbol(*up); +- if (STREQ(sym, "netconsole_netdump") || ++ ++ if (XEN_CORE_DUMPFILE()) { ++ if (STREQ(sym, "xen_machine_kexec")) { ++ *eip = *up; ++ *esp = bt->stackbase + ((char *)(up+1) - bt->stackbuf); ++ return; ++ } ++ if (STREQ(sym, "crash_kexec")) { ++ halt_eip = *up; ++ halt_esp = bt->stackbase + ((char *)(up+1) - bt->stackbuf); ++ } ++ } else if (STREQ(sym, "netconsole_netdump") || STREQ(sym, "netpoll_start_netdump") || STREQ(sym, "start_disk_dump") || + STREQ(sym, "crash_kexec") || STREQ(sym, "disk_dump")) { *eip = *up; *esp = search ? -@@ -1354,7 +1655,7 @@ +@@ -1354,7 +1894,7 @@ next_sysrq: *eip = *up; *esp = bt->stackbase + ((char *)(up+4) - bt->stackbuf); @@ -20154,7 +34855,7 @@ for (i++, up++; i < LONGS_PER_STACK; i++, up++) { sym = closest_symbol(*up); if (STREQ(sym, "sysrq_handle_crash")) -@@ -1371,7 +1672,15 @@ +@@ -1371,7 +1911,15 @@ *esp = search ? bt->stackbase + ((char *)(up+1) - bt->stackbuf) : *(up-1); @@ -20171,16 +34872,43 @@ return; } -@@ -1418,7 +1727,7 @@ +@@ -1385,6 +1933,18 @@ + bt->stackbase + ((char *)(up-1) - bt->stackbuf); + ipintr_func = *(up - 2); + } ++ ++ if (XEN_CORE_DUMPFILE() && !panic_task && (bt->tc->pid == 0) && ++ STREQ(sym, "safe_halt")) { ++ halt_eip = *up; ++ halt_esp = bt->stackbase + ((char *)(up+1) - bt->stackbuf); ++ } ++ ++ if (XEN_CORE_DUMPFILE() && !panic_task && (bt->tc->pid == 0) && ++ !halt_eip && STREQ(sym, "xen_idle")) { ++ halt_eip = *up; ++ halt_esp = bt->stackbase + ((char *)(up+1) - bt->stackbuf); ++ } + } + + if (ipintr_eip) { +@@ -1418,7 +1978,15 @@ goto retry; } - console("get_netdump_regs_x86: cannot find anything useful\n"); -+ console("get_netdump_regs_x86: cannot find anything useful for task: %lx\n", bt->task); ++ if (halt_eip && halt_esp) { ++ *eip = halt_eip; ++ *esp = halt_esp; ++ return; ++ } ++ ++ if (CRASHDEBUG(1)) ++ error(INFO, ++ "get_netdump_regs_x86: cannot find anything useful (task: %lx)\n", bt->task); machdep->get_stack_frame(bt, eip, esp); } -@@ -1429,8 +1738,18 @@ +@@ -1429,8 +1997,18 @@ Elf64_Nhdr *note; size_t len; @@ -20201,7 +34929,7 @@ len = sizeof(Elf64_Nhdr); len = roundup(len + note->n_namesz, 4); -@@ -1446,3 +1765,156 @@ +@@ -1446,3 +2024,205 @@ { return (nd->flags & PARTIAL_DUMP ? TRUE : FALSE); } @@ -20234,7 +34962,7 @@ +int +read_kdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) +{ -+ if ((nd->flags & KDUMP_XEN_HV)) { ++ if (XEN_CORE_DUMPFILE() && !XEN_HYPER_MODE()) { + if (!(nd->xen_kdump_data->flags & KDUMP_P2M_INIT)) { + if (!machdep->xen_kdump_p2m_create) + error(FATAL, @@ -20321,11 +35049,17 @@ + if (pc->curcmd_flags & XEN_MACHINE_ADDR) + return pseudo; + ++#ifdef IA64 ++ return ia64_xen_kdump_p2m(xkd, pseudo); ++#endif ++ + xkd->accesses++; + + pfn = (ulong)BTOP(pseudo); + mfn_idx = pfn / (PAGESIZE()/sizeof(ulong)); + frame_idx = pfn % (PAGESIZE()/sizeof(ulong)); ++ if (mfn_idx >= xkd->p2m_frames) ++ return P2M_FAILURE; + mfn_frame = xkd->p2m_mfn_frame_list[mfn_idx]; + + if (mfn_frame == xkd->last_mfn_read) @@ -20358,8 +35092,51 @@ + + return &vmcore_data; +} ---- crash/diskdump.c.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/diskdump.c 2006-03-23 14:30:14.000000000 -0500 ++ ++/* ++ * Override the dom0 p2m mfn in the XEN_ELFNOTE_CRASH_INFO note ++ * in order to initiate a crash session of a guest kernel. ++ */ ++void ++xen_kdump_p2m_mfn(char *arg) ++{ ++ ulong value; ++ int errflag; ++ ++ errflag = 0; ++ value = htol(arg, RETURN_ON_ERROR|QUIET, &errflag); ++ if (!errflag) { ++ xen_kdump_data.p2m_mfn = value; ++ if (CRASHDEBUG(1)) ++ error(INFO, ++ "xen_kdump_data.p2m_mfn override: %lx\n", ++ value); ++ } else ++ error(WARNING, "invalid p2m_mfn argument: %s\n", arg); ++} ++ ++/* ++ * Fujitsu dom0/HV sadump-generated dumpfile, which requires ++ * the --p2m_mfn command line argument. ++ */ ++int ++is_sadump_xen(void) ++{ ++ if (xen_kdump_data.p2m_mfn) { ++ if (!XEN_CORE_DUMPFILE()) { ++ pc->flags |= XEN_CORE; ++ nd->xen_kdump_data = &xen_kdump_data; ++ nd->xen_kdump_data->last_mfn_read = UNINITIALIZED; ++ nd->xen_kdump_data->last_pmd_read = UNINITIALIZED; ++ nd->xen_kdump_data->flags |= KDUMP_MFN_LIST; ++ } ++ return TRUE; ++ } ++ ++ return FALSE; ++} +--- crash/diskdump.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/diskdump.c 2007-04-10 10:20:29.000000000 -0400 @@ -1,16 +1,16 @@ /* * diskdump.c @@ -20377,14 +35154,16 @@ + * netdump dumpfiles, the facilities in netdump.c are used. For + * compressed dumpfiles, the facilities in this file are used. * - * Copyright (C) 2004, 2005 David Anderson - * Copyright (C) 2004, 2005 Red Hat, Inc. All rights reserved. +- * Copyright (C) 2004, 2005 David Anderson +- * Copyright (C) 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2004, 2005, 2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2005 FUJITSU LIMITED + * Copyright (C) 2005 NEC Corporation * * This software may be freely redistributed under the terms of the * GNU General Public License. -@@ -18,23 +18,230 @@ +@@ -18,22 +18,261 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. @@ -20406,6 +35185,7 @@ + /* header */ + struct disk_dump_header *header; + struct disk_dump_sub_header *sub_header; ++ struct kdump_sub_header *sub_header_kdump; + + size_t data_offset; + int block_size; @@ -20429,11 +35209,15 @@ + ulong evictions; /* total evictions done */ + ulong cached_reads; + ulong *valid_pages; ++ ulong accesses; }; static struct diskdump_data diskdump_data = { 0 }; static struct diskdump_data *dd = &diskdump_data; - ++static int get_dump_level(void); ++ ++ulong *diskdump_flags = &diskdump_data.flags; ++ +static inline int get_bit(char *map, int byte, int bit) +{ + return map[byte] & (1<dfd, 0, SEEK_SET) == failed) { + if (CRASHDEBUG(1)) @@ -20497,8 +35283,15 @@ + } + + /* validate dump header */ -+ if (memcmp(header->signature, DISK_DUMP_SIGNATURE, ++ if (!memcmp(header->signature, DISK_DUMP_SIGNATURE, + sizeof(header->signature))) { ++ dd->flags |= DISKDUMP_LOCAL; ++ } else if (!memcmp(header->signature, KDUMP_SIGNATURE, ++ sizeof(header->signature))) { ++ dd->flags |= KDUMP_CMPRS_LOCAL; ++ if (header->header_version >= 1) ++ dd->flags |= ERROR_EXCLUDED; ++ } else { + if (CRASHDEBUG(1)) + error(INFO, "diskdump: dump does not have panic dump header\n"); + goto err; @@ -20524,14 +35317,28 @@ + error(INFO, "diskdump: cannot lseek dump sub header\n"); + goto err; + } -+ sub_header = malloc(block_size); -+ if (read(dd->dfd, sub_header, block_size) -+ < block_size) { -+ error(INFO, "diskdump: cannot read dump sub header\n"); -+ goto err; -+ } + -+ dd->sub_header = sub_header; ++ if (DISKDUMP_VALID()) { ++ if ((sub_header = malloc(block_size)) == NULL) ++ error(FATAL, "diskdump: cannot malloc sub_header buffer\n"); ++ ++ if (read(dd->dfd, sub_header, block_size) ++ < block_size) { ++ error(INFO, "diskdump: cannot read dump sub header\n"); ++ goto err; ++ } ++ dd->sub_header = sub_header; ++ } else if (KDUMP_CMPRS_VALID()) { ++ if ((sub_header_kdump = malloc(block_size)) == NULL) ++ error(FATAL, "diskdump: cannot malloc sub_header_kdump buffer\n"); ++ ++ if (read(dd->dfd, sub_header_kdump, block_size) ++ < block_size) { ++ error(INFO, "diskdump: cannot read dump sub header\n"); ++ goto err; ++ } ++ dd->sub_header_kdump = sub_header_kdump; ++ } + + /* read memory bitmap */ + bitmap_len = block_size * header->bitmap_blocks; @@ -20543,7 +35350,8 @@ + goto err; + } + -+ dd->bitmap = malloc(bitmap_len); ++ if ((dd->bitmap = malloc(bitmap_len)) == NULL) ++ error(FATAL, "diskdump: cannot malloc bitmap buffer\n"); + dd->dumpable_bitmap = calloc(bitmap_len, 1); + if (read(dd->dfd, dd->bitmap, bitmap_len) < bitmap_len) { + error(INFO, "diskdump: cannot read memory bitmap\n"); @@ -20592,10 +35400,13 @@ + free(header); + if (sub_header) + free(sub_header); ++ if (sub_header_kdump) ++ free(sub_header_kdump); + if (dd->bitmap) + free(dd->bitmap); + if (dd->dumpable_bitmap) + free(dd->dumpable_bitmap); ++ dd->flags &= ~(DISKDUMP_LOCAL|KDUMP_CMPRS_LOCAL); + return FALSE; +} + @@ -20613,14 +35424,14 @@ + return desc_pos; +} + -+ + /* * Determine whether a file is a diskdump creation, and if TRUE, - * initialize the diskdump_data structure based upon the contents -@@ -43,6 +250,31 @@ +@@ -43,7 +282,26 @@ int is_diskdump(char *file) { +- return FALSE; + int sz, i; + + if (!open_dump_file(file) || !read_dump_header()) @@ -20628,34 +35439,29 @@ + + sz = dd->block_size * (DISKDUMP_CACHED_PAGES); + if ((dd->page_cache_buf = malloc(sz)) == NULL) -+ return FALSE; ++ error(FATAL, "diskdump: cannot malloc compressed page_cache_buf\n"); + + for (i = 0; i < DISKDUMP_CACHED_PAGES; i++) + dd->page_cache_hdr[i].pg_bufptr = + &dd->page_cache_buf[i * dd->block_size]; + + if ((dd->compressed_page = (char *)malloc(dd->block_size)) == NULL) -+ goto err; ++ error(FATAL, "diskdump: cannot malloc compressed page space\n"); + -+ dd->flags |= DISKDUMP_LOCAL; ++ if (CRASHDEBUG(1)) ++ diskdump_memory_dump(fp); + + return TRUE; -+ -+err: -+ if (dd->page_cache_buf) -+ free(dd->page_cache_buf); -+ if (dd->compressed_page) -+ free(dd->compressed_page); - return FALSE; } -@@ -53,11 +285,123 @@ + /* +@@ -53,11 +311,139 @@ int diskdump_init(char *unused, FILE *fptr) { - if (!DISKDUMP_VALID()) - return FALSE; -+ if (!DISKDUMP_VALID()) ++ if (!DISKDUMP_VALID() && !KDUMP_CMPRS_VALID()) + return FALSE; - dd->ofp = fptr; @@ -20665,6 +35471,20 @@ +} + +/* ++ * Get the relocational offset from the sub header of kdump. ++ */ ++int ++diskdump_phys_base(unsigned long *phys_base) ++{ ++ if (KDUMP_CMPRS_VALID()) { ++ *phys_base = dd->sub_header_kdump->phys_base; ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/* + * Check whether paddr is already cached. + */ +static int @@ -20673,6 +35493,8 @@ + int i; + struct page_cache_hdr *pgc; + ++ dd->accesses++; ++ + for (i = 0; i < DISKDUMP_CACHED_PAGES; i++) { + + pgc = &dd->page_cache_hdr[i]; @@ -20777,7 +35599,7 @@ } /* -@@ -66,7 +410,28 @@ +@@ -66,7 +452,31 @@ int read_diskdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) { @@ -20793,6 +35615,9 @@ + if ((pfn >= dd->header->max_mapnr) || !page_is_ram(pfn)) + return SEEK_ERROR; + if (!page_is_dumpable(pfn)) { ++ if ((dd->flags & (ZERO_EXCLUDED|ERROR_EXCLUDED)) == ++ ERROR_EXCLUDED) ++ return PAGE_EXCLUDED; + memset(bufptr, 0, cnt); + return cnt; + } @@ -20807,12 +35632,13 @@ } /* -@@ -81,7 +446,22 @@ +@@ -81,7 +491,23 @@ ulong get_diskdump_panic_task(void) { - return NO_TASK; -+ if (!DISKDUMP_VALID() || !get_active_set()) ++ if ((!DISKDUMP_VALID() && !KDUMP_CMPRS_VALID()) ++ || !get_active_set()) + return NO_TASK; + + return (ulong)dd->header->tasks[dd->header->current_cpu]; @@ -20824,14 +35650,14 @@ +static void +get_diskdump_regs_ppc64(struct bt_info *bt, ulong *eip, ulong *esp) +{ -+ if (bt->task == tt->panic_task) ++ if ((bt->task == tt->panic_task) && DISKDUMP_VALID()) + bt->machdep = &dd->sub_header->elf_regs; + + machdep->get_stack_frame(bt, eip, esp); } /* -@@ -91,12 +471,32 @@ +@@ -91,12 +517,32 @@ void get_diskdump_regs(struct bt_info *bt, ulong *eip, ulong *esp) { @@ -20870,26 +35696,261 @@ } /* -@@ -105,7 +505,10 @@ +@@ -105,7 +551,10 @@ uint diskdump_page_size(void) { - return 0; -+ if (!DISKDUMP_VALID()) ++ if (!DISKDUMP_VALID() && !KDUMP_CMPRS_VALID()) + return 0; + + return dd->header->block_size; } /* ---- crash/xendump.c.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/xendump.c 2006-07-11 15:49:24.000000000 -0400 -@@ -0,0 +1,1170 @@ +@@ -131,6 +580,197 @@ + int + diskdump_memory_dump(FILE *fp) + { ++ int i, others, dump_level; ++ struct disk_dump_header *dh; ++ struct disk_dump_sub_header *dsh; ++ struct kdump_sub_header *kdsh; ++ ulong *tasks; ++ ++ fprintf(fp, "diskdump_data: \n"); ++ fprintf(fp, " flags: %lx (", dd->flags); ++ others = 0; ++ if (dd->flags & DISKDUMP_LOCAL) ++ fprintf(fp, "%sDISKDUMP_LOCAL", others++ ? "|" : ""); ++ if (dd->flags & KDUMP_CMPRS_LOCAL) ++ fprintf(fp, "%sKDUMP_CMPRS_LOCAL", others++ ? "|" : ""); ++ if (dd->flags & ERROR_EXCLUDED) ++ fprintf(fp, "%sERROR_EXCLUDED", others++ ? "|" : ""); ++ if (dd->flags & ZERO_EXCLUDED) ++ fprintf(fp, "%sZERO_EXCLUDED", others++ ? "|" : ""); ++ fprintf(fp, ")\n"); ++ fprintf(fp, " dfd: %d\n", dd->dfd); ++ fprintf(fp, " ofp: %lx\n", (ulong)dd->ofp); ++ fprintf(fp, " machine_type: %d ", dd->machine_type); ++ switch (dd->machine_type) ++ { ++ case EM_386: ++ fprintf(fp, "(EM_386)\n"); break; ++ case EM_X86_64: ++ fprintf(fp, "(EM_X86_64)\n"); break; ++ case EM_IA_64: ++ fprintf(fp, "(EM_IA_64)\n"); break; ++ case EM_PPC64: ++ fprintf(fp, "(EM_PPC64)\n"); break; ++ default: ++ fprintf(fp, "(unknown)\n"); break; ++ } ++ ++ fprintf(fp, "\n header: %lx\n", (ulong)dd->header); ++ dh = dd->header; ++ fprintf(fp, " signature: \""); ++ for (i = 0; i < SIG_LEN; i++) ++ if (dh->signature[i]) ++ fprintf(fp, "%c", dh->signature[i]); ++ fprintf(fp, "\"\n"); ++ fprintf(fp, " header_version: %d\n", dh->header_version); ++ fprintf(fp, " utsname:\n"); ++ fprintf(fp, " sysname: %s\n", dh->utsname.sysname); ++ fprintf(fp, " nodename: %s\n", dh->utsname.nodename); ++ fprintf(fp, " release: %s\n", dh->utsname.release); ++ fprintf(fp, " version: %s\n", dh->utsname.version); ++ fprintf(fp, " machine: %s\n", dh->utsname.machine); ++ fprintf(fp, " domainname: %s\n", dh->utsname.domainname); ++ fprintf(fp, " timestamp:\n"); ++ fprintf(fp, " tv_sec: %lx\n", dh->timestamp.tv_sec); ++ fprintf(fp, " tv_usec: %lx\n", dh->timestamp.tv_usec); ++ fprintf(fp, " status: %x (", dh->status); ++ others = 0; ++ if (dh->status & DUMP_HEADER_COMPLETED) ++ fprintf(fp, "%sDUMP_HEADER_COMPLETED", others++ ? "|" : ""); ++ if (dh->status & DUMP_HEADER_INCOMPLETED) ++ fprintf(fp, "%sDUMP_HEADER_INCOMPLETED", others++ ? "|" : ""); ++ if (dh->status & DUMP_HEADER_COMPRESSED) ++ fprintf(fp, "%sDUMP_HEADER_COMPRESSED", others++ ? "|" : ""); ++ fprintf(fp, ")\n"); ++ fprintf(fp, " block_size: %d\n", dh->block_size); ++ fprintf(fp, " sub_hdr_size: %d\n", dh->sub_hdr_size); ++ fprintf(fp, " bitmap_blocks: %u\n", dh->bitmap_blocks); ++ fprintf(fp, " max_mapnr: %u\n", dh->max_mapnr); ++ fprintf(fp, " total_ram_blocks: %u\n", dh->total_ram_blocks); ++ fprintf(fp, " device_blocks: %u\n", dh->device_blocks); ++ fprintf(fp, " written_blocks: %u\n", dh->written_blocks); ++ fprintf(fp, " current_cpu: %u\n", dh->current_cpu); ++ fprintf(fp, " nr_cpus: %d\n", dh->nr_cpus); ++ tasks = (ulong *)&dh->tasks[0]; ++ fprintf(fp, " tasks[nr_cpus]: %lx\n", *tasks); ++ for (tasks++, i = 1; i < dh->nr_cpus; i++) { ++ fprintf(fp, " %lx\n", *tasks); ++ tasks++; ++ } ++ fprintf(fp, "\n"); ++ fprintf(fp, " sub_header: %lx ", (ulong)dd->sub_header); ++ if ((dsh = dd->sub_header)) { ++ fprintf(fp, "\n elf_regs: %lx\n", ++ (ulong)&dsh->elf_regs); ++ fprintf(fp, " dump_level: "); ++ if ((pc->flags & RUNTIME) && ++ ((dump_level = get_dump_level()) >= 0)) { ++ fprintf(fp, "%d (0x%x) %s", dump_level, dump_level, ++ dump_level ? "(" : ""); ++ ++#define DUMP_EXCLUDE_CACHE 0x00000001 /* Exclude LRU & SwapCache pages*/ ++#define DUMP_EXCLUDE_CLEAN 0x00000002 /* Exclude all-zero pages */ ++#define DUMP_EXCLUDE_FREE 0x00000004 /* Exclude free pages */ ++#define DUMP_EXCLUDE_ANON 0x00000008 /* Exclude Anon pages */ ++#define DUMP_SAVE_PRIVATE 0x00000010 /* Save private pages */ ++ ++ others = 0; ++ if (dump_level & DUMP_EXCLUDE_CACHE) ++ fprintf(fp, "%sDUMP_EXCLUDE_CACHE", ++ others++ ? "|" : ""); ++ if (dump_level & DUMP_EXCLUDE_CLEAN) ++ fprintf(fp, "%sDUMP_EXCLUDE_CLEAN", ++ others++ ? "|" : ""); ++ if (dump_level & DUMP_EXCLUDE_FREE) ++ fprintf(fp, "%sDUMP_EXCLUDE_FREE", ++ others++ ? "|" : ""); ++ if (dump_level & DUMP_EXCLUDE_ANON) ++ fprintf(fp, "%sDUMP_EXCLUDE_ANON", ++ others++ ? "|" : ""); ++ if (dump_level & DUMP_SAVE_PRIVATE) ++ fprintf(fp, "%sDUMP_SAVE_PRIVATE", ++ others++ ? "|" : ""); ++ fprintf(fp, "%s\n\n", dump_level ? ")" : ""); ++ } else ++ fprintf(fp, "%s\n\n", pc->flags & RUNTIME ? ++ "(unknown)" : "(undetermined)"); ++ ++ } else ++ fprintf(fp, "(n/a)\n\n"); ++ ++ fprintf(fp, " sub_header_kdump: %lx ", (ulong)dd->sub_header_kdump); ++ if ((kdsh = dd->sub_header_kdump)) { ++ fprintf(fp, "\n phys_base: %lx\n", ++ (ulong)kdsh->phys_base); ++ fprintf(fp, " dump_level: "); ++ if ((dump_level = get_dump_level()) >= 0) { ++ fprintf(fp, "%d (0x%x) %s", dump_level, dump_level, ++ dump_level ? "(" : ""); ++ ++#define DL_EXCLUDE_ZERO (0x001) /* Exclude Pages filled with Zeros */ ++#define DL_EXCLUDE_CACHE (0x002) /* Exclude Cache Pages without Private Pages */ ++#define DL_EXCLUDE_CACHE_PRI (0x004) /* Exclude Cache Pages with Private Pages */ ++#define DL_EXCLUDE_USER_DATA (0x008) /* Exclude UserProcessData Pages */ ++#define DL_EXCLUDE_FREE (0x010) /* Exclude Free Pages */ ++ ++ if (dump_level & DL_EXCLUDE_ZERO) ++ fprintf(fp, "%sDUMP_EXCLUDE_ZERO", ++ others++ ? "|" : ""); ++ if (dump_level & DL_EXCLUDE_CACHE) ++ fprintf(fp, "%sDUMP_EXCLUDE_CACHE", ++ others++ ? "|" : ""); ++ if (dump_level & DL_EXCLUDE_CACHE_PRI) ++ fprintf(fp, "%sDUMP_EXCLUDE_CACHE_PRI", ++ others++ ? "|" : ""); ++ if (dump_level & DL_EXCLUDE_USER_DATA) ++ fprintf(fp, "%sDUMP_EXCLUDE_USER_DATA", ++ others++ ? "|" : ""); ++ if (dump_level & DL_EXCLUDE_FREE) ++ fprintf(fp, "%sDUMP_EXCLUDE_FREE", ++ others++ ? "|" : ""); ++ others = 0; ++ ++ fprintf(fp, "%s\n\n", dump_level ? ")" : ""); ++ } else ++ fprintf(fp, "(unknown)\n\n"); ++ } else ++ fprintf(fp, "(n/a)\n\n"); ++ ++ fprintf(fp, " data_offset: %lx\n", (ulong)dd->data_offset); ++ fprintf(fp, " block_size: %d\n", dd->block_size); ++ fprintf(fp, " block_shift: %d\n", dd->block_shift); ++ fprintf(fp, " bitmap: %lx\n", (ulong)dd->bitmap); ++ fprintf(fp, " bitmap_len: %d\n", dd->bitmap_len); ++ fprintf(fp, " dumpable_bitmap: %lx\n", (ulong)dd->dumpable_bitmap); ++ fprintf(fp, " byte: %d\n", dd->byte); ++ fprintf(fp, " bit: %d\n", dd->bit); ++ fprintf(fp, " compressed_page: %lx\n", (ulong)dd->compressed_page); ++ fprintf(fp, " curbufptr: %lx\n\n", (ulong)dd->curbufptr); ++ ++ for (i = 0; i < DISKDUMP_CACHED_PAGES; i++) { ++ fprintf(fp, "%spage_cache_hdr[%d]:\n", i < 10 ? " " : "", i); ++ fprintf(fp, " pg_flags: %x (", dd->page_cache_hdr[i].pg_flags); ++ others = 0; ++ if (dd->page_cache_hdr[i].pg_flags & PAGE_VALID) ++ fprintf(fp, "%sPAGE_VALID", others++ ? "|" : ""); ++ fprintf(fp, ")\n"); ++ fprintf(fp, " pg_addr: %llx\n", (ulonglong)dd->page_cache_hdr[i].pg_addr); ++ fprintf(fp, " pg_bufptr: %lx\n", (ulong)dd->page_cache_hdr[i].pg_bufptr); ++ fprintf(fp, " pg_hit_count: %ld\n", dd->page_cache_hdr[i].pg_hit_count); ++ } ++ ++ fprintf(fp, "\n page_cache_buf: %lx\n", (ulong)dd->page_cache_buf); ++ fprintf(fp, " evict_index: %d\n", dd->evict_index); ++ fprintf(fp, " evictions: %ld\n", dd->evictions); ++ fprintf(fp, " accesses: %ld\n", dd->accesses); ++ fprintf(fp, " cached_reads: %ld ", dd->cached_reads); ++ if (dd->accesses) ++ fprintf(fp, "(%ld%%)\n", ++ dd->cached_reads * 100 / dd->accesses); ++ else ++ fprintf(fp, "\n"); ++ fprintf(fp, " valid_pages: %lx\n", (ulong)dd->valid_pages); ++ + return 0; + } + +@@ -142,3 +782,36 @@ + { + return 0; + } ++ ++/* ++ * Versions of disk_dump that support it contain the "dump_level" symbol. ++ * Version 1 and later compressed kdump dumpfiles contain the dump level ++ * in an additional field of the sub_header_kdump structure. ++ */ ++static int ++get_dump_level(void) ++{ ++ int dump_level; ++ ++ if (DISKDUMP_VALID()) { ++ if (symbol_exists("dump_level") && ++ readmem(symbol_value("dump_level"), KVADDR, &dump_level, ++ sizeof(dump_level), "dump_level", QUIET|RETURN_ON_ERROR)) ++ return dump_level; ++ } else if (KDUMP_CMPRS_VALID()) { ++ if (dd->header->header_version >= 1) ++ return dd->sub_header_kdump->dump_level; ++ } ++ ++ return -1; ++} ++ ++/* ++ * Used by the "sys" command to display [PARTIAL DUMP] ++ * after the dumpfile name. ++ */ ++int ++is_partial_diskdump(void) ++{ ++ return (get_dump_level() > 0 ? TRUE : FALSE); ++} +--- crash/xendump.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/xendump.c 2007-03-23 14:10:12.000000000 -0500 +@@ -0,0 +1,2829 @@ +/* + * xendump.c + * -+ * Copyright (C) 2006 David Anderson -+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2006, 2007 David Anderson ++ * Copyright (C) 2006, 2007 Red Hat, Inc. All rights reserved. + * + * This software may be freely redistributed under the terms of the + * GNU General Public License. @@ -20909,14 +35970,35 @@ +static int xc_core_verify(char *); +static int xc_save_read(void *, int, ulong, physaddr_t); +static int xc_core_read(void *, int, ulong, physaddr_t); ++static int xc_core_mfns(ulong, FILE *); + +static void poc_store(ulong, off_t); +static off_t poc_get(ulong, int *); + +static void xen_dump_vmconfig(FILE *); + -+static void xc_core_p2m_create(void); ++static void xc_core_create_pfn_tables(void); +static ulong xc_core_pfn_to_page_index(ulong); ++static int xc_core_pfn_valid(ulong); ++ ++static void xendump_print(char *fmt, ...); ++ ++static int xc_core_elf_verify(char *); ++static void xc_core_elf_dump(void); ++static char *xc_core_elf_mfn_to_page(ulong, char *); ++static int xc_core_elf_mfn_to_page_index(ulong); ++static ulong xc_core_elf_pfn_valid(ulong); ++static ulong xc_core_elf_pfn_to_page_index(ulong); ++static void xc_core_dump_Elf32_Ehdr(Elf32_Ehdr *); ++static void xc_core_dump_Elf64_Ehdr(Elf64_Ehdr *); ++static void xc_core_dump_Elf32_Shdr(Elf32_Off offset, int); ++static void xc_core_dump_Elf64_Shdr(Elf64_Off offset, int); ++static char *xc_core_strtab(uint32_t, char *); ++static void xc_core_dump_elfnote(off_t, size_t, int); ++static void xc_core_elf_pfn_init(void); ++ ++#define ELFSTORE 1 ++#define ELFREAD 0 + +/* + * Determine whether a file is a xendump creation, and if TRUE, @@ -20941,6 +36023,8 @@ + + if (machine_type("X86") || machine_type("X86_64")) + xd->page_size = 4096; ++ else if (machine_type("IA64") && !machdep->pagesize) ++ xd->page_size = 16384; + else + xd->page_size = machdep->pagesize; + @@ -20963,14 +36047,18 @@ + + xcp = (struct xc_core_header *)buf; + -+ if (xcp->xch_magic != XC_CORE_MAGIC) ++ if (xc_core_elf_verify(buf)) ++ return TRUE; ++ ++ if ((xcp->xch_magic != XC_CORE_MAGIC) && ++ (xcp->xch_magic != XC_CORE_MAGIC_HVM)) + return FALSE; + + if (!xcp->xch_nr_vcpus) { + error(INFO, + "faulty xc_core dump file header: xch_nr_vcpus is 0\n\n"); + -+ fprintf(stderr, " xch_magic: %x (XC_CORE_MAGIC)\n", xcp->xch_magic); ++ fprintf(stderr, " xch_magic: %x\n", xcp->xch_magic); + fprintf(stderr, " xch_nr_vcpus: %d\n", xcp->xch_nr_vcpus); + fprintf(stderr, " xch_nr_pages: %d\n", xcp->xch_nr_pages); + fprintf(stderr, " xch_ctxt_offset: %d\n", xcp->xch_ctxt_offset); @@ -20983,7 +36071,10 @@ + BCOPY(xcp, &xd->xc_core.header, + sizeof(struct xc_core_header)); + -+ xd->flags |= (XENDUMP_LOCAL | XC_CORE); ++ xd->flags |= (XENDUMP_LOCAL | XC_CORE_ORIG | XC_CORE_P2M_CREATE); ++ ++ if (xc_core_mfns(XC_CORE_64BIT_HOST, stderr)) ++ xd->flags |= XC_CORE_64BIT_HOST; + + if (!xd->page_size) + error(FATAL, @@ -21014,8 +36105,8 @@ + off_t offset; + int redundant; + -+ if (!(xd->flags & XC_CORE_P2M_INIT)) -+ xc_core_p2m_create(); ++ if (xd->flags & (XC_CORE_P2M_CREATE|XC_CORE_PFN_CREATE)) ++ xc_core_create_pfn_tables(); + + pfn = (ulong)BTOP(paddr); + @@ -21026,6 +36117,7 @@ + if (read(xd->xfd, xd->page, xd->page_size) != + xd->page_size) + return READ_ERROR; ++ xd->last_pfn = pfn; + } + + BCOPY(xd->page + PAGEOFFSET(paddr), bufptr, cnt); @@ -21082,6 +36174,7 @@ + int i, batch_count, done_batch, *intptr; + ulong flags, *ulongptr; + ulong batch_index, total_pages_read; ++ ulong N; + + if (!STRNEQ(buf, XC_SAVE_SIGNATURE)) + return FALSE; @@ -21155,20 +36248,23 @@ + if (CRASHDEBUG(1)) { + for (i = 0; i < sizeof(ulong); i++) + fprintf(stderr, "[%x]", buf[i] & 0xff); -+ fprintf(stderr, ": %lx (native)\n", *ulongptr); ++ fprintf(stderr, ": %lx (nr_pfns)\n", *ulongptr); + } + + xd->xc_save.nr_pfns = *ulongptr; + ++ if (machine_type("IA64")) ++ goto xc_save_ia64; ++ + /* + * Get a local copy of the live_P2M_frame_list + */ + if (!(xd->xc_save.p2m_frame_list = (unsigned long *)malloc(P2M_FL_SIZE))) -+ error(FATAL, "Cannot allocate p2m_frame_list array"); ++ error(FATAL, "cannot allocate p2m_frame_list array"); + + if (!(xd->xc_save.batch_offsets = (off_t *)calloc((size_t)P2M_FL_ENTRIES, + sizeof(off_t)))) -+ error(FATAL, "Cannot allocate batch_offsets array"); ++ error(FATAL, "cannot allocate batch_offsets array"); + + xd->xc_save.batch_count = P2M_FL_ENTRIES; + @@ -21311,6 +36407,100 @@ + + return TRUE; + ++xc_save_ia64: ++ ++ /* ++ * Completely different format for ia64: ++ * ++ * ... ++ * pfn # ++ * page data ++ * pfn # ++ * page data ++ * ... ++ */ ++ free(xd->poc); ++ xd->poc = NULL; ++ free(xd->xc_save.region_pfn_type); ++ xd->xc_save.region_pfn_type = NULL; ++ ++ if (!(xd->xc_save.ia64_page_offsets = ++ (ulong *)calloc(xd->xc_save.nr_pfns, sizeof(off_t)))) ++ error(FATAL, "cannot allocate ia64_page_offsets array"); ++ ++ /* ++ * version ++ */ ++ if (read(xd->xfd, buf, sizeof(ulong)) != sizeof(ulong)) ++ goto xc_save_bailout; ++ ++ xd->xc_save.ia64_version = *((ulong *)buf); ++ ++ if (CRASHDEBUG(1)) ++ fprintf(stderr, "ia64 version: %lx\n", ++ xd->xc_save.ia64_version); ++ ++ /* ++ * xen_domctl_arch_setup structure ++ */ ++ if (read(xd->xfd, buf, sizeof(xen_domctl_arch_setup_t)) != ++ sizeof(xen_domctl_arch_setup_t)) ++ goto xc_save_bailout; ++ ++ if (CRASHDEBUG(1)) { ++ xen_domctl_arch_setup_t *setup = ++ (xen_domctl_arch_setup_t *)buf; ++ ++ fprintf(stderr, "xen_domctl_arch_setup:\n"); ++ fprintf(stderr, " flags: %lx\n", (ulong)setup->flags); ++ fprintf(stderr, " bp: %lx\n", (ulong)setup->bp); ++ fprintf(stderr, " maxmem: %lx\n", (ulong)setup->maxmem); ++ fprintf(stderr, " xsi_va: %lx\n", (ulong)setup->xsi_va); ++ fprintf(stderr, "hypercall_imm: %x\n", setup->hypercall_imm); ++ } ++ ++ for (i = N = 0; i < xd->xc_save.nr_pfns; i++) { ++ if (read(xd->xfd, &N, sizeof(N)) != sizeof(N)) ++ goto xc_save_bailout; ++ ++ if (N < xd->xc_save.nr_pfns) ++ xd->xc_save.ia64_page_offsets[N] = ++ lseek(xd->xfd, 0, SEEK_CUR); ++ else ++ error(WARNING, ++ "[%d]: pfn of %lx (0x%lx) in ia64 canonical page list exceeds %ld\n", ++ i, N, N, xd->xc_save.nr_pfns); ++ ++ if (CRASHDEBUG(1)) { ++ if ((i < 10) || (N >= (xd->xc_save.nr_pfns-10))) ++ fprintf(stderr, "[%d]: %ld\n%s", i, N, ++ i == 9 ? "...\n" : ""); ++ } ++ ++ if ((N+1) >= xd->xc_save.nr_pfns) ++ break; ++ ++ if (lseek(xd->xfd, xd->page_size, SEEK_CUR) == -1) ++ goto xc_save_bailout; ++ } ++ ++ if (CRASHDEBUG(1)) { ++ for (i = N = 0; i < xd->xc_save.nr_pfns; i++) { ++ if (!xd->xc_save.ia64_page_offsets[i]) ++ N++; ++ } ++ fprintf(stderr, "%ld out of %ld pfns not dumped\n", ++ N, xd->xc_save.nr_pfns); ++ } ++ ++ xd->flags |= (XENDUMP_LOCAL | flags | XC_SAVE_IA64); ++ kt->xen_flags |= (CANONICAL_PAGE_TABLES|XEN_SUSPEND); ++ ++ if (CRASHDEBUG(1)) ++ xendump_memory_dump(stderr); ++ ++ return TRUE; ++ +xc_save_bailout: + + error(INFO, @@ -21354,12 +36544,49 @@ + "xc_save_read(bufptr: %lx cnt: %d addr: %lx paddr: %llx (%ld, 0x%lx)\n", + (ulong)bufptr, cnt, addr, (ulonglong)paddr, reqpfn, reqpfn); + ++ if (xd->flags & XC_SAVE_IA64) { ++ if (reqpfn >= xd->xc_save.nr_pfns) { ++ if (CRASHDEBUG(1)) ++ fprintf(xd->ofp, ++ "xc_save_read: pfn %lx too large: nr_pfns: %lx\n", ++ reqpfn, xd->xc_save.nr_pfns); ++ return SEEK_ERROR; ++ } ++ ++ file_offset = xd->xc_save.ia64_page_offsets[reqpfn]; ++ if (!file_offset) { ++ if (CRASHDEBUG(1)) ++ fprintf(xd->ofp, ++ "xc_save_read: pfn %lx not stored in xendump\n", ++ reqpfn); ++ return SEEK_ERROR; ++ } ++ ++ if (reqpfn != xd->last_pfn) { ++ if (lseek(xd->xfd, file_offset, SEEK_SET) == -1) ++ return SEEK_ERROR; ++ ++ if (read(xd->xfd, xd->page, xd->page_size) != xd->page_size) ++ return READ_ERROR; ++ } else { ++ xd->redundant++; ++ xd->cache_hits++; ++ } ++ ++ xd->accesses++; ++ xd->last_pfn = reqpfn; ++ ++ BCOPY(xd->page + PAGEOFFSET(paddr), bufptr, cnt); ++ return cnt; ++ } ++ + if ((file_offset = poc_get(reqpfn, &redundant))) { + if (!redundant) { + if (lseek(xd->xfd, file_offset, SEEK_SET) == -1) + return SEEK_ERROR; + if (read(xd->xfd, xd->page, xd->page_size) != xd->page_size) + return READ_ERROR; ++ xd->last_pfn = reqpfn; + } else if (CRASHDEBUG(1)) + console("READ %ld (0x%lx) skipped!\n", reqpfn, reqpfn); + @@ -21513,7 +36740,6 @@ + if (poc->cnt && (poc->pfn == pfn)) { + poc->cnt++; + xd->cache_hits++; -+ xd->last_pfn = pfn; + return poc->file_offset; + } + } @@ -21541,12 +36767,13 @@ + if (pc->curcmd_flags & XEN_MACHINE_ADDR) + return READ_ERROR; + -+ switch (xd->flags & (XC_SAVE|XC_CORE)) ++ switch (xd->flags & (XC_SAVE|XC_CORE_ORIG|XC_CORE_ELF)) + { + case XC_SAVE: + return xc_save_read(bufptr, cnt, addr, paddr); + -+ case XC_CORE: ++ case XC_CORE_ORIG: ++ case XC_CORE_ELF: + return xc_core_read(bufptr, cnt, addr, paddr); + + default: @@ -21555,6 +36782,32 @@ +} + +int ++read_xendump_hyper(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) ++{ ++ ulong pfn, page_index; ++ off_t offset; ++ ++ pfn = (ulong)BTOP(paddr); ++ ++ /* ODA: pfn == mfn !!! */ ++ if ((page_index = xc_core_mfn_to_page_index(pfn)) == PFN_NOT_FOUND) ++ return READ_ERROR; ++ ++ offset = (off_t)xd->xc_core.header.xch_pages_offset + ++ ((off_t)(page_index) * (off_t)xd->page_size); ++ ++ if (lseek(xd->xfd, offset, SEEK_SET) == -1) ++ return SEEK_ERROR; ++ ++ if (read(xd->xfd, xd->page, xd->page_size) != xd->page_size) ++ return READ_ERROR; ++ ++ BCOPY(xd->page + PAGEOFFSET(paddr), bufptr, cnt); ++ ++ return cnt; ++} ++ ++int +write_xendump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) +{ + return WRITE_ERROR; @@ -21594,6 +36847,9 @@ +{ + int i, linefeed, used, others; + ulong *ulongptr; ++ Elf32_Off offset32; ++ Elf64_Off offset64; ++ FILE *fpsave; + + fprintf(fp, " flags: %lx (", xd->flags); + others = 0; @@ -21601,10 +36857,20 @@ + fprintf(fp, "%sXENDUMP_LOCAL", others++ ? "|" : ""); + if (xd->flags & XC_SAVE) + fprintf(fp, "%sXC_SAVE", others++ ? "|" : ""); -+ if (xd->flags & XC_CORE) -+ fprintf(fp, "%sXC_CORE", others++ ? "|" : ""); -+ if (xd->flags & XC_CORE_P2M_INIT) -+ fprintf(fp, "%sXC_CORE_P2M_INIT", others++ ? "|" : ""); ++ if (xd->flags & XC_CORE_ORIG) ++ fprintf(fp, "%sXC_CORE_ORIG", others++ ? "|" : ""); ++ if (xd->flags & XC_CORE_ELF) ++ fprintf(fp, "%sXC_CORE_ELF", others++ ? "|" : ""); ++ if (xd->flags & XC_CORE_P2M_CREATE) ++ fprintf(fp, "%sXC_CORE_P2M_CREATE", others++ ? "|" : ""); ++ if (xd->flags & XC_CORE_PFN_CREATE) ++ fprintf(fp, "%sXC_CORE_PFN_CREATE", others++ ? "|" : ""); ++ if (xd->flags & XC_CORE_NO_P2M) ++ fprintf(fp, "%sXC_CORE_NO_P2M", others++ ? "|" : ""); ++ if (xd->flags & XC_SAVE_IA64) ++ fprintf(fp, "%sXC_SAVE_IA64", others++ ? "|" : ""); ++ if (xd->flags & XC_CORE_64BIT_HOST) ++ fprintf(fp, "%sXC_CORE_64BIT_HOST", others++ ? "|" : ""); + fprintf(fp, ")\n"); + fprintf(fp, " xfd: %d\n", xd->xfd); + fprintf(fp, " page_size: %d\n", xd->page_size); @@ -21625,10 +36891,13 @@ + else + fprintf(fp, "\n"); + for (i = used = 0; i < PFN_TO_OFFSET_CACHE_ENTRIES; i++) -+ if (xd->poc[i].cnt) ++ if (xd->poc && xd->poc[i].cnt) + used++; -+ fprintf(fp, " poc[%d]: %lx %s", PFN_TO_OFFSET_CACHE_ENTRIES, (ulong)xd->poc, -+ xd->poc ? "" : "(none)"); ++ if (xd->poc) ++ fprintf(fp, " poc[%d]: %lx %s", PFN_TO_OFFSET_CACHE_ENTRIES, ++ (ulong)xd->poc, xd->poc ? "" : "(none)"); ++ else ++ fprintf(fp, " poc[0]: (unused)\n"); + for (i = 0; i < PFN_TO_OFFSET_CACHE_ENTRIES; i++) { + if (!xd->poc) + break; @@ -21638,17 +36907,19 @@ + break; + } else if (!i) + fprintf(fp, "(%d used)\n", used); -+ fprintf(fp, " [%d]: pfn: %ld (0x%lx) count: %ld file_offset: %llx\n", -+ i, -+ xd->poc[i].pfn, -+ xd->poc[i].pfn, -+ xd->poc[i].cnt, -+ (ulonglong)xd->poc[i].file_offset); ++ if (CRASHDEBUG(2)) ++ fprintf(fp, ++ " [%d]: pfn: %ld (0x%lx) count: %ld file_offset: %llx\n", ++ i, ++ xd->poc[i].pfn, ++ xd->poc[i].pfn, ++ xd->poc[i].cnt, ++ (ulonglong)xd->poc[i].file_offset); + } + if (!xd->poc) + fprintf(fp, "\n"); + -+ fprintf(fp, " xc_save:\n"); ++ fprintf(fp, "\n xc_save:\n"); + fprintf(fp, " nr_pfns: %ld (0x%lx)\n", + xd->xc_save.nr_pfns, xd->xc_save.nr_pfns); + fprintf(fp, " vmconfig_size: %d (0x%x)\n", xd->xc_save.vmconfig_size, @@ -21657,7 +36928,7 @@ + if (xd->flags & XC_SAVE) + xen_dump_vmconfig(fp); + fprintf(fp, " p2m_frame_list: %lx ", (ulong)xd->xc_save.p2m_frame_list); -+ if (xd->flags & XC_SAVE) { ++ if ((xd->flags & XC_SAVE) && xd->xc_save.p2m_frame_list) { + fprintf(fp, "\n"); + ulongptr = xd->xc_save.p2m_frame_list; + for (i = 0; i < P2M_FL_ENTRIES; i++, ulongptr++) @@ -21688,13 +36959,23 @@ + } + if (linefeed) + fprintf(fp, "\n"); ++ fprintf(fp, " ia64_version: %ld\n", (ulong)xd->xc_save.ia64_version); ++ fprintf(fp, " ia64_page_offsets: %lx ", (ulong)xd->xc_save.ia64_page_offsets); ++ if (xd->xc_save.ia64_page_offsets) ++ fprintf(fp, "(%ld entries)\n\n", xd->xc_save.nr_pfns); ++ else ++ fprintf(fp, "(none)\n\n"); + + fprintf(fp, " xc_core:\n"); + fprintf(fp, " header:\n"); -+ fprintf(fp, " xch_magic: %x (%s)\n", -+ xd->xc_core.header.xch_magic, -+ xd->xc_core.header.xch_magic == XC_CORE_MAGIC ? -+ "XC_CORE_MAGIC" : "unknown"); ++ fprintf(fp, " xch_magic: %x ", ++ xd->xc_core.header.xch_magic); ++ if (xd->xc_core.header.xch_magic == XC_CORE_MAGIC) ++ fprintf(fp, "(XC_CORE_MAGIC)\n"); ++ else if (xd->xc_core.header.xch_magic == XC_CORE_MAGIC_HVM) ++ fprintf(fp, "(XC_CORE_MAGIC_HVM)\n"); ++ else ++ fprintf(fp, "(unknown)\n"); + fprintf(fp, " xch_nr_vcpus: %d\n", + xd->xc_core.header.xch_nr_vcpus); + fprintf(fp, " xch_nr_pages: %d (0x%x)\n", @@ -21710,14 +36991,89 @@ + xd->xc_core.header.xch_pages_offset, + xd->xc_core.header.xch_pages_offset); + ++ fprintf(fp, " elf_class: %s\n", xd->xc_core.elf_class == ELFCLASS64 ? "ELFCLASS64" : ++ xd->xc_core.elf_class == ELFCLASS32 ? "ELFCLASS32" : "n/a"); ++ fprintf(fp, " elf_strtab_offset: %lld (0x%llx)\n", ++ (ulonglong)xd->xc_core.elf_strtab_offset, ++ (ulonglong)xd->xc_core.elf_strtab_offset); ++ fprintf(fp, " format_version: %016llx\n", ++ (ulonglong)xd->xc_core.format_version); ++ fprintf(fp, " shared_info_offset: %lld (0x%llx)\n", ++ (ulonglong)xd->xc_core.shared_info_offset, ++ (ulonglong)xd->xc_core.shared_info_offset); ++ if (machine_type("IA64")) ++ fprintf(fp, " ia64_mapped_regs_offset: %lld (0x%llx)\n", ++ (ulonglong)xd->xc_core.ia64_mapped_regs_offset, ++ (ulonglong)xd->xc_core.ia64_mapped_regs_offset); ++ fprintf(fp, " elf_index_pfn[%d]: %s", INDEX_PFN_COUNT, ++ xd->xc_core.elf_class ? "\n" : "(none used)\n"); ++ if (xd->xc_core.elf_class) { ++ for (i = 0; i < INDEX_PFN_COUNT; i++) { ++ fprintf(fp, "%ld:%ld ", ++ xd->xc_core.elf_index_pfn[i].index, ++ xd->xc_core.elf_index_pfn[i].pfn); ++ } ++ fprintf(fp, "\n"); ++ } ++ fprintf(fp, " last_batch:\n"); ++ fprintf(fp, " index: %ld (%ld - %ld)\n", ++ xd->xc_core.last_batch.index, ++ xd->xc_core.last_batch.start, xd->xc_core.last_batch.end); ++ fprintf(fp, " accesses: %ld\n", ++ xd->xc_core.last_batch.accesses); ++ fprintf(fp, " duplicates: %ld ", ++ xd->xc_core.last_batch.duplicates); ++ if (xd->xc_core.last_batch.accesses) ++ fprintf(fp, "(%ld%%)\n", ++ xd->xc_core.last_batch.duplicates * 100 / ++ xd->xc_core.last_batch.accesses); ++ else ++ fprintf(fp, "\n"); ++ ++ fprintf(fp, " elf32: %lx\n", (ulong)xd->xc_core.elf32); ++ fprintf(fp, " elf64: %lx\n", (ulong)xd->xc_core.elf64); ++ + fprintf(fp, " p2m_frames: %d\n", + xd->xc_core.p2m_frames); -+ fprintf(fp, " p2m_frame_index_list:\n"); ++ fprintf(fp, " p2m_frame_index_list: %s\n", ++ (xd->flags & (XC_CORE_NO_P2M|XC_SAVE)) ? "(not used)" : ""); + for (i = 0; i < xd->xc_core.p2m_frames; i++) { + fprintf(fp, "%ld ", + xd->xc_core.p2m_frame_index_list[i]); + } -+ fprintf(fp, xd->xc_core.p2m_frames ? "\n\n" : "\n"); ++ fprintf(fp, xd->xc_core.p2m_frames ? "\n" : ""); ++ ++ if ((xd->flags & XC_CORE_ORIG) && CRASHDEBUG(8)) ++ xc_core_mfns(XENDUMP_LOCAL, fp); ++ ++ switch (xd->xc_core.elf_class) ++ { ++ case ELFCLASS32: ++ fpsave = xd->ofp; ++ xd->ofp = fp; ++ xc_core_elf_dump(); ++ offset32 = xd->xc_core.elf32->e_shoff; ++ for (i = 0; i < xd->xc_core.elf32->e_shnum; i++) { ++ xc_core_dump_Elf32_Shdr(offset32, ELFREAD); ++ offset32 += xd->xc_core.elf32->e_shentsize; ++ } ++ xendump_print("\n"); ++ xd->ofp = fpsave; ++ break; ++ ++ case ELFCLASS64: ++ fpsave = xd->ofp; ++ xd->ofp = fp; ++ xc_core_elf_dump(); ++ offset64 = xd->xc_core.elf64->e_shoff; ++ for (i = 0; i < xd->xc_core.elf64->e_shnum; i++) { ++ xc_core_dump_Elf64_Shdr(offset64, ELFREAD); ++ offset64 += xd->xc_core.elf64->e_shentsize; ++ } ++ xendump_print("\n"); ++ xd->ofp = fpsave; ++ break; ++ } + + return 0; +} @@ -21757,9 +37113,10 @@ + ulong task; + struct task_context *tc; + -+ switch (xd->flags & (XC_CORE|XC_SAVE)) ++ switch (xd->flags & (XC_CORE_ORIG|XC_CORE_ELF|XC_SAVE)) + { -+ case XC_CORE: ++ case XC_CORE_ORIG: ++ case XC_CORE_ELF: + if (machdep->xendump_panic_task) + return (machdep->xendump_panic_task((void *)xd)); + break; @@ -21794,9 +37151,10 @@ + return; + } + -+ switch (xd->flags & (XC_CORE|XC_SAVE)) ++ switch (xd->flags & (XC_CORE_ORIG|XC_CORE_ELF|XC_SAVE)) + { -+ case XC_CORE: ++ case XC_CORE_ORIG: ++ case XC_CORE_ELF: + if (machdep->get_xendump_regs) + return (machdep->get_xendump_regs(xd, bt, pc, sp)); + break; @@ -21827,20 +37185,26 @@ +} + +/* -+ * Farm out most of the work to the proper architecture. ++ * Farm out most of the work to the proper architecture to create ++ * the p2m table. For ELF core dumps, create the index;pfn table. + */ +static void -+xc_core_p2m_create(void) ++xc_core_create_pfn_tables(void) +{ -+ if (!machdep->xendump_p2m_create) -+ error(FATAL, -+ "xen xc_core dumpfiles not supported on this architecture"); ++ if (xd->flags & XC_CORE_P2M_CREATE) { ++ if (!machdep->xendump_p2m_create) ++ error(FATAL, ++ "xen xc_core dumpfiles not supported on this architecture"); ++ ++ if (!machdep->xendump_p2m_create((void *)xd)) ++ error(FATAL, ++ "cannot create xen pfn-to-mfn mapping\n"); ++ } + -+ if (!machdep->xendump_p2m_create((void *)xd)) -+ error(FATAL, -+ "cannot create xen pfn-to-mfn mapping\n"); ++ if (xd->flags & XC_CORE_ELF) ++ xc_core_elf_pfn_init(); + -+ xd->flags |= XC_CORE_P2M_INIT; ++ xd->flags &= ~(XC_CORE_P2M_CREATE|XC_CORE_PFN_CREATE); + + if (CRASHDEBUG(1)) + xendump_memory_dump(xd->ofp); @@ -21856,6 +37220,10 @@ + int i, b, idx, done; + ulong tmp[MAX_BATCH_SIZE]; + off_t offset; ++ uint nr_pages; ++ ++ if (xd->flags & XC_CORE_ELF) ++ return xc_core_elf_mfn_to_page(mfn, pgbuf); + + if (lseek(xd->xfd, (off_t)xd->xc_core.header.xch_index_offset, + SEEK_SET) == -1) { @@ -21863,9 +37231,12 @@ + return NULL; + } + ++ nr_pages = xd->xc_core.header.xch_nr_pages; ++ if (xd->flags & XC_CORE_64BIT_HOST) ++ nr_pages *= 2; ++ + for (b = 0, idx = -1, done = FALSE; -+ !done && (b < xd->xc_core.header.xch_nr_pages); -+ b += MAX_BATCH_SIZE) { ++ !done && (b < nr_pages); b += MAX_BATCH_SIZE) { + + if (read(xd->xfd, tmp, sizeof(ulong) * MAX_BATCH_SIZE) != + (MAX_BATCH_SIZE * sizeof(ulong))) { @@ -21874,13 +37245,13 @@ + } + + for (i = 0; i < MAX_BATCH_SIZE; i++) { -+ if ((b+i) >= xd->xc_core.header.xch_nr_pages) { ++ if ((b+i) >= nr_pages) { + done = TRUE; + break; + } + if (tmp[i] == mfn) { + idx = i+b; -+ if (CRASHDEBUG(2)) ++ if (CRASHDEBUG(4)) + fprintf(xd->ofp, + "page: found mfn 0x%lx (%ld) at index %d\n", + mfn, mfn, idx); @@ -21916,6 +37287,79 @@ + return pgbuf; +} + ++/* ++ * Find the page index containing the mfn, and read the ++ * machine page into the buffer. ++ */ ++static char * ++xc_core_elf_mfn_to_page(ulong mfn, char *pgbuf) ++{ ++ int i, b, idx, done; ++ off_t offset; ++ size_t size; ++ uint nr_pages; ++ ulong tmp; ++ struct xen_dumpcore_p2m p2m_batch[MAX_BATCH_SIZE]; ++ ++ offset = xd->xc_core.header.xch_index_offset; ++ size = sizeof(struct xen_dumpcore_p2m) * MAX_BATCH_SIZE; ++ nr_pages = xd->xc_core.header.xch_nr_pages; ++ ++ if (lseek(xd->xfd, offset, SEEK_SET) == -1) ++ error(FATAL, "cannot lseek to page index\n"); ++ ++ for (b = 0, idx = -1, done = FALSE; ++ !done && (b < nr_pages); b += MAX_BATCH_SIZE) { ++ ++ if (read(xd->xfd, &p2m_batch[0], size) != size) { ++ error(INFO, "cannot read index page %d\n", b); ++ return NULL; ++ } ++ ++ for (i = 0; i < MAX_BATCH_SIZE; i++) { ++ if ((b+i) >= nr_pages) { ++ done = TRUE; ++ break; ++ } ++ ++ tmp = (ulong)p2m_batch[i].gmfn; ++ ++ if (tmp == mfn) { ++ idx = i+b; ++ if (CRASHDEBUG(4)) ++ fprintf(xd->ofp, ++ "page: found mfn 0x%lx (%ld) at index %d\n", ++ mfn, mfn, idx); ++ done = TRUE; ++ } ++ } ++ } ++ ++ if (idx == -1) { ++ error(INFO, "cannot find mfn %ld (0x%lx) in page index\n", ++ mfn, mfn); ++ return NULL; ++ } ++ ++ if (lseek(xd->xfd, (off_t)xd->xc_core.header.xch_pages_offset, ++ SEEK_SET) == -1) ++ error(FATAL, "cannot lseek to xch_pages_offset\n"); ++ ++ offset = (off_t)(idx) * (off_t)xd->page_size; ++ ++ if (lseek(xd->xfd, offset, SEEK_CUR) == -1) { ++ error(INFO, "cannot lseek to mfn-specified page\n"); ++ return NULL; ++ } ++ ++ if (read(xd->xfd, pgbuf, xd->page_size) != xd->page_size) { ++ error(INFO, "cannot read mfn-specified page\n"); ++ return NULL; ++ } ++ ++ return pgbuf; ++} ++ + +/* + * Find and return the page index containing the mfn. @@ -21925,6 +37369,10 @@ +{ + int i, b; + ulong tmp[MAX_BATCH_SIZE]; ++ uint nr_pages; ++ ++ if (xd->flags & XC_CORE_ELF) ++ return xc_core_elf_mfn_to_page_index(mfn); + + if (lseek(xd->xfd, (off_t)xd->xc_core.header.xch_index_offset, + SEEK_SET) == -1) { @@ -21932,7 +37380,11 @@ + return MFN_NOT_FOUND; + } + -+ for (b = 0; b < xd->xc_core.header.xch_nr_pages; b += MAX_BATCH_SIZE) { ++ nr_pages = xd->xc_core.header.xch_nr_pages; ++ if (xd->flags & XC_CORE_64BIT_HOST) ++ nr_pages *= 2; ++ ++ for (b = 0; b < nr_pages; b += MAX_BATCH_SIZE) { + + if (read(xd->xfd, tmp, sizeof(ulong) * MAX_BATCH_SIZE) != + (MAX_BATCH_SIZE * sizeof(ulong))) { @@ -21941,11 +37393,11 @@ + } + + for (i = 0; i < MAX_BATCH_SIZE; i++) { -+ if ((b+i) >= xd->xc_core.header.xch_nr_pages) ++ if ((b+i) >= nr_pages) + break; + + if (tmp[i] == mfn) { -+ if (CRASHDEBUG(2)) ++ if (CRASHDEBUG(4)) + fprintf(xd->ofp, + "index: batch: %d found mfn %ld (0x%lx) at index %d\n", + b/MAX_BATCH_SIZE, mfn, mfn, i+b); @@ -21958,6 +37410,169 @@ +} + +/* ++ * Find and return the page index containing the mfn. ++ */ ++static int ++xc_core_elf_mfn_to_page_index(ulong mfn) ++{ ++ int i, b; ++ off_t offset; ++ size_t size; ++ uint nr_pages; ++ ulong tmp; ++ struct xen_dumpcore_p2m p2m_batch[MAX_BATCH_SIZE]; ++ ++ offset = xd->xc_core.header.xch_index_offset; ++ size = sizeof(struct xen_dumpcore_p2m) * MAX_BATCH_SIZE; ++ nr_pages = xd->xc_core.header.xch_nr_pages; ++ ++ if (lseek(xd->xfd, offset, SEEK_SET) == -1) ++ error(FATAL, "cannot lseek to page index\n"); ++ ++ for (b = 0; b < nr_pages; b += MAX_BATCH_SIZE) { ++ ++ if (read(xd->xfd, &p2m_batch[0], size) != size) { ++ error(INFO, "cannot read index page %d\n", b); ++ return MFN_NOT_FOUND; ++ } ++ ++ for (i = 0; i < MAX_BATCH_SIZE; i++) { ++ if ((b+i) >= nr_pages) ++ break; ++ ++ tmp = (ulong)p2m_batch[i].gmfn; ++ ++ if (tmp == mfn) { ++ if (CRASHDEBUG(4)) ++ fprintf(xd->ofp, ++ "index: batch: %d found mfn %ld (0x%lx) at index %d\n", ++ b/MAX_BATCH_SIZE, mfn, mfn, i+b); ++ return (i+b); ++ } ++ } ++ } ++ ++ return MFN_NOT_FOUND; ++} ++ ++ ++/* ++ * XC_CORE mfn-related utility function. ++ */ ++static int ++xc_core_mfns(ulong arg, FILE *ofp) ++{ ++ int i, b; ++ uint nr_pages; ++ ulong tmp[MAX_BATCH_SIZE]; ++ ulonglong tmp64[MAX_BATCH_SIZE]; ++ ++ if (lseek(xd->xfd, (off_t)xd->xc_core.header.xch_index_offset, ++ SEEK_SET) == -1) { ++ error(INFO, "cannot lseek to page index\n"); ++ return FALSE; ++ } ++ ++ switch (arg) ++ { ++ case XC_CORE_64BIT_HOST: ++ /* ++ * Determine whether this is a 32-bit guest xendump that ++ * was taken on a 64-bit xen host. ++ */ ++ if (machine_type("X86_64") || machine_type("IA64")) ++ return FALSE; ++check_next_4: ++ if (read(xd->xfd, tmp, sizeof(ulong) * 4) != (4 * sizeof(ulong))) { ++ error(INFO, "cannot read index pages\n"); ++ return FALSE; ++ } ++ ++ if ((tmp[0] == 0xffffffff) || (tmp[1] == 0xffffffff) || ++ (tmp[2] == 0xffffffff) || (tmp[3] == 0xffffffff) || ++ (!tmp[0] && !tmp[1]) || (!tmp[2] && !tmp[3])) ++ goto check_next_4; ++ ++ if (CRASHDEBUG(2)) ++ fprintf(ofp, "mfns: %08lx %08lx %08lx %08lx\n", ++ tmp[0], tmp[1], tmp[2], tmp[3]); ++ ++ if (tmp[0] && !tmp[1] && tmp[2] && !tmp[3]) ++ return TRUE; ++ else ++ return FALSE; ++ ++ case XENDUMP_LOCAL: ++ if (BITS64() || (xd->flags & XC_CORE_64BIT_HOST)) ++ goto show_64bit_mfns; ++ ++ fprintf(ofp, "xch_index_offset mfn list:\n"); ++ ++ nr_pages = xd->xc_core.header.xch_nr_pages; ++ ++ for (b = 0; b < nr_pages; b += MAX_BATCH_SIZE) { ++ if (read(xd->xfd, tmp, sizeof(ulong) * MAX_BATCH_SIZE) != ++ (MAX_BATCH_SIZE * sizeof(ulong))) { ++ error(INFO, "cannot read index page %d\n", b); ++ return FALSE; ++ } ++ ++ if (b) fprintf(ofp, "\n"); ++ ++ for (i = 0; i < MAX_BATCH_SIZE; i++) { ++ if ((b+i) >= nr_pages) ++ break; ++ if ((i%8) == 0) ++ fprintf(ofp, "%s[%d]:", ++ i ? "\n" : "", b+i); ++ if (tmp[i] == 0xffffffff) ++ fprintf(ofp, " INVALID"); ++ else ++ fprintf(ofp, " %lx", tmp[i]); ++ } ++ } ++ ++ fprintf(ofp, "\nxch_nr_pages: %d\n", ++ xd->xc_core.header.xch_nr_pages); ++ return TRUE; ++ ++show_64bit_mfns: ++ fprintf(ofp, "xch_index_offset mfn list: %s\n", ++ BITS32() ? "(64-bit mfns)" : ""); ++ ++ nr_pages = xd->xc_core.header.xch_nr_pages; ++ ++ for (b = 0; b < nr_pages; b += MAX_BATCH_SIZE) { ++ if (read(xd->xfd, tmp64, sizeof(ulonglong) * MAX_BATCH_SIZE) != ++ (MAX_BATCH_SIZE * sizeof(ulonglong))) { ++ error(INFO, "cannot read index page %d\n", b); ++ return FALSE; ++ } ++ ++ if (b) fprintf(ofp, "\n"); ++ ++ for (i = 0; i < MAX_BATCH_SIZE; i++) { ++ if ((b+i) >= nr_pages) ++ break; ++ if ((i%8) == 0) ++ fprintf(ofp, "%s[%d]:", ++ i ? "\n" : "", b+i); ++ if (tmp64[i] == 0xffffffffffffffffULL) ++ fprintf(ofp, " INVALID"); ++ else ++ fprintf(ofp, " %llx", tmp64[i]); ++ } ++ } ++ ++ fprintf(ofp, "\nxch_nr_pages: %d\n", nr_pages); ++ return TRUE; ++ ++ default: ++ return FALSE; ++ } ++} ++ ++/* + * Given a normal kernel pfn, determine the page index in the dumpfile. + * + * - First determine which of the pages making up the @@ -21965,7 +37580,6 @@ + * - From the phys_to_machine_mapping page, determine the mfn. + * - Find the mfn in the dumpfile page index. + */ -+ +#define PFNS_PER_PAGE (xd->page_size/sizeof(unsigned long)) + +static ulong @@ -21975,6 +37589,22 @@ + ulong *up, mfn; + off_t offset; + ++ /* ++ * This function does not apply when there's no p2m ++ * mapping and/or if this is an ELF format dumpfile. ++ */ ++ switch (xd->flags & (XC_CORE_NO_P2M|XC_CORE_ELF)) ++ { ++ case (XC_CORE_NO_P2M|XC_CORE_ELF): ++ return xc_core_elf_pfn_valid(pfn); ++ ++ case XC_CORE_NO_P2M: ++ return(xc_core_pfn_valid(pfn) ? pfn : PFN_NOT_FOUND); ++ ++ case XC_CORE_ELF: ++ return xc_core_elf_pfn_to_page_index(pfn); ++ } ++ + idx = pfn/PFNS_PER_PAGE; + + if (idx >= xd->xc_core.p2m_frames) { @@ -22016,6 +37646,213 @@ + return mfn_idx; +} + ++ ++/* ++ * Search the .xen_p2m array for the target pfn, starting at a ++ * higher batch if appropriate. This presumes that the pfns ++ * are laid out in ascending order. ++ */ ++static ulong ++xc_core_elf_pfn_to_page_index(ulong pfn) ++{ ++ int i, b, start_index; ++ off_t offset; ++ size_t size; ++ uint nr_pages; ++ ulong tmp; ++ struct xen_dumpcore_p2m p2m_batch[MAX_BATCH_SIZE]; ++ ++ offset = xd->xc_core.header.xch_index_offset; ++ size = sizeof(struct xen_dumpcore_p2m) * MAX_BATCH_SIZE; ++ nr_pages = xd->xc_core.header.xch_nr_pages; ++ ++ /* ++ * Initialize the start_index. ++ */ ++ xd->xc_core.last_batch.accesses++; ++ ++ if ((pfn >= xd->xc_core.last_batch.start) && ++ (pfn <= xd->xc_core.last_batch.end)) { ++ xd->xc_core.last_batch.duplicates++; ++ start_index = xd->xc_core.last_batch.index; ++ } else { ++ for (i = 0; i <= INDEX_PFN_COUNT; i++) { ++ if ((i == INDEX_PFN_COUNT) || ++ (pfn < xd->xc_core.elf_index_pfn[i].pfn)) { ++ if (--i < 0) ++ i = 0; ++ start_index = xd->xc_core.elf_index_pfn[i].index; ++ break; ++ } ++ } ++ } ++ ++ offset += (start_index * sizeof(struct xen_dumpcore_p2m)); ++ if (lseek(xd->xfd, offset, SEEK_SET) == -1) ++ error(FATAL, "cannot lseek to page index\n"); ++ ++ for (b = start_index; b < nr_pages; b += MAX_BATCH_SIZE) { ++ ++ if (read(xd->xfd, &p2m_batch[0], size) != size) { ++ error(INFO, "cannot read index page %d\n", b); ++ return PFN_NOT_FOUND; ++ } ++ ++ for (i = 0; i < MAX_BATCH_SIZE; i++) { ++ if ((b+i) >= nr_pages) ++ break; ++ ++ tmp = (ulong)p2m_batch[i].pfn; ++ ++ if (tmp == pfn) { ++ if (CRASHDEBUG(4)) ++ fprintf(xd->ofp, ++ "index: batch: %d found pfn %ld (0x%lx) at index %d\n", ++ b/MAX_BATCH_SIZE, pfn, pfn, i+b); ++ ++ if ((b+MAX_BATCH_SIZE) < nr_pages) { ++ xd->xc_core.last_batch.index = b; ++ xd->xc_core.last_batch.start = p2m_batch[0].pfn; ++ xd->xc_core.last_batch.end = p2m_batch[MAX_BATCH_SIZE-1].pfn; ++ } ++ ++ return (i+b); ++ } ++ } ++ } ++ ++ return PFN_NOT_FOUND; ++} ++ ++/* ++ * In xendumps containing INVALID_MFN markers in the page index, ++ * return the validity of the pfn. ++ */ ++static int ++xc_core_pfn_valid(ulong pfn) ++{ ++ ulong mfn; ++ off_t offset; ++ ++ if (pfn >= (ulong)xd->xc_core.header.xch_nr_pages) ++ return FALSE; ++ ++ offset = (off_t)xd->xc_core.header.xch_index_offset; ++ ++ if (xd->flags & XC_CORE_64BIT_HOST) ++ offset += (off_t)(pfn * sizeof(ulonglong)); ++ else ++ offset += (off_t)(pfn * sizeof(ulong)); ++ ++ /* ++ * The lseek and read should never fail, so report ++ * any errors unconditionally. ++ */ ++ if (lseek(xd->xfd, offset, SEEK_SET) == -1) { ++ error(INFO, ++ "xendump: cannot lseek to page index for pfn %lx\n", ++ pfn); ++ return FALSE; ++ } ++ ++ if (read(xd->xfd, &mfn, sizeof(ulong)) != sizeof(ulong)) { ++ error(INFO, ++ "xendump: cannot read index page for pfn %lx\n", ++ pfn); ++ return FALSE; ++ } ++ ++ /* ++ * If it's an invalid mfn, let the caller decide whether ++ * to display an error message (unless debugging). ++ */ ++ if (mfn == INVALID_MFN) { ++ if (CRASHDEBUG(1)) ++ error(INFO, ++ "xendump: pfn %lx contains INVALID_MFN\n", ++ pfn); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++/* ++ * Return the index into the .xen_pfn array containing the pfn. ++ * If not found, return PFN_NOT_FOUND. ++ */ ++static ulong ++xc_core_elf_pfn_valid(ulong pfn) ++{ ++ int i, b, start_index; ++ off_t offset; ++ size_t size; ++ uint nr_pages; ++ ulong tmp; ++ uint64_t pfn_batch[MAX_BATCH_SIZE]; ++ ++ offset = xd->xc_core.header.xch_index_offset; ++ size = sizeof(uint64_t) * MAX_BATCH_SIZE; ++ nr_pages = xd->xc_core.header.xch_nr_pages; ++ ++ /* ++ * Initialize the start_index. ++ */ ++ xd->xc_core.last_batch.accesses++; ++ ++ if ((pfn >= xd->xc_core.last_batch.start) && ++ (pfn <= xd->xc_core.last_batch.end)) { ++ xd->xc_core.last_batch.duplicates++; ++ start_index = xd->xc_core.last_batch.index; ++ } else { ++ for (i = 0; i <= INDEX_PFN_COUNT; i++) { ++ if ((i == INDEX_PFN_COUNT) || ++ (pfn < xd->xc_core.elf_index_pfn[i].pfn)) { ++ if (--i < 0) ++ i = 0; ++ start_index = xd->xc_core.elf_index_pfn[i].index; ++ break; ++ } ++ } ++ } ++ ++ offset += (start_index * sizeof(uint64_t)); ++ if (lseek(xd->xfd, offset, SEEK_SET) == -1) ++ error(FATAL, "cannot lseek to page index\n"); ++ ++ for (b = start_index; b < nr_pages; b += MAX_BATCH_SIZE) { ++ ++ if (read(xd->xfd, &pfn_batch[0], size) != size) { ++ error(INFO, "cannot read index page %d\n", b); ++ return PFN_NOT_FOUND; ++ } ++ ++ for (i = 0; i < MAX_BATCH_SIZE; i++) { ++ if ((b+i) >= nr_pages) ++ break; ++ ++ tmp = (ulong)pfn_batch[i]; ++ ++ if (tmp == pfn) { ++ if (CRASHDEBUG(4)) ++ fprintf(xd->ofp, ++ "index: batch: %d found pfn %ld (0x%lx) at index %d\n", ++ b/MAX_BATCH_SIZE, pfn, pfn, i+b); ++ ++ if ((b+MAX_BATCH_SIZE) < nr_pages) { ++ xd->xc_core.last_batch.index = b; ++ xd->xc_core.last_batch.start = (ulong)pfn_batch[0]; ++ xd->xc_core.last_batch.end = (ulong)pfn_batch[MAX_BATCH_SIZE-1]; ++ } ++ ++ return (i+b); ++ } ++ } ++ } ++ ++ return PFN_NOT_FOUND; ++} ++ +/* + * Store the panic task's stack hooks from where it was found + * in get_active_set_panic_task(). @@ -22028,6 +37865,9 @@ + char buf[BUFSIZE]; + ulong value, *sp; + ++ if (machine_type("IA64")) /* needs switch_stack address */ ++ return; ++ + strcpy(buf, stack); + + argc = parse_line(buf, arglist); @@ -22055,9 +37895,917 @@ + } + } +} ---- crash/unwind.c.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/unwind.c 2005-11-23 09:40:14.000000000 -0500 -@@ -1397,9 +1397,22 @@ ++ ++static void ++xendump_print(char *fmt, ...) ++{ ++ char buf[BUFSIZE]; ++ va_list ap; ++ ++ if (!fmt || !strlen(fmt)) ++ return; ++ ++ va_start(ap, fmt); ++ (void)vsnprintf(buf, BUFSIZE, fmt, ap); ++ va_end(ap); ++ ++ if (xd->ofp) ++ fprintf(xd->ofp, buf); ++ else if (!XENDUMP_VALID() && CRASHDEBUG(7)) ++ fprintf(stderr, buf); ++ ++} ++ ++/* ++ * Support for xc_core ELF dumpfile format. ++ */ ++static int ++xc_core_elf_verify(char *buf) ++{ ++ int i; ++ Elf32_Ehdr *elf32; ++ Elf64_Ehdr *elf64; ++ Elf32_Off offset32; ++ Elf64_Off offset64; ++ ++ elf32 = (Elf32_Ehdr *)buf; ++ elf64 = (Elf64_Ehdr *)buf; ++ ++ if (STRNEQ(elf32->e_ident, ELFMAG) && ++ (elf32->e_ident[EI_CLASS] == ELFCLASS32) && ++ (elf32->e_ident[EI_DATA] == ELFDATA2LSB) && ++ (elf32->e_ident[EI_VERSION] == EV_CURRENT) && ++ (elf32->e_type == ET_CORE) && ++ (elf32->e_version == EV_CURRENT) && ++ (elf32->e_shnum > 0)) { ++ switch (elf32->e_machine) ++ { ++ case EM_386: ++ if (machine_type("X86")) ++ break; ++ default: ++ goto bailout; ++ } ++ ++ xd->xc_core.elf_class = ELFCLASS32; ++ if ((xd->xc_core.elf32 = (Elf32_Ehdr *)malloc(sizeof(Elf32_Ehdr))) == NULL) { ++ fprintf(stderr, "cannot malloc ELF header buffer\n"); ++ clean_exit(1); ++ } ++ BCOPY(buf, xd->xc_core.elf32, sizeof(Elf32_Ehdr)); ++ ++ } else if (STRNEQ(elf64->e_ident, ELFMAG) && ++ (elf64->e_ident[EI_CLASS] == ELFCLASS64) && ++ (elf64->e_ident[EI_VERSION] == EV_CURRENT) && ++ (elf64->e_type == ET_CORE) && ++ (elf64->e_version == EV_CURRENT) && ++ (elf64->e_shnum > 0)) { ++ switch (elf64->e_machine) ++ { ++ case EM_IA_64: ++ if ((elf64->e_ident[EI_DATA] == ELFDATA2LSB) && ++ machine_type("IA64")) ++ break; ++ else ++ goto bailout; ++ ++ case EM_X86_64: ++ if ((elf64->e_ident[EI_DATA] == ELFDATA2LSB) && ++ machine_type("X86_64")) ++ break; ++ else ++ goto bailout; ++ ++ case EM_386: ++ if ((elf64->e_ident[EI_DATA] == ELFDATA2LSB) && ++ machine_type("X86")) ++ break; ++ else ++ goto bailout; ++ ++ default: ++ goto bailout; ++ } ++ ++ xd->xc_core.elf_class = ELFCLASS64; ++ if ((xd->xc_core.elf64 = (Elf64_Ehdr *)malloc(sizeof(Elf64_Ehdr))) == NULL) { ++ fprintf(stderr, "cannot malloc ELF header buffer\n"); ++ clean_exit(1); ++ } ++ BCOPY(buf, xd->xc_core.elf64, sizeof(Elf64_Ehdr)); ++ ++ } else { ++ if (CRASHDEBUG(1)) ++ error(INFO, "xc_core_elf_verify: not a xen ELF core file\n"); ++ goto bailout; ++ } ++ ++ xc_core_elf_dump(); ++ ++ switch (xd->xc_core.elf_class) ++ { ++ case ELFCLASS32: ++ offset32 = xd->xc_core.elf32->e_shoff; ++ for (i = 0; i < xd->xc_core.elf32->e_shnum; i++) { ++ xc_core_dump_Elf32_Shdr(offset32, ELFSTORE); ++ offset32 += xd->xc_core.elf32->e_shentsize; ++ } ++ xendump_print("\n"); ++ break; ++ ++ case ELFCLASS64: ++ offset64 = xd->xc_core.elf64->e_shoff; ++ for (i = 0; i < xd->xc_core.elf64->e_shnum; i++) { ++ xc_core_dump_Elf64_Shdr(offset64, ELFSTORE); ++ offset64 += xd->xc_core.elf64->e_shentsize; ++ } ++ xendump_print("\n"); ++ break; ++ } ++ ++ xd->flags |= (XENDUMP_LOCAL | XC_CORE_ELF); ++ ++ if (!xd->page_size) ++ error(FATAL, ++ "unknown page size: use -p command line option\n"); ++ ++ if (!(xd->page = (char *)malloc(xd->page_size))) ++ error(FATAL, "cannot malloc page space."); ++ ++ if (!(xd->poc = (struct pfn_offset_cache *)calloc ++ (PFN_TO_OFFSET_CACHE_ENTRIES, ++ sizeof(struct pfn_offset_cache)))) ++ error(FATAL, "cannot malloc pfn_offset_cache\n"); ++ xd->last_pfn = ~(0UL); ++ ++ for (i = 0; i < INDEX_PFN_COUNT; i++) ++ xd->xc_core.elf_index_pfn[i].pfn = ~0UL; ++ ++ if (CRASHDEBUG(1)) ++ xendump_memory_dump(fp); ++ ++ return TRUE; ++ ++bailout: ++ return FALSE; ++} ++ ++/* ++ * Dump the relevant ELF header. ++ */ ++static void ++xc_core_elf_dump(void) ++{ ++ switch (xd->xc_core.elf_class) ++ { ++ case ELFCLASS32: ++ xc_core_dump_Elf32_Ehdr(xd->xc_core.elf32); ++ break; ++ case ELFCLASS64: ++ xc_core_dump_Elf64_Ehdr(xd->xc_core.elf64); ++ break; ++ } ++} ++ ++ ++/* ++ * Dump the 32-bit ELF header, and grab a pointer to the strtab section. ++ */ ++static void ++xc_core_dump_Elf32_Ehdr(Elf32_Ehdr *elf) ++{ ++ char buf[BUFSIZE]; ++ Elf32_Off offset32; ++ Elf32_Shdr shdr; ++ ++ BZERO(buf, BUFSIZE); ++ BCOPY(elf->e_ident, buf, SELFMAG); ++ xendump_print("\nElf32_Ehdr:\n"); ++ xendump_print(" e_ident: \\%o%s\n", buf[0], ++ &buf[1]); ++ xendump_print(" e_ident[EI_CLASS]: %d ", elf->e_ident[EI_CLASS]); ++ switch (elf->e_ident[EI_CLASS]) ++ { ++ case ELFCLASSNONE: ++ xendump_print("(ELFCLASSNONE)"); ++ break; ++ case ELFCLASS32: ++ xendump_print("(ELFCLASS32)\n"); ++ break; ++ case ELFCLASS64: ++ xendump_print("(ELFCLASS64)\n"); ++ break; ++ case ELFCLASSNUM: ++ xendump_print("(ELFCLASSNUM)\n"); ++ break; ++ default: ++ xendump_print("(?)\n"); ++ break; ++ } ++ xendump_print(" e_ident[EI_DATA]: %d ", elf->e_ident[EI_DATA]); ++ switch (elf->e_ident[EI_DATA]) ++ { ++ case ELFDATANONE: ++ xendump_print("(ELFDATANONE)\n"); ++ break; ++ case ELFDATA2LSB: ++ xendump_print("(ELFDATA2LSB)\n"); ++ break; ++ case ELFDATA2MSB: ++ xendump_print("(ELFDATA2MSB)\n"); ++ break; ++ case ELFDATANUM: ++ xendump_print("(ELFDATANUM)\n"); ++ break; ++ default: ++ xendump_print("(?)\n"); ++ } ++ xendump_print(" e_ident[EI_VERSION]: %d ", ++ elf->e_ident[EI_VERSION]); ++ if (elf->e_ident[EI_VERSION] == EV_CURRENT) ++ xendump_print("(EV_CURRENT)\n"); ++ else ++ xendump_print("(?)\n"); ++ xendump_print(" e_ident[EI_OSABI]: %d ", elf->e_ident[EI_OSABI]); ++ switch (elf->e_ident[EI_OSABI]) ++ { ++ case ELFOSABI_SYSV: ++ xendump_print("(ELFOSABI_SYSV)\n"); ++ break; ++ case ELFOSABI_HPUX: ++ xendump_print("(ELFOSABI_HPUX)\n"); ++ break; ++ case ELFOSABI_ARM: ++ xendump_print("(ELFOSABI_ARM)\n"); ++ break; ++ case ELFOSABI_STANDALONE: ++ xendump_print("(ELFOSABI_STANDALONE)\n"); ++ break; ++ default: ++ xendump_print("(?)\n"); ++ } ++ xendump_print(" e_ident[EI_ABIVERSION]: %d\n", ++ elf->e_ident[EI_ABIVERSION]); ++ ++ xendump_print(" e_type: %d ", elf->e_type); ++ switch (elf->e_type) ++ { ++ case ET_NONE: ++ xendump_print("(ET_NONE)\n"); ++ break; ++ case ET_REL: ++ xendump_print("(ET_REL)\n"); ++ break; ++ case ET_EXEC: ++ xendump_print("(ET_EXEC)\n"); ++ break; ++ case ET_DYN: ++ xendump_print("(ET_DYN)\n"); ++ break; ++ case ET_CORE: ++ xendump_print("(ET_CORE)\n"); ++ break; ++ case ET_NUM: ++ xendump_print("(ET_NUM)\n"); ++ break; ++ case ET_LOOS: ++ xendump_print("(ET_LOOS)\n"); ++ break; ++ case ET_HIOS: ++ xendump_print("(ET_HIOS)\n"); ++ break; ++ case ET_LOPROC: ++ xendump_print("(ET_LOPROC)\n"); ++ break; ++ case ET_HIPROC: ++ xendump_print("(ET_HIPROC)\n"); ++ break; ++ default: ++ xendump_print("(?)\n"); ++ } ++ ++ xendump_print(" e_machine: %d ", elf->e_machine); ++ switch (elf->e_machine) ++ { ++ case EM_386: ++ xendump_print("(EM_386)\n"); ++ break; ++ default: ++ xendump_print("(unsupported)\n"); ++ break; ++ } ++ ++ xendump_print(" e_version: %ld ", (ulong)elf->e_version); ++ xendump_print("%s\n", elf->e_version == EV_CURRENT ? ++ "(EV_CURRENT)" : ""); ++ ++ xendump_print(" e_entry: %lx\n", (ulong)elf->e_entry); ++ xendump_print(" e_phoff: %lx\n", (ulong)elf->e_phoff); ++ xendump_print(" e_shoff: %lx\n", (ulong)elf->e_shoff); ++ xendump_print(" e_flags: %lx\n", (ulong)elf->e_flags); ++ xendump_print(" e_ehsize: %x\n", elf->e_ehsize); ++ xendump_print(" e_phentsize: %x\n", elf->e_phentsize); ++ xendump_print(" e_phnum: %x\n", elf->e_phnum); ++ xendump_print(" e_shentsize: %x\n", elf->e_shentsize); ++ xendump_print(" e_shnum: %x\n", elf->e_shnum); ++ xendump_print(" e_shstrndx: %x\n", elf->e_shstrndx); ++ ++ /* Determine the strtab location. */ ++ ++ offset32 = elf->e_shoff + ++ (elf->e_shstrndx * elf->e_shentsize); ++ ++ if (lseek(xd->xfd, offset32, SEEK_SET) != offset32) ++ error(FATAL, ++ "xc_core_dump_Elf32_Ehdr: cannot seek to strtab Elf32_Shdr\n"); ++ if (read(xd->xfd, &shdr, sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)) ++ error(FATAL, ++ "xc_core_dump_Elf32_Ehdr: cannot read strtab Elf32_Shdr\n"); ++ ++ xd->xc_core.elf_strtab_offset = (ulonglong)shdr.sh_offset; ++} ++ ++/* ++ * Dump the 64-bit ELF header, and grab a pointer to the strtab section. ++ */ ++static void ++xc_core_dump_Elf64_Ehdr(Elf64_Ehdr *elf) ++{ ++ char buf[BUFSIZE]; ++ Elf64_Off offset64; ++ Elf64_Shdr shdr; ++ ++ BZERO(buf, BUFSIZE); ++ BCOPY(elf->e_ident, buf, SELFMAG); ++ xendump_print("\nElf64_Ehdr:\n"); ++ xendump_print(" e_ident: \\%o%s\n", buf[0], ++ &buf[1]); ++ xendump_print(" e_ident[EI_CLASS]: %d ", elf->e_ident[EI_CLASS]); ++ switch (elf->e_ident[EI_CLASS]) ++ { ++ case ELFCLASSNONE: ++ xendump_print("(ELFCLASSNONE)"); ++ break; ++ case ELFCLASS32: ++ xendump_print("(ELFCLASS32)\n"); ++ break; ++ case ELFCLASS64: ++ xendump_print("(ELFCLASS64)\n"); ++ break; ++ case ELFCLASSNUM: ++ xendump_print("(ELFCLASSNUM)\n"); ++ break; ++ default: ++ xendump_print("(?)\n"); ++ break; ++ } ++ xendump_print(" e_ident[EI_DATA]: %d ", elf->e_ident[EI_DATA]); ++ switch (elf->e_ident[EI_DATA]) ++ { ++ case ELFDATANONE: ++ xendump_print("(ELFDATANONE)\n"); ++ break; ++ case ELFDATA2LSB: ++ xendump_print("(ELFDATA2LSB)\n"); ++ break; ++ case ELFDATA2MSB: ++ xendump_print("(ELFDATA2MSB)\n"); ++ break; ++ case ELFDATANUM: ++ xendump_print("(ELFDATANUM)\n"); ++ break; ++ default: ++ xendump_print("(?)\n"); ++ } ++ xendump_print(" e_ident[EI_VERSION]: %d ", ++ elf->e_ident[EI_VERSION]); ++ if (elf->e_ident[EI_VERSION] == EV_CURRENT) ++ xendump_print("(EV_CURRENT)\n"); ++ else ++ xendump_print("(?)\n"); ++ xendump_print(" e_ident[EI_OSABI]: %d ", elf->e_ident[EI_OSABI]); ++ switch (elf->e_ident[EI_OSABI]) ++ { ++ case ELFOSABI_SYSV: ++ xendump_print("(ELFOSABI_SYSV)\n"); ++ break; ++ case ELFOSABI_HPUX: ++ xendump_print("(ELFOSABI_HPUX)\n"); ++ break; ++ case ELFOSABI_ARM: ++ xendump_print("(ELFOSABI_ARM)\n"); ++ break; ++ case ELFOSABI_STANDALONE: ++ xendump_print("(ELFOSABI_STANDALONE)\n"); ++ break; ++ default: ++ xendump_print("(?)\n"); ++ } ++ xendump_print(" e_ident[EI_ABIVERSION]: %d\n", ++ elf->e_ident[EI_ABIVERSION]); ++ ++ xendump_print(" e_type: %d ", elf->e_type); ++ switch (elf->e_type) ++ { ++ case ET_NONE: ++ xendump_print("(ET_NONE)\n"); ++ break; ++ case ET_REL: ++ xendump_print("(ET_REL)\n"); ++ break; ++ case ET_EXEC: ++ xendump_print("(ET_EXEC)\n"); ++ break; ++ case ET_DYN: ++ xendump_print("(ET_DYN)\n"); ++ break; ++ case ET_CORE: ++ xendump_print("(ET_CORE)\n"); ++ break; ++ case ET_NUM: ++ xendump_print("(ET_NUM)\n"); ++ break; ++ case ET_LOOS: ++ xendump_print("(ET_LOOS)\n"); ++ break; ++ case ET_HIOS: ++ xendump_print("(ET_HIOS)\n"); ++ break; ++ case ET_LOPROC: ++ xendump_print("(ET_LOPROC)\n"); ++ break; ++ case ET_HIPROC: ++ xendump_print("(ET_HIPROC)\n"); ++ break; ++ default: ++ xendump_print("(?)\n"); ++ } ++ ++ xendump_print(" e_machine: %d ", elf->e_machine); ++ switch (elf->e_machine) ++ { ++ case EM_386: ++ xendump_print("(EM_386)\n"); ++ break; ++ case EM_IA_64: ++ xendump_print("(EM_IA_64)\n"); ++ break; ++ case EM_PPC64: ++ xendump_print("(EM_PPC64)\n"); ++ break; ++ case EM_X86_64: ++ xendump_print("(EM_X86_64)\n"); ++ break; ++ default: ++ xendump_print("(unsupported)\n"); ++ break; ++ } ++ ++ xendump_print(" e_version: %ld ", (ulong)elf->e_version); ++ xendump_print("%s\n", elf->e_version == EV_CURRENT ? ++ "(EV_CURRENT)" : ""); ++ ++ xendump_print(" e_entry: %lx\n", (ulong)elf->e_entry); ++ xendump_print(" e_phoff: %lx\n", (ulong)elf->e_phoff); ++ xendump_print(" e_shoff: %lx\n", (ulong)elf->e_shoff); ++ xendump_print(" e_flags: %lx\n", (ulong)elf->e_flags); ++ xendump_print(" e_ehsize: %x\n", elf->e_ehsize); ++ xendump_print(" e_phentsize: %x\n", elf->e_phentsize); ++ xendump_print(" e_phnum: %x\n", elf->e_phnum); ++ xendump_print(" e_shentsize: %x\n", elf->e_shentsize); ++ xendump_print(" e_shnum: %x\n", elf->e_shnum); ++ xendump_print(" e_shstrndx: %x\n", elf->e_shstrndx); ++ ++ /* Determine the strtab location. */ ++ ++ offset64 = elf->e_shoff + ++ (elf->e_shstrndx * elf->e_shentsize); ++ ++ if (lseek(xd->xfd, offset64, SEEK_SET) != offset64) ++ error(FATAL, ++ "xc_core_dump_Elf64_Ehdr: cannot seek to strtab Elf32_Shdr\n"); ++ if (read(xd->xfd, &shdr, sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)) ++ error(FATAL, ++ "xc_core_dump_Elf64_Ehdr: cannot read strtab Elf32_Shdr\n"); ++ ++ xd->xc_core.elf_strtab_offset = (ulonglong)shdr.sh_offset; ++} ++ ++/* ++ * Dump each 32-bit section header and the data that they reference. ++ */ ++static void ++xc_core_dump_Elf32_Shdr(Elf32_Off offset, int store) ++{ ++ Elf32_Shdr shdr; ++ char name[BUFSIZE]; ++ int i; ++ char c; ++ ++ if (lseek(xd->xfd, offset, SEEK_SET) != offset) ++ error(FATAL, ++ "xc_core_dump_Elf32_Shdr: cannot seek to Elf32_Shdr\n"); ++ if (read(xd->xfd, &shdr, sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)) ++ error(FATAL, ++ "xc_core_dump_Elf32_Shdr: cannot read Elf32_Shdr\n"); ++ ++ xendump_print("\nElf32_Shdr:\n"); ++ xendump_print(" sh_name: %lx ", shdr.sh_name); ++ xendump_print("\"%s\"\n", xc_core_strtab(shdr.sh_name, name)); ++ xendump_print(" sh_type: %lx ", shdr.sh_type); ++ switch (shdr.sh_type) ++ { ++ case SHT_NULL: ++ xendump_print("(SHT_NULL)\n"); ++ break; ++ case SHT_PROGBITS: ++ xendump_print("(SHT_PROGBITS)\n"); ++ break; ++ case SHT_STRTAB: ++ xendump_print("(SHT_STRTAB)\n"); ++ break; ++ case SHT_NOTE: ++ xendump_print("(SHT_NOTE)\n"); ++ break; ++ default: ++ xendump_print("\n"); ++ break; ++ } ++ xendump_print(" sh_flags: %lx\n", shdr.sh_flags); ++ xendump_print(" sh_addr: %lx\n", shdr.sh_addr); ++ xendump_print(" sh_offset: %lx\n", shdr.sh_offset); ++ xendump_print(" sh_size: %lx\n", shdr.sh_size); ++ xendump_print(" sh_link: %lx\n", shdr.sh_link); ++ xendump_print(" sh_info: %lx\n", shdr.sh_info); ++ xendump_print(" sh_addralign: %lx\n", shdr.sh_addralign); ++ xendump_print(" sh_entsize: %lx\n", shdr.sh_entsize); ++ ++ if (STREQ(name, ".shstrtab")) { ++ if (lseek(xd->xfd, xd->xc_core.elf_strtab_offset, SEEK_SET) != ++ xd->xc_core.elf_strtab_offset) ++ error(FATAL, ++ "xc_core_dump_Elf32_Shdr: cannot seek to strtab data\n"); ++ ++ xendump_print(" "); ++ for (i = 0; i < shdr.sh_size; i++) { ++ if (read(xd->xfd, &c, sizeof(char)) != sizeof(char)) ++ error(FATAL, ++ "xc_core_dump_Elf32_Shdr: cannot read strtab data\n"); ++ if (i && !c) ++ xendump_print("\n "); ++ else ++ xendump_print("%c", c); ++ } ++ } ++ ++ if (STREQ(name, ".note.Xen")) ++ xc_core_dump_elfnote((off_t)shdr.sh_offset, ++ (size_t)shdr.sh_size, store); ++ ++ if (!store) ++ return; ++ ++ if (STREQ(name, ".xen_prstatus")) ++ xd->xc_core.header.xch_ctxt_offset = ++ (unsigned int)shdr.sh_offset; ++ ++ if (STREQ(name, ".xen_shared_info")) ++ xd->xc_core.shared_info_offset = (off_t)shdr.sh_offset; ++ ++ if (STREQ(name, ".xen_pfn")) { ++ xd->xc_core.header.xch_index_offset = shdr.sh_offset; ++ xd->flags |= (XC_CORE_NO_P2M|XC_CORE_PFN_CREATE); ++ } ++ ++ if (STREQ(name, ".xen_p2m")) { ++ xd->xc_core.header.xch_index_offset = shdr.sh_offset; ++ xd->flags |= XC_CORE_P2M_CREATE; ++ } ++ ++ if (STREQ(name, ".xen_pages")) ++ xd->xc_core.header.xch_pages_offset = ++ (unsigned int)shdr.sh_offset; ++ ++ if (STREQ(name, ".xen_ia64_mapped_regs")) ++ xd->xc_core.ia64_mapped_regs_offset = ++ (off_t)shdr.sh_offset; ++} ++ ++/* ++ * Dump each 64-bit section header and the data that they reference. ++ */ ++static void ++xc_core_dump_Elf64_Shdr(Elf64_Off offset, int store) ++{ ++ Elf64_Shdr shdr; ++ char name[BUFSIZE]; ++ int i; ++ char c; ++ ++ if (lseek(xd->xfd, offset, SEEK_SET) != offset) ++ error(FATAL, ++ "xc_core_dump_Elf64_Shdr: cannot seek to Elf64_Shdr\n"); ++ if (read(xd->xfd, &shdr, sizeof(Elf64_Shdr)) != sizeof(Elf64_Shdr)) ++ error(FATAL, ++ "xc_core_dump_Elf64_Shdr: cannot read Elf64_Shdr\n"); ++ ++ xendump_print("\nElf64_Shdr:\n"); ++ xendump_print(" sh_name: %x ", shdr.sh_name); ++ xendump_print("\"%s\"\n", xc_core_strtab(shdr.sh_name, name)); ++ xendump_print(" sh_type: %x ", shdr.sh_type); ++ switch (shdr.sh_type) ++ { ++ case SHT_NULL: ++ xendump_print("(SHT_NULL)\n"); ++ break; ++ case SHT_PROGBITS: ++ xendump_print("(SHT_PROGBITS)\n"); ++ break; ++ case SHT_STRTAB: ++ xendump_print("(SHT_STRTAB)\n"); ++ break; ++ case SHT_NOTE: ++ xendump_print("(SHT_NOTE)\n"); ++ break; ++ default: ++ xendump_print("\n"); ++ break; ++ } ++ xendump_print(" sh_flags: %lx\n", shdr.sh_flags); ++ xendump_print(" sh_addr: %lx\n", shdr.sh_addr); ++ xendump_print(" sh_offset: %lx\n", shdr.sh_offset); ++ xendump_print(" sh_size: %lx\n", shdr.sh_size); ++ xendump_print(" sh_link: %x\n", shdr.sh_link); ++ xendump_print(" sh_info: %x\n", shdr.sh_info); ++ xendump_print(" sh_addralign: %lx\n", shdr.sh_addralign); ++ xendump_print(" sh_entsize: %lx\n", shdr.sh_entsize); ++ ++ if (STREQ(name, ".shstrtab")) { ++ if (lseek(xd->xfd, xd->xc_core.elf_strtab_offset, SEEK_SET) != ++ xd->xc_core.elf_strtab_offset) ++ error(FATAL, ++ "xc_core_dump_Elf64_Shdr: cannot seek to strtab data\n"); ++ ++ xendump_print(" "); ++ for (i = 0; i < shdr.sh_size; i++) { ++ if (read(xd->xfd, &c, sizeof(char)) != sizeof(char)) ++ error(FATAL, ++ "xc_core_dump_Elf64_Shdr: cannot read strtab data\n"); ++ if (i && !c) ++ xendump_print("\n "); ++ else ++ xendump_print("%c", c); ++ } ++ } ++ ++ if (STREQ(name, ".note.Xen")) ++ xc_core_dump_elfnote((off_t)shdr.sh_offset, ++ (size_t)shdr.sh_size, store); ++ ++ if (!store) ++ return; ++ ++ if (STREQ(name, ".xen_prstatus")) ++ xd->xc_core.header.xch_ctxt_offset = ++ (unsigned int)shdr.sh_offset; ++ ++ if (STREQ(name, ".xen_shared_info")) ++ xd->xc_core.shared_info_offset = (off_t)shdr.sh_offset; ++ ++ if (STREQ(name, ".xen_pfn")) { ++ xd->xc_core.header.xch_index_offset = shdr.sh_offset; ++ xd->flags |= (XC_CORE_NO_P2M|XC_CORE_PFN_CREATE); ++ } ++ ++ if (STREQ(name, ".xen_p2m")) { ++ xd->xc_core.header.xch_index_offset = shdr.sh_offset; ++ xd->flags |= XC_CORE_P2M_CREATE; ++ } ++ ++ if (STREQ(name, ".xen_pages")) ++ xd->xc_core.header.xch_pages_offset = ++ (unsigned int)shdr.sh_offset; ++ ++ if (STREQ(name, ".xen_ia64_mapped_regs")) ++ xd->xc_core.ia64_mapped_regs_offset = ++ (off_t)shdr.sh_offset; ++} ++ ++/* ++ * Return the string found at the specified index into ++ * the dumpfile's strtab. ++ */ ++static char * ++xc_core_strtab(uint32_t index, char *buf) ++{ ++ off_t offset; ++ int i; ++ ++ offset = xd->xc_core.elf_strtab_offset + index; ++ ++ if (lseek(xd->xfd, offset, SEEK_SET) != offset) ++ error(FATAL, ++ "xc_core_strtab: cannot seek to Elf64_Shdr\n"); ++ ++ BZERO(buf, BUFSIZE); ++ i = 0; ++ ++ while (read(xd->xfd, &buf[i], sizeof(char)) == sizeof(char)) { ++ if (buf[i] == NULLCHAR) ++ break; ++ i++; ++ } ++ ++ return buf; ++} ++ ++ ++/* ++ * Dump the array of elfnote structures, storing relevant info ++ * when requested during initialization. This function is ++ * common to both 32-bit and 64-bit ELF files. ++ */ ++static void ++xc_core_dump_elfnote(off_t sh_offset, size_t sh_size, int store) ++{ ++ int i, lf, index; ++ char *notes_buffer; ++ struct elfnote *elfnote; ++ ulonglong *data; ++ struct xen_dumpcore_elfnote_header_desc *elfnote_header; ++ struct xen_dumpcore_elfnote_format_version_desc *format_version; ++ ++ elfnote_header = NULL; ++ ++ if (!(notes_buffer = (char *)malloc(sh_size))) ++ error(FATAL, "cannot malloc notes space."); ++ ++ if (lseek(xd->xfd, sh_offset, SEEK_SET) != sh_offset) ++ error(FATAL, ++ "xc_core_dump_elfnote: cannot seek to sh_offset\n"); ++ ++ if (read(xd->xfd, notes_buffer, sh_size) != sh_size) ++ error(FATAL, ++ "xc_core_dump_elfnote: cannot read elfnote data\n"); ++ ++ for (index = 0; index < sh_size; ) { ++ elfnote = (struct elfnote *)¬es_buffer[index]; ++ xendump_print(" namesz: %d\n", elfnote->namesz); ++ xendump_print(" descz: %d\n", elfnote->descsz); ++ xendump_print(" type: %x ", elfnote->type); ++ switch (elfnote->type) ++ { ++ case XEN_ELFNOTE_DUMPCORE_NONE: ++ xendump_print("(XEN_ELFNOTE_DUMPCORE_NONE)\n"); ++ break; ++ case XEN_ELFNOTE_DUMPCORE_HEADER: ++ xendump_print("(XEN_ELFNOTE_DUMPCORE_HEADER)\n"); ++ elfnote_header = (struct xen_dumpcore_elfnote_header_desc *) ++ (elfnote+1); ++ break; ++ case XEN_ELFNOTE_DUMPCORE_XEN_VERSION: ++ xendump_print("(XEN_ELFNOTE_DUMPCORE_XEN_VERSION)\n"); ++ break; ++ case XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION: ++ xendump_print("(XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION)\n"); ++ format_version = (struct xen_dumpcore_elfnote_format_version_desc *) ++ (elfnote+1); ++ break; ++ default: ++ xendump_print("(unknown)\n"); ++ break; ++ } ++ xendump_print(" name: %s\n", elfnote->name); ++ ++ data = (ulonglong *)(elfnote+1); ++ for (i = lf = 0; i < elfnote->descsz/sizeof(ulonglong); i++) { ++ if (((i%2)==0)) { ++ xendump_print("%s ", ++ i ? "\n" : ""); ++ lf++; ++ } else ++ lf = 0; ++ xendump_print("%016llx ", *data++); ++ } ++ if (!elfnote->descsz) ++ xendump_print(" (empty)"); ++ xendump_print("\n"); ++ ++ index += sizeof(struct elfnote) + elfnote->descsz; ++ } ++ ++ if (!store) ++ return; ++ ++ if (elfnote_header) { ++ xd->xc_core.header.xch_magic = elfnote_header->xch_magic; ++ xd->xc_core.header.xch_nr_vcpus = elfnote_header->xch_nr_vcpus; ++ xd->xc_core.header.xch_nr_pages = elfnote_header->xch_nr_pages; ++ xd->page_size = elfnote_header->xch_page_size; ++ } ++ ++ if (format_version) { ++ switch (format_version->version) ++ { ++ case FORMAT_VERSION_0000000000000001: ++ break; ++ default: ++ error(WARNING, ++ "unsupported xen dump-core format version: %016llx\n", ++ format_version->version); ++ } ++ xd->xc_core.format_version = format_version->version; ++ } ++ ++} ++ ++/* ++ * Initialize the batching list for the .xen_p2m or .xen_pfn ++ * arrays. ++ */ ++static void ++xc_core_elf_pfn_init(void) ++{ ++ int i, c, chunk; ++ off_t offset; ++ struct xen_dumpcore_p2m p2m; ++ uint64_t pfn; ++ ++ switch (xd->flags & (XC_CORE_ELF|XC_CORE_NO_P2M)) ++ { ++ case (XC_CORE_ELF|XC_CORE_NO_P2M): ++ chunk = xd->xc_core.header.xch_nr_pages/INDEX_PFN_COUNT; ++ ++ for (i = c = 0; i < INDEX_PFN_COUNT; i++, c += chunk) { ++ offset = (off_t)xd->xc_core.header.xch_index_offset + ++ (off_t)(c * sizeof(uint64_t)); ++ ++ if (lseek(xd->xfd, offset, SEEK_SET) == -1) ++ error(FATAL, ++ "cannot lseek to page index %d\n", c); ++ if (read(xd->xfd, &pfn, sizeof(uint64_t)) != ++ sizeof(uint64_t)) ++ error(FATAL, ++ "cannot read page index %d\n", c); ++ ++ xd->xc_core.elf_index_pfn[i].index = c; ++ xd->xc_core.elf_index_pfn[i].pfn = (ulong)pfn; ++ } ++ break; ++ ++ case XC_CORE_ELF: ++ chunk = xd->xc_core.header.xch_nr_pages/INDEX_PFN_COUNT; ++ ++ for (i = c = 0; i < INDEX_PFN_COUNT; i++, c += chunk) { ++ offset = (off_t)xd->xc_core.header.xch_index_offset + ++ (off_t)(c * sizeof(struct xen_dumpcore_p2m)); ++ ++ if (lseek(xd->xfd, offset, SEEK_SET) == -1) ++ error(FATAL, ++ "cannot lseek to page index %d\n", c); ++ if (read(xd->xfd, &p2m, sizeof(struct xen_dumpcore_p2m)) != ++ sizeof(struct xen_dumpcore_p2m)) ++ error(FATAL, ++ "cannot read page index %d\n", c); ++ ++ xd->xc_core.elf_index_pfn[i].index = c; ++ xd->xc_core.elf_index_pfn[i].pfn = (ulong)p2m.pfn; ++ } ++ break; ++ } ++} ++ +--- crash/unwind.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/unwind.c 2007-03-15 08:16:14.000000000 -0500 +@@ -6,8 +6,8 @@ + /* + * unwind.c + * +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. All rights reserved. + * + * Adapted from: + * +@@ -36,6 +36,7 @@ + /* #include can't include this -- it's changing over time! */ + + #include "defs.h" ++#include "xen_hyper_defs.h" + + typedef unsigned char u8; + typedef unsigned long long u64; +@@ -64,6 +65,8 @@ + struct bt_info *); + static int unw_switch_from_osinit_v2(struct unw_frame_info *, + struct bt_info *); ++static int unw_switch_from_osinit_v3(struct unw_frame_info *, ++ struct bt_info *, char *); + static unsigned long get_init_stack_ulong(unsigned long addr); + static void unw_init_frame_info(struct unw_frame_info *, + struct bt_info *, ulong); +@@ -1397,9 +1400,22 @@ req = &request; if (get_symbol_type("unw", "tables", req) == TYPE_CODE_UNDEF) { @@ -22083,16 +38831,6620 @@ machdep->machspec->unw_tables_offset = req->member_offset/BITS_PER_BYTE; ---- crash/defs.h.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/defs.h 2006-08-31 16:00:41.000000000 -0400 +@@ -1658,8 +1674,13 @@ + unw_get_sp(info, &sp); + unw_get_bsp(info, &bsp); + +- if (ip < GATE_ADDR + PAGE_SIZE) +- break; ++ if (XEN_HYPER_MODE()) { ++ if (!IS_KVADDR(ip)) ++ break; ++ } else { ++ if (ip < GATE_ADDR + PAGE_SIZE) ++ break; ++ } + + if ((sm = value_search(ip, NULL))) + name = sm->name; +@@ -1720,11 +1741,29 @@ + * ia64_init_handler. + */ + if (STREQ(name, "ia64_init_handler")) { +- unw_switch_from_osinit_v2(info, bt); +- frame++; +- goto restart; ++ if (symbol_exists("ia64_mca_modify_original_stack")) { ++ /* ++ * 2.6.14 or later kernels no longer keep ++ * minstate info in pt_regs/switch_stack. ++ * unw_switch_from_osinit_v3() will try ++ * to find the interrupted task and restart ++ * backtrace itself. ++ */ ++ if (unw_switch_from_osinit_v3(info, bt, "INIT") == FALSE) ++ break; ++ } else { ++ if (unw_switch_from_osinit_v2(info, bt) == FALSE) ++ break; ++ frame++; ++ goto restart; ++ } + } + ++ if (STREQ(name, "ia64_mca_handler") && ++ symbol_exists("ia64_mca_modify_original_stack")) ++ if (unw_switch_from_osinit_v3(info, bt, "MCA") == FALSE) ++ break; ++ + frame++; + + } while (unw_unwind(info) >= 0); +@@ -1844,8 +1883,13 @@ + ulong sw; + + sw = SWITCH_STACK_ADDR(bt->task); +- if (!INSTACK(sw, bt) && !ia64_in_init_stack(sw)) +- return FALSE; ++ if (XEN_HYPER_MODE()) { ++ if (!INSTACK(sw, bt) && !ia64_in_mca_stack_hyper(sw, bt)) ++ return FALSE; ++ } else { ++ if (!INSTACK(sw, bt) && !ia64_in_init_stack(sw)) ++ return FALSE; ++ } + + unw_init_frame_info(info, bt, sw); + return TRUE; +@@ -1967,6 +2011,124 @@ + return TRUE; + } + ++/* CPL (current privilege level) is 2-bit field */ ++#define IA64_PSR_CPL0_BIT 32 ++#define IA64_PSR_CPL_MASK (3UL << IA64_PSR_CPL0_BIT) ++ ++static int ++user_mode(struct bt_info *bt, unsigned long pt) ++{ ++ unsigned long cr_ipsr; ++ ++ cr_ipsr = IA64_GET_STACK_ULONG(pt + offsetof(struct pt_regs, cr_ipsr)); ++ if (cr_ipsr & IA64_PSR_CPL_MASK) ++ return 1; ++ return 0; ++} ++ ++/* ++ * Cope with INIT/MCA stack for the kernel 2.6.14 or later ++ * ++ * Returns FALSE if no more unwinding is needed. ++ */ ++#define ALIGN16(x) ((x)&~15) ++static int ++unw_switch_from_osinit_v3(struct unw_frame_info *info, struct bt_info *bt, ++ char *type) ++{ ++ unsigned long pt, sw, pid; ++ int processor; ++ char *p, *q; ++ struct task_context *tc = NULL; ++ struct bt_info clone_bt; ++ ++ /* ++ * The structure of INIT/MCA stack ++ * ++ * +---------------------------+ <-------- IA64_STK_OFFSET ++ * | pt_regs | ++ * +---------------------------+ ++ * | switch_stack | ++ * +---------------------------+ ++ * | SAL/OS state | ++ * +---------------------------+ ++ * | 16 byte scratch area | ++ * +---------------------------+ <-------- SP at start of C handler ++ * | ..... | ++ * +---------------------------+ ++ * | RBS for MCA/INIT handler | ++ * +---------------------------+ ++ * | struct task for MCA/INIT | ++ * +---------------------------+ <-------- bt->task ++ */ ++ pt = ALIGN16(bt->task + IA64_STK_OFFSET - STRUCT_SIZE("pt_regs")); ++ sw = ALIGN16(pt - STRUCT_SIZE("switch_stack")); ++ ++ /* ++ * 1. Try to find interrupted task from comm ++ * ++ * comm format of INIT/MCA task: ++ * - " " ++ * - " " ++ * where "" is either "INIT" or "MCA". ++ * The latter form is chosen if PID is 0. ++ * ++ * See ia64_mca_modify_comm() in arch/ia64/kernel/mca.c ++ */ ++ if (!bt->tc || !bt->tc->comm) ++ goto find_exframe; ++ ++ if ((p = strstr(bt->tc->comm, type))) { ++ p += strlen(type); ++ if (*p != ' ') ++ goto find_exframe; ++ if ((q = strchr(++p, ' '))) { ++ /* " " */ ++ if (sscanf(++q, "%d", &processor) > 0) { ++ tc = pid_to_context(0); ++ while (tc) { ++ if (tc != bt->tc && ++ tc->processor == processor) ++ break; ++ tc = tc->tc_next; ++ } ++ } ++ } else if (sscanf(p, "%lu", &pid) > 0) ++ /* " " */ ++ tc = pid_to_context(pid); ++ } ++ ++ if (tc) { ++ /* Clone bt_info and do backtrace */ ++ clone_bt_info(bt, &clone_bt, tc); ++ if (!BT_REFERENCE_CHECK(&clone_bt)) { ++ fprintf(fp, "(%s) INTERRUPTED TASK\n", type); ++ print_task_header(fp, tc, 0); ++ } ++ if (!user_mode(bt, pt)) ++ back_trace(&clone_bt); ++ else if (!BT_REFERENCE_CHECK(bt)) { ++ fprintf(fp, " #0 [interrupted in user space]\n"); ++ /* at least show the incomplete exception frame */ ++ bt->flags |= BT_INCOMPLETE_USER_EFRAME; ++ ia64_exception_frame(pt, bt); ++ } ++ return FALSE; ++ } ++ ++ /* task matching with INIT/MCA task's comm is not found */ ++ ++find_exframe: ++ /* ++ * 2. If step 1 doesn't work, try best to find exception frame ++ */ ++ unw_init_from_interruption(info, bt, pt, sw); ++ if (!BT_REFERENCE_CHECK(bt)) ++ ia64_exception_frame(pt, bt); ++ ++ return TRUE; ++} ++ + static void + unw_init_frame_info (struct unw_frame_info *info, struct bt_info *bt, ulong sw) + { +--- crash/unwind_x86_32_64.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/unwind_x86_32_64.c 2006-11-15 14:44:58.000000000 -0500 +@@ -0,0 +1,1220 @@ ++#if defined(X86_64) ++/* ++ * Support for genarating DWARF CFI based backtraces. ++ * Borrowed heavily from the kernel's implementation of unwinding using the ++ * DWARF CFI written by Jan Beulich ++ */ ++ ++#ifdef X86_64 ++#include "unwind_x86_64.h" ++#endif ++#ifdef X86 ++#include "unwind_x86.h" ++#endif ++ ++#include "defs.h" ++ ++#define MAX_STACK_DEPTH 8 ++ ++static struct local_unwind_table { ++ struct { ++ unsigned long pc; ++ unsigned long range; ++ } core, init; ++ void *address; ++ unsigned long size; ++} *local_unwind_tables, default_unwind_table; ++ ++static int gather_in_memory_unwind_tables(void); ++static int populate_local_tables(ulong, char *); ++static int unwind_tables_cnt = 0; ++static struct local_unwind_table *find_table(unsigned long); ++static void dump_local_unwind_tables(void); ++ ++static const struct { ++ unsigned offs:BITS_PER_LONG / 2; ++ unsigned width:BITS_PER_LONG / 2; ++} reg_info[] = { ++ UNW_REGISTER_INFO ++}; ++ ++#undef PTREGS_INFO ++#undef EXTRA_INFO ++ ++#ifndef REG_INVALID ++#define REG_INVALID(r) (reg_info[r].width == 0) ++#endif ++ ++#define DW_CFA_nop 0x00 ++#define DW_CFA_set_loc 0x01 ++#define DW_CFA_advance_loc1 0x02 ++#define DW_CFA_advance_loc2 0x03 ++#define DW_CFA_advance_loc4 0x04 ++#define DW_CFA_offset_extended 0x05 ++#define DW_CFA_restore_extended 0x06 ++#define DW_CFA_undefined 0x07 ++#define DW_CFA_same_value 0x08 ++#define DW_CFA_register 0x09 ++#define DW_CFA_remember_state 0x0a ++#define DW_CFA_restore_state 0x0b ++#define DW_CFA_def_cfa 0x0c ++#define DW_CFA_def_cfa_register 0x0d ++#define DW_CFA_def_cfa_offset 0x0e ++#define DW_CFA_def_cfa_expression 0x0f ++#define DW_CFA_expression 0x10 ++#define DW_CFA_offset_extended_sf 0x11 ++#define DW_CFA_def_cfa_sf 0x12 ++#define DW_CFA_def_cfa_offset_sf 0x13 ++#define DW_CFA_val_offset 0x14 ++#define DW_CFA_val_offset_sf 0x15 ++#define DW_CFA_val_expression 0x16 ++#define DW_CFA_lo_user 0x1c ++#define DW_CFA_GNU_window_save 0x2d ++#define DW_CFA_GNU_args_size 0x2e ++#define DW_CFA_GNU_negative_offset_extended 0x2f ++#define DW_CFA_hi_user 0x3f ++ ++#define DW_EH_PE_FORM 0x07 ++#define DW_EH_PE_native 0x00 ++#define DW_EH_PE_leb128 0x01 ++#define DW_EH_PE_data2 0x02 ++#define DW_EH_PE_data4 0x03 ++#define DW_EH_PE_data8 0x04 ++#define DW_EH_PE_signed 0x08 ++#define DW_EH_PE_ADJUST 0x70 ++#define DW_EH_PE_abs 0x00 ++#define DW_EH_PE_pcrel 0x10 ++#define DW_EH_PE_textrel 0x20 ++#define DW_EH_PE_datarel 0x30 ++#define DW_EH_PE_funcrel 0x40 ++#define DW_EH_PE_aligned 0x50 ++#define DW_EH_PE_indirect 0x80 ++#define DW_EH_PE_omit 0xff ++ ++#define min(x,y) ({ \ ++ typeof(x) _x = (x); \ ++ typeof(y) _y = (y); \ ++ (void) (&_x == &_y); \ ++ _x < _y ? _x : _y; }) ++ ++#define max(x,y) ({ \ ++ typeof(x) _x = (x); \ ++ typeof(y) _y = (y); \ ++ (void) (&_x == &_y); \ ++ _x > _y ? _x : _y; }) ++#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1)) ++ ++typedef unsigned long uleb128_t; ++typedef signed long sleb128_t; ++ ++struct unwind_item { ++ enum item_location { ++ Nowhere, ++ Memory, ++ Register, ++ Value ++ } where; ++ uleb128_t value; ++}; ++ ++struct unwind_state { ++ uleb128_t loc, org; ++ const u8 *cieStart, *cieEnd; ++ uleb128_t codeAlign; ++ sleb128_t dataAlign; ++ struct cfa { ++ uleb128_t reg, offs; ++ } cfa; ++ struct unwind_item regs[ARRAY_SIZE(reg_info)]; ++ unsigned stackDepth:8; ++ unsigned version:8; ++ const u8 *label; ++ const u8 *stack[MAX_STACK_DEPTH]; ++}; ++ ++static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 }; ++ ++static uleb128_t get_uleb128(const u8 **pcur, const u8 *end) ++{ ++ const u8 *cur = *pcur; ++ uleb128_t value; ++ unsigned shift; ++ ++ for (shift = 0, value = 0; cur < end; shift += 7) { ++ if (shift + 7 > 8 * sizeof(value) ++ && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) { ++ cur = end + 1; ++ break; ++ } ++ value |= (uleb128_t)(*cur & 0x7f) << shift; ++ if (!(*cur++ & 0x80)) ++ break; ++ } ++ *pcur = cur; ++ ++ return value; ++} ++ ++static sleb128_t get_sleb128(const u8 **pcur, const u8 *end) ++{ ++ const u8 *cur = *pcur; ++ sleb128_t value; ++ unsigned shift; ++ ++ for (shift = 0, value = 0; cur < end; shift += 7) { ++ if (shift + 7 > 8 * sizeof(value) ++ && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) { ++ cur = end + 1; ++ break; ++ } ++ value |= (sleb128_t)(*cur & 0x7f) << shift; ++ if (!(*cur & 0x80)) { ++ value |= -(*cur++ & 0x40) << shift; ++ break; ++ } ++ } ++ *pcur = cur; ++ ++ return value; ++} ++ ++static unsigned long read_pointer(const u8 **pLoc, ++ const void *end, ++ signed ptrType) ++{ ++ unsigned long value = 0; ++ union { ++ const u8 *p8; ++ const u16 *p16u; ++ const s16 *p16s; ++ const u32 *p32u; ++ const s32 *p32s; ++ const unsigned long *pul; ++ } ptr; ++ ++ if (ptrType < 0 || ptrType == DW_EH_PE_omit) ++ return 0; ++ ptr.p8 = *pLoc; ++ switch(ptrType & DW_EH_PE_FORM) { ++ case DW_EH_PE_data2: ++ if (end < (const void *)(ptr.p16u + 1)) ++ return 0; ++ if(ptrType & DW_EH_PE_signed) ++ value = get_unaligned(ptr.p16s++); ++ else ++ value = get_unaligned(ptr.p16u++); ++ break; ++ case DW_EH_PE_data4: ++#ifdef CONFIG_64BIT ++ if (end < (const void *)(ptr.p32u + 1)) ++ return 0; ++ if(ptrType & DW_EH_PE_signed) ++ value = get_unaligned(ptr.p32s++); ++ else ++ value = get_unaligned(ptr.p32u++); ++ break; ++ case DW_EH_PE_data8: ++ BUILD_BUG_ON(sizeof(u64) != sizeof(value)); ++#else ++ BUILD_BUG_ON(sizeof(u32) != sizeof(value)); ++#endif ++ case DW_EH_PE_native: ++ if (end < (const void *)(ptr.pul + 1)) ++ return 0; ++ value = get_unaligned(ptr.pul++); ++ break; ++ case DW_EH_PE_leb128: ++ BUILD_BUG_ON(sizeof(uleb128_t) > sizeof(value)); ++ value = ptrType & DW_EH_PE_signed ++ ? get_sleb128(&ptr.p8, end) ++ : get_uleb128(&ptr.p8, end); ++ if ((const void *)ptr.p8 > end) ++ return 0; ++ break; ++ default: ++ return 0; ++ } ++ switch(ptrType & DW_EH_PE_ADJUST) { ++ case DW_EH_PE_abs: ++ break; ++ case DW_EH_PE_pcrel: ++ value += (unsigned long)*pLoc; ++ break; ++ default: ++ return 0; ++ } ++ ++/* TBD ++ if ((ptrType & DW_EH_PE_indirect) ++ && __get_user(value, (unsigned long *)value)) ++ return 0; ++*/ ++ *pLoc = ptr.p8; ++ ++ return value; ++} ++ ++static signed fde_pointer_type(const u32 *cie) ++{ ++ const u8 *ptr = (const u8 *)(cie + 2); ++ unsigned version = *ptr; ++ ++ if (version != 1) ++ return -1; /* unsupported */ ++ if (*++ptr) { ++ const char *aug; ++ const u8 *end = (const u8 *)(cie + 1) + *cie; ++ uleb128_t len; ++ ++ /* check if augmentation size is first (and thus present) */ ++ if (*ptr != 'z') ++ return -1; ++ /* check if augmentation string is nul-terminated */ ++ if ((ptr = memchr(aug = (const void *)ptr, 0, end - ptr)) == NULL) ++ return -1; ++ ++ptr; /* skip terminator */ ++ get_uleb128(&ptr, end); /* skip code alignment */ ++ get_sleb128(&ptr, end); /* skip data alignment */ ++ /* skip return address column */ ++ version <= 1 ? (void)++ptr : (void)get_uleb128(&ptr, end); ++ len = get_uleb128(&ptr, end); /* augmentation length */ ++ if (ptr + len < ptr || ptr + len > end) ++ return -1; ++ end = ptr + len; ++ while (*++aug) { ++ if (ptr >= end) ++ return -1; ++ switch(*aug) { ++ case 'L': ++ ++ptr; ++ break; ++ case 'P': { ++ signed ptrType = *ptr++; ++ ++ if (!read_pointer(&ptr, end, ptrType) || ptr > end) ++ return -1; ++ } ++ break; ++ case 'R': ++ return *ptr; ++ default: ++ return -1; ++ } ++ } ++ } ++ return DW_EH_PE_native|DW_EH_PE_abs; ++} ++ ++static int advance_loc(unsigned long delta, struct unwind_state *state) ++{ ++ state->loc += delta * state->codeAlign; ++ ++ return delta > 0; ++} ++ ++static void set_rule(uleb128_t reg, ++ enum item_location where, ++ uleb128_t value, ++ struct unwind_state *state) ++{ ++ if (reg < ARRAY_SIZE(state->regs)) { ++ state->regs[reg].where = where; ++ state->regs[reg].value = value; ++ } ++} ++ ++static int processCFI(const u8 *start, ++ const u8 *end, ++ unsigned long targetLoc, ++ signed ptrType, ++ struct unwind_state *state) ++{ ++ union { ++ const u8 *p8; ++ const u16 *p16; ++ const u32 *p32; ++ } ptr; ++ int result = 1; ++ ++ if (start != state->cieStart) { ++ state->loc = state->org; ++ result = processCFI(state->cieStart, state->cieEnd, 0, ptrType, state); ++ if (targetLoc == 0 && state->label == NULL) ++ return result; ++ } ++ for (ptr.p8 = start; result && ptr.p8 < end; ) { ++ switch(*ptr.p8 >> 6) { ++ uleb128_t value; ++ ++ case 0: ++ switch(*ptr.p8++) { ++ case DW_CFA_nop: ++ break; ++ case DW_CFA_set_loc: ++ if ((state->loc = read_pointer(&ptr.p8, end, ++ ptrType)) == 0) ++ result = 0; ++ break; ++ case DW_CFA_advance_loc1: ++ result = ptr.p8 < end && advance_loc(*ptr.p8++, state); ++ break; ++ case DW_CFA_advance_loc2: ++ result = ptr.p8 <= end + 2 ++ && advance_loc(*ptr.p16++, state); ++ break; ++ case DW_CFA_advance_loc4: ++ result = ptr.p8 <= end + 4 ++ && advance_loc(*ptr.p32++, state); ++ break; ++ case DW_CFA_offset_extended: ++ value = get_uleb128(&ptr.p8, end); ++ set_rule(value, Memory, ++ get_uleb128(&ptr.p8, end), state); ++ break; ++ case DW_CFA_val_offset: ++ value = get_uleb128(&ptr.p8, end); ++ set_rule(value, Value, ++ get_uleb128(&ptr.p8, end), state); ++ break; ++ case DW_CFA_offset_extended_sf: ++ value = get_uleb128(&ptr.p8, end); ++ set_rule(value, Memory, ++ get_sleb128(&ptr.p8, end), state); ++ break; ++ case DW_CFA_val_offset_sf: ++ value = get_uleb128(&ptr.p8, end); ++ set_rule(value, Value, ++ get_sleb128(&ptr.p8, end), state); ++ break; ++ case DW_CFA_restore_extended: ++ case DW_CFA_undefined: ++ case DW_CFA_same_value: ++ set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0, state); ++ break; ++ case DW_CFA_register: ++ value = get_uleb128(&ptr.p8, end); ++ set_rule(value, Register, ++ get_uleb128(&ptr.p8, end), state); ++ break; ++ case DW_CFA_remember_state: ++ if (ptr.p8 == state->label) { ++ state->label = NULL; ++ return 1; ++ } ++ if (state->stackDepth >= MAX_STACK_DEPTH) ++ return 0; ++ state->stack[state->stackDepth++] = ptr.p8; ++ break; ++ case DW_CFA_restore_state: ++ if (state->stackDepth) { ++ const uleb128_t loc = state->loc; ++ const u8 *label = state->label; ++ ++ state->label = state->stack[state->stackDepth - 1]; ++ memcpy(&state->cfa, &badCFA, sizeof(state->cfa)); ++ memset(state->regs, 0, sizeof(state->regs)); ++ state->stackDepth = 0; ++ result = processCFI(start, end, 0, ptrType, state); ++ state->loc = loc; ++ state->label = label; ++ } else ++ return 0; ++ break; ++ case DW_CFA_def_cfa: ++ state->cfa.reg = get_uleb128(&ptr.p8, end); ++ /*nobreak*/ ++ case DW_CFA_def_cfa_offset: ++ state->cfa.offs = get_uleb128(&ptr.p8, end); ++ break; ++ case DW_CFA_def_cfa_sf: ++ state->cfa.reg = get_uleb128(&ptr.p8, end); ++ /*nobreak*/ ++ case DW_CFA_def_cfa_offset_sf: ++ state->cfa.offs = get_sleb128(&ptr.p8, end) ++ * state->dataAlign; ++ break; ++ case DW_CFA_def_cfa_register: ++ state->cfa.reg = get_uleb128(&ptr.p8, end); ++ break; ++ /*todo case DW_CFA_def_cfa_expression: */ ++ /*todo case DW_CFA_expression: */ ++ /*todo case DW_CFA_val_expression: */ ++ case DW_CFA_GNU_args_size: ++ get_uleb128(&ptr.p8, end); ++ break; ++ case DW_CFA_GNU_negative_offset_extended: ++ value = get_uleb128(&ptr.p8, end); ++ set_rule(value, Memory, (uleb128_t)0 - ++ get_uleb128(&ptr.p8, end), state); ++ break; ++ case DW_CFA_GNU_window_save: ++ default: ++ result = 0; ++ break; ++ } ++ break; ++ case 1: ++ result = advance_loc(*ptr.p8++ & 0x3f, state); ++ break; ++ case 2: ++ value = *ptr.p8++ & 0x3f; ++ set_rule(value, Memory, get_uleb128(&ptr.p8, end), ++ state); ++ break; ++ case 3: ++ set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state); ++ break; ++ } ++ if (ptr.p8 > end) ++ result = 0; ++ if (result && targetLoc != 0 && targetLoc < state->loc) ++ return 1; ++ } ++ ++ return result ++ && ptr.p8 == end ++ && (targetLoc == 0 ++ || (/*todo While in theory this should apply, gcc in practice omits ++ everything past the function prolog, and hence the location ++ never reaches the end of the function. ++ targetLoc < state->loc &&*/ state->label == NULL)); ++} ++ ++ ++/* Unwind to previous to frame. Returns 0 if successful, negative ++ * number in case of an error. */ ++int ++unwind(struct unwind_frame_info *frame) ++{ ++#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs]) ++ const u32 *fde = NULL, *cie = NULL; ++ const u8 *ptr = NULL, *end = NULL; ++ unsigned long startLoc = 0, endLoc = 0, cfa; ++ unsigned i; ++ signed ptrType = -1; ++ uleb128_t retAddrReg = 0; ++// struct unwind_table *table; ++ void *unwind_table; ++ struct local_unwind_table *table; ++ struct unwind_state state; ++ u64 reg_ptr = 0; ++ ++ ++ if (UNW_PC(frame) == 0) ++ return -EINVAL; ++ ++ if ((table = find_table(UNW_PC(frame)))) { ++// unsigned long tableSize = unwind_table_size; ++ unsigned long tableSize = table->size; ++ ++ unwind_table = table->address; ++ ++ for (fde = unwind_table; ++ tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde; ++ tableSize -= sizeof(*fde) + *fde, ++ fde += 1 + *fde / sizeof(*fde)) { ++ if (!*fde || (*fde & (sizeof(*fde) - 1))) ++ break; ++ if (!fde[1]) ++ continue; /* this is a CIE */ ++ if ((fde[1] & (sizeof(*fde) - 1)) ++ || fde[1] > (unsigned long)(fde + 1) ++ - (unsigned long)unwind_table) ++ continue; /* this is not a valid FDE */ ++ cie = fde + 1 - fde[1] / sizeof(*fde); ++ if (*cie <= sizeof(*cie) + 4 ++ || *cie >= fde[1] - sizeof(*fde) ++ || (*cie & (sizeof(*cie) - 1)) ++ || cie[1] ++ || (ptrType = fde_pointer_type(cie)) < 0) { ++ cie = NULL; /* this is not a (valid) CIE */ ++ continue; ++ } ++ ptr = (const u8 *)(fde + 2); ++ startLoc = read_pointer(&ptr, ++ (const u8 *)(fde + 1) + *fde, ++ ptrType); ++ endLoc = startLoc ++ + read_pointer(&ptr, ++ (const u8 *)(fde + 1) + *fde, ++ ptrType & DW_EH_PE_indirect ++ ? ptrType ++ : ptrType & (DW_EH_PE_FORM|DW_EH_PE_signed)); ++ if (UNW_PC(frame) >= startLoc && UNW_PC(frame) < endLoc) ++ break; ++ cie = NULL; ++ } ++ } ++ if (cie != NULL) { ++ memset(&state, 0, sizeof(state)); ++ state.cieEnd = ptr; /* keep here temporarily */ ++ ptr = (const u8 *)(cie + 2); ++ end = (const u8 *)(cie + 1) + *cie; ++ if ((state.version = *ptr) != 1) ++ cie = NULL; /* unsupported version */ ++ else if (*++ptr) { ++ /* check if augmentation size is first (and thus present) */ ++ if (*ptr == 'z') { ++ /* check for ignorable (or already handled) ++ * nul-terminated augmentation string */ ++ while (++ptr < end && *ptr) ++ if (strchr("LPR", *ptr) == NULL) ++ break; ++ } ++ if (ptr >= end || *ptr) ++ cie = NULL; ++ } ++ ++ptr; ++ } ++ if (cie != NULL) { ++ /* get code aligment factor */ ++ state.codeAlign = get_uleb128(&ptr, end); ++ /* get data aligment factor */ ++ state.dataAlign = get_sleb128(&ptr, end); ++ if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end) ++ cie = NULL; ++ else { ++ retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end); ++ /* skip augmentation */ ++ if (((const char *)(cie + 2))[1] == 'z') ++ ptr += get_uleb128(&ptr, end); ++ if (ptr > end ++ || retAddrReg >= ARRAY_SIZE(reg_info) ++ || REG_INVALID(retAddrReg) ++ || reg_info[retAddrReg].width != sizeof(unsigned long)) ++ cie = NULL; ++ } ++ } ++ if (cie != NULL) { ++ state.cieStart = ptr; ++ ptr = state.cieEnd; ++ state.cieEnd = end; ++ end = (const u8 *)(fde + 1) + *fde; ++ /* skip augmentation */ ++ if (((const char *)(cie + 2))[1] == 'z') { ++ uleb128_t augSize = get_uleb128(&ptr, end); ++ ++ if ((ptr += augSize) > end) ++ fde = NULL; ++ } ++ } ++ if (cie == NULL || fde == NULL) ++ return -ENXIO; ++ ++ state.org = startLoc; ++ memcpy(&state.cfa, &badCFA, sizeof(state.cfa)); ++ /* process instructions */ ++ if (!processCFI(ptr, end, UNW_PC(frame), ptrType, &state) ++ || state.loc > endLoc ++ || state.regs[retAddrReg].where == Nowhere ++ || state.cfa.reg >= ARRAY_SIZE(reg_info) ++ || reg_info[state.cfa.reg].width != sizeof(unsigned long) ++ || state.cfa.offs % sizeof(unsigned long)) { ++ return -EIO; ++ } ++ /* update frame */ ++ cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs; ++ startLoc = min((unsigned long)UNW_SP(frame), cfa); ++ endLoc = max((unsigned long)UNW_SP(frame), cfa); ++ if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) { ++ startLoc = min(STACK_LIMIT(cfa), cfa); ++ endLoc = max(STACK_LIMIT(cfa), cfa); ++ } ++#ifndef CONFIG_64BIT ++# define CASES CASE(8); CASE(16); CASE(32) ++#else ++# define CASES CASE(8); CASE(16); CASE(32); CASE(64) ++#endif ++ for (i = 0; i < ARRAY_SIZE(state.regs); ++i) { ++ if (REG_INVALID(i)) { ++ if (state.regs[i].where == Nowhere) ++ continue; ++ return -EIO; ++ } ++ switch(state.regs[i].where) { ++ default: ++ break; ++ case Register: ++ if (state.regs[i].value >= ARRAY_SIZE(reg_info) ++ || REG_INVALID(state.regs[i].value) ++ || reg_info[i].width > reg_info[state.regs[i].value].width){ ++ return -EIO; ++ } ++ switch(reg_info[state.regs[i].value].width) { ++#define CASE(n) \ ++ case sizeof(u##n): \ ++ state.regs[i].value = FRAME_REG(state.regs[i].value, \ ++ const u##n); \ ++ break ++ CASES; ++#undef CASE ++ default: ++ return -EIO; ++ } ++ break; ++ } ++ } ++ for (i = 0; i < ARRAY_SIZE(state.regs); ++i) { ++ if (REG_INVALID(i)) ++ continue; ++ switch(state.regs[i].where) { ++ case Nowhere: ++ if (reg_info[i].width != sizeof(UNW_SP(frame)) ++ || &FRAME_REG(i, __typeof__(UNW_SP(frame))) ++ != &UNW_SP(frame)) ++ continue; ++ UNW_SP(frame) = cfa; ++ break; ++ case Register: ++ switch(reg_info[i].width) { ++#define CASE(n) case sizeof(u##n): \ ++ FRAME_REG(i, u##n) = state.regs[i].value; \ ++ break ++ CASES; ++#undef CASE ++ default: ++ return -EIO; ++ } ++ break; ++ case Value: ++ if (reg_info[i].width != sizeof(unsigned long)){ ++ return -EIO;} ++ FRAME_REG(i, unsigned long) = cfa + state.regs[i].value ++ * state.dataAlign; ++ break; ++ case Memory: { ++ unsigned long addr = cfa + state.regs[i].value ++ * state.dataAlign; ++ if ((state.regs[i].value * state.dataAlign) ++ % sizeof(unsigned long) ++ || addr < startLoc ++ || addr + sizeof(unsigned long) < addr ++ || addr + sizeof(unsigned long) > endLoc){ ++ return -EIO;} ++ switch(reg_info[i].width) { ++#define CASE(n) case sizeof(u##n): \ ++ readmem(addr, KVADDR, ®_ptr,sizeof(u##n), "register", RETURN_ON_ERROR|QUIET); \ ++ FRAME_REG(i, u##n) = (u##n)reg_ptr;\ ++ break ++ CASES; ++#undef CASE ++ default: ++ return -EIO; ++ } ++ } ++ break; ++ } ++ } ++ return 0; ++#undef CASES ++#undef FRAME_REG ++} ++ ++/* ++ * Initialize the unwind table(s) in the best-case order: ++ * ++ * 1. Use the in-memory kernel and module unwind tables. ++ * 2. Use the in-memory kernel-only .eh_frame data. (possible?) ++ * 3. Use the kernel-only .eh_frame data from the vmlinux file. ++ */ ++void ++init_unwind_table(void) ++{ ++ ulong unwind_table_size; ++ void *unwind_table; ++ ++ kt->flags &= ~DWARF_UNWIND; ++ ++ if (gather_in_memory_unwind_tables()) { ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "init_unwind_table: DWARF_UNWIND_MEMORY (%d tables)\n", ++ unwind_tables_cnt); ++ ++ kt->flags |= DWARF_UNWIND_MEMORY; ++ if (unwind_tables_cnt > 1) ++ kt->flags |= DWARF_UNWIND_MODULES; ++ if (!(kt->flags & NO_DWARF_UNWIND)) ++ kt->flags |= DWARF_UNWIND; ++ ++ return; ++ } ++ ++ if (symbol_exists("__start_unwind") && ++ symbol_exists("__end_unwind")) { ++ unwind_table_size = symbol_value("__end_unwind") - ++ symbol_value("__start_unwind"); ++ ++ if (!(unwind_table = malloc(unwind_table_size))) { ++ error(WARNING, "cannot malloc unwind table space\n"); ++ goto try_eh_frame; ++ } ++ ++ if (!readmem(symbol_value("__start_unwind"), KVADDR, unwind_table, ++ unwind_table_size, "unwind table", RETURN_ON_ERROR)) { ++ error(WARNING, "cannot read unwind table data\n"); ++ free(unwind_table); ++ goto try_eh_frame; ++ } ++ ++ kt->flags |= DWARF_UNWIND_MEMORY; ++ if (!(kt->flags & NO_DWARF_UNWIND)) ++ kt->flags |= DWARF_UNWIND; ++ ++ default_unwind_table.size = unwind_table_size; ++ default_unwind_table.address = unwind_table; ++ ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "init_unwind_table: DWARF_UNWIND_MEMORY\n"); ++ ++ return; ++ } ++ ++try_eh_frame: ++ ++ if (st->dwarf_eh_frame_size) { ++ int fd; ++ ++ unwind_table_size = st->dwarf_eh_frame_size; ++ ++ if (!(unwind_table = malloc(unwind_table_size))) { ++ error(WARNING, "cannot malloc unwind table space\n"); ++ return; ++ } ++ ++ if ((fd = open(pc->namelist, O_RDONLY)) < 0) { ++ error(WARNING, "cannot open %s for .eh_frame data\n", ++ pc->namelist); ++ free(unwind_table); ++ return; ++ } ++ ++ lseek(fd, st->dwarf_eh_frame_file_offset, SEEK_SET); ++ ++ if (read(fd, unwind_table, st->dwarf_eh_frame_size) != ++ st->dwarf_eh_frame_size) { ++ error(WARNING, "cannot read .eh_frame data from %s\n", ++ pc->namelist); ++ free(unwind_table); ++ return; ++ } ++ ++ close(fd); ++ ++ default_unwind_table.size = unwind_table_size; ++ default_unwind_table.address = unwind_table; ++ ++ kt->flags |= DWARF_UNWIND_EH_FRAME; ++ if (!(kt->flags & NO_DWARF_UNWIND)) ++ kt->flags |= DWARF_UNWIND; ++ ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "init_unwind_table: DWARF_UNWIND_EH_FRAME\n"); ++ ++ return; ++ } ++} ++ ++/* ++ * Find the appropriate kernel-only "root_table" unwind_table, ++ * and pass it to populate_local_tables() to do the heavy lifting. ++ */ ++static int ++gather_in_memory_unwind_tables(void) ++{ ++ int i, cnt, found; ++ struct syment *sp, *root_tables[10]; ++ char *root_table_buf; ++ char buf[BUFSIZE]; ++ ulong name; ++ ++ STRUCT_SIZE_INIT(unwind_table, "unwind_table"); ++ MEMBER_OFFSET_INIT(unwind_table_core, "unwind_table", "core"); ++ MEMBER_OFFSET_INIT(unwind_table_init, "unwind_table", "init"); ++ MEMBER_OFFSET_INIT(unwind_table_address, "unwind_table", "address"); ++ MEMBER_OFFSET_INIT(unwind_table_size, "unwind_table", "size"); ++ MEMBER_OFFSET_INIT(unwind_table_link, "unwind_table", "link"); ++ MEMBER_OFFSET_INIT(unwind_table_name, "unwind_table", "name"); ++ ++ if (INVALID_SIZE(unwind_table) || ++ INVALID_MEMBER(unwind_table_core) || ++ INVALID_MEMBER(unwind_table_init) || ++ INVALID_MEMBER(unwind_table_address) || ++ INVALID_MEMBER(unwind_table_size) || ++ INVALID_MEMBER(unwind_table_link) || ++ INVALID_MEMBER(unwind_table_name)) { ++ if (CRASHDEBUG(1)) ++ error(NOTE, ++ "unwind_table structure has changed, or does not exist in this kernel\n"); ++ return 0; ++ } ++ ++ /* ++ * Unfortunately there are two kernel root_table symbols. ++ */ ++ if (!(cnt = get_syment_array("root_table", root_tables, 10))) ++ return 0; ++ ++ root_table_buf = GETBUF(SIZE(unwind_table)); ++ for (i = found = 0; i < cnt; i++) { ++ sp = root_tables[i]; ++ if (!readmem(sp->value, KVADDR, root_table_buf, ++ SIZE(unwind_table), "root unwind_table", ++ RETURN_ON_ERROR|QUIET)) ++ goto gather_failed; ++ ++ name = ULONG(root_table_buf + OFFSET(unwind_table_name)); ++ if (read_string(name, buf, strlen("kernel")+1) && ++ STREQ("kernel", buf)) { ++ found++; ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "root_table name: %lx [%s]\n", ++ name, buf); ++ break; ++ } ++ } ++ ++ if (!found) ++ goto gather_failed; ++ ++ cnt = populate_local_tables(sp->value, root_table_buf); ++ ++ FREEBUF(root_table_buf); ++ return cnt; ++ ++gather_failed: ++ ++ FREEBUF(root_table_buf); ++ return 0; ++} ++ ++/* ++ * Transfer the relevant data from the kernel and module unwind_table ++ * structures to the local_unwind_table structures. ++ */ ++static int ++populate_local_tables(ulong root, char *buf) ++{ ++ struct list_data list_data, *ld; ++ int i, cnt; ++ ulong *table_list; ++ ulong vaddr; ++ struct local_unwind_table *tp; ++ ++ ld = &list_data; ++ BZERO(ld, sizeof(struct list_data)); ++ ld->start = root; ++ ld->member_offset = OFFSET(unwind_table_link); ++ if (CRASHDEBUG(1)) ++ ld->flags |= VERBOSE; ++ ++ hq_open(); ++ cnt = do_list(ld); ++ table_list = (ulong *)GETBUF(cnt * sizeof(ulong)); ++ cnt = retrieve_list(table_list, cnt); ++ hq_close(); ++ ++ if (!(local_unwind_tables = ++ malloc(sizeof(struct local_unwind_table) * cnt))) { ++ error(WARNING, "cannot malloc unwind_table space (%d tables)\n", ++ cnt); ++ FREEBUF(table_list); ++ return 0; ++ } ++ ++ for (i = 0; i < cnt; i++, tp++) { ++ ++ if (!readmem(table_list[i], KVADDR, buf, ++ SIZE(unwind_table), "unwind_table", ++ RETURN_ON_ERROR|QUIET)) { ++ error(WARNING, "cannot read unwind_table\n"); ++ goto failed; ++ } ++ ++ tp = &local_unwind_tables[i]; ++ ++ /* ++ * Copy the required table info for find_table(). ++ */ ++ BCOPY(buf + OFFSET(unwind_table_core), ++ (char *)&tp->core.pc, sizeof(ulong)*2); ++ BCOPY(buf + OFFSET(unwind_table_init), ++ (char *)&tp->init.pc, sizeof(ulong)*2); ++ BCOPY(buf + OFFSET(unwind_table_size), ++ (char *)&tp->size, sizeof(ulong)); ++ ++ /* ++ * Then read the DWARF CFI data. ++ */ ++ vaddr = ULONG(buf + OFFSET(unwind_table_address)); ++ ++ if (!(tp->address = malloc(tp->size))) { ++ error(WARNING, "cannot malloc unwind_table space\n"); ++ goto failed; ++ break; ++ } ++ if (!readmem(vaddr, KVADDR, tp->address, ++ tp->size, "DWARF CFI data", RETURN_ON_ERROR|QUIET)) { ++ error(WARNING, "cannot read unwind_table data\n"); ++ goto failed; ++ } ++ } ++ ++ unwind_tables_cnt = cnt; ++ ++ if (CRASHDEBUG(7)) ++ dump_local_unwind_tables(); ++ ++failed: ++ ++ FREEBUF(table_list); ++ return unwind_tables_cnt; ++} ++ ++/* ++ * Find the unwind_table containing a pc. ++ */ ++static struct local_unwind_table * ++find_table(unsigned long pc) ++{ ++ int i; ++ struct local_unwind_table *tp, *table; ++ ++ table = &default_unwind_table; ++ ++ for (i = 0; i < unwind_tables_cnt; i++, tp++) { ++ tp = &local_unwind_tables[i]; ++ if ((pc >= tp->core.pc ++ && pc < tp->core.pc + tp->core.range) ++ || (pc >= tp->init.pc ++ && pc < tp->init.pc + tp->init.range)) { ++ table = tp; ++ break; ++ } ++ } ++ ++ return table; ++} ++ ++static void ++dump_local_unwind_tables(void) ++{ ++ int i, others; ++ struct local_unwind_table *tp; ++ ++ others = 0; ++ fprintf(fp, "DWARF flags: ("); ++ if (kt->flags & DWARF_UNWIND) ++ fprintf(fp, "%sDWARF_UNWIND", others++ ? "|" : ""); ++ if (kt->flags & NO_DWARF_UNWIND) ++ fprintf(fp, "%sNO_DWARF_UNWIND", others++ ? "|" : ""); ++ if (kt->flags & DWARF_UNWIND_MEMORY) ++ fprintf(fp, "%sDWARF_UNWIND_MEMORY", others++ ? "|" : ""); ++ if (kt->flags & DWARF_UNWIND_EH_FRAME) ++ fprintf(fp, "%sDWARF_UNWIND_EH_FRAME", others++ ? "|" : ""); ++ if (kt->flags & DWARF_UNWIND_MODULES) ++ fprintf(fp, "%sDWARF_UNWIND_MODULES", others++ ? "|" : ""); ++ fprintf(fp, ")\n\n"); ++ ++ fprintf(fp, "default_unwind_table:\n"); ++ fprintf(fp, " address: %lx\n", ++ (ulong)default_unwind_table.address); ++ fprintf(fp, " size: %ld\n\n", ++ (ulong)default_unwind_table.size); ++ ++ fprintf(fp, "local_unwind_tables[%d]:\n", unwind_tables_cnt); ++ for (i = 0; i < unwind_tables_cnt; i++, tp++) { ++ tp = &local_unwind_tables[i]; ++ fprintf(fp, "[%d]\n", i); ++ fprintf(fp, " core: pc: %lx\n", tp->core.pc); ++ fprintf(fp, " range: %ld\n", tp->core.range); ++ fprintf(fp, " init: pc: %lx\n", tp->init.pc); ++ fprintf(fp, " range: %ld\n", tp->init.range); ++ fprintf(fp, " address: %lx\n", (ulong)tp->address); ++ fprintf(fp, " size: %ld\n", tp->size); ++ } ++} ++ ++ ++int ++dwarf_backtrace(struct bt_info *bt, int level, ulong stacktop) ++{ ++ unsigned long bp, offset; ++ struct syment *sp; ++ char *name; ++ struct unwind_frame_info *frame; ++ ++ frame = (struct unwind_frame_info *)GETBUF(sizeof(struct unwind_frame_info)); ++// frame->regs.rsp = bt->stkptr; ++// frame->regs.rip = bt->instptr; ++ UNW_SP(frame) = bt->stkptr; ++ UNW_PC(frame) = bt->instptr; ++ ++ /* read rbp from stack for non active tasks */ ++ if (!(bt->flags & BT_DUMPFILE_SEARCH) && !bt->bptr) { ++// readmem(frame->regs.rsp, KVADDR, &bp, ++ readmem(UNW_SP(frame), KVADDR, &bp, ++ sizeof(unsigned long), "reading bp", FAULT_ON_ERROR); ++ frame->regs.rbp = bp; /* fixme for x86 */ ++ } ++ ++ sp = value_search(UNW_PC(frame), &offset); ++ if (!sp) { ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "unwind: cannot find symbol for PC: %lx\n", ++ UNW_PC(frame)); ++ goto bailout; ++ } ++ ++ /* ++ * If offset is zero, it means we have crossed over to the next ++ * function. Recalculate by adjusting the text address ++ */ ++ if (!offset) { ++ sp = value_search(UNW_PC(frame) - 1, &offset); ++ if (!sp) { ++ if (CRASHDEBUG(1)) ++ fprintf(fp, ++ "unwind: cannot find symbol for PC: %lx\n", ++ UNW_PC(frame)-1); ++ goto bailout; ++ } ++ } ++ ++ ++ ++ name = sp->name; ++ fprintf(fp, " #%d [%016lx] %s at %016lx \n", level, UNW_SP(frame), name, UNW_PC(frame)); ++ ++ if (CRASHDEBUG(2)) ++ fprintf(fp, " < SP: %lx PC: %lx FP: %lx >\n", UNW_SP(frame), ++ UNW_PC(frame), frame->regs.rbp); ++ ++ while ((UNW_SP(frame) < stacktop) ++ && !unwind(frame) && UNW_PC(frame)) { ++ /* To prevent rip pushed on IRQ stack being reported both ++ * both on the IRQ and process stacks ++ */ ++ if ((bt->flags & BT_IRQSTACK) && (UNW_SP(frame) >= stacktop - 16)) ++ break; ++ level++; ++ sp = value_search(UNW_PC(frame), &offset); ++ if (!sp) { ++ if (CRASHDEBUG(1)) ++ fprintf(fp, ++ "unwind: cannot find symbol for PC: %lx\n", ++ UNW_PC(frame)); ++ break; ++ } ++ ++ /* ++ * If offset is zero, it means we have crossed over to the next ++ * function. Recalculate by adjusting the text address ++ */ ++ if (!offset) { ++ sp = value_search(UNW_PC(frame) - 1, &offset); ++ if (!sp) { ++ if (CRASHDEBUG(1)) ++ fprintf(fp, ++ "unwind: cannot find symbol for PC: %lx\n", ++ UNW_PC(frame)-1); ++ goto bailout; ++ } ++ } ++ name = sp->name; ++ fprintf(fp, "%s#%d [%016lx] %s at %016lx \n", level < 10 ? " " : "", ++ level, UNW_SP(frame), name, UNW_PC(frame)); ++ ++ if (CRASHDEBUG(2)) ++ fprintf(fp, " < SP: %lx PC: %lx FP: %lx >\n", UNW_SP(frame), ++ UNW_PC(frame), frame->regs.rbp); ++ } ++ ++bailout: ++ FREEBUF(frame); ++ return ++level; ++} ++ ++int ++dwarf_print_stack_entry(struct bt_info *bt, int level) ++{ ++ unsigned long offset; ++ struct syment *sp; ++ char *name; ++ struct unwind_frame_info *frame; ++ ++ frame = (struct unwind_frame_info *)GETBUF(sizeof(struct unwind_frame_info)); ++ UNW_SP(frame) = bt->stkptr; ++ UNW_PC(frame) = bt->instptr; ++ ++ sp = value_search(UNW_PC(frame), &offset); ++ if (!sp) { ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "unwind: cannot find symbol for PC: %lx\n", ++ UNW_PC(frame)); ++ goto bailout; ++ } ++ ++ /* ++ * If offset is zero, it means we have crossed over to the next ++ * function. Recalculate by adjusting the text address ++ */ ++ if (!offset) { ++ sp = value_search(UNW_PC(frame) - 1, &offset); ++ if (!sp) { ++ if (CRASHDEBUG(1)) ++ fprintf(fp, ++ "unwind: cannot find symbol for PC: %lx\n", ++ UNW_PC(frame)-1); ++ goto bailout; ++ } ++ } ++ name = sp->name; ++ fprintf(fp, " #%d [%016lx] %s at %016lx \n", level, UNW_SP(frame), name, UNW_PC(frame)); ++ ++bailout: ++ FREEBUF(frame); ++ return level; ++} ++ ++void ++dwarf_debug(struct bt_info *bt) ++{ ++ struct unwind_frame_info *frame; ++ ulong bp; ++ ++ if (!bt->hp->eip) { ++ dump_local_unwind_tables(); ++ return; ++ } ++ ++ if (!(kt->flags & DWARF_UNWIND_CAPABLE)) { ++ error(INFO, "not DWARF capable\n"); ++ return; ++ } ++ ++ frame = (struct unwind_frame_info *)GETBUF(sizeof(struct unwind_frame_info)); ++ ++ /* ++ * XXX: This only works for the first PC/SP pair seen in a normal ++ * backtrace, so it's not particularly helpful. Ideally it should ++ * be capable to take any PC/SP pair in a stack, but it appears to ++ * related to the rbp value. ++ */ ++ ++ UNW_PC(frame) = bt->hp->eip; ++ UNW_SP(frame) = bt->hp->esp; ++ ++ readmem(UNW_SP(frame), KVADDR, &bp, ++ sizeof(unsigned long), "reading bp", FAULT_ON_ERROR); ++ frame->regs.rbp = bp; /* fixme for x86 */ ++ ++ unwind(frame); ++ ++ fprintf(fp, "frame size: %lx (%lx)\n", ++ (ulong)UNW_SP(frame), (ulong)UNW_SP(frame) - bt->hp->esp); ++ ++ FREEBUF(frame); ++} ++ ++ ++#endif +--- crash/xen_hyper.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/xen_hyper.c 2007-08-23 17:02:54.000000000 -0400 +@@ -0,0 +1,1975 @@ ++/* ++ * xen_hyper.c ++ * ++ * Portions Copyright (C) 2006-2007 Fujitsu Limited ++ * Portions Copyright (C) 2006-2007 VA Linux Systems Japan K.K. ++ * ++ * Authors: Itsuro Oda ++ * Fumihiko Kakuma ++ * ++ * This file is part of Xencrash. ++ * ++ * Xencrash 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 (version 2 of the License). ++ * ++ * Xencrash 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with Xencrash; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include "defs.h" ++ ++#ifdef XEN_HYPERVISOR_ARCH ++#include "xen_hyper_defs.h" ++ ++static void xen_hyper_schedule_init(void); ++ ++/* ++ * Do initialization for Xen Hyper system here. ++ */ ++void ++xen_hyper_init(void) ++{ ++ char *buf; ++#if defined(X86) || defined(X86_64) ++ long member_offset; ++#endif ++ ++ if (symbol_exists("crashing_cpu")) { ++ get_symbol_data("crashing_cpu", sizeof(xht->crashing_cpu), ++ &xht->crashing_cpu); ++ } else { ++ xht->crashing_cpu = XEN_HYPER_PCPU_ID_INVALID; ++ } ++ machdep->get_smp_cpus(); ++ machdep->memory_size(); ++ ++#ifdef IA64 ++ if (symbol_exists("__per_cpu_offset")) { ++ xht->flags |= XEN_HYPER_SMP; ++ if((xht->__per_cpu_offset = malloc(sizeof(ulong) * XEN_HYPER_MAX_CPUS())) == NULL) { ++ error(FATAL, "cannot malloc __per_cpu_offset space.\n"); ++ } ++ if (!readmem(symbol_value("__per_cpu_offset"), KVADDR, ++ xht->__per_cpu_offset, sizeof(ulong) * XEN_HYPER_MAX_CPUS(), ++ "__per_cpu_offset", RETURN_ON_ERROR)) { ++ error(FATAL, "cannot read __per_cpu_offset.\n"); ++ } ++ } ++#endif ++ ++#if defined(X86) || defined(X86_64) ++ member_offset = MEMBER_OFFSET("cpuinfo_x86", "x86_model_id"); ++ buf = GETBUF(XEN_HYPER_SIZE(cpuinfo_x86)); ++ if (xen_hyper_test_pcpu_id(XEN_HYPER_CRASHING_CPU())) { ++ xen_hyper_x86_fill_cpu_data(XEN_HYPER_CRASHING_CPU(), buf); ++ } else { ++ xen_hyper_x86_fill_cpu_data(xht->cpu_idxs[0], buf); ++ } ++ strncpy(xht->utsname.machine, (char *)(buf + member_offset), ++ sizeof(xht->utsname.machine)-1); ++ FREEBUF(buf); ++#elif defined(IA64) ++ buf = GETBUF(XEN_HYPER_SIZE(cpuinfo_ia64)); ++ if (xen_hyper_test_pcpu_id(XEN_HYPER_CRASHING_CPU())) { ++ xen_hyper_ia64_fill_cpu_data(XEN_HYPER_CRASHING_CPU(), buf); ++ } else { ++ xen_hyper_ia64_fill_cpu_data(xht->cpu_idxs[0], buf); ++ } ++ strncpy(xht->utsname.machine, (char *)(buf + XEN_HYPER_OFFSET(cpuinfo_ia64_vendor)), ++ sizeof(xht->utsname.machine)-1); ++ FREEBUF(buf); ++#endif ++ ++#ifndef IA64 ++ XEN_HYPER_STRUCT_SIZE_INIT(note_buf_t, "note_buf_t"); ++ XEN_HYPER_STRUCT_SIZE_INIT(crash_note_t, "crash_note_t"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_t_core, "crash_note_t", "core"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_t_xen, "crash_note_t", "xen"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_t_xen_regs, "crash_note_t", "xen_regs"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_t_xen_info, "crash_note_t", "xen_info"); ++ ++ XEN_HYPER_STRUCT_SIZE_INIT(crash_note_core_t, "crash_note_core_t"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_core_t_note, "crash_note_core_t", "note"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_core_t_desc, "crash_note_core_t", "desc"); ++ ++ XEN_HYPER_STRUCT_SIZE_INIT(crash_note_xen_t, "crash_note_xen_t"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_xen_t_note, "crash_note_xen_t", "note"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_xen_t_desc, "crash_note_xen_t", "desc"); ++ XEN_HYPER_STRUCT_SIZE_INIT(crash_note_xen_core_t, "crash_note_xen_core_t"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_xen_core_t_note, "crash_note_xen_core_t", "note"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_xen_core_t_desc, "crash_note_xen_core_t", "desc"); ++ XEN_HYPER_STRUCT_SIZE_INIT(crash_note_xen_info_t, "crash_note_xen_info_t"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_xen_info_t_note, "crash_note_xen_info_t", "note"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_xen_info_t_desc, "crash_note_xen_info_t", "desc"); ++ XEN_HYPER_STRUCT_SIZE_INIT(crash_xen_core_t, "crash_xen_core_t"); ++ XEN_HYPER_STRUCT_SIZE_INIT(crash_xen_info_t, "crash_xen_info_t"); ++ XEN_HYPER_STRUCT_SIZE_INIT(xen_crash_xen_regs_t, "xen_crash_xen_regs_t"); ++ ++ XEN_HYPER_STRUCT_SIZE_INIT(ELF_Prstatus,"ELF_Prstatus"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_info, "ELF_Prstatus", "pr_info"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_cursig, "ELF_Prstatus", "pr_cursig"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_sigpend, "ELF_Prstatus", "pr_sigpend"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_sighold, "ELF_Prstatus", "pr_sighold"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_pid, "ELF_Prstatus", "pr_pid"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_ppid, "ELF_Prstatus", "pr_ppid"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_pgrp, "ELF_Prstatus", "pr_pgrp"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_sid, "ELF_Prstatus", "pr_sid"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_utime, "ELF_Prstatus", "pr_utime"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_stime, "ELF_Prstatus", "pr_stime"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_cutime, "ELF_Prstatus", "pr_cutime"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_cstime, "ELF_Prstatus", "pr_cstime"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_reg, "ELF_Prstatus", "pr_reg"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_fpvalid, "ELF_Prstatus", "pr_fpvalid"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Timeval_tv_sec, "ELF_Timeval", "tv_sec"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Timeval_tv_usec, "ELF_Timeval", "tv_usec"); ++ XEN_HYPER_STRUCT_SIZE_INIT(ELF_Signifo,"ELF_Signifo"); ++ XEN_HYPER_STRUCT_SIZE_INIT(ELF_Gregset,"ELF_Gregset"); ++ XEN_HYPER_STRUCT_SIZE_INIT(ELF_Timeval,"ELF_Timeval"); ++#endif ++ XEN_HYPER_STRUCT_SIZE_INIT(domain, "domain"); ++ XEN_HYPER_STRUCT_SIZE_INIT(vcpu, "vcpu"); ++#ifndef IA64 ++ XEN_HYPER_STRUCT_SIZE_INIT(cpu_info, "cpu_info"); ++#endif ++ XEN_HYPER_STRUCT_SIZE_INIT(cpu_user_regs, "cpu_user_regs"); ++ ++ /* ++ * Do some initialization. ++ */ ++#ifndef IA64 ++ xen_hyper_dumpinfo_init(); ++#endif ++ xhmachdep->pcpu_init(); ++ xen_hyper_domain_init(); ++ xen_hyper_vcpu_init(); ++ xen_hyper_misc_init(); ++ /* ++ * xen_hyper_post_init() have to be called after all initialize ++ * functions finished. ++ */ ++ xen_hyper_post_init(); ++} ++ ++/* ++ * Do initialization for Domain of Xen Hyper system here. ++ */ ++void ++xen_hyper_domain_init(void) ++{ ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_domain_id, "domain", "domain_id"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_tot_pages, "domain", "tot_pages"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_max_pages, "domain", "max_pages"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_xenheap_pages, "domain", "xenheap_pages"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_shared_info, "domain", "shared_info"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_sched_priv, "domain", "sched_priv"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_next_in_list, "domain", "next_in_list"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_domain_flags, "domain", "domain_flags"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_evtchn, "domain", "evtchn"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_is_hvm, "domain", "is_hvm"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_is_privileged, "domain", "is_privileged"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_debugger_attached, "domain", "debugger_attached"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_is_polling, "domain", "is_polling"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_is_dying, "domain", "is_dying"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_is_paused_by_controller, "domain", "is_paused_by_controller"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_is_shutting_down, "domain", "is_shutting_down"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_is_shut_down, "domain", "is_shut_down"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_vcpu, "domain", "vcpu"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(domain_arch, "domain", "arch"); ++ ++ XEN_HYPER_STRUCT_SIZE_INIT(arch_shared_info, "arch_shared_info"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(arch_shared_info_max_pfn, "arch_shared_info", "max_pfn"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(arch_shared_info_pfn_to_mfn_frame_list_list, "arch_shared_info", "pfn_to_mfn_frame_list_list"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(arch_shared_info_nmi_reason, "arch_shared_info", "nmi_reason"); ++ ++ XEN_HYPER_STRUCT_SIZE_INIT(shared_info, "shared_info"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(shared_info_vcpu_info, "shared_info", "vcpu_info"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(shared_info_evtchn_pending, "shared_info", "evtchn_pending"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(shared_info_evtchn_mask, "shared_info", "evtchn_mask"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(shared_info_arch, "shared_info", "arch"); ++ ++ XEN_HYPER_STRUCT_SIZE_INIT(arch_domain, "arch_domain"); ++#ifdef IA64 ++ XEN_HYPER_MEMBER_OFFSET_INIT(arch_domain_mm, "arch_domain", "mm"); ++ ++ XEN_HYPER_STRUCT_SIZE_INIT(mm_struct, "mm_struct"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(mm_struct_pgd, "mm_struct", "pgd"); ++#endif ++ ++ if((xhdt->domain_struct = malloc(XEN_HYPER_SIZE(domain))) == NULL) { ++ error(FATAL, "cannot malloc domain struct space.\n"); ++ } ++ if((xhdt->domain_struct_verify = malloc(XEN_HYPER_SIZE(domain))) == NULL) { ++ error(FATAL, "cannot malloc domain struct space to verification.\n"); ++ } ++ xen_hyper_refresh_domain_context_space(); ++ xhdt->flags |= XEN_HYPER_DOMAIN_F_INIT; ++} ++ ++/* ++ * Do initialization for vcpu of Xen Hyper system here. ++ */ ++void ++xen_hyper_vcpu_init(void) ++{ ++ XEN_HYPER_STRUCT_SIZE_INIT(timer, "timer"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(timer_expires, "timer", "expires"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(timer_cpu, "timer", "cpu"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(timer_function, "timer", "function"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(timer_data, "timer", "data"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(timer_heap_offset, "timer", "heap_offset"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(timer_killed, "timer", "killed"); ++ ++ XEN_HYPER_STRUCT_SIZE_INIT(vcpu_runstate_info, "vcpu_runstate_info"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_runstate_info_state, "vcpu_runstate_info", "state"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_runstate_info_state_entry_time, "vcpu_runstate_info", "state_entry_time"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_runstate_info_time, "vcpu_runstate_info", "time"); ++ ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_vcpu_id, "vcpu", "vcpu_id"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_processor, "vcpu", "processor"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_vcpu_info, "vcpu", "vcpu_info"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_domain, "vcpu", "domain"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_next_in_list, "vcpu", "next_in_list"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_timer, "vcpu", "timer"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_sleep_tick, "vcpu", "sleep_tick"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_poll_timer, "vcpu", "poll_timer"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_sched_priv, "vcpu", "sched_priv"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_runstate, "vcpu", "runstate"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_runstate_guest, "vcpu", "runstate_guest"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_vcpu_flags, "vcpu", "vcpu_flags"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_pause_count, "vcpu", "pause_count"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_virq_to_evtchn, "vcpu", "virq_to_evtchn"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_cpu_affinity, "vcpu", "cpu_affinity"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_nmi_addr, "vcpu", "nmi_addr"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_vcpu_dirty_cpumask, "vcpu", "vcpu_dirty_cpumask"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_arch, "vcpu", "arch"); ++ ++#ifdef IA64 ++ XEN_HYPER_ASSIGN_OFFSET(vcpu_thread_ksp) = ++ MEMBER_OFFSET("vcpu", "arch") + MEMBER_OFFSET("arch_vcpu", "_thread") + ++ MEMBER_OFFSET("thread_struct", "ksp"); ++#endif ++ ++ if((xhvct->vcpu_struct = malloc(XEN_HYPER_SIZE(vcpu))) == NULL) { ++ error(FATAL, "cannot malloc vcpu struct space.\n"); ++ } ++ if((xhvct->vcpu_struct_verify = malloc(XEN_HYPER_SIZE(vcpu))) == NULL) { ++ error(FATAL, "cannot malloc vcpu struct space to verification.\n"); ++ } ++ ++ xen_hyper_refresh_vcpu_context_space(); ++ xhvct->flags |= XEN_HYPER_VCPU_F_INIT; ++ xhvct->idle_vcpu = symbol_value("idle_vcpu"); ++} ++ ++/* ++ * Do initialization for pcpu of Xen Hyper system here. ++ */ ++#if defined(X86) || defined(X86_64) ++void ++xen_hyper_x86_pcpu_init(void) ++{ ++ ulong cpu_info; ++ ulong init_tss_base, init_tss; ++ ulong sp; ++ struct xen_hyper_pcpu_context *pcc; ++ char *buf, *bp; ++ int i, cpuid; ++ ++ XEN_HYPER_MEMBER_OFFSET_INIT(cpu_info_guest_cpu_user_regs, "cpu_info", "guest_cpu_user_regs"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(cpu_info_processor_id, "cpu_info", "processor_id"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(cpu_info_current_vcpu, "cpu_info", "current_vcpu"); ++ ++ if((xhpct->pcpu_struct = malloc(XEN_HYPER_SIZE(cpu_info))) == NULL) { ++ error(FATAL, "cannot malloc pcpu struct space.\n"); ++ } ++ ++ /* get physical cpu context */ ++ xen_hyper_alloc_pcpu_context_space(XEN_HYPER_MAX_CPUS()); ++ init_tss_base = symbol_value("init_tss"); ++ buf = GETBUF(XEN_HYPER_SIZE(tss_struct)); ++ for_cpu_indexes(i, cpuid) ++ { ++ init_tss = init_tss_base + XEN_HYPER_SIZE(tss_struct) * cpuid; ++ if (!readmem(init_tss, KVADDR, buf, ++ XEN_HYPER_SIZE(tss_struct), "init_tss", RETURN_ON_ERROR)) { ++ error(FATAL, "cannot read init_tss.\n"); ++ } ++ if (machine_type("X86")) { ++ sp = ULONG(buf + XEN_HYPER_OFFSET(tss_struct_esp0)); ++ } else if (machine_type("X86_64")) { ++ sp = ULONG(buf + XEN_HYPER_OFFSET(tss_struct_rsp0)); ++ } ++ cpu_info = XEN_HYPER_GET_CPU_INFO(sp); ++ if (CRASHDEBUG(1)) { ++ fprintf(fp, "sp=%lx, cpu_info=%lx\n", sp, cpu_info); ++ } ++ if(!(bp = xen_hyper_read_pcpu(cpu_info))) { ++ error(FATAL, "cannot read cpu_info.\n"); ++ } ++ pcc = &xhpct->context_array[cpuid]; ++ xen_hyper_store_pcpu_context(pcc, cpu_info, bp); ++ xen_hyper_store_pcpu_context_tss(pcc, init_tss, buf); ++ } ++ FREEBUF(buf); ++} ++ ++#elif defined(IA64) ++void ++xen_hyper_ia64_pcpu_init(void) ++{ ++ struct xen_hyper_pcpu_context *pcc; ++ int i, cpuid; ++ ++ /* get physical cpu context */ ++ xen_hyper_alloc_pcpu_context_space(XEN_HYPER_MAX_CPUS()); ++ for_cpu_indexes(i, cpuid) ++ { ++ pcc = &xhpct->context_array[cpuid]; ++ pcc->processor_id = cpuid; ++ } ++} ++#endif ++ ++/* ++ * Do initialization for some miscellaneous thing ++ * of Xen Hyper system here. ++ */ ++void ++xen_hyper_misc_init(void) ++{ ++ XEN_HYPER_STRUCT_SIZE_INIT(schedule_data, "schedule_data"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_schedule_lock, "schedule_data", "schedule_lock"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_curr, "schedule_data", "curr"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_idle, "schedule_data", "idle"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_sched_priv, "schedule_data", "sched_priv"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_s_timer, "schedule_data", "s_timer"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_tick, "schedule_data", "tick"); ++ ++ XEN_HYPER_STRUCT_SIZE_INIT(scheduler, "scheduler"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_name, "scheduler", "name"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_opt_name, "scheduler", "opt_name"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_sched_id, "scheduler", "sched_id"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_init, "scheduler", "init"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_tick, "scheduler", "tick"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_init_vcpu, "scheduler", "init_vcpu"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_destroy_domain, "scheduler", "destroy_domain"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_sleep, "scheduler", "sleep"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_wake, "scheduler", "wake"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_set_affinity, "scheduler", "set_affinity"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_do_schedule, "scheduler", "do_schedule"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_adjust, "scheduler", "adjust"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_dump_settings, "scheduler", "dump_settings"); ++ XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_dump_cpu_state, "scheduler", "dump_cpu_state"); ++ ++ xen_hyper_schedule_init(); ++} ++ ++/* ++ * Do initialization for scheduler of Xen Hyper system here. ++ */ ++#define XEN_HYPER_SCHEDULERS_ARRAY_CNT 10 ++#define XEN_HYPER_SCHEDULER_NAME 1024 ++ ++static void ++xen_hyper_schedule_init(void) ++{ ++ ulong addr, opt_sched, schedulers, opt_name; ++ long scheduler_opt_name; ++ long schedulers_buf[XEN_HYPER_SCHEDULERS_ARRAY_CNT]; ++ struct xen_hyper_sched_context *schc; ++ char *buf; ++ char opt_name_buf[XEN_HYPER_OPT_SCHED_SIZE]; ++ int i, cpuid, flag; ++ ++ /* get scheduler information */ ++ if((xhscht->scheduler_struct = ++ malloc(XEN_HYPER_SIZE(scheduler))) == NULL) { ++ error(FATAL, "cannot malloc scheduler struct space.\n"); ++ } ++ buf = GETBUF(XEN_HYPER_SCHEDULER_NAME); ++ opt_sched = symbol_value("opt_sched"); ++ if (!readmem(opt_sched, KVADDR, xhscht->opt_sched, ++ XEN_HYPER_OPT_SCHED_SIZE, "opt_sched,", RETURN_ON_ERROR)) { ++ error(FATAL, "cannot read opt_sched,.\n"); ++ } ++ schedulers = symbol_value("schedulers"); ++ scheduler_opt_name = XEN_HYPER_OFFSET(scheduler_opt_name); ++ addr = schedulers; ++ while (xhscht->name == NULL) { ++ if (!readmem(addr, KVADDR, schedulers_buf, ++ sizeof(long) * XEN_HYPER_SCHEDULERS_ARRAY_CNT, ++ "schedulers", RETURN_ON_ERROR)) { ++ error(FATAL, "cannot read schedulers.\n"); ++ } ++ for (i = 0; i < XEN_HYPER_SCHEDULERS_ARRAY_CNT; i++) { ++ if (schedulers_buf[i] == 0) { ++ error(FATAL, "schedule data not found.\n"); ++ } ++ if (!readmem(schedulers_buf[i], KVADDR, ++ xhscht->scheduler_struct, XEN_HYPER_SIZE(scheduler), ++ "scheduler", RETURN_ON_ERROR)) { ++ error(FATAL, "cannot read scheduler.\n"); ++ } ++ opt_name = ULONG(xhscht->scheduler_struct + ++ scheduler_opt_name); ++ if (!readmem(opt_name, KVADDR, opt_name_buf, ++ XEN_HYPER_OPT_SCHED_SIZE, "opt_name", RETURN_ON_ERROR)) { ++ error(FATAL, "cannot read opt_name.\n"); ++ } ++ if (strncmp(xhscht->opt_sched, opt_name_buf, ++ XEN_HYPER_OPT_SCHED_SIZE)) ++ continue; ++ xhscht->scheduler = schedulers_buf[i]; ++ xhscht->sched_id = INT(xhscht->scheduler_struct + ++ XEN_HYPER_OFFSET(scheduler_sched_id)); ++ addr = ULONG(xhscht->scheduler_struct + ++ XEN_HYPER_OFFSET(scheduler_name)); ++ if (!readmem(addr, KVADDR, buf, XEN_HYPER_SCHEDULER_NAME, ++ "scheduler_name", RETURN_ON_ERROR)) { ++ error(FATAL, "cannot read scheduler_name.\n"); ++ } ++ if (strlen(buf) >= XEN_HYPER_SCHEDULER_NAME) { ++ error(FATAL, "cannot read scheduler_name.\n"); ++ } ++ if((xhscht->name = malloc(strlen(buf) + 1)) == NULL) { ++ error(FATAL, "cannot malloc scheduler_name space.\n"); ++ } ++ BZERO(xhscht->name, strlen(buf) + 1); ++ strncpy(xhscht->name, buf, strlen(buf)); ++ break; ++ } ++ addr += sizeof(long) * XEN_HYPER_SCHEDULERS_ARRAY_CNT; ++ } ++ FREEBUF(buf); ++ ++ /* get schedule_data information */ ++ if((xhscht->sched_context_array = ++ malloc(sizeof(struct xen_hyper_sched_context) * XEN_HYPER_MAX_CPUS())) == NULL) { ++ error(FATAL, "cannot malloc xen_hyper_sched_context struct space.\n"); ++ } ++ BZERO(xhscht->sched_context_array, ++ sizeof(struct xen_hyper_sched_context) * XEN_HYPER_MAX_CPUS()); ++ buf = GETBUF(XEN_HYPER_SIZE(schedule_data)); ++ if (symbol_exists("per_cpu__schedule_data")) { ++ addr = symbol_value("per_cpu__schedule_data"); ++ flag = TRUE; ++ } else { ++ addr = symbol_value("schedule_data"); ++ flag = FALSE; ++ } ++ for_cpu_indexes(i, cpuid) ++ { ++ schc = &xhscht->sched_context_array[cpuid]; ++ if (flag) { ++ schc->schedule_data = ++ xen_hyper_per_cpu(addr, i); ++ } else { ++ schc->schedule_data = addr + ++ XEN_HYPER_SIZE(schedule_data) * i; ++ } ++ if (!readmem(schc->schedule_data, ++ KVADDR, buf, XEN_HYPER_SIZE(schedule_data), ++ "schedule_data", RETURN_ON_ERROR)) { ++ error(FATAL, "cannot read schedule_data.\n"); ++ } ++ schc->cpu_id = cpuid; ++ schc->curr = ULONG(buf + XEN_HYPER_OFFSET(schedule_data_curr)); ++ schc->idle = ULONG(buf + XEN_HYPER_OFFSET(schedule_data_idle)); ++ schc->sched_priv = ++ ULONG(buf + XEN_HYPER_OFFSET(schedule_data_sched_priv)); ++ if (XEN_HYPER_VALID_MEMBER(schedule_data_tick)) ++ schc->tick = ULONG(buf + XEN_HYPER_OFFSET(schedule_data_tick)); ++ } ++ FREEBUF(buf); ++} ++ ++/* ++ * This should be called after all initailize process finished. ++ */ ++void ++xen_hyper_post_init(void) ++{ ++ struct xen_hyper_pcpu_context *pcc; ++ int i, cpuid; ++ ++ /* set current vcpu to pcpu context */ ++ for_cpu_indexes(i, cpuid) ++ { ++ pcc = &xhpct->context_array[cpuid]; ++ if (!pcc->current_vcpu) { ++ pcc->current_vcpu = ++ xen_hyper_get_active_vcpu_from_pcpuid(cpuid); ++ } ++ } ++ ++ /* set pcpu last */ ++ if (!(xhpct->last = ++ xen_hyper_id_to_pcpu_context(XEN_HYPER_CRASHING_CPU()))) { ++ xhpct->last = &xhpct->context_array[xht->cpu_idxs[0]]; ++ } ++ ++ /* set vcpu last */ ++ if (xhpct->last) { ++ xhvct->last = ++ xen_hyper_vcpu_to_vcpu_context(xhpct->last->current_vcpu); ++ /* set crashing vcpu */ ++ xht->crashing_vcc = xhvct->last; ++ } ++ if (!xhvct->last) { ++ xhvct->last = xhvct->vcpu_context_arrays->context_array; ++ } ++ ++ /* set domain last */ ++ if (xhvct->last) { ++ xhdt->last = ++ xen_hyper_domain_to_domain_context(xhvct->last->domain); ++ } ++ if (!xhdt->last) { ++ xhdt->last = xhdt->context_array; ++ } ++} ++ ++/* ++ * Do initialization for dump information here. ++ */ ++void ++xen_hyper_dumpinfo_init(void) ++{ ++ Elf32_Nhdr *note; ++ char *buf, *bp, *np, *upp; ++ char *nccp, *xccp; ++ ulong addr; ++ long size; ++ int i, cpuid, samp_cpuid; ++ ++ /* ++ * NOTE kakuma: It is not clear that what kind of ++ * a elf note format each one of the xen uses. ++ * So, we decide it confirming whether a symbol exists. ++ */ ++ if (STRUCT_EXISTS("note_buf_t")) ++ xhdit->note_ver = XEN_HYPER_ELF_NOTE_V1; ++ else if (STRUCT_EXISTS("crash_note_xen_t")) ++ xhdit->note_ver = XEN_HYPER_ELF_NOTE_V2; ++ else if (STRUCT_EXISTS("crash_xen_core_t")) { ++ if (STRUCT_EXISTS("crash_note_xen_core_t")) ++ xhdit->note_ver = XEN_HYPER_ELF_NOTE_V3; ++ else ++ xhdit->note_ver = XEN_HYPER_ELF_NOTE_V4; ++ } else { ++ error(WARNING, "found unsupported elf note format while checking of xen dumpinfo.\n"); ++ return; ++ } ++ if (!xen_hyper_test_pcpu_id(XEN_HYPER_CRASHING_CPU())) { ++ error(WARNING, "crashing_cpu not found.\n"); ++ return; ++ } ++ ++ /* allocate a context area */ ++ size = sizeof(struct xen_hyper_dumpinfo_context) * XEN_HYPER_MAX_CPUS(); ++ if((xhdit->context_array = malloc(size)) == NULL) { ++ error(FATAL, "cannot malloc dumpinfo table context space.\n"); ++ } ++ BZERO(xhdit->context_array, size); ++ size = sizeof(struct xen_hyper_dumpinfo_context_xen_core) * XEN_HYPER_MAX_CPUS(); ++ if((xhdit->context_xen_core_array = malloc(size)) == NULL) { ++ error(FATAL, "cannot malloc dumpinfo table context_xen_core_array space.\n"); ++ } ++ BZERO(xhdit->context_xen_core_array, size); ++ addr = symbol_value("per_cpu__crash_notes"); ++ for (i = 0; i < XEN_HYPER_MAX_CPUS(); i++) { ++ ulong addr_notes; ++ ++ addr_notes = xen_hyper_per_cpu(addr, i); ++ if (xhdit->note_ver == XEN_HYPER_ELF_NOTE_V4) { ++ if (!readmem(addr_notes, KVADDR, &(xhdit->context_array[i].note), ++ sizeof(ulong), "per_cpu__crash_notes", RETURN_ON_ERROR)) { ++ error(WARNING, "cannot read per_cpu__crash_notes.\n"); ++ return; ++ } ++ } else { ++ xhdit->context_array[i].note = addr_notes; ++ } ++ } ++ ++ if (xhdit->note_ver == XEN_HYPER_ELF_NOTE_V1) { ++ xhdit->note_size = XEN_HYPER_SIZE(note_buf_t); ++ } else if (xhdit->note_ver == XEN_HYPER_ELF_NOTE_V4) { ++ xhdit->note_size = XEN_HYPER_ELF_NOTE_V4_NOTE_SIZE; ++ } else { ++ xhdit->note_size = XEN_HYPER_SIZE(crash_note_t); ++ } ++ ++ /* read a sample note */ ++ buf = GETBUF(xhdit->note_size); ++ if (xhdit->note_ver == XEN_HYPER_ELF_NOTE_V4) ++ samp_cpuid = xht->cpu_idxs[0]; ++ else ++ samp_cpuid = XEN_HYPER_CRASHING_CPU(); ++ xhdit->xen_info_cpu = samp_cpuid; ++ if (!xen_hyper_fill_elf_notes(xhdit->context_array[samp_cpuid].note, ++ buf, XEN_HYPER_ELF_NOTE_FILL_T_NOTE)) { ++ error(FATAL, "cannot read per_cpu__crash_notes.\n"); ++ } ++ bp = buf; ++ ++ /* Get elf format information for each version. */ ++ switch (xhdit->note_ver) { ++ case XEN_HYPER_ELF_NOTE_V1: ++ /* core data */ ++ note = (Elf32_Nhdr *)bp; ++ np = bp + sizeof(Elf32_Nhdr); ++ upp = np + note->n_namesz; ++ upp = (char *)roundup((ulong)upp, 4); ++ xhdit->core_offset = (Elf_Word)((ulong)upp - (ulong)note); ++ note = (Elf32_Nhdr *)(upp + note->n_descsz); ++ /* cr3 data */ ++ np = (char *)note + sizeof(Elf32_Nhdr); ++ upp = np + note->n_namesz; ++ upp = (char *)roundup((ulong)upp, 4); ++ upp = upp + note->n_descsz; ++ xhdit->core_size = upp - bp; ++ break; ++ case XEN_HYPER_ELF_NOTE_V2: ++ /* core data */ ++ xhdit->core_offset = XEN_HYPER_OFFSET(crash_note_core_t_desc); ++ xhdit->core_size = XEN_HYPER_SIZE(crash_note_core_t); ++ /* xen core */ ++ xhdit->xen_info_offset = XEN_HYPER_OFFSET(crash_note_xen_t_desc); ++ xhdit->xen_info_size = XEN_HYPER_SIZE(crash_note_xen_t); ++ break; ++ case XEN_HYPER_ELF_NOTE_V3: ++ /* core data */ ++ xhdit->core_offset = XEN_HYPER_OFFSET(crash_note_core_t_desc); ++ xhdit->core_size = XEN_HYPER_SIZE(crash_note_core_t); ++ /* xen core */ ++ xhdit->xen_core_offset = XEN_HYPER_OFFSET(crash_note_xen_core_t_desc); ++ xhdit->xen_core_size = XEN_HYPER_SIZE(crash_note_xen_core_t); ++ /* xen info */ ++ xhdit->xen_info_offset = XEN_HYPER_OFFSET(crash_note_xen_info_t_desc); ++ xhdit->xen_info_size = XEN_HYPER_SIZE(crash_note_xen_info_t); ++ break; ++ case XEN_HYPER_ELF_NOTE_V4: ++ /* core data */ ++ note = (Elf32_Nhdr *)bp; ++ np = bp + sizeof(Elf32_Nhdr); ++ upp = np + note->n_namesz; ++ upp = (char *)roundup((ulong)upp, 4); ++ xhdit->core_offset = (Elf_Word)((ulong)upp - (ulong)note); ++ upp = upp + note->n_descsz; ++ xhdit->core_size = (Elf_Word)((ulong)upp - (ulong)note); ++ if (XEN_HYPER_ELF_NOTE_V4_NOTE_SIZE < xhdit->core_size + 32) { ++ error(WARNING, "note size is assumed on crash is incorrect.(core data)\n"); ++ return; ++ } ++ /* xen core */ ++ note = (Elf32_Nhdr *)upp; ++ np = (char *)note + sizeof(Elf32_Nhdr); ++ upp = np + note->n_namesz; ++ upp = (char *)roundup((ulong)upp, 4); ++ xhdit->xen_core_offset = (Elf_Word)((ulong)upp - (ulong)note); ++ upp = upp + note->n_descsz; ++ xhdit->xen_core_size = (Elf_Word)((ulong)upp - (ulong)note); ++ if (XEN_HYPER_ELF_NOTE_V4_NOTE_SIZE < ++ xhdit->core_size + xhdit->xen_core_size + 32) { ++ error(WARNING, "note size is assumed on crash is incorrect.(xen core)\n"); ++ return; ++ } ++ /* xen info */ ++ note = (Elf32_Nhdr *)upp; ++ np = (char *)note + sizeof(Elf32_Nhdr); ++ upp = np + note->n_namesz; ++ upp = (char *)roundup((ulong)upp, 4); ++ xhdit->xen_info_offset = (Elf_Word)((ulong)upp - (ulong)note); ++ upp = upp + note->n_descsz; ++ xhdit->xen_info_size = (Elf_Word)((ulong)upp - (ulong)note); ++ if (XEN_HYPER_ELF_NOTE_V4_NOTE_SIZE < ++ xhdit->core_size + xhdit->xen_core_size + xhdit->xen_info_size) { ++ error(WARNING, "note size is assumed on crash is incorrect.(xen info)\n"); ++ return; ++ } ++ xhdit->note_size = xhdit->core_size + xhdit->xen_core_size + xhdit->xen_info_size; ++ break; ++ default: ++ error(FATAL, "logic error in cheking elf note format occurs.\n"); ++ } ++ ++ /* fill xen info context. */ ++ if (xhdit->note_ver >= XEN_HYPER_ELF_NOTE_V3) { ++ if((xhdit->crash_note_xen_info_ptr = ++ malloc(xhdit->xen_info_size)) == NULL) { ++ error(FATAL, "cannot malloc dumpinfo table " ++ "crash_note_xen_info_ptr space.\n"); ++ } ++ memcpy(xhdit->crash_note_xen_info_ptr, ++ bp + xhdit->core_size + xhdit->xen_core_size, ++ xhdit->xen_info_size); ++ xhdit->context_xen_info.note = ++ xhdit->context_array[samp_cpuid].note + ++ xhdit->core_size + xhdit->xen_core_size; ++ xhdit->context_xen_info.pcpu_id = samp_cpuid; ++ xhdit->context_xen_info.crash_xen_info_ptr = ++ xhdit->crash_note_xen_info_ptr + xhdit->xen_info_offset; ++ } ++ ++ /* allocate note core */ ++ size = xhdit->core_size * XEN_HYPER_NR_PCPUS(); ++ if(!(xhdit->crash_note_core_array = malloc(size))) { ++ error(FATAL, "cannot malloc crash_note_core_array space.\n"); ++ } ++ nccp = xhdit->crash_note_core_array; ++ BZERO(nccp, size); ++ ++ /* allocate xen core */ ++ if (xhdit->note_ver >= XEN_HYPER_ELF_NOTE_V2) { ++ size = xhdit->xen_core_size * XEN_HYPER_NR_PCPUS(); ++ if(!(xhdit->crash_note_xen_core_array = malloc(size))) { ++ error(FATAL, "cannot malloc dumpinfo table " ++ "crash_note_xen_core_array space.\n"); ++ } ++ xccp = xhdit->crash_note_xen_core_array; ++ BZERO(xccp, size); ++ } ++ ++ /* fill a context. */ ++ for_cpu_indexes(i, cpuid) ++ { ++ /* fill core context. */ ++ addr = xhdit->context_array[cpuid].note; ++ if (!xen_hyper_fill_elf_notes(addr, nccp, ++ XEN_HYPER_ELF_NOTE_FILL_T_CORE)) { ++ error(FATAL, "cannot read elf note core.\n"); ++ } ++ xhdit->context_array[cpuid].pcpu_id = cpuid; ++ xhdit->context_array[cpuid].ELF_Prstatus_ptr = ++ nccp + xhdit->core_offset; ++ xhdit->context_array[cpuid].pr_reg_ptr = ++ nccp + xhdit->core_offset + ++ XEN_HYPER_OFFSET(ELF_Prstatus_pr_reg); ++ ++ /* Is there xen core data? */ ++ if (xhdit->note_ver < XEN_HYPER_ELF_NOTE_V2) { ++ nccp += xhdit->core_size; ++ continue; ++ } ++ if (xhdit->note_ver == XEN_HYPER_ELF_NOTE_V2 && ++ cpuid != samp_cpuid) { ++ xccp += xhdit->xen_core_size; ++ nccp += xhdit->core_size; ++ continue; ++ } ++ ++ /* fill xen core context, in case of more elf note V2. */ ++ xhdit->context_xen_core_array[cpuid].note = ++ xhdit->context_array[cpuid].note + ++ xhdit->core_size; ++ xhdit->context_xen_core_array[cpuid].pcpu_id = cpuid; ++ xhdit->context_xen_core_array[cpuid].crash_xen_core_ptr = ++ xccp + xhdit->xen_core_offset; ++ if (!xen_hyper_fill_elf_notes(xhdit->context_xen_core_array[cpuid].note, ++ xccp, XEN_HYPER_ELF_NOTE_FILL_T_XEN_CORE)) { ++ error(FATAL, "cannot read elf note xen core.\n"); ++ } ++ xccp += xhdit->xen_core_size; ++ nccp += xhdit->core_size; ++ } ++ ++ FREEBUF(buf); ++} ++ ++/* ++ * Get dump information context from physical cpu id. ++ */ ++struct xen_hyper_dumpinfo_context * ++xen_hyper_id_to_dumpinfo_context(uint id) ++{ ++ if (!xen_hyper_test_pcpu_id(id)) ++ return NULL; ++ return &xhdit->context_array[id]; ++} ++ ++/* ++ * Get dump information context from ELF Note address. ++ */ ++struct xen_hyper_dumpinfo_context * ++xen_hyper_note_to_dumpinfo_context(ulong note) ++{ ++ int i; ++ ++ for (i = 0; i < XEN_HYPER_MAX_CPUS(); i++) { ++ if (note == xhdit->context_array[i].note) { ++ return &xhdit->context_array[i]; ++ } ++ } ++ return NULL; ++} ++ ++/* ++ * Fill ELF Notes header here. ++ * This assume that variable note has a top address of an area for ++ * specified type. ++ */ ++char * ++xen_hyper_fill_elf_notes(ulong note, char *note_buf, int type) ++{ ++ long size; ++ ulong rp = note; ++ ++ if (type == XEN_HYPER_ELF_NOTE_FILL_T_NOTE) ++ size = xhdit->note_size; ++ else if (type == XEN_HYPER_ELF_NOTE_FILL_T_CORE) ++ size = xhdit->core_size; ++ else if (type == XEN_HYPER_ELF_NOTE_FILL_T_XEN_CORE) ++ size = xhdit->xen_core_size; ++ else if (type == XEN_HYPER_ELF_NOTE_FILL_T_XEN_CORE_M) ++ size = xhdit->core_size + xhdit->xen_core_size; ++ else if (type == XEN_HYPER_ELF_NOTE_FILL_T_PRS) ++ size = XEN_HYPER_SIZE(ELF_Prstatus); ++ else if (type == XEN_HYPER_ELF_NOTE_FILL_T_XEN_REGS) ++ size = XEN_HYPER_SIZE(xen_crash_xen_regs_t); ++ else ++ return NULL; ++ ++ if (!readmem(rp, KVADDR, note_buf, size, ++ "note_buf_t or crash_note_t", RETURN_ON_ERROR)) { ++ if (type == XEN_HYPER_ELF_NOTE_FILL_T_NOTE) ++ error(WARNING, "cannot fill note_buf_t or crash_note_t.\n"); ++ else if (type == XEN_HYPER_ELF_NOTE_FILL_T_CORE) ++ error(WARNING, "cannot fill note core.\n"); ++ else if (type == XEN_HYPER_ELF_NOTE_FILL_T_XEN_CORE) ++ error(WARNING, "cannot fill note xen core.\n"); ++ else if (type == XEN_HYPER_ELF_NOTE_FILL_T_XEN_CORE_M) ++ error(WARNING, "cannot fill note core & xen core.\n"); ++ else if (type == XEN_HYPER_ELF_NOTE_FILL_T_PRS) ++ error(WARNING, "cannot fill ELF_Prstatus.\n"); ++ else if (type == XEN_HYPER_ELF_NOTE_FILL_T_XEN_REGS) ++ error(WARNING, "cannot fill xen_crash_xen_regs_t.\n"); ++ return NULL; ++ } ++ return note_buf; ++} ++ ++ ++ ++/* ++ * Get domain status. ++ */ ++ulong ++xen_hyper_domain_state(struct xen_hyper_domain_context *dc) ++{ ++ if (ACTIVE()) { ++ if (xen_hyper_read_domain_verify(dc->domain) == NULL) { ++ return XEN_HYPER_DOMF_ERROR; ++ } ++ } ++ return dc->domain_flags; ++} ++ ++/* ++ * Allocate domain context space. ++ */ ++void ++xen_hyper_refresh_domain_context_space(void) ++{ ++ char *domain_struct; ++ ulong domain, next, dom_xen, dom_io, idle_vcpu; ++ struct xen_hyper_domain_context *dc; ++ struct xen_hyper_domain_context *dom0; ++ ++ if ((xhdt->flags & XEN_HYPER_DOMAIN_F_INIT) && !ACTIVE()) { ++ return; ++ } ++ ++ XEN_HYPER_RUNNING_DOMAINS() = XEN_HYPER_NR_DOMAINS() = ++ xen_hyper_get_domains(); ++ xen_hyper_alloc_domain_context_space(XEN_HYPER_NR_DOMAINS()); ++ ++ dc = xhdt->context_array; ++ ++ /* restore an dom_io context. */ ++ get_symbol_data("dom_io", sizeof(dom_io), &dom_io); ++ if ((domain_struct = xen_hyper_read_domain(dom_io)) == NULL) { ++ error(FATAL, "cannot read dom_io.\n"); ++ } ++ xen_hyper_store_domain_context(dc, dom_io, domain_struct); ++ xhdt->dom_io = dc; ++ dc++; ++ ++ /* restore an dom_xen context. */ ++ get_symbol_data("dom_xen", sizeof(dom_xen), &dom_xen); ++ if ((domain_struct = xen_hyper_read_domain(dom_xen)) == NULL) { ++ error(FATAL, "cannot read dom_xen.\n"); ++ } ++ xen_hyper_store_domain_context(dc, dom_xen, domain_struct); ++ xhdt->dom_xen = dc; ++ dc++; ++ ++ /* restore an idle domain context. */ ++ get_symbol_data("idle_vcpu", sizeof(idle_vcpu), &idle_vcpu); ++ if (!readmem(idle_vcpu + MEMBER_OFFSET("vcpu", "domain"), ++ KVADDR, &domain, sizeof(domain), "domain", RETURN_ON_ERROR)) { ++ error(WARNING, "cannot read domain member in vcpu.\n"); ++ } ++ if (CRASHDEBUG(1)) { ++ fprintf(fp, "idle_vcpu=%lx, domain=%lx\n", idle_vcpu, domain); ++ } ++ if ((domain_struct = xen_hyper_read_domain(domain)) == NULL) { ++ error(FATAL, "cannot read idle domain.\n"); ++ } ++ xen_hyper_store_domain_context(dc, domain, domain_struct); ++ xhdt->idle_domain = dc; ++ dc++; ++ ++ /* restore domain contexts from dom0 symbol. */ ++ xen_hyper_get_domain_next(XEN_HYPER_DOMAIN_READ_DOM0, &next); ++ domain = next; ++ dom0 = dc; ++ while((domain_struct = ++ xen_hyper_get_domain_next(XEN_HYPER_DOMAIN_READ_NEXT, &next)) != NULL) { ++ xen_hyper_store_domain_context(dc, domain, domain_struct); ++ domain = next; ++ dc++; ++ } ++ xhdt->dom0 = dom0; ++} ++ ++/* ++ * Get number of domain. ++ */ ++int ++xen_hyper_get_domains(void) ++{ ++ ulong domain, next_in_list; ++ long domain_next_in_list; ++ int i; ++ ++ get_symbol_data("dom0", sizeof(void *), &domain); ++ domain_next_in_list = MEMBER_OFFSET("domain", "next_in_list"); ++ i = 0; ++ while (domain != 0) { ++ i++; ++ next_in_list = domain + domain_next_in_list; ++ if (!readmem(next_in_list, KVADDR, &domain, sizeof(void *), ++ "domain.next_in_list", RETURN_ON_ERROR)) { ++ error(FATAL, "cannot read domain.next_in_list.\n"); ++ } ++ } ++ i += 3; /* for dom_io, dom_xen and idle domain */ ++ return i; ++} ++ ++/* ++ * Get next domain struct. ++ * mod - XEN_HYPER_DOMAIN_READ_DOM0:start from dom0 symbol ++ * - XEN_HYPER_DOMAIN_READ_INIT:start from xhdt->context_array ++ * - XEN_HYPER_DOMAIN_READ_NEXT:next ++ */ ++char * ++xen_hyper_get_domain_next(int mod, ulong *next) ++{ ++ static int idx = 0; ++ ++ char *domain_struct; ++ struct xen_hyper_domain_context *dc; ++ ++ switch (mod) { ++ case XEN_HYPER_DOMAIN_READ_DOM0: ++ /* Case of search from dom0 symbol. */ ++ idx = 0; ++ if (xhdt->dom0) { ++ *next = xhdt->dom0->domain; ++ } else { ++ get_symbol_data("dom0", sizeof(void *), next); ++ } ++ return xhdt->domain_struct; ++ break; ++ case XEN_HYPER_DOMAIN_READ_INIT: ++ /* Case of search from context_array. */ ++ if (xhdt->context_array && xhdt->context_array->domain) { ++ idx = 1; /* this has a next index. */ ++ *next = xhdt->context_array->domain; ++ } else { ++ idx = 0; ++ *next = 0; ++ return NULL; ++ } ++ return xhdt->domain_struct; ++ break; ++ case XEN_HYPER_DOMAIN_READ_NEXT: ++ break; ++ default : ++ error(FATAL, "xen_hyper_get_domain_next mod error: %d\n", mod); ++ return NULL; ++ } ++ ++ /* Finished search */ ++ if (!*next) { ++ return NULL; ++ } ++ ++ domain_struct = NULL; ++ /* Is domain context array valid? */ ++ if (idx) { ++ if ((domain_struct = ++ xen_hyper_read_domain(*next)) == NULL) { ++ error(FATAL, "cannot get next domain from domain context array.\n"); ++ } ++ if (idx > XEN_HYPER_NR_DOMAINS()) { ++ *next = 0; ++ } else { ++ dc = xhdt->context_array; ++ dc += idx; ++ *next = dc->domain; ++ idx++; ++ } ++ return domain_struct; ++ } ++ ++ /* Search from dom0 symbol. */ ++ if ((domain_struct = ++ xen_hyper_read_domain(*next)) == NULL) { ++ error(FATAL, "cannot get next domain from dom0 symbol.\n"); ++ } ++ *next = ULONG(domain_struct + XEN_HYPER_OFFSET(domain_next_in_list)); ++ return domain_struct; ++} ++ ++/* ++ * from domain address to id. ++ */ ++domid_t ++xen_hyper_domain_to_id(ulong domain) ++{ ++ struct xen_hyper_domain_context *dc; ++ ++ /* Is domain context array valid? */ ++ if (xhdt->context_array && xhdt->context_array->domain) { ++ if ((dc = xen_hyper_domain_to_domain_context(domain)) == NULL) { ++ return XEN_HYPER_DOMAIN_ID_INVALID; ++ } else { ++ return dc->domain_id; ++ } ++ } else { ++ return XEN_HYPER_DOMAIN_ID_INVALID; ++ } ++} ++ ++/* ++ * Get domain struct from id. ++ */ ++char * ++xen_hyper_id_to_domain_struct(domid_t id) ++{ ++ char *domain_struct; ++ struct xen_hyper_domain_context *dc; ++ ++ domain_struct = NULL; ++ ++ /* Is domain context array valid? */ ++ if (xhdt->context_array && xhdt->context_array->domain) { ++ if ((dc = xen_hyper_id_to_domain_context(id)) == NULL) { ++ return NULL; ++ } else { ++ if ((domain_struct = ++ xen_hyper_read_domain(dc->domain)) == NULL) { ++ error(FATAL, "cannot get domain from domain context array with id.\n"); ++ } ++ return domain_struct; ++ } ++ } else { ++ return NULL; ++ } ++} ++ ++/* ++ * Get domain context from domain address. ++ */ ++struct xen_hyper_domain_context * ++xen_hyper_domain_to_domain_context(ulong domain) ++{ ++ struct xen_hyper_domain_context *dc; ++ int i; ++ ++ if (xhdt->context_array == NULL || ++ xhdt->context_array->domain == 0) { ++ return NULL; ++ } ++ if (!domain) { ++ return NULL; ++ } ++ for (i = 0, dc = xhdt->context_array; i < XEN_HYPER_NR_DOMAINS(); ++ i++, dc++) { ++ if (domain == dc->domain) { ++ return dc; ++ } ++ } ++ return NULL; ++} ++ ++/* ++ * Get domain context from domain id. ++ */ ++struct xen_hyper_domain_context * ++xen_hyper_id_to_domain_context(domid_t id) ++{ ++ struct xen_hyper_domain_context *dc; ++ int i; ++ ++ if (xhdt->context_array == NULL || ++ xhdt->context_array->domain == 0) { ++ return NULL; ++ } ++ if (id == XEN_HYPER_DOMAIN_ID_INVALID) { ++ return NULL; ++ } ++ for (i = 0, dc = xhdt->context_array; i < XEN_HYPER_NR_DOMAINS(); ++ i++, dc++) { ++ if (id == dc->domain_id) { ++ return dc; ++ } ++ } ++ return NULL; ++} ++ ++/* ++ * Store domain struct contents. ++ */ ++struct xen_hyper_domain_context * ++xen_hyper_store_domain_context(struct xen_hyper_domain_context *dc, ++ ulong domain, char *dp) ++{ ++ int i; ++ ++ dc->domain = domain; ++ BCOPY((char *)(dp + XEN_HYPER_OFFSET(domain_domain_id)), ++ &dc->domain_id, sizeof(domid_t)); ++ dc->tot_pages = UINT(dp + XEN_HYPER_OFFSET(domain_tot_pages)); ++ dc->max_pages = UINT(dp + XEN_HYPER_OFFSET(domain_max_pages)); ++ dc->xenheap_pages = UINT(dp + XEN_HYPER_OFFSET(domain_xenheap_pages)); ++ dc->shared_info = ULONG(dp + XEN_HYPER_OFFSET(domain_shared_info)); ++ dc->sched_priv = ULONG(dp + XEN_HYPER_OFFSET(domain_sched_priv)); ++ dc->next_in_list = ULONG(dp + XEN_HYPER_OFFSET(domain_next_in_list)); ++ if (XEN_HYPER_VALID_MEMBER(domain_domain_flags)) ++ dc->domain_flags = ULONG(dp + XEN_HYPER_OFFSET(domain_domain_flags)); ++ else if (XEN_HYPER_VALID_MEMBER(domain_is_shut_down)) { ++ dc->domain_flags = 0; ++ if (*(dp + XEN_HYPER_OFFSET(domain_is_hvm))) { ++ dc->domain_flags |= XEN_HYPER_DOMS_HVM; ++ } else if (*(dp + XEN_HYPER_OFFSET(domain_is_privileged))) { ++ dc->domain_flags |= XEN_HYPER_DOMS_privileged; ++ } else if (*(dp + XEN_HYPER_OFFSET(domain_debugger_attached))) { ++ dc->domain_flags |= XEN_HYPER_DOMS_debugging; ++ } else if (*(dp + XEN_HYPER_OFFSET(domain_is_polling))) { ++ dc->domain_flags |= XEN_HYPER_DOMS_polling; ++ } else if (*(dp + XEN_HYPER_OFFSET(domain_is_paused_by_controller))) { ++ dc->domain_flags |= XEN_HYPER_DOMS_ctrl_pause; ++ } else if (*(dp + XEN_HYPER_OFFSET(domain_is_dying))) { ++ dc->domain_flags |= XEN_HYPER_DOMS_dying; ++ } else if (*(dp + XEN_HYPER_OFFSET(domain_is_shutting_down))) { ++ dc->domain_flags |= XEN_HYPER_DOMS_shuttingdown; ++ } else if (*(dp + XEN_HYPER_OFFSET(domain_is_shut_down))) { ++ dc->domain_flags |= XEN_HYPER_DOMS_shutdown; ++ } ++ } else { ++ dc->domain_flags = XEN_HYPER_DOMF_ERROR; ++ } ++ dc->evtchn = ULONG(dp + XEN_HYPER_OFFSET(domain_evtchn)); ++ for (i = 0; i < XEN_HYPER_MAX_VIRT_CPUS; i++) { ++ dc->vcpu[i] = ULONG(dp + XEN_HYPER_OFFSET(domain_vcpu) + i*sizeof(void *)); ++ if (dc->vcpu[i]) XEN_HYPER_NR_VCPUS_IN_DOM(dc)++; ++ } ++ ++ return dc; ++} ++ ++/* ++ * Read domain struct from domain context. ++ */ ++char * ++xen_hyper_read_domain_from_context(struct xen_hyper_domain_context *dc) ++{ ++ return xen_hyper_fill_domain_struct(dc->domain, xhdt->domain_struct); ++} ++ ++/* ++ * Read domain struct. ++ */ ++char * ++xen_hyper_read_domain(ulong domain) ++{ ++ return xen_hyper_fill_domain_struct(domain, xhdt->domain_struct); ++} ++ ++/* ++ * Read domain struct to verification. ++ */ ++char * ++xen_hyper_read_domain_verify(ulong domain) ++{ ++ return xen_hyper_fill_domain_struct(domain, xhdt->domain_struct_verify); ++} ++ ++/* ++ * Fill domain struct. ++ */ ++char * ++xen_hyper_fill_domain_struct(ulong domain, char *domain_struct) ++{ ++ if (!readmem(domain, KVADDR, domain_struct, ++ XEN_HYPER_SIZE(domain), "fill_domain_struct", ++ ACTIVE() ? (RETURN_ON_ERROR|QUIET) : RETURN_ON_ERROR)) { ++ error(WARNING, "cannot fill domain struct.\n"); ++ return NULL; ++ } ++ return domain_struct; ++} ++ ++/* ++ * Allocate domain context space. ++ */ ++void ++xen_hyper_alloc_domain_context_space(int domains) ++{ ++ if (xhdt->context_array == NULL) { ++ if (!(xhdt->context_array = ++ malloc(domains * sizeof(struct xen_hyper_domain_context)))) { ++ error(FATAL, "cannot malloc context array (%d domains).", ++ domains); ++ } ++ xhdt->context_array_cnt = domains; ++ } else if (domains > xhdt->context_array_cnt) { ++ if (!(xhdt->context_array = ++ realloc(xhdt->context_array, ++ domains * sizeof(struct xen_hyper_domain_context)))) { ++ error(FATAL, "cannot realloc context array (%d domains).", ++ domains); ++ } ++ xhdt->context_array_cnt = domains; ++ } ++ BZERO(xhdt->context_array, ++ domains * sizeof(struct xen_hyper_domain_context)); ++} ++ ++ ++ ++/* ++ * Get vcpu status. ++ */ ++int ++xen_hyper_vcpu_state(struct xen_hyper_vcpu_context *vcc) ++{ ++ if (ACTIVE()) { ++ if (xen_hyper_read_vcpu_verify(vcc->vcpu) == NULL) { ++ return XEN_HYPER_RUNSTATE_ERROR; ++ } ++ } ++ return vcc->state; ++} ++ ++/* ++ * Allocate vcpu context space. ++ */ ++void ++xen_hyper_refresh_vcpu_context_space(void) ++{ ++ struct xen_hyper_domain_context *dc; ++ struct xen_hyper_vcpu_context_array *vcca; ++ struct xen_hyper_vcpu_context *vcc; ++ int i, j; ++ ++ if ((xhvct->flags & XEN_HYPER_VCPU_F_INIT) && !ACTIVE()) { ++ return; ++ } ++ ++ xen_hyper_alloc_vcpu_context_arrays_space(XEN_HYPER_NR_DOMAINS()); ++ for (i = 0, xht->vcpus = 0, dc = xhdt->context_array, ++ vcca = xhvct->vcpu_context_arrays; ++ i < XEN_HYPER_NR_DOMAINS(); i++, dc++, vcca++) { ++ dc->vcpu_context_array = vcca; ++ xen_hyper_alloc_vcpu_context_space(vcca, ++ XEN_HYPER_NR_VCPUS_IN_DOM(dc)); ++ for (j = 0, vcc = vcca->context_array; ++ j < XEN_HYPER_NR_VCPUS_IN_DOM(dc); j++, vcc++) { ++ xen_hyper_read_vcpu(dc->vcpu[j]); ++ xen_hyper_store_vcpu_context(vcc, dc->vcpu[j], ++ xhvct->vcpu_struct); ++ } ++ if (dc == xhdt->idle_domain) { ++ xhvct->idle_vcpu_context_array = vcca; ++ } ++ xht->vcpus += vcca->context_array_cnt; ++ } ++} ++ ++/* ++ * Get vcpu context from vcpu address. ++ */ ++struct xen_hyper_vcpu_context * ++xen_hyper_vcpu_to_vcpu_context(ulong vcpu) ++{ ++ struct xen_hyper_vcpu_context_array *vcca; ++ struct xen_hyper_vcpu_context *vcc; ++ int i, j; ++ ++ if (!vcpu) { ++ return NULL; ++ } ++ for (i = 0, vcca = xhvct->vcpu_context_arrays; ++ i < xhvct->vcpu_context_arrays_cnt; i++, vcca++) { ++ for (j = 0, vcc = vcca->context_array; ++ j < vcca->context_array_cnt; j++, vcc++) { ++ if (vcpu == vcc->vcpu) { ++ return vcc; ++ } ++ } ++ } ++ return NULL; ++} ++ ++/* ++ * Get vcpu context. ++ */ ++struct xen_hyper_vcpu_context * ++xen_hyper_id_to_vcpu_context(ulong domain, domid_t did, int vcid) ++{ ++ struct xen_hyper_vcpu_context_array *vcca; ++ struct xen_hyper_vcpu_context *vcc; ++ int i; ++ ++ if (vcid == XEN_HYPER_VCPU_ID_INVALID) { ++ return NULL; ++ } ++ if ((vcca = xen_hyper_domain_to_vcpu_context_array(domain))) { ++ ; ++ } else if (!(vcca = xen_hyper_domid_to_vcpu_context_array(did))) { ++ return NULL; ++ } ++ for (i = 0, vcc = vcca->context_array; ++ i < vcca->context_array_cnt; i++, vcc++) { ++ if (vcid == vcc->vcpu_id) { ++ return vcc; ++ } ++ } ++ return NULL; ++} ++ ++/* ++ * Get pointer of a vcpu context array from domain address. ++ */ ++struct xen_hyper_vcpu_context_array * ++xen_hyper_domain_to_vcpu_context_array(ulong domain) ++{ ++ struct xen_hyper_domain_context *dc; ++ ++ if(!(dc = xen_hyper_domain_to_domain_context(domain))) { ++ return NULL; ++ } ++ return dc->vcpu_context_array; ++} ++ ++/* ++ * Get pointer of a vcpu context array from domain id. ++ */ ++struct xen_hyper_vcpu_context_array * ++xen_hyper_domid_to_vcpu_context_array(domid_t id) ++{ ++ struct xen_hyper_domain_context *dc; ++ ++ if (!(dc = xen_hyper_id_to_domain_context(id))) { ++ return NULL; ++ } ++ return dc->vcpu_context_array; ++} ++ ++/* ++ * Store vcpu struct contents. ++ */ ++struct xen_hyper_vcpu_context * ++xen_hyper_store_vcpu_context(struct xen_hyper_vcpu_context *vcc, ++ ulong vcpu, char *vcp) ++{ ++ vcc->vcpu = vcpu; ++ vcc->vcpu_id = INT(vcp + XEN_HYPER_OFFSET(vcpu_vcpu_id)); ++ vcc->processor = INT(vcp + XEN_HYPER_OFFSET(vcpu_processor)); ++ vcc->vcpu_info = ULONG(vcp + XEN_HYPER_OFFSET(vcpu_vcpu_info)); ++ vcc->domain = ULONG(vcp + XEN_HYPER_OFFSET(vcpu_domain)); ++ vcc->next_in_list = ULONG(vcp + XEN_HYPER_OFFSET(vcpu_next_in_list)); ++ if (XEN_HYPER_VALID_MEMBER(vcpu_sleep_tick)) ++ vcc->sleep_tick = ULONG(vcp + XEN_HYPER_OFFSET(vcpu_sleep_tick)); ++ vcc->sched_priv = ULONG(vcp + XEN_HYPER_OFFSET(vcpu_sched_priv)); ++ vcc->state = INT(vcp + XEN_HYPER_OFFSET(vcpu_runstate) + ++ XEN_HYPER_OFFSET(vcpu_runstate_info_state)); ++ vcc->state_entry_time = ULONGLONG(vcp + ++ XEN_HYPER_OFFSET(vcpu_runstate) + ++ XEN_HYPER_OFFSET(vcpu_runstate_info_state_entry_time)); ++ vcc->runstate_guest = ULONG(vcp + XEN_HYPER_OFFSET(vcpu_runstate_guest)); ++ if (XEN_HYPER_VALID_MEMBER(vcpu_vcpu_flags)) ++ vcc->vcpu_flags = ULONG(vcp + XEN_HYPER_OFFSET(vcpu_vcpu_flags)); ++ else ++ vcc->vcpu_flags = XEN_HYPER_VCPUF_ERROR; ++ return vcc; ++} ++ ++/* ++ * Read vcpu struct from vcpu context. ++ */ ++char * ++xen_hyper_read_vcpu_from_context(struct xen_hyper_vcpu_context *vcc) ++{ ++ return xen_hyper_fill_vcpu_struct(vcc->vcpu, xhvct->vcpu_struct); ++} ++ ++/* ++ * Read vcpu struct. ++ */ ++char * ++xen_hyper_read_vcpu(ulong vcpu) ++{ ++ return xen_hyper_fill_vcpu_struct(vcpu, xhvct->vcpu_struct); ++} ++ ++/* ++ * Read vcpu struct to verification. ++ */ ++char * ++xen_hyper_read_vcpu_verify(ulong vcpu) ++{ ++ return xen_hyper_fill_vcpu_struct(vcpu, xhvct->vcpu_struct_verify); ++} ++ ++/* ++ * Fill vcpu struct. ++ */ ++char * ++xen_hyper_fill_vcpu_struct(ulong vcpu, char *vcpu_struct) ++{ ++ if (!readmem(vcpu, KVADDR, vcpu_struct, ++ XEN_HYPER_SIZE(vcpu), "fill_vcpu_struct", ++ ACTIVE() ? (RETURN_ON_ERROR|QUIET) : RETURN_ON_ERROR)) { ++ error(WARNING, "cannot fill vcpu struct.\n"); ++ return NULL; ++ } ++ return vcpu_struct; ++} ++ ++/* ++ * Allocate vcpu context arrays space. ++ */ ++void ++xen_hyper_alloc_vcpu_context_arrays_space(int domains) ++{ ++ struct xen_hyper_vcpu_context_array *vcca; ++ ++ if (xhvct->vcpu_context_arrays == NULL) { ++ if (!(xhvct->vcpu_context_arrays = ++ malloc(domains * sizeof(struct xen_hyper_vcpu_context_array)))) { ++ error(FATAL, "cannot malloc context arrays (%d domains).", ++ domains); ++ } ++ BZERO(xhvct->vcpu_context_arrays, domains * sizeof(struct xen_hyper_vcpu_context_array)); ++ xhvct->vcpu_context_arrays_cnt = domains; ++ } else if (domains > xhvct->vcpu_context_arrays_cnt) { ++ if (!(xhvct->vcpu_context_arrays = ++ realloc(xhvct->vcpu_context_arrays, ++ domains * sizeof(struct xen_hyper_vcpu_context_array)))) { ++ error(FATAL, "cannot realloc context arrays (%d domains).", ++ domains); ++ } ++ vcca = xhvct->vcpu_context_arrays + domains; ++ BZERO(vcca, (domains - xhvct->vcpu_context_arrays_cnt) * ++ sizeof(struct xen_hyper_vcpu_context_array)); ++ xhvct->vcpu_context_arrays_cnt = domains; ++ } ++} ++ ++/* ++ * Allocate vcpu context space. ++ */ ++void ++xen_hyper_alloc_vcpu_context_space(struct xen_hyper_vcpu_context_array *vcca, int vcpus) ++{ ++ if (!vcpus) { ++ if (vcca->context_array != NULL) { ++ free(vcca->context_array); ++ vcca->context_array = NULL; ++ } ++ vcca->context_array_cnt = vcpus; ++ } else if (vcca->context_array == NULL) { ++ if (!(vcca->context_array = ++ malloc(vcpus * sizeof(struct xen_hyper_vcpu_context)))) { ++ error(FATAL, "cannot malloc context array (%d vcpus).", ++ vcpus); ++ } ++ vcca->context_array_cnt = vcpus; ++ } else if (vcpus > vcca->context_array_cnt) { ++ if (!(vcca->context_array = ++ realloc(vcca->context_array, ++ vcpus * sizeof(struct xen_hyper_vcpu_context_array)))) { ++ error(FATAL, "cannot realloc context array (%d vcpus).", ++ vcpus); ++ } ++ vcca->context_array_cnt = vcpus; ++ } ++ vcca->context_array_valid = vcpus; ++ BZERO(vcca->context_array, vcpus * sizeof(struct xen_hyper_vcpu_context)); ++} ++ ++ ++ ++/* ++ * Get pcpu context from pcpu id. ++ */ ++struct xen_hyper_pcpu_context * ++xen_hyper_id_to_pcpu_context(uint id) ++{ ++ if (xhpct->context_array == NULL) { ++ return NULL; ++ } ++ if (!xen_hyper_test_pcpu_id(id)) { ++ return NULL; ++ } ++ return &xhpct->context_array[id]; ++} ++ ++/* ++ * Get pcpu context from pcpu address. ++ */ ++struct xen_hyper_pcpu_context * ++xen_hyper_pcpu_to_pcpu_context(ulong pcpu) ++{ ++ struct xen_hyper_pcpu_context *pcc; ++ int i; ++ uint cpuid; ++ ++ if (xhpct->context_array == NULL) { ++ return NULL; ++ } ++ if (!pcpu) { ++ return NULL; ++ } ++ for_cpu_indexes(i, cpuid) ++ { ++ pcc = &xhpct->context_array[cpuid]; ++ if (pcpu == pcc->pcpu) { ++ return pcc; ++ } ++ } ++ return NULL; ++} ++ ++/* ++ * Store pcpu struct contents. ++ */ ++struct xen_hyper_pcpu_context * ++xen_hyper_store_pcpu_context(struct xen_hyper_pcpu_context *pcc, ++ ulong pcpu, char *pcp) ++{ ++ pcc->pcpu = pcpu; ++ pcc->processor_id = ++ UINT(pcp + XEN_HYPER_OFFSET(cpu_info_processor_id)); ++ pcc->guest_cpu_user_regs = (ulong)(pcpu + ++ XEN_HYPER_OFFSET(cpu_info_guest_cpu_user_regs)); ++ pcc->current_vcpu = ++ ULONG(pcp + XEN_HYPER_OFFSET(cpu_info_current_vcpu)); ++ return pcc; ++} ++ ++/* ++ * Store init_tss contents. ++ */ ++struct xen_hyper_pcpu_context * ++xen_hyper_store_pcpu_context_tss(struct xen_hyper_pcpu_context *pcc, ++ ulong init_tss, char *tss) ++{ ++ int i; ++ uint64_t *ist_p; ++ ++ pcc->init_tss = init_tss; ++ if (machine_type("X86")) { ++ pcc->sp.esp0 = ULONG(tss + XEN_HYPER_OFFSET(tss_struct_esp0)); ++ } else if (machine_type("X86_64")) { ++ pcc->sp.rsp0 = ULONG(tss + XEN_HYPER_OFFSET(tss_struct_rsp0)); ++ ist_p = (uint64_t *)(tss + XEN_HYPER_OFFSET(tss_struct_ist)); ++ for (i = 0; i < XEN_HYPER_TSS_IST_MAX; i++, ist_p++) { ++ pcc->ist[i] = ULONG(ist_p); ++ } ++ } ++ return pcc; ++} ++ ++/* ++ * Read pcpu struct. ++ */ ++char * ++xen_hyper_read_pcpu(ulong pcpu) ++{ ++ return xen_hyper_fill_pcpu_struct(pcpu, xhpct->pcpu_struct); ++} ++ ++/* ++ * Fill pcpu struct. ++ */ ++char * ++xen_hyper_fill_pcpu_struct(ulong pcpu, char *pcpu_struct) ++{ ++ if (!readmem(pcpu, KVADDR, pcpu_struct, ++ XEN_HYPER_SIZE(cpu_info), "fill_pcpu_struct", ++ ACTIVE() ? (RETURN_ON_ERROR|QUIET) : RETURN_ON_ERROR)) { ++ error(WARNING, "cannot fill pcpu_struct.\n"); ++ return NULL; ++ } ++ return pcpu_struct; ++} ++ ++/* ++ * Allocate pcpu context space. ++ */ ++void ++xen_hyper_alloc_pcpu_context_space(int pcpus) ++{ ++ if (xhpct->context_array == NULL) { ++ if (!(xhpct->context_array = ++ malloc(pcpus * sizeof(struct xen_hyper_pcpu_context)))) { ++ error(FATAL, "cannot malloc context array (%d pcpus).", ++ pcpus); ++ } ++ } ++ BZERO(xhpct->context_array, pcpus * sizeof(struct xen_hyper_pcpu_context)); ++} ++ ++ ++ ++/* ++ * Fill cpu_data. ++ */ ++char * ++xen_hyper_x86_fill_cpu_data(int idx, char *cpuinfo_x86) ++{ ++ ulong cpu_data; ++ ++ if (!xen_hyper_test_pcpu_id(idx) || !xht->cpu_data_address) ++ return NULL; ++ cpu_data = xht->cpu_data_address + XEN_HYPER_SIZE(cpuinfo_x86) * idx; ++ if (!readmem(cpu_data, KVADDR, cpuinfo_x86, XEN_HYPER_SIZE(cpuinfo_x86), ++ "cpu_data", RETURN_ON_ERROR)) { ++ error(WARNING, "cannot read cpu_data.\n"); ++ return NULL; ++ } ++ return cpuinfo_x86; ++} ++ ++char * ++xen_hyper_ia64_fill_cpu_data(int idx, char *cpuinfo_ia64) ++{ ++ ulong cpu_data; ++ ++ if (!xen_hyper_test_pcpu_id(idx) || !xht->cpu_data_address) ++ return NULL; ++ cpu_data = xen_hyper_per_cpu(xht->cpu_data_address, idx); ++ if (!readmem(cpu_data, KVADDR, cpuinfo_ia64, XEN_HYPER_SIZE(cpuinfo_ia64), ++ "cpu_data", RETURN_ON_ERROR)) { ++ error(WARNING, "cannot read cpu_data.\n"); ++ return NULL; ++ } ++ return cpuinfo_ia64; ++} ++ ++/* ++ * Return whether vcpu is crashing. ++ */ ++int ++xen_hyper_is_vcpu_crash(struct xen_hyper_vcpu_context *vcc) ++{ ++ if (vcc == xht->crashing_vcc) ++ return TRUE; ++ return FALSE; ++} ++ ++/* ++ * Test whether cpu for pcpu id exists. ++ */ ++int ++xen_hyper_test_pcpu_id(uint pcpu_id) ++{ ++ ulong *cpumask = xht->cpumask; ++ uint i, j; ++ ++ if (pcpu_id == XEN_HYPER_PCPU_ID_INVALID || ++ pcpu_id > XEN_HYPER_MAX_CPUS()) { ++ return FALSE; ++ } ++ ++ i = pcpu_id / (sizeof(ulong) * 8); ++ j = pcpu_id % (sizeof(ulong) * 8); ++ cpumask += i; ++ if (*cpumask & (1UL << j)) { ++ return TRUE; ++ } else { ++ return FALSE; ++ } ++} ++ ++ ++ ++/* ++ * Calculate and return the uptime. ++ */ ++ulonglong ++xen_hyper_get_uptime_hyper(void) ++{ ++ ulong jiffies, tmp1, tmp2; ++ ulonglong jiffies_64, wrapped; ++ ++ if (symbol_exists("jiffies_64")) { ++ get_symbol_data("jiffies_64", sizeof(ulonglong), &jiffies_64); ++ wrapped = (jiffies_64 & 0xffffffff00000000ULL); ++ if (wrapped) { ++ wrapped -= 0x100000000ULL; ++ jiffies_64 &= 0x00000000ffffffffULL; ++ jiffies_64 |= wrapped; ++ jiffies_64 += (ulonglong)(300*machdep->hz); ++ } else { ++ tmp1 = (ulong)(uint)(-300*machdep->hz); ++ tmp2 = (ulong)jiffies_64; ++ jiffies_64 = (ulonglong)(tmp2 - tmp1); ++ } ++ } else { ++ get_symbol_data("jiffies", sizeof(long), &jiffies); ++ jiffies_64 = (ulonglong)jiffies; ++ } ++ ++ return jiffies_64; ++} ++ ++/* ++ * Get cpu informatin around. ++ */ ++void ++xen_hyper_get_cpu_info(void) ++{ ++ ulong addr; ++ ulong *cpumask; ++ uint *cpu_idx; ++ int i, j, cpus; ++ ++ get_symbol_data("max_cpus", sizeof(xht->max_cpus), &xht->max_cpus); ++ XEN_HYPER_STRUCT_SIZE_INIT(cpumask_t, "cpumask_t"); ++ if (XEN_HYPER_SIZE(cpumask_t) * 8 > xht->max_cpus) { ++ xht->max_cpus = XEN_HYPER_SIZE(cpumask_t) * 8; ++ } ++ if (xht->cpumask) { ++ free(xht->cpumask); ++ } ++ if((xht->cpumask = malloc(XEN_HYPER_SIZE(cpumask_t))) == NULL) { ++ error(FATAL, "cannot malloc cpumask space.\n"); ++ } ++ /* kakuma: It may be better to use cpu_present_map. */ ++ addr = symbol_value("cpu_online_map"); ++ if (!readmem(addr, KVADDR, xht->cpumask, ++ XEN_HYPER_SIZE(cpumask_t), "cpu_online_map", RETURN_ON_ERROR)) { ++ error(FATAL, "cannot read cpu_online_map.\n"); ++ } ++ if (xht->cpu_idxs) { ++ free(xht->cpu_idxs); ++ } ++ if((xht->cpu_idxs = malloc(sizeof(uint) * XEN_HYPER_MAX_CPUS())) == NULL) { ++ error(FATAL, "cannot malloc cpu_idxs space.\n"); ++ } ++ memset(xht->cpu_idxs, 0xff, sizeof(uint) * XEN_HYPER_MAX_CPUS()); ++ ++ for (i = cpus = 0, cpumask = xht->cpumask, cpu_idx = xht->cpu_idxs; ++ i < (XEN_HYPER_SIZE(cpumask_t)/sizeof(ulong)); i++, cpumask++) { ++ for (j = 0; j < sizeof(ulong) * 8; j++) { ++ if (*cpumask & (1UL << j)) { ++ *cpu_idx++ = i * sizeof(ulong) * 8 + j; ++ cpus++; ++ } ++ } ++ } ++ xht->pcpus = cpus; ++} ++ ++/* ++ * Calculate the number of physical cpu for x86. ++ */ ++int ++xen_hyper_x86_get_smp_cpus(void) ++{ ++ if (xht->pcpus) { ++ return xht->pcpus; ++ } ++ xen_hyper_get_cpu_info(); ++ return xht->pcpus; ++} ++ ++/* ++ * Calculate used memory size for x86. ++ */ ++uint64_t ++xen_hyper_x86_memory_size(void) ++{ ++ ulong vaddr; ++ ++ if (machdep->memsize) { ++ return machdep->memsize; ++ } ++ vaddr = symbol_value("total_pages"); ++ if (!readmem(vaddr, KVADDR, &xht->total_pages, sizeof(xht->total_pages), ++ "total_pages", RETURN_ON_ERROR)) { ++ error(WARNING, "cannot read total_pages.\n"); ++ } ++ xht->sys_pages = xht->total_pages; ++ machdep->memsize = (uint64_t)(xht->sys_pages) * (uint64_t)(machdep->pagesize); ++ return machdep->memsize; ++} ++ ++ ++/* ++ * Calculate the number of physical cpu for ia64. ++ */ ++int ++xen_hyper_ia64_get_smp_cpus(void) ++{ ++ return xen_hyper_x86_get_smp_cpus(); ++} ++ ++/* ++ * Calculate used memory size for ia64. ++ */ ++uint64_t ++xen_hyper_ia64_memory_size(void) ++{ ++ return xen_hyper_x86_memory_size(); ++} ++ ++/* ++ * Calculate and return the speed of the processor. ++ */ ++ulong ++xen_hyper_ia64_processor_speed(void) ++{ ++ ulong mhz, proc_freq; ++ ++ if (machdep->mhz) ++ return(machdep->mhz); ++ ++ mhz = 0; ++ ++ if (!xht->cpu_data_address || ++ !XEN_HYPER_VALID_STRUCT(cpuinfo_ia64) || ++ XEN_HYPER_INVALID_MEMBER(cpuinfo_ia64_proc_freq)) ++ return (machdep->mhz = mhz); ++ ++ readmem(xen_hyper_per_cpu(xht->cpu_data_address, xht->cpu_idxs[0]) + ++ XEN_HYPER_OFFSET(cpuinfo_ia64_proc_freq), ++ KVADDR, &proc_freq, sizeof(ulong), ++ "cpuinfo_ia64 proc_freq", FAULT_ON_ERROR); ++ ++ mhz = proc_freq/1000000; ++ ++ return (machdep->mhz = mhz); ++} ++ ++ ++ ++/* ++ * Print an aligned string with specified length. ++ */ ++void ++xen_hyper_fpr_indent(FILE *fp, int len, char *str1, char *str2, int flag) ++{ ++ char buf[XEN_HYPER_CMD_BUFSIZE]; ++ int sl, r; ++ char *s1, *s2; ++ ++ sl = strlen(str1); ++ if (sl > len) { ++ r = 0; ++ } else { ++ r = len - sl; ++ } ++ ++ memset(buf, ' ', sizeof(buf)); ++ buf[r] = '\0'; ++ if (flag & XEN_HYPER_PRI_L) { ++ s1 = str1; ++ s2 = buf; ++ } else { ++ s1 = buf; ++ s2 = str1; ++ } ++ if (str2) { ++ fprintf(fp, "%s%s%s", s1, s2, str2); ++ } else { ++ fprintf(fp, "%s%s", s1, s2); ++ } ++ if (flag & XEN_HYPER_PRI_LF) { ++ fprintf(fp, "\n"); ++ } ++} ++ ++ulong ++xen_hyper_get_active_vcpu_from_pcpuid(ulong pcpuid) ++{ ++ struct xen_hyper_pcpu_context *pcc; ++ struct xen_hyper_vcpu_context_array *vcca; ++ struct xen_hyper_vcpu_context *vcc; ++ int i, j; ++ ++ if (!xen_hyper_test_pcpu_id(pcpuid)) ++ return 0; ++ ++ pcc = &xhpct->context_array[pcpuid]; ++ if (pcc->current_vcpu) ++ return pcc->current_vcpu; ++ ++ for (i = 0, vcca = xhvct->vcpu_context_arrays; ++ i < xhvct->vcpu_context_arrays_cnt; i++, vcca++) { ++ for (j = 0, vcc = vcca->context_array; ++ j < vcca->context_array_cnt; j++, vcc++) { ++ if (vcc->processor == pcpuid && ++ vcc->state == XEN_HYPER_RUNSTATE_running) { ++ return vcc->vcpu; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++ulong ++xen_hyper_pcpu_to_active_vcpu(ulong pcpu) ++{ ++ ulong vcpu; ++ ++ /* if pcpu is vcpu address, return it. */ ++ if (pcpu & (~(PAGESIZE() - 1))) { ++ return pcpu; ++ } ++ ++ if(!(vcpu = XEN_HYPER_CURR_VCPU(pcpu))) ++ error(FATAL, "invalid pcpu id\n"); ++ return vcpu; ++} ++ ++void ++xen_hyper_print_bt_header(FILE *out, ulong vcpu, int newline) ++{ ++ struct xen_hyper_vcpu_context *vcc; ++ ++ if (newline) ++ fprintf(out, "\n"); ++ ++ vcc = xen_hyper_vcpu_to_vcpu_context(vcpu); ++ if (!vcc) ++ error(FATAL, "invalid vcpu\n"); ++ fprintf(out, "PCPU: %2d VCPU: %lx\n", vcc->processor, vcpu); ++} ++#endif +--- crash/xen_hyper_command.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/xen_hyper_command.c 2007-08-23 17:02:54.000000000 -0400 +@@ -0,0 +1,1856 @@ ++/* ++ * xen_hyper_command.c ++ * ++ * Portions Copyright (C) 2006-2007 Fujitsu Limited ++ * Portions Copyright (C) 2006-2007 VA Linux Systems Japan K.K. ++ * ++ * Authors: Itsuro Oda ++ * Fumihiko Kakuma ++ * ++ * This file is part of Xencrash. ++ * ++ * Xencrash 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 (version 2 of the License). ++ * ++ * Xencrash 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with Xencrash; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include "defs.h" ++ ++#ifdef XEN_HYPERVISOR_ARCH ++#include "xen_hyper_defs.h" ++ ++#ifdef X86 ++char *xhregt[] = { ++ "ebx", "ecx", "edx", "esi", "edi", "ebp", "eax", "ds", "es", ++ "fs", "gs", "orig_eax", "eip", "cs", "eflags", "esp", "ss", ++ NULL ++}; ++#endif ++ ++#ifdef X86_64 ++char *xhregt[] = { ++ "r15", "r14", "r13", "r12", "rbp", "rbx", "r11", "r10", "r9", "r8", ++ "rax", "rcx", "rdx", "rsi", "rdi", "orig_rax", "rip", "cs", "eflags", ++ "rsp", "ss", "fs", "gs", "ds", "es", "fs", "gs", ++ NULL ++}; ++#endif ++ ++#ifdef IA64 ++char *xhregt[] = { ++ "aaa", "bbb", ++ NULL ++}; ++#endif ++ ++static void xen_hyper_do_domain(struct xen_hyper_cmd_args *da); ++static void xen_hyper_do_doms(struct xen_hyper_cmd_args *da); ++static void xen_hyper_show_doms(struct xen_hyper_domain_context *dc); ++static void xen_hyper_do_dumpinfo(ulong flag, struct xen_hyper_cmd_args *dia); ++static void xen_hyper_show_dumpinfo(ulong flag, ++ struct xen_hyper_dumpinfo_context *dic); ++static void xen_hyper_do_pcpus(ulong flag, struct xen_hyper_cmd_args *pca); ++static void xen_hyper_show_pcpus(ulong flag, struct xen_hyper_pcpu_context *pcc); ++static void xen_hyper_do_sched(ulong flag, struct xen_hyper_cmd_args *scha); ++static void xen_hyper_show_sched(ulong flag, struct xen_hyper_sched_context *schc); ++static void xen_hyper_do_vcpu(struct xen_hyper_cmd_args *vca); ++static void xen_hyper_do_vcpus(struct xen_hyper_cmd_args *vca); ++static void xen_hyper_show_vcpus(struct xen_hyper_vcpu_context *vcc); ++static char *xen_hyper_domain_to_type(ulong domain, int *type, char *buf, int verbose); ++static char *xen_hyper_domain_context_to_type( ++ struct xen_hyper_domain_context *dc, int *type, char *buf, int verbose); ++static int xen_hyper_str_to_domain_context(char *string, ulong *value, ++ struct xen_hyper_domain_context **dcp); ++static int xen_hyper_str_to_dumpinfo_context(char *string, ulong *value, struct xen_hyper_dumpinfo_context **dicp); ++static int xen_hyper_strvcpu_to_vcpu_context(char *string, ulong *value, ++ struct xen_hyper_vcpu_context **vccp); ++static int ++xen_hyper_strid_to_vcpu_context(char *strdom, char *strvc, ulong *valdom, ++ ulong *valvc, struct xen_hyper_vcpu_context **vccp); ++static int xen_hyper_str_to_pcpu_context(char *string, ulong *value, ++ struct xen_hyper_pcpu_context **pccp); ++ ++/* ++ * Display domain struct. ++ */ ++void ++xen_hyper_cmd_domain(void) ++{ ++ struct xen_hyper_cmd_args da; ++ struct xen_hyper_domain_context *dc; ++ ulong val; ++ int c, cnt, type, bogus; ++ ++ BZERO(&da, sizeof(struct xen_hyper_cmd_args)); ++ while ((c = getopt(argcnt, args, "")) != EOF) { ++ switch(c) ++ { ++ default: ++ argerrs++; ++ break; ++ } ++ } ++ ++ if (argerrs) ++ cmd_usage(pc->curcmd, SYNOPSIS); ++ ++ cnt = bogus = 0; ++ while (args[optind]) { ++ if (IS_A_NUMBER(args[optind])) { ++ type = xen_hyper_str_to_domain_context(args[optind], &val, &dc); ++ switch (type) { ++ case XEN_HYPER_STR_DID: ++ case XEN_HYPER_STR_DOMAIN: ++ da.value[cnt] = val; ++ da.type[cnt] = type; ++ da.addr[cnt] = dc->domain; ++ da.context[cnt] = dc; ++ cnt++; ++ break; ++ case XEN_HYPER_STR_INVALID: ++ error(INFO, "invalid domain or id value: %s\n\n", ++ args[optind]); ++ bogus++; ++ } ++ } else { ++ error(FATAL, "invalid address: %s\n", ++ args[optind]); ++ } ++ optind++; ++ } ++ da.cnt = cnt; ++ if (bogus && !cnt) { ++ return; ++ } ++ ++ xen_hyper_do_domain(&da); ++} ++ ++/* ++ * Do the work requested by xen_hyper_cmd_dom(). ++ */ ++static void ++xen_hyper_do_domain(struct xen_hyper_cmd_args *da) ++{ ++ int i; ++ ++ if (da->cnt) { ++ if (da->cnt == 1) { ++ xhdt->last = da->context[0]; ++ } ++ for (i = 0; i < da->cnt; i++) { ++ dump_struct("domain", da->addr[i], 0); ++ } ++ } else { ++ dump_struct("domain", xhdt->last->domain, 0); ++ } ++} ++ ++/* ++ * Display domain status. ++ */ ++void ++xen_hyper_cmd_doms(void) ++{ ++ struct xen_hyper_cmd_args da; ++ struct xen_hyper_domain_context *dc; ++ ulong val; ++ int c, cnt, type, bogus; ++ ++ BZERO(&da, sizeof(struct xen_hyper_cmd_args)); ++ while ((c = getopt(argcnt, args, "")) != EOF) { ++ switch(c) ++ { ++ default: ++ argerrs++; ++ break; ++ } ++ } ++ ++ if (argerrs) ++ cmd_usage(pc->curcmd, SYNOPSIS); ++ ++ cnt = bogus = 0; ++ while (args[optind]) { ++ if (IS_A_NUMBER(args[optind])) { ++ type = xen_hyper_str_to_domain_context(args[optind], &val, &dc); ++ switch (type) { ++ case XEN_HYPER_STR_DID: ++ case XEN_HYPER_STR_DOMAIN: ++ da.value[cnt] = val; ++ da.type[cnt] = type; ++ da.addr[cnt] = dc->domain; ++ da.context[cnt] = dc; ++ cnt++; ++ break; ++ case XEN_HYPER_STR_INVALID: ++ error(INFO, "invalid domain or id value: %s\n\n", ++ args[optind]); ++ bogus++; ++ } ++ } else { ++ error(FATAL, "invalid address: %s\n", ++ args[optind]); ++ } ++ optind++; ++ } ++ da.cnt = cnt; ++ if (bogus && !cnt) { ++ return; ++ } ++ ++ xen_hyper_do_doms(&da); ++} ++ ++/* ++ * Do the work requested by xen_hyper_cmd_doms(). ++ */ ++static void ++xen_hyper_do_doms(struct xen_hyper_cmd_args *da) ++{ ++ struct xen_hyper_domain_context *dca; ++ char buf1[XEN_HYPER_CMD_BUFSIZE]; ++ char buf2[XEN_HYPER_CMD_BUFSIZE]; ++ int i; ++ ++ sprintf(buf1, " DID %s ST T ", ++ mkstring(buf2, VADDR_PRLEN, CENTER|RJUST, "DOMAIN")); ++ mkstring(&buf1[strlen(buf1)], INT_PRLEN, CENTER|RJUST, "MAXPAGE"); ++ strncat(buf1, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf1)-1); ++ mkstring(&buf1[strlen(buf1)], INT_PRLEN, CENTER|RJUST, "TOTPAGE"); ++ strncat(buf1, " VCPU ", XEN_HYPER_CMD_BUFSIZE-strlen(buf1)-1); ++ mkstring(&buf1[strlen(buf1)], VADDR_PRLEN, CENTER|RJUST, "SHARED_I"); ++ strncat(buf1, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf1)-1); ++ mkstring(&buf1[strlen(buf1)], LONG_PRLEN, CENTER|RJUST, "P2M_MFN"); ++ fprintf(fp, "%s\n", buf1); ++ if (da->cnt) { ++ for (i = 0; i < da->cnt; i++) { ++ xen_hyper_show_doms(da->context[i]); ++ } ++ } else { ++ for (i = 0, dca=xhdt->context_array; i < XEN_HYPER_NR_DOMAINS(); ++ i++, dca++) { ++ xen_hyper_show_doms(dca); ++ } ++ } ++} ++ ++static void ++xen_hyper_show_doms(struct xen_hyper_domain_context *dc) ++{ ++ char *act, *crash; ++ uint cpuid; ++ int type, i, j; ++ struct xen_hyper_pcpu_context *pcc; ++#if defined(X86) || defined(X86_64) ++ char *shared_info; ++#elif defined(IA64) ++ char *domain_struct; ++ ulong pgd; ++#endif ++ char buf1[XEN_HYPER_CMD_BUFSIZE]; ++ char buf2[XEN_HYPER_CMD_BUFSIZE]; ++ ++ if (!(dc->domain)) { ++ return; ++ } ++ ++#if defined(X86) || defined(X86_64) ++ shared_info = GETBUF(XEN_HYPER_SIZE(shared_info)); ++ if (dc->shared_info) { ++ if (!readmem(dc->shared_info, KVADDR, shared_info, ++ XEN_HYPER_SIZE(shared_info), "fill_shared_info_struct", ++ ACTIVE() ? (RETURN_ON_ERROR|QUIET) : RETURN_ON_ERROR)) { ++ error(WARNING, "cannot fill shared_info struct.\n"); ++ BZERO(shared_info, XEN_HYPER_SIZE(shared_info)); ++ } ++ } ++#elif defined(IA64) ++ if ((domain_struct = xen_hyper_read_domain(dc->domain)) == NULL) { ++ error(FATAL, "cannot read domain.\n"); ++ } ++#endif ++ act = NULL; ++ for_cpu_indexes(i, cpuid) ++ { ++ pcc = xen_hyper_id_to_pcpu_context(cpuid); ++ for (j = 0; j < dc->vcpu_cnt; j++) { ++ if (pcc->current_vcpu == dc->vcpu[j]) { ++ act = ">"; ++ break; ++ } ++ } ++ if (act) break; ++ } ++ if (act == NULL) act = " "; ++ if (xht->crashing_vcc && dc->domain == xht->crashing_vcc->domain) { ++ crash = "*"; ++ } else { ++ crash = " "; ++ } ++ sprintf(buf1, "%s%s%5d ", act, crash, dc->domain_id); ++ mkstring(&buf1[strlen(buf1)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, (char *)(dc->domain)); ++ strncat(buf1, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf1)-1); ++ sprintf(&buf1[strlen(buf1)], "%s ", ++ xen_hyper_domain_state_string(dc, buf2, !VERBOSE)); ++ sprintf(&buf1[strlen(buf1)], "%s ", ++ xen_hyper_domain_context_to_type(dc, &type, buf2, !VERBOSE)); ++ mkstring(&buf1[strlen(buf1)], INT_PRLEN, CENTER|INT_HEX|RJUST, ++ MKSTR((long)(dc->max_pages))); ++ strncat(buf1, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf1)-1); ++ mkstring(&buf1[strlen(buf1)], INT_PRLEN, CENTER|INT_HEX|RJUST, ++ MKSTR((long)(dc->tot_pages))); ++ sprintf(&buf1[strlen(buf1)], " %3d ", dc->vcpu_cnt); ++ mkstring(&buf1[strlen(buf1)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(dc->shared_info)); ++ strncat(buf1, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf1)-1); ++#if defined(X86) || defined(X86_64) ++ if (dc->shared_info) { ++ mkstring(&buf1[strlen(buf1)], LONG_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(ULONG(shared_info + ++ XEN_HYPER_OFFSET(shared_info_arch) + ++ XEN_HYPER_OFFSET(arch_shared_info_pfn_to_mfn_frame_list_list))) ++ ); ++ } else { ++ mkstring(&buf1[strlen(buf1)], LONG_PRLEN, CENTER|RJUST, "----"); ++ } ++ FREEBUF(shared_info); ++#elif defined(IA64) ++ pgd = ULONG(domain_struct + XEN_HYPER_OFFSET(domain_arch) + ++ XEN_HYPER_OFFSET(arch_domain_mm) + ++ XEN_HYPER_OFFSET(mm_struct_pgd)); ++ if (pgd) { ++ mkstring(&buf1[strlen(buf1)], LONG_PRLEN, ++ CENTER|LONG_HEX|RJUST, ++ MKSTR((pgd - DIRECTMAP_VIRT_START) >> machdep->pageshift)); ++ } else { ++ mkstring(&buf1[strlen(buf1)], LONG_PRLEN, CENTER|RJUST, "----"); ++ } ++#endif ++ ++ fprintf(fp, "%s\n", buf1); ++} ++ ++/* ++ * Display ELF Notes information. ++ */ ++void ++xen_hyper_cmd_dumpinfo(void) ++{ ++ struct xen_hyper_cmd_args dia; ++ ulong flag; ++ ulong val; ++ struct xen_hyper_dumpinfo_context *dic; ++ int c, cnt, type, bogus; ++ ++ BZERO(&dia, sizeof(struct xen_hyper_cmd_args)); ++ flag= 0; ++ while ((c = getopt(argcnt, args, "rt")) != EOF) { ++ switch(c) ++ { ++ case 't': ++ flag |= XEN_HYPER_DUMPINFO_TIME; ++ break; ++ case 'r': ++ flag |= XEN_HYPER_DUMPINFO_REGS; ++ break; ++ default: ++ argerrs++; ++ break; ++ } ++ } ++ ++ if (argerrs) ++ cmd_usage(pc->curcmd, SYNOPSIS); ++ ++ cnt = bogus = 0; ++ while (args[optind]) { ++ if (IS_A_NUMBER(args[optind])) { ++ type = xen_hyper_str_to_dumpinfo_context(args[optind], &val, &dic); ++ switch (type) ++ { ++ case XEN_HYPER_STR_PCID: ++ case XEN_HYPER_STR_ADDR: ++ dia.value[cnt] = val; ++ dia.type[cnt] = type; ++ dia.context[cnt] = dic; ++ cnt++; ++ break; ++ ++ case XEN_HYPER_STR_INVALID: ++ error(INFO, "invalid note address or id " ++ "value: %s\n\n", args[optind]); ++ bogus++; ++ break; ++ } ++ } else { ++ error(INFO, "invalid note address or id " ++ "value: %s\n\n", args[optind]); ++ } ++ optind++; ++ } ++ dia.cnt = cnt; ++ if (!cnt && bogus) { ++ return; ++ } ++ ++ xen_hyper_do_dumpinfo(flag, &dia); ++} ++ ++/* ++ * Do the work requested by xen_hyper_cmd_dumpinfo(). ++ */ ++static void ++xen_hyper_do_dumpinfo(ulong flag, struct xen_hyper_cmd_args *dia) ++{ ++ struct xen_hyper_dumpinfo_context *dic; ++ char buf[XEN_HYPER_CMD_BUFSIZE]; ++ int i, cnt; ++ ++ if (dia->cnt) { ++ cnt = dia->cnt; ++ } else { ++ cnt = XEN_HYPER_NR_PCPUS(); ++ } ++ for (i = 0; i < cnt; i++) { ++ if (i == 0 || flag & XEN_HYPER_DUMPINFO_REGS || ++ flag & XEN_HYPER_DUMPINFO_TIME) { ++ if (i) { ++ fprintf(fp, "\n"); ++ } ++ sprintf(buf, " PCID "); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "ENOTE"); ++// sprintf(&buf[strlen(buf)], " PID PPID PGRP SID"); ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "CORE"); ++ if (xhdit->note_ver >= XEN_HYPER_ELF_NOTE_V2) { ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "XEN_CORE"); ++ } ++ if (xhdit->note_ver >= XEN_HYPER_ELF_NOTE_V3) { ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "XEN_INFO"); ++ } ++ fprintf(fp, "%s\n", buf); ++ } ++ if (dia->cnt) { ++ dic = dia->context[i]; ++ } else { ++ dic = xen_hyper_id_to_dumpinfo_context(xht->cpu_idxs[i]); ++ } ++ xen_hyper_show_dumpinfo(flag, dic); ++ } ++} ++ ++static void ++xen_hyper_show_dumpinfo(ulong flag, struct xen_hyper_dumpinfo_context *dic) ++{ ++ char buf[XEN_HYPER_CMD_BUFSIZE]; ++ char *note_buf; ++ ulong addr; ++ ulong *regs; ++ long tv_sec, tv_usec; ++ int i, regcnt; ++ ++ if (!dic || !dic->note) { ++ return; ++ } ++ ++ note_buf = dic->ELF_Prstatus_ptr; ++ sprintf(buf, "%5d ", dic->pcpu_id); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(dic->note)); ++ ++#if 0 ++ pid = INT(note_buf + XEN_HYPER_OFFSET(ELF_Prstatus_pr_pid)); ++ sprintf(&buf[strlen(buf)], " %5d ", pid); ++ pid = INT(note_buf + XEN_HYPER_OFFSET(ELF_Prstatus_pr_ppid)); ++ sprintf(&buf[strlen(buf)], "%5d ", pid); ++ pid = INT(note_buf + XEN_HYPER_OFFSET(ELF_Prstatus_pr_pgrp)); ++ sprintf(&buf[strlen(buf)], "%5d ", pid); ++ pid = INT(note_buf + XEN_HYPER_OFFSET(ELF_Prstatus_pr_sid)); ++ sprintf(&buf[strlen(buf)], "%5d", pid); ++#endif ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(dic->note)); ++ if (xhdit->note_ver >= XEN_HYPER_ELF_NOTE_V2) { ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(dic->note + xhdit->core_size)); ++ } ++ if (xhdit->note_ver >= XEN_HYPER_ELF_NOTE_V3) { ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ if (xhdit->xen_info_cpu == dic->pcpu_id) ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(dic->note + xhdit->core_size + xhdit->xen_core_size)); ++ else ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "--"); ++ ++ } ++ ++ fprintf(fp, "%s\n", buf); ++ ++ if (flag & XEN_HYPER_DUMPINFO_TIME) { ++ sprintf(buf, " "); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "tv_sec"); ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "tv_usec"); ++ fprintf(fp, "%s\n", buf); ++ ++ addr = (ulong)note_buf + ++ XEN_HYPER_OFFSET(ELF_Prstatus_pr_utime); ++ for (i = 0; i < 4; i++, addr += XEN_HYPER_SIZE(ELF_Timeval)) { ++ switch (i) ++ { ++ case 0: ++ sprintf(buf, " pr_utime "); ++ break; ++ case 1: ++ sprintf(buf, " pr_stime "); ++ break; ++ case 2: ++ sprintf(buf, " pr_cutime "); ++ break; ++ case 3: ++ sprintf(buf, " pr_cstime "); ++ break; ++ } ++ tv_sec = LONG(addr + ++ XEN_HYPER_OFFSET(ELF_Timeval_tv_sec)); ++ tv_usec = LONG(addr + ++ XEN_HYPER_OFFSET(ELF_Timeval_tv_sec) + ++ XEN_HYPER_OFFSET(ELF_Timeval_tv_usec)); ++ mkstring(&buf[strlen(buf)], LONG_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(tv_sec)); ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], LONG_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(tv_usec)); ++ fprintf(fp, "%s\n", buf); ++ } ++ } ++ ++ if (flag & XEN_HYPER_DUMPINFO_REGS) { ++ regcnt = XEN_HYPER_SIZE(ELF_Gregset) / sizeof(long); ++ addr = (ulong)note_buf + ++ XEN_HYPER_OFFSET(ELF_Prstatus_pr_reg); ++ regs = (ulong *)addr; ++ fprintf(fp, "Register information(%lx):\n", ++ dic->note + xhdit->core_offset + XEN_HYPER_OFFSET(ELF_Prstatus_pr_reg)); ++ for (i = 0; i < regcnt; i++, regs++) { ++ if (xhregt[i] == NULL) { ++ break; ++ } ++ fprintf(fp, " %s = ", xhregt[i]); ++ fprintf(fp, "0x%s\n", ++ mkstring(buf, LONG_PRLEN, LONG_HEX|LJUST, MKSTR(*regs))); ++ } ++ } ++} ++ ++/* ++ * Dump the Xen conring in chronological order. ++ */ ++void ++xen_hyper_cmd_log(void) ++{ ++ int c; ++ ++ while ((c = getopt(argcnt, args, "")) != EOF) { ++ switch(c) ++ { ++ default: ++ argerrs++; ++ break; ++ } ++ } ++ ++ if (argerrs) ++ cmd_usage(pc->curcmd, SYNOPSIS); ++ ++ xen_hyper_dump_log(); ++} ++ ++void ++xen_hyper_dump_log(void) ++{ ++ uint conringc, conringp; ++ uint warp, start, len, idx, i; ++ ulong conring; ++ char *buf; ++ char last; ++ ++ conring = symbol_value("conring"); ++ get_symbol_data("conringc", sizeof(uint), &conringc); ++ get_symbol_data("conringp", sizeof(uint), &conringp); ++ warp = FALSE; ++ if (conringp >= XEN_HYPER_CONRING_SIZE) { ++ if ((start = conringp & (XEN_HYPER_CONRING_SIZE - 1))) { ++ warp = TRUE; ++ } ++ } else { ++ start = 0; ++ } ++ ++ buf = GETBUF(XEN_HYPER_CONRING_SIZE); ++ readmem(conring, KVADDR, buf, XEN_HYPER_CONRING_SIZE, ++ "conring contents", FAULT_ON_ERROR); ++ idx = start; ++ len = XEN_HYPER_CONRING_SIZE; ++ ++wrap_around: ++ for (i = idx; i < len; i++) { ++ if (buf[i]) { ++ fputc(ascii(buf[i]) ? buf[i] : '.', fp); ++ last = buf[i]; ++ } ++ } ++ if (warp) { ++ len = idx; ++ idx = 0; ++ warp = FALSE; ++ goto wrap_around; ++ } ++ if (last != '\n') { ++ fprintf(fp, "\n"); ++ } ++ FREEBUF(buf); ++} ++ ++/* ++ * Display physical cpu information. ++ */ ++void ++xen_hyper_cmd_pcpus(void) ++{ ++ struct xen_hyper_cmd_args pca; ++ struct xen_hyper_pcpu_context *pcc; ++ ulong flag; ++ ulong val; ++ int c, cnt, type, bogus; ++ ++ BZERO(&pca, sizeof(struct xen_hyper_cmd_args)); ++ flag= 0; ++ while ((c = getopt(argcnt, args, "rt")) != EOF) { ++ switch(c) ++ { ++ case 'r': ++ flag |= XEN_HYPER_PCPUS_REGS; ++ break; ++ case 't': ++ flag |= XEN_HYPER_PCPUS_TSS; ++ break; ++ default: ++ argerrs++; ++ break; ++ } ++ } ++ ++ if (argerrs) ++ cmd_usage(pc->curcmd, SYNOPSIS); ++ ++ cnt = bogus = 0; ++ while (args[optind]) { ++ if (IS_A_NUMBER(args[optind])) { ++ type = xen_hyper_str_to_pcpu_context(args[optind], &val, &pcc); ++ switch (type) { ++ case XEN_HYPER_STR_PCID: ++ case XEN_HYPER_STR_PCPU: ++ pca.value[cnt] = val; ++ pca.type[cnt] = type; ++ pca.addr[cnt] = pcc->pcpu; ++ pca.context[cnt] = pcc; ++ cnt++; ++ break; ++ case XEN_HYPER_STR_INVALID: ++ error(INFO, "invalid pcpu or id value: %s\n\n", ++ args[optind]); ++ bogus++; ++ } ++ } else { ++ error(FATAL, "invalid address: %s\n", ++ args[optind]); ++ } ++ optind++; ++ } ++ pca.cnt = cnt; ++ if (bogus && !cnt) { ++ return; ++ } ++ ++ xen_hyper_do_pcpus(flag, &pca); ++} ++ ++/* ++ * Do the work requested by xen_hyper_cmd_pcpu(). ++ */ ++static void ++xen_hyper_do_pcpus(ulong flag, struct xen_hyper_cmd_args *pca) ++{ ++ struct xen_hyper_pcpu_context *pcc; ++ uint cpuid; ++ int i; ++ ++ if (pca->cnt) { ++ for (i = 0; i < pca->cnt; i++) { ++ xen_hyper_show_pcpus(flag, pca->context[i]); ++ flag |= XEN_HYPER_PCPUS_1STCALL; ++ } ++ } else { ++ for_cpu_indexes(i, cpuid) ++ { ++ pcc = xen_hyper_id_to_pcpu_context(cpuid); ++ xen_hyper_show_pcpus(flag, pcc); ++ flag |= XEN_HYPER_PCPUS_1STCALL; ++ } ++ } ++} ++ ++static void ++xen_hyper_show_pcpus(ulong flag, struct xen_hyper_pcpu_context *pcc) ++{ ++ char *act = " "; ++ char buf[XEN_HYPER_CMD_BUFSIZE]; ++ ++ if (!(pcc->pcpu)) { ++ return; ++ } ++ if (XEN_HYPER_CRASHING_CPU() == pcc->processor_id) { ++ act = " *"; ++ } ++ if ((flag & XEN_HYPER_PCPUS_REGS) || (flag & XEN_HYPER_PCPUS_TSS) || ++ !(flag & XEN_HYPER_PCPUS_1STCALL)) { ++ if (((flag & XEN_HYPER_PCPUS_REGS) || (flag & XEN_HYPER_PCPUS_TSS)) && ++ (flag & XEN_HYPER_PCPUS_1STCALL)) { ++ fprintf(fp, "\n"); ++ } ++ sprintf(buf, " PCID "); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "PCPU"); ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "CUR-VCPU"); ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "TSS"); ++ fprintf(fp, "%s\n", buf); ++ } ++ ++ sprintf(buf, "%s%5d ", act, pcc->processor_id); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, MKSTR(pcc->pcpu)); ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(pcc->current_vcpu)); ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(pcc->init_tss)); ++ fprintf(fp, "%s\n", buf); ++ if (flag & XEN_HYPER_PCPUS_REGS) { ++ fprintf(fp, "Register information:\n"); ++ dump_struct("cpu_user_regs", pcc->guest_cpu_user_regs, 0); ++ } ++ if (flag & XEN_HYPER_PCPUS_TSS) { ++ fprintf(fp, "init_tss information:\n"); ++ dump_struct("tss_struct", pcc->init_tss, 0); ++ } ++} ++ ++/* ++ * Display schedule info. ++ */ ++void ++xen_hyper_cmd_sched(void) ++{ ++ struct xen_hyper_cmd_args scha; ++ struct xen_hyper_pcpu_context *pcc; ++ ulong flag; ++ ulong val; ++ int c, cnt, type, bogus; ++ ++ BZERO(&scha, sizeof(struct xen_hyper_cmd_args)); ++ flag = 0; ++ while ((c = getopt(argcnt, args, "v")) != EOF) { ++ switch(c) ++ { ++ case 'v': ++ flag |= XEN_HYPER_SCHED_VERBOSE; ++ break; ++ ++ default: ++ argerrs++; ++ break; ++ } ++ } ++ ++ if (argerrs) ++ cmd_usage(pc->curcmd, SYNOPSIS); ++ ++ cnt = bogus = 0; ++ while (args[optind]) { ++ if (IS_A_NUMBER(args[optind])) { ++ type = xen_hyper_str_to_pcpu_context(args[optind], &val, &pcc); ++ switch (type) { ++ case XEN_HYPER_STR_PCID: ++ scha.value[cnt] = val; ++ scha.type[cnt] = type; ++ scha.context[cnt] = &xhscht->sched_context_array[val]; ++ cnt++; ++ break; ++ case XEN_HYPER_STR_PCPU: ++ case XEN_HYPER_STR_INVALID: ++ error(INFO, "invalid pcpu id value: %s\n\n", ++ args[optind]); ++ bogus++; ++ } ++ } else { ++ error(FATAL, "invalid address: %s\n", ++ args[optind]); ++ } ++ optind++; ++ } ++ scha.cnt = cnt; ++ if (bogus && !cnt) { ++ return; ++ } ++ ++ xen_hyper_do_sched(flag, &scha); ++} ++ ++/* ++ * Do the work requested by xen_hyper_cmd_pcpu(). ++ */ ++static void ++xen_hyper_do_sched(ulong flag, struct xen_hyper_cmd_args *scha) ++{ ++ struct xen_hyper_sched_context *schc; ++ uint cpuid; ++ int i; ++ ++ fprintf(fp, "Scheduler name : %s\n\n", xhscht->name); ++ ++ if (scha->cnt) { ++ for (i = 0; i < scha->cnt; i++) { ++ xen_hyper_show_sched(flag, scha->context[i]); ++ flag |= XEN_HYPER_SCHED_1STCALL; ++ } ++ } else { ++ for_cpu_indexes(i, cpuid) ++ { ++ schc = &xhscht->sched_context_array[cpuid]; ++ xen_hyper_show_sched(flag, schc); ++ flag |= XEN_HYPER_SCHED_1STCALL; ++ } ++ } ++} ++ ++static void ++xen_hyper_show_sched(ulong flag, struct xen_hyper_sched_context *schc) ++{ ++ char buf[XEN_HYPER_CMD_BUFSIZE]; ++ ++ if (!(schc->schedule_data)) { ++ return; ++ } ++ if ((flag & XEN_HYPER_SCHED_VERBOSE) || ++ !(flag & XEN_HYPER_SCHED_1STCALL)) { ++ if ((flag & XEN_HYPER_SCHED_1STCALL) && ++ (flag & XEN_HYPER_SCHED_VERBOSE)) { ++ fprintf(fp, "\n"); ++ } ++ sprintf(buf, " CPU "); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "SCH-DATA"); ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "SCH-PRIV"); ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "CUR-VCPU"); ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "IDL-VCPU"); ++ if (XEN_HYPER_VALID_MEMBER(schedule_data_tick)) { ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], LONG_PRLEN, CENTER|RJUST, "TICK"); ++ } ++ fprintf(fp, "%s\n", buf); ++ } ++ ++ sprintf(buf, "%5d ", schc->cpu_id); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(schc->schedule_data)); ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(schc->sched_priv)); ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(schc->curr)); ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(schc->idle)); ++ if (XEN_HYPER_VALID_MEMBER(schedule_data_tick)) { ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ mkstring(&buf[strlen(buf)], LONG_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(schc->tick)); ++ } ++ fprintf(fp, "%s\n", buf); ++ if (flag & XEN_HYPER_SCHED_VERBOSE) { ++ ; ++ } ++} ++ ++/* ++ * Display general system info. ++ */ ++void ++xen_hyper_cmd_sys(void) ++{ ++ int c; ++ ulong sflag; ++ ++ sflag = FALSE; ++ ++ while ((c = getopt(argcnt, args, "c")) != EOF) { ++ switch(c) ++ { ++ case 'c': ++ sflag = TRUE; ++ break; ++ ++ default: ++ argerrs++; ++ break; ++ } ++ } ++ ++ if (argerrs) ++ cmd_usage(pc->curcmd, SYNOPSIS); ++ ++ if (!args[optind]) { ++ if (sflag) ++ fprintf(fp, "No support argument\n"); ++ /* display config info here. */ ++ else ++ xen_hyper_display_sys_stats(); ++ return; ++ } ++} ++ ++/* ++ * Display system stats at init-time or for the sys command. ++ */ ++void ++xen_hyper_display_sys_stats(void) ++{ ++ struct new_utsname *uts; ++ char buf1[XEN_HYPER_CMD_BUFSIZE]; ++ char buf2[XEN_HYPER_CMD_BUFSIZE]; ++ ulong mhz; ++ int len, flag; ++ ++ uts = &xht->utsname; ++ len = 11; ++ flag = XEN_HYPER_PRI_R; ++ ++ /* ++ * It's now safe to unlink the remote namelist. ++ */ ++ if (pc->flags & UNLINK_NAMELIST) { ++ unlink(pc->namelist); ++ pc->flags &= ~UNLINK_NAMELIST; ++ pc->flags |= NAMELIST_UNLINKED; ++ } ++ ++ if (REMOTE()) { ++ switch (pc->flags & ++ (NAMELIST_LOCAL|NAMELIST_UNLINKED|NAMELIST_SAVED)) ++ { ++ case NAMELIST_UNLINKED: ++ XEN_HYPER_PRI(fp, len, "KERNEL: ", buf1, flag, ++ (buf1, "%s (temporary)\n", pc->namelist)); ++ break; ++ ++ case (NAMELIST_UNLINKED|NAMELIST_SAVED): ++ case NAMELIST_LOCAL: ++ XEN_HYPER_PRI(fp, len, "KERNEL: ", buf1, flag, ++ (buf1, "%s\n", pc->namelist)); ++ break; ++ ++ } ++ } else { ++ if (pc->system_map) { ++ XEN_HYPER_PRI(fp, len, "SYSTEM MAP: ", buf1, flag, ++ (buf1, "%s\n", pc->system_map)); ++ XEN_HYPER_PRI(fp, len, "DEBUG KERNEL: ", buf1, flag, ++ (buf1, "%s\n", pc->namelist)); ++ } else { ++ XEN_HYPER_PRI(fp, len, "KERNEL: ", buf1, flag, ++ (buf1, "%s\n", pc->namelist)); ++ } ++ } ++ ++ if (pc->debuginfo_file) { ++ XEN_HYPER_PRI(fp, len, "DEBUGINFO: ", buf1, flag, ++ (buf1, "%s\n", pc->debuginfo_file)); ++ } else if (pc->namelist_debug) { ++ XEN_HYPER_PRI(fp, len, "DEBUG KERNEL: ", buf1, flag, ++ (buf1, "%s\n", pc->namelist_debug)); ++ } ++ ++ XEN_HYPER_PRI_CONST(fp, len, "DUMPFILE: ", flag); ++ if (ACTIVE()) { ++ if (REMOTE_ACTIVE()) ++ fprintf(fp, "%s@%s (remote live system)\n", ++ pc->server_memsrc, pc->server); ++ else ++ fprintf(fp, "%s\n", pc->live_memsrc); ++ } else { ++ if (REMOTE_DUMPFILE()) ++ fprintf(fp, "%s@%s (remote dumpfile)", ++ pc->server_memsrc, pc->server); ++ else ++ fprintf(fp, "%s", pc->dumpfile); ++ ++ fprintf(fp, "\n"); ++ } ++ ++ XEN_HYPER_PRI(fp, len, "CPUS: ", buf1, flag, ++ (buf1, "%d\n", XEN_HYPER_NR_PCPUS())); ++ XEN_HYPER_PRI(fp, len, "DOMAINS: ", buf1, flag, ++ (buf1, "%d\n", XEN_HYPER_NR_DOMAINS())); ++ /* !!!Display a date here if it can be found. */ ++ XEN_HYPER_PRI(fp, len, "UPTIME: ", buf1, flag, ++ (buf1, "%s\n", convert_time(xen_hyper_get_uptime_hyper(), buf2))); ++ /* !!!Display a version here if it can be found. */ ++ XEN_HYPER_PRI_CONST(fp, len, "MACHINE: ", flag); ++ if (strlen(uts->machine)) { ++ fprintf(fp, "%s ", uts->machine); ++ } else { ++ fprintf(fp, "unknown "); ++ } ++ if ((mhz = machdep->processor_speed())) ++ fprintf(fp, "(%ld Mhz)\n", mhz); ++ else ++ fprintf(fp, "(unknown Mhz)\n"); ++ XEN_HYPER_PRI(fp, len, "MEMORY: ", buf1, flag, ++ (buf1, "%s\n", get_memory_size(buf2))); ++ if (XENDUMP_DUMPFILE() && (kt->xen_flags & XEN_SUSPEND)) ++ return; ++} ++ ++/* ++ * Display vcpu struct. ++ */ ++void ++xen_hyper_cmd_vcpu(void) ++{ ++ struct xen_hyper_cmd_args vca; ++ struct xen_hyper_vcpu_context *vcc; ++ ulong flag; ++ ulong valvc, valdom; ++ int c, cnt, type, bogus; ++ ++ BZERO(&vca, sizeof(struct xen_hyper_cmd_args)); ++ flag = 0; ++ while ((c = getopt(argcnt, args, "i")) != EOF) { ++ switch(c) ++ { ++ case 'i': ++ flag |= XEN_HYPER_VCPUS_ID; ++ break; ++ default: ++ argerrs++; ++ break; ++ } ++ } ++ ++ if (argerrs) ++ cmd_usage(pc->curcmd, SYNOPSIS); ++ ++ cnt = bogus = 0; ++ while (args[optind]) { ++ if (IS_A_NUMBER(args[optind])) { ++ if (flag & XEN_HYPER_VCPUS_ID) { ++ type = xen_hyper_strid_to_vcpu_context( ++ args[optind], args[optind+1], ++ &valdom, &valvc, &vcc); ++ } else { ++ type = xen_hyper_strvcpu_to_vcpu_context( ++ args[optind], &valvc, &vcc); ++ } ++ switch (type) { ++ case XEN_HYPER_STR_VCID: ++ case XEN_HYPER_STR_VCPU: ++ vca.value[cnt] = valvc; ++ vca.type[cnt] = type; ++ vca.addr[cnt] = vcc->vcpu; ++ vca.context[cnt] = vcc; ++ cnt++; ++ break; ++ case XEN_HYPER_STR_INVALID: ++ error(INFO, "invalid vcpu or id value: %s\n\n", ++ args[optind]); ++ bogus++; ++ } ++ } else { ++ error(FATAL, "invalid address: %s\n", ++ args[optind]); ++ } ++ optind++; ++ if (flag & XEN_HYPER_VCPUS_ID) optind++; ++ } ++ vca.cnt = cnt; ++ if (bogus && !cnt) { ++ return; ++ } ++ ++ xen_hyper_do_vcpu(&vca); ++} ++ ++/* ++ * Do the work requested by xen_hyper_cmd_vcpu(). ++ */ ++static void ++xen_hyper_do_vcpu(struct xen_hyper_cmd_args *vca) ++{ ++ int i; ++ ++ if (vca->cnt) { ++ if (vca->cnt == 1) { ++ xhvct->last = vca->context[0]; ++ } ++ for (i = 0; i < vca->cnt; i++) { ++ dump_struct("vcpu", vca->addr[i], 0); ++ } ++ } else { ++ dump_struct("vcpu", xhvct->last->vcpu, 0); ++ } ++} ++ ++/* ++ * Display vcpu status. ++ */ ++void ++xen_hyper_cmd_vcpus(void) ++{ ++ struct xen_hyper_cmd_args vca; ++ struct xen_hyper_vcpu_context *vcc; ++ ulong flag; ++ ulong valvc, valdom; ++ int c, cnt, type, bogus; ++ ++ BZERO(&vca, sizeof(struct xen_hyper_cmd_args)); ++ flag = 0; ++ while ((c = getopt(argcnt, args, "i")) != EOF) { ++ switch(c) ++ { ++ case 'i': ++ flag |= XEN_HYPER_VCPUS_ID; ++ break; ++ default: ++ argerrs++; ++ break; ++ } ++ } ++ ++ if (argerrs) ++ cmd_usage(pc->curcmd, SYNOPSIS); ++ ++ cnt = bogus = 0; ++ while (args[optind]) { ++ if (IS_A_NUMBER(args[optind])) { ++ if (flag & XEN_HYPER_VCPUS_ID) { ++ type = xen_hyper_strid_to_vcpu_context( ++ args[optind], args[optind+1], ++ &valdom, &valvc, &vcc); ++ } else { ++ type = xen_hyper_strvcpu_to_vcpu_context( ++ args[optind], &valvc, &vcc); ++ } ++ switch (type) { ++ case XEN_HYPER_STR_VCID: ++ case XEN_HYPER_STR_VCPU: ++ vca.value[cnt] = valvc; ++ vca.type[cnt] = type; ++ vca.addr[cnt] = vcc->vcpu; ++ vca.context[cnt] = vcc; ++ cnt++; ++ break; ++ case XEN_HYPER_STR_INVALID: ++ error(INFO, "invalid vcpu or id value: %s\n\n", ++ args[optind]); ++ bogus++; ++ } ++ } else { ++ error(FATAL, "invalid address: %s\n", ++ args[optind]); ++ } ++ optind++; ++ } ++ vca.cnt = cnt; ++ if (bogus && !cnt) { ++ return; ++ } ++ ++ xen_hyper_do_vcpus(&vca); ++} ++ ++/* ++ * Do the work requested by xen_hyper_cmd_vcpus(). ++ */ ++static void ++xen_hyper_do_vcpus(struct xen_hyper_cmd_args *vca) ++{ ++ struct xen_hyper_vcpu_context_array *vcca; ++ struct xen_hyper_vcpu_context *vcc; ++ char buf1[XEN_HYPER_CMD_BUFSIZE]; ++ char buf2[XEN_HYPER_CMD_BUFSIZE]; ++ int i, j; ++ ++ fprintf(fp, " VCID PCID %s ST T DOMID %s\n", ++ mkstring(buf1, VADDR_PRLEN, CENTER|RJUST, "VCPU"), ++ mkstring(buf2, VADDR_PRLEN, CENTER|RJUST, "DOMAIN")); ++ if (vca->cnt) { ++ for (i = 0; i < vca->cnt; i++) { ++ xen_hyper_show_vcpus(vca->context[i]); ++ } ++ } else { ++ for (i = 0, vcca = xhvct->vcpu_context_arrays; ++ i < XEN_HYPER_NR_DOMAINS(); i++, vcca++) { ++ for (j = 0, vcc = vcca->context_array; ++ j < vcca->context_array_valid; j++, vcc++) { ++ xen_hyper_show_vcpus(vcc); ++ } ++ } ++ } ++} ++ ++static void ++xen_hyper_show_vcpus(struct xen_hyper_vcpu_context *vcc) ++{ ++ int type; ++ char *act, *crash; ++ char buf[XEN_HYPER_CMD_BUFSIZE]; ++ struct xen_hyper_pcpu_context *pcc; ++ domid_t domid; ++ ++ if (!(vcc->vcpu)) { ++ return; ++ } ++ if((pcc = xen_hyper_id_to_pcpu_context(vcc->processor))) { ++ if (pcc->current_vcpu == vcc->vcpu) { ++ act = ">"; ++ } else { ++ act = " "; ++ } ++ } else { ++ act = " "; ++ } ++ if (xht->crashing_vcc && vcc->vcpu == xht->crashing_vcc->vcpu) { ++ crash = "*"; ++ } else { ++ crash = " "; ++ } ++ sprintf(buf, "%s%s%5d %5d ", act, crash, vcc->vcpu_id, vcc->processor); ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(vcc->vcpu)); ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ xen_hyper_vcpu_state_string(vcc, &buf[strlen(buf)], !VERBOSE); ++ strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1); ++ xen_hyper_domain_to_type(vcc->domain, &type, &buf[strlen(buf)], !VERBOSE); ++ if ((domid = xen_hyper_domain_to_id(vcc->domain)) == XEN_HYPER_DOMAIN_ID_INVALID) { ++ sprintf(&buf[strlen(buf)], " ????? "); ++ } else { ++ sprintf(&buf[strlen(buf)], " %5d ", domid); ++ } ++ mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, ++ MKSTR(vcc->domain)); ++ fprintf(fp, "%s\n", buf); ++} ++ ++ ++ ++/* ++ * Get string for domain status. ++ * - This may need some data in domain struct. ++ */ ++char * ++xen_hyper_domain_state_string(struct xen_hyper_domain_context *dc, ++ char *buf, int verbose) ++{ ++ ulong stat; ++ ++ stat = xen_hyper_domain_state(dc); ++ ++ if (stat == XEN_HYPER_DOMF_ERROR) { ++ sprintf(buf, verbose ? "(unknown)" : "??"); ++ } else if (XEN_HYPER_VALID_MEMBER(domain_domain_flags)) { ++ if (stat & XEN_HYPER_DOMF_shutdown) { ++ sprintf(buf, verbose ? "DOMAIN_SHUTDOWN" : "SF"); ++ } else if (stat & XEN_HYPER_DOMF_dying) { ++ sprintf(buf, verbose ? "DOMAIN_DYING" : "DY"); ++ } else if (stat & XEN_HYPER_DOMF_ctrl_pause) { ++ sprintf(buf, verbose ? "DOMAIN_CTRL_PAUSE" : "CP"); ++ } else if (stat & XEN_HYPER_DOMF_polling) { ++ sprintf(buf, verbose ? "DOMAIN_POLLING" : "PO"); ++ } else if (stat & XEN_HYPER_DOMF_paused) { ++ sprintf(buf, verbose ? "DOMAIN_PAUSED" : "PA"); ++ } else { ++ sprintf(buf, verbose ? "DOMAIN_RUNNING" : "RU"); ++ } ++ } else { ++ if (stat & XEN_HYPER_DOMS_shutdown) { ++ sprintf(buf, verbose ? "DOMAIN_SHUTDOWN" : "SF"); ++ } else if (stat & XEN_HYPER_DOMS_shuttingdown) { ++ sprintf(buf, verbose ? "DOMAIN_SHUTTINGDOWN" : "SH"); ++ } else if (stat & XEN_HYPER_DOMS_dying) { ++ sprintf(buf, verbose ? "DOMAIN_DYING" : "DY"); ++ } else if (stat & XEN_HYPER_DOMS_ctrl_pause) { ++ sprintf(buf, verbose ? "DOMAIN_CTRL_PAUSE" : "CP"); ++ } else if (stat & XEN_HYPER_DOMS_polling) { ++ sprintf(buf, verbose ? "DOMAIN_POLLING" : "PO"); ++ } else { ++ sprintf(buf, verbose ? "DOMAIN_RUNNING" : "RU"); ++ } ++ } ++ ++ return buf; ++} ++ ++/* ++ * Get string for vcpu status. ++ * - This may need some data in vcpu struct. ++ */ ++char * ++xen_hyper_vcpu_state_string(struct xen_hyper_vcpu_context *vcc, ++ char *buf, int verbose) ++{ ++ int stat; ++ ++ stat = xen_hyper_vcpu_state(vcc); ++ ++ if (stat == XEN_HYPER_RUNSTATE_ERROR) { ++ sprintf(buf, verbose ? "(unknown)" : "??"); ++ } else if (stat == XEN_HYPER_RUNSTATE_running || ++ stat == XEN_HYPER_RUNSTATE_runnable) { ++ sprintf(buf, verbose ? "VCPU_RUNNING" : "RU"); ++ } else if (stat == XEN_HYPER_RUNSTATE_blocked) { ++ sprintf(buf, verbose ? "VCPU_BLOCKED" : "BL"); ++ } else if (stat == XEN_HYPER_RUNSTATE_offline) { ++ sprintf(buf, verbose ? "VCPU_OFFLINE" : "OF"); ++ } else { ++ sprintf(buf, verbose ? "(unknown)" : "??"); ++ } ++ ++ return buf; ++} ++ ++/* ++ * Get domain type from domain address. ++ */ ++static char * ++xen_hyper_domain_to_type(ulong domain, int *type, char *buf, int verbose) ++{ ++ struct xen_hyper_domain_context *dc; ++ ++ if ((dc = xen_hyper_domain_to_domain_context(domain)) == NULL) { ++ error(WARNING, "cannot get context from domain address.\n"); ++ return NULL; ++ } ++ return xen_hyper_domain_context_to_type(dc, type, buf, verbose); ++} ++ ++/* ++ * Get domain type from domain context. ++ */ ++static char * ++xen_hyper_domain_context_to_type(struct xen_hyper_domain_context *dc, int *type, ++ char *buf, int verbose) ++{ ++ if (!dc) { ++ *type = XEN_HYPER_DOMAIN_TYPE_INVALID; ++ return NULL; ++ } else if (dc->domain_id == XEN_HYPER_DOMID_IO) { ++ *type = XEN_HYPER_DOMAIN_TYPE_IO; ++ sprintf(buf, verbose ? "dom_io" : "O"); ++ } else if (dc->domain_id == XEN_HYPER_DOMID_XEN) { ++ *type = XEN_HYPER_DOMAIN_TYPE_XEN; ++ sprintf(buf, verbose ? "dom_xen" : "X"); ++ } else if (dc == xhdt->idle_domain) { ++ *type = XEN_HYPER_DOMAIN_TYPE_IDLE; ++ sprintf(buf, verbose ? "idle domain" : "I"); ++ } else if (dc == xhdt->dom0) { ++ *type = XEN_HYPER_DOMAIN_TYPE_DOM0; ++ sprintf(buf, verbose ? "domain 0" : "0"); ++ } else { ++ *type = XEN_HYPER_DOMAIN_TYPE_GUEST; ++ sprintf(buf, verbose ? "domain U" : "U"); ++ } ++ return buf; ++} ++ ++/* ++ * Check a type for value. And return domain context. ++ */ ++static int ++xen_hyper_str_to_domain_context(char *string, ulong *value, ++ struct xen_hyper_domain_context **dcp) ++{ ++ ulong dvalue, hvalue; ++ int found, type; ++ char *s; ++ struct xen_hyper_domain_context *dc_did, *dc_ddc, *dc_hid, *dc_hdc; ++ ++ if (string == NULL) { ++ error(INFO, "received NULL string\n"); ++ return STR_INVALID; ++ } ++ ++ s = string; ++ dvalue = hvalue = BADADDR; ++ ++ if (decimal(s, 0)) ++ dvalue = dtol(s, RETURN_ON_ERROR, NULL); ++ ++ if (hexadecimal(s, 0)) { ++ if (STRNEQ(s, "0x") || STRNEQ(s, "0X")) ++ s += 2; ++ if (strlen(s) <= MAX_HEXADDR_STRLEN) ++ hvalue = htol(s, RETURN_ON_ERROR, NULL); ++ } ++ ++ found = 0; ++ dc_did = dc_ddc = dc_hid = dc_hdc = NULL; ++ type = XEN_HYPER_STR_INVALID; ++ ++ if (dvalue != BADADDR) { ++ if ((dc_did = xen_hyper_id_to_domain_context(dvalue))) ++ found++; ++ if ((dc_ddc = xen_hyper_domain_to_domain_context(dvalue))) ++ found++; ++ } ++ ++ if ((hvalue != BADADDR) && (dvalue != hvalue)) { ++ if ((dc_hid = xen_hyper_id_to_domain_context(hvalue))) ++ found++; ++ if ((dc_hdc = xen_hyper_domain_to_domain_context(hvalue))) ++ found++; ++ } ++ ++ switch (found) ++ { ++ case 2: ++ if (dc_did && dc_hid) { ++ *dcp = dc_did; ++ *value = dvalue; ++ type = STR_PID; ++ } ++ break; ++ ++ case 1: ++ if (dc_did) { ++ *dcp = dc_did; ++ *value = dvalue; ++ type = XEN_HYPER_STR_DID; ++ } ++ ++ if (dc_ddc) { ++ *dcp = dc_ddc; ++ *value = dvalue; ++ type = XEN_HYPER_STR_DOMAIN; ++ } ++ ++ if (dc_hid) { ++ *dcp = dc_hid; ++ *value = hvalue; ++ type = XEN_HYPER_STR_DID; ++ } ++ ++ if (dc_hdc) { ++ *dcp = dc_hdc; ++ *value = hvalue; ++ type = XEN_HYPER_STR_DOMAIN; ++ } ++ break; ++ } ++ ++ return type; ++} ++ ++ ++ ++/* ++ * Display a vcpu context. ++ */ ++void ++xen_hyper_show_vcpu_context(struct xen_hyper_vcpu_context *vcc) ++{ ++ char buf[XEN_HYPER_CMD_BUFSIZE]; ++ struct xen_hyper_pcpu_context *pcc; ++ struct xen_hyper_domain_context *dc; ++ int len, flag; ++ ++ len = 6; ++ len += pc->flags & RUNTIME ? 0 : 5; ++ flag = XEN_HYPER_PRI_R; ++ ++ if (!(pcc = xen_hyper_id_to_pcpu_context(vcc->processor))) { ++ error(WARNING, "cannot get pcpu context vcpu belongs.\n"); ++ return; ++ } ++ if (!(dc = xen_hyper_domain_to_domain_context(vcc->domain))) { ++ error(WARNING, "cannot get domain context vcpu belongs.\n"); ++ return; ++ } ++ XEN_HYPER_PRI(fp, len, "PCPU-ID: ", buf, flag, ++ (buf, "%d\n", vcc->processor)); ++ XEN_HYPER_PRI(fp, len, "PCPU: ", buf, flag, ++ (buf, "%lx\n", pcc->pcpu)); ++ XEN_HYPER_PRI(fp, len, "VCPU-ID: ", buf, flag, ++ (buf, "%d\n", vcc->vcpu_id)); ++ XEN_HYPER_PRI(fp, len, "VCPU: ", buf, flag, ++ (buf, "%lx ", vcc->vcpu)); ++ fprintf(fp, "(%s)\n", xen_hyper_vcpu_state_string(vcc, buf, VERBOSE)); ++ XEN_HYPER_PRI(fp, len, "DOMAIN-ID: ", buf, flag, ++ (buf, "%d\n", dc->domain_id)); ++ XEN_HYPER_PRI(fp, len, "DOMAIN: ", buf, flag, ++ (buf, "%lx ", vcc->domain)); ++ fprintf(fp, "(%s)\n", xen_hyper_domain_state_string(dc, buf, VERBOSE)); ++ XEN_HYPER_PRI_CONST(fp, len, "STATE: ", flag); ++ if (machdep->flags & HWRESET) { ++ fprintf(fp, "HARDWARE RESET"); ++ } else if (machdep->flags & INIT) { ++ fprintf(fp, "INIT"); ++ } else if (xen_hyper_is_vcpu_crash(vcc)) { ++ fprintf(fp, "CRASH"); ++ } else { ++ fprintf(fp, "ACTIVE"); ++ } ++ ++ fprintf(fp, "\n"); ++} ++ ++/* ++ * Check a type for value. And return dump information context address. ++ */ ++static int ++xen_hyper_str_to_dumpinfo_context(char *string, ulong *value, ++ struct xen_hyper_dumpinfo_context **dicp) ++{ ++ ulong dvalue, hvalue; ++ struct xen_hyper_dumpinfo_context *note_did, *note_hid; ++ struct xen_hyper_dumpinfo_context *note_dad, *note_had; ++ int found, type; ++ char *s; ++ ++ if (string == NULL) { ++ error(INFO, "received NULL string\n"); ++ return STR_INVALID; ++ } ++ ++ s = string; ++ dvalue = hvalue = BADADDR; ++ ++ if (decimal(s, 0)) ++ dvalue = dtol(s, RETURN_ON_ERROR, NULL); ++ if (hexadecimal(s, 0)) { ++ if (STRNEQ(s, "0x") || STRNEQ(s, "0X")) ++ s += 2; ++ if (strlen(s) <= MAX_HEXADDR_STRLEN) ++ hvalue = htol(s, RETURN_ON_ERROR, NULL); ++ } ++ ++ found = 0; ++ note_did = note_hid = note_dad = note_had = 0; ++ type = XEN_HYPER_STR_INVALID; ++ ++ if (dvalue != BADADDR) { ++ if (dvalue > XEN_HYPER_MAX_CPUS()) { ++ note_dad = xen_hyper_note_to_dumpinfo_context(dvalue); ++ } else { ++ note_did = xen_hyper_id_to_dumpinfo_context(dvalue); ++ } ++ found++; ++ } ++ if ((hvalue != BADADDR)) { ++ if (hvalue > XEN_HYPER_MAX_CPUS()) { ++ note_had = xen_hyper_note_to_dumpinfo_context(hvalue); ++ } else { ++ note_hid = xen_hyper_id_to_dumpinfo_context(hvalue); ++ } ++ found++; ++ } ++ ++ switch (found) ++ { ++ case 2: ++ if (note_did && note_hid) { ++ *value = dvalue; ++ *dicp = note_did; ++ type = XEN_HYPER_STR_PCID; ++ } ++ break; ++ case 1: ++ if (note_did) { ++ *value = dvalue; ++ *dicp = note_did; ++ type = XEN_HYPER_STR_PCID; ++ } ++ ++ if (note_hid) { ++ *value = hvalue; ++ *dicp = note_hid; ++ type = XEN_HYPER_STR_PCID; ++ } ++ ++ if (note_dad) { ++ *value = dvalue; ++ *dicp = note_dad; ++ type = XEN_HYPER_STR_ADDR; ++ } ++ ++ if (note_had) { ++ *value = hvalue; ++ *dicp = note_had; ++ type = XEN_HYPER_STR_ADDR; ++ } ++ break; ++ } ++ ++ return type; ++} ++ ++/* ++ * Check a type for value. And return vcpu context. ++ */ ++static int ++xen_hyper_strvcpu_to_vcpu_context(char *string, ulong *value, ++ struct xen_hyper_vcpu_context **vccp) ++{ ++ ulong dvalue, hvalue; ++ int found, type; ++ char *s; ++ struct xen_hyper_vcpu_context *vcc_dvc, *vcc_hvc; ++ ++ if (string == NULL) { ++ error(INFO, "received NULL string\n"); ++ return STR_INVALID; ++ } ++ ++ s = string; ++ dvalue = hvalue = BADADDR; ++ ++ if (decimal(s, 0)) ++ dvalue = dtol(s, RETURN_ON_ERROR, NULL); ++ ++ if (hexadecimal(s, 0)) { ++ if (STRNEQ(s, "0x") || STRNEQ(s, "0X")) ++ s += 2; ++ if (strlen(s) <= MAX_HEXADDR_STRLEN) ++ hvalue = htol(s, RETURN_ON_ERROR, NULL); ++ } ++ ++ found = 0; ++ vcc_dvc = vcc_hvc = NULL; ++ type = XEN_HYPER_STR_INVALID; ++ ++ if (dvalue != BADADDR) { ++ if ((vcc_dvc = xen_hyper_vcpu_to_vcpu_context(dvalue))) ++ found++; ++ } ++ ++ if ((hvalue != BADADDR) && (dvalue != hvalue)) { ++ if ((vcc_hvc = xen_hyper_vcpu_to_vcpu_context(hvalue))) ++ found++; ++ } ++ ++ switch (found) ++ { ++ case 1: ++ if (vcc_dvc) { ++ *vccp = vcc_dvc; ++ *value = dvalue; ++ type = XEN_HYPER_STR_VCPU; ++ } ++ ++ if (vcc_hvc) { ++ *vccp = vcc_hvc; ++ *value = hvalue; ++ type = XEN_HYPER_STR_VCPU; ++ } ++ break; ++ } ++ ++ return type; ++} ++ ++/* ++ * Check a type for id value. And return vcpu context. ++ */ ++static int ++xen_hyper_strid_to_vcpu_context(char *strdom, char *strvc, ulong *valdom, ++ ulong *valvc, struct xen_hyper_vcpu_context **vccp) ++{ ++ ulong dvalue, hvalue; ++ int found, type; ++ char *s; ++ struct xen_hyper_vcpu_context *vcc_did, *vcc_hid; ++ struct xen_hyper_domain_context *dc; ++ ++ if (strdom == NULL || strvc == NULL) { ++ error(INFO, "received NULL string\n"); ++ return STR_INVALID; ++ } ++ ++ if (xen_hyper_str_to_domain_context(strdom, valdom, &dc) == ++ XEN_HYPER_STR_INVALID) { ++ error(INFO, "invalid domain id string.\n"); ++ return STR_INVALID; ++ } ++ ++ s = strvc; ++ dvalue = hvalue = BADADDR; ++ if (decimal(s, 0)) ++ dvalue = dtol(s, RETURN_ON_ERROR, NULL); ++ ++ if (hexadecimal(s, 0)) { ++ if (STRNEQ(s, "0x") || STRNEQ(s, "0X")) ++ s += 2; ++ if (strlen(s) <= MAX_HEXADDR_STRLEN) ++ hvalue = htol(s, RETURN_ON_ERROR, NULL); ++ } ++ ++ found = 0; ++ vcc_did = vcc_hid = NULL; ++ type = XEN_HYPER_STR_INVALID; ++ ++ if (dvalue != BADADDR) { ++ if ((vcc_did = xen_hyper_id_to_vcpu_context(dc->domain, ++ XEN_HYPER_DOMAIN_ID_INVALID, dvalue))) ++ found++; ++ } ++ ++ if ((hvalue != BADADDR) && (dvalue != hvalue)) { ++ if ((vcc_hid = xen_hyper_id_to_vcpu_context(dc->domain, ++ XEN_HYPER_DOMAIN_ID_INVALID, hvalue))) ++ found++; ++ } ++ ++ switch (found) ++ { ++ case 2: ++ if (vcc_did && vcc_hid) { ++ *vccp = vcc_did; ++ *valvc = dvalue; ++ type = XEN_HYPER_STR_VCID; ++ } ++ break; ++ case 1: ++ if (vcc_did) { ++ *vccp = vcc_did; ++ *valvc = dvalue; ++ type = XEN_HYPER_STR_VCID; ++ } ++ ++ if (vcc_hid) { ++ *vccp = vcc_hid; ++ *valvc = hvalue; ++ type = XEN_HYPER_STR_VCID; ++ } ++ break; ++ } ++ ++ return type; ++} ++ ++/* ++ * Check a type for value. And return pcpu context. ++ */ ++static int ++xen_hyper_str_to_pcpu_context(char *string, ulong *value, ++ struct xen_hyper_pcpu_context **pccp) ++{ ++ ulong dvalue, hvalue; ++ int found, type; ++ char *s; ++ struct xen_hyper_pcpu_context *pcc_did, *pcc_dpc, *pcc_hid, *pcc_hpc; ++ ++ if (string == NULL) { ++ error(INFO, "received NULL string\n"); ++ return STR_INVALID; ++ } ++ ++ s = string; ++ dvalue = hvalue = BADADDR; ++ ++ if (decimal(s, 0)) ++ dvalue = dtol(s, RETURN_ON_ERROR, NULL); ++ ++ if (hexadecimal(s, 0)) { ++ if (STRNEQ(s, "0x") || STRNEQ(s, "0X")) ++ s += 2; ++ if (strlen(s) <= MAX_HEXADDR_STRLEN) ++ hvalue = htol(s, RETURN_ON_ERROR, NULL); ++ } ++ ++ found = 0; ++ pcc_did = pcc_dpc = pcc_hid = pcc_hpc = NULL; ++ type = XEN_HYPER_STR_INVALID; ++ ++ if (dvalue != BADADDR) { ++ if ((pcc_did = xen_hyper_id_to_pcpu_context(dvalue))) ++ found++; ++ if ((pcc_dpc = xen_hyper_pcpu_to_pcpu_context(dvalue))) ++ found++; ++ } ++ ++ if ((hvalue != BADADDR) && (dvalue != hvalue)) { ++ if ((pcc_hid = xen_hyper_id_to_pcpu_context(hvalue))) ++ found++; ++ if ((pcc_hpc = xen_hyper_pcpu_to_pcpu_context(hvalue))) ++ found++; ++ } ++ ++ switch (found) ++ { ++ case 2: ++ if (pcc_did && pcc_hid) { ++ *pccp = pcc_did; ++ *value = dvalue; ++ type = STR_PID; ++ } ++ break; ++ ++ case 1: ++ if (pcc_did) { ++ *pccp = pcc_did; ++ *value = dvalue; ++ type = XEN_HYPER_STR_PCID; ++ } ++ ++ if (pcc_dpc) { ++ *pccp = pcc_dpc; ++ *value = dvalue; ++ type = XEN_HYPER_STR_PCPU; ++ } ++ ++ if (pcc_hid) { ++ *pccp = pcc_hid; ++ *value = hvalue; ++ type = XEN_HYPER_STR_PCID; ++ } ++ ++ if (pcc_hpc) { ++ *pccp = pcc_hpc; ++ *value = hvalue; ++ type = XEN_HYPER_STR_PCPU; ++ } ++ break; ++ } ++ ++ return type; ++} ++ ++#endif +--- crash/xen_hyper_global_data.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/xen_hyper_global_data.c 2007-08-23 17:02:54.000000000 -0400 +@@ -0,0 +1,400 @@ ++/* ++ * xen_hyper_global_data.c ++ * ++ * Portions Copyright (C) 2006-2007 Fujitsu Limited ++ * Portions Copyright (C) 2006-2007 VA Linux Systems Japan K.K. ++ * ++ * Authors: Itsuro Oda ++ * Fumihiko Kakuma ++ * ++ * This file is part of Xencrash. ++ * ++ * Xencrash 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 (version 2 of the License). ++ * ++ * Xencrash 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with Xencrash; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include "defs.h" ++ ++#ifdef XEN_HYPERVISOR_ARCH ++#include "xen_hyper_defs.h" ++ ++/* ++ * Global data for Xen hypervisor. ++ */ ++ ++struct xen_hyper_machdep_table xen_hyper_machdep_table = { 0 }; ++struct xen_hyper_machdep_table *xhmachdep = &xen_hyper_machdep_table; ++ ++struct xen_hyper_table xen_hyper_table = { 0 }; ++struct xen_hyper_table *xht = &xen_hyper_table; ++ ++struct xen_hyper_dumpinfo_table xen_hyper_dumpinfo_table = { 0 }; ++struct xen_hyper_dumpinfo_table *xhdit = &xen_hyper_dumpinfo_table; ++ ++struct xen_hyper_domain_table xen_hyper_domain_table = { 0 }; ++struct xen_hyper_domain_table *xhdt = &xen_hyper_domain_table; ++ ++struct xen_hyper_vcpu_table xen_hyper_vcpu_table = { 0 }; ++struct xen_hyper_vcpu_table *xhvct = &xen_hyper_vcpu_table; ++ ++struct xen_hyper_pcpu_table xen_hyper_pcpu_table = { 0 }; ++struct xen_hyper_pcpu_table *xhpct = &xen_hyper_pcpu_table; ++ ++struct xen_hyper_sched_table xen_hyper_sched_table = { 0 }; ++struct xen_hyper_sched_table *xhscht = &xen_hyper_sched_table; ++ ++struct xen_hyper_symbol_table_data xen_hyper_symbol_table_data = { 0 }; ++struct xen_hyper_symbol_table_data *xhsymt = &xen_hyper_symbol_table_data; ++ ++/* ++ * The following commands are for Xen hypervisor. ++ */ ++ ++struct command_table_entry xen_hyper_command_table[] = { ++ {"*", cmd_pointer, help_pointer, 0}, ++ {"alias", cmd_alias, help_alias, 0}, ++ {"ascii", cmd_ascii, help_ascii, 0}, ++ {"bt", cmd_bt, help_bt, 0}, ++ {"dis", cmd_dis, help_dis, 0}, ++ {"domain", xen_hyper_cmd_domain, xen_hyper_help_domain, REFRESH_TASK_TABLE}, ++ {"doms", xen_hyper_cmd_doms, xen_hyper_help_doms, REFRESH_TASK_TABLE}, ++#if defined(X86) || defined(X86_64) ++ {"dumpinfo",xen_hyper_cmd_dumpinfo, xen_hyper_help_dumpinfo,0}, ++#endif ++ {"eval", cmd_eval, help_eval, 0}, ++ {"exit", cmd_quit, help_exit, 0}, ++ {"extend", cmd_extend, help_extend, 0}, ++ {"foreach", cmd_foreach, help_foreach, 0}, ++ {"gdb", cmd_gdb, help_gdb, 0}, ++ {"help", xen_hyper_cmd_help, help_help, 0}, ++ {"list", cmd_list, help__list, 0}, ++ {"log", xen_hyper_cmd_log, xen_hyper_help_log, 0}, ++ {"p", cmd_p, help_p, 0}, ++ {"pcpus", xen_hyper_cmd_pcpus, xen_hyper_help_pcpus, 0}, ++ {"pte", cmd_pte, help_pte, 0}, ++ {"q", cmd_quit, help_quit, 0}, ++ {"rd", cmd_rd, help_rd, 0}, ++ {"repeat", cmd_repeat, help_repeat, 0}, ++ {"sched", xen_hyper_cmd_sched, xen_hyper_help_sched, 0}, ++ {"search", cmd_search, help_search, 0}, ++ {"set", cmd_set, help_set, 0}, ++ {"struct", cmd_struct, help_struct, 0}, ++ {"sym", cmd_sym, help_sym, 0}, ++ {"sys", xen_hyper_cmd_sys, xen_hyper_help_sys, 0}, ++ {"test", cmd_test, NULL, HIDDEN_COMMAND}, ++ {"union", cmd_union, help_union, 0}, ++ {"vcpu", xen_hyper_cmd_vcpu, xen_hyper_help_vcpu, REFRESH_TASK_TABLE}, ++ {"vcpus", xen_hyper_cmd_vcpus, xen_hyper_help_vcpus, REFRESH_TASK_TABLE}, ++ {"whatis", cmd_whatis, help_whatis, 0}, ++ {"wr", cmd_wr, help_wr, 0}, ++ {(char *)NULL} ++}; ++ ++/* ++ * ++ */ ++struct xen_hyper_offset_table xen_hyper_offset_table = { 0 }; ++struct xen_hyper_size_table xen_hyper_size_table = { 0 }; ++ ++/* ++ * help data ++ */ ++ ++char *xen_hyper_help_domain[] = { ++"domain", ++"display contents of domain struct", ++"[domain-id | domainp] ...", ++" This command displays contents of domain struct for selected, or all, domains", ++" domain-id a domain id.", ++" domainp a domain pointer.", ++NULL ++}; ++ ++char *xen_hyper_help_doms[] = { ++"doms", ++"display domain status information", ++"[domain-id | domainp] ...", ++" This command displays domain status for selected, or all, domains" , ++" domain-id a domain id.", ++" domainp a domain pointer.", ++" ", ++" 1. the DOMAIN-ID.", ++" 2. the struct domain pointer.", ++" 3. the domain state", ++" (SF:fully shut down, SH:shutting down, DY:dying,", ++" CP:pause by controller software, PO:polling event channels,", ++" PA:pause by the hypervisor, RU:running).", ++" 4. the TYPE of domain", ++" (O:dom_io, X:dom_xen, I:idle domain, 0:domain 0, U:domain U).", ++" 5. displays max_pages member of domain.", ++" 6. displays tot_pages member of domain.", ++" 7. a number of vcpu that domain is assigned.", ++" 8. the shared_info pointer of domain.", ++" 9. frame containing list of mfns containing list of mfns" , ++" containing p2m.", ++" ", ++" The active domain on each CPU will be highlighted by an angle ", ++" bracket (\">\") preceding its information.", ++" The crashing domain on each CPU will be highlighted by an aster ", ++" (\"*\") preceding its information.", ++"\nEXAMPLES", ++" Show the domain status of all:\n", ++" %s> doms", ++" DID DOMAIN ST T MAXPAGE TOTPAGE VCPU SHARED_I P2M_MFN", ++" 32753 ffbf8080 RU O 0 0 0 0 ----", ++" 32754 ffbfa080 RU X 0 0 0 0 ----", ++" 32767 ffbfc080 RU I 0 0 2 0 ----", ++" >* 0 ff198080 RU 0 ffffffff 32900 2 ff194000 18d0", ++" 4 ffbee080 RU U 4000 4000 2 ff18d000 3eb92", ++" 5 ff186080 RU U 4000 4000 2 ff184000 298d3", ++" %s>", ++NULL ++}; ++ ++char *xen_hyper_help_dumpinfo[] = { ++"dumpinfo", ++"display Xen dump information", ++"[-t | -r] [pcpu-id | enotep] ...", ++" This command displays Xen dump information for selected, or all, cpus" , ++" pcpu-id a physical cpu id.", ++" enotep a ELF Note pointer.", ++" -t display time information.", ++" -r display register information.", ++NULL ++}; ++ ++char *xen_hyper_help_log[] = { ++"log", ++"dump system message buffer", ++" ", ++" This command dumps the xen conring contents in chronological order." , ++" ", ++"EXAMPLES", ++" Dump the Xen message buffer:\n", ++" %s> log", ++" __ __ _____ ___ _ _ _", ++" \\ \\/ /___ _ __ |___ / / _ \\ _ _ _ __ ___| |_ __ _| |__ | | ___", ++" \\ // _ \\ '_ \\ |_ \\| | | |__| | | | '_ \\/ __| __/ _` | '_ \\| |/ _ \\", ++" / \\ __/ | | | ___) | |_| |__| |_| | | | \\__ \\ || (_| | |_) | | __/", ++" /_/\\_\\___|_| |_| |____(_)___/ \\__,_|_| |_|___/\\__\\__,_|_.__/|_|\\___|", ++" ", ++" http://www.cl.cam.ac.uk/netos/xen", ++" University of Cambridge Computer Laboratory", ++" ", ++" Xen version 3.0-unstable (damm@) (gcc version 3.4.6 (Gentoo 3.4.6-r1, ssp-3.4.5-1.0,", ++" pie-8.7.9)) Wed Dec 6 17:34:32 JST 2006", ++" Latest ChangeSet: unavailable", ++" ", ++" (XEN) Console output is synchronous.", ++" (XEN) Command line: 12733-i386-pae/xen.gz console=com1 sync_console conswitch=bb com1", ++" =115200,8n1,0x3f8 dom0_mem=480000 crashkernel=64M@32M", ++" (XEN) Physical RAM map:", ++" (XEN) 0000000000000000 - 0000000000098000 (usable)", ++" (XEN) 0000000000098000 - 00000000000a0000 (reserved)", ++" (XEN) 00000000000f0000 - 0000000000100000 (reserved)", ++" (XEN) 0000000000100000 - 000000003f7f0000 (usable)", ++" (XEN) 000000003f7f0000 - 000000003f7f3000 (ACPI NVS)", ++" (XEN) 000000003f7f3000 - 000000003f800000 (ACPI data)", ++" (XEN) 00000000e0000000 - 00000000f0000000 (reserved)", ++" (XEN) 00000000fec00000 - 0000000100000000 (reserved)", ++" (XEN) Kdump: 64MB (65536kB) at 0x2000000", ++" (XEN) System RAM: 1015MB (1039904kB)", ++" (XEN) ACPI: RSDP (v000 XPC ) @ 0x000f9250", ++" ...", ++NULL ++}; ++ ++char *xen_hyper_help_pcpus[] = { ++"pcpus", ++"display physical cpu information", ++"[-r][-t] [pcpu-id | pcpup] ...", ++" This command displays physical cpu information for selected, or all, cpus" , ++" pcpu-id a physical cpu id.", ++" pcpup a physical cpu pointer.", ++" cur-vcpu a current virtual cpu pointer.", ++" -r display register information.", ++" -t display init_tss information.", ++" ", ++" The crashing physical cpu will be highlighted by an aster ", ++" (\"*\") preceding its information.", ++"\nEXAMPLES", ++" Show the physical cpu status of all:\n", ++" %s> pcpus", ++" PCID PCPU CUR-VCPU", ++" 0 ff1a3fb4 ffbf9080", ++" * 1 ff1dbfb4 ffbf8080", ++" %s>", ++" ", ++" Show the physical cpu status of all with register information:\n", ++" %s> pcpus -r", ++" PCID PCPU CUR-VCPU", ++" * 0 ff1b7fb4 ffbef080", ++" Register information:", ++" struct cpu_user_regs {", ++" ebx = 0x0,", ++" ecx = 0xdcf4bed8,", ++" edx = 0xc0326887,", ++" esi = 0x63,", ++" edi = 0x0,", ++" ebp = 0xdcf4bee0,", ++" eax = 0x25,", ++" error_code = 0x6,", ++" entry_vector = 0xe,", ++" eip = 0xc01014a7,", ++" cs = 0x61,", ++" saved_upcall_mask = 0x0,", ++" _pad0 = 0x0,", ++" eflags = 0x202,", ++" esp = 0xdcf4bed0,", ++" ss = 0x69,", ++" _pad1 = 0x0,", ++" es = 0x7b,", ++" _pad2 = 0x0,", ++" ds = 0x7b,", ++" _pad3 = 0x0,", ++" fs = 0x0,", ++" _pad4 = 0x0,", ++" gs = 0x0,", ++" _pad5 = 0x0", ++" }", ++" ", ++" Show the physical cpu status of all with init_tss information:\n", ++" %s> pcpus -t", ++" PCID PCPU CUR-VCPU", ++" * 0 ff1b7fb4 ffbef080", ++" init_tss information:", ++" struct tss_struct {", ++" back_link = 0x0,", ++" __blh = 0x0,", ++" esp0 = 0xff1b7fe8,", ++" ss0 = 0xe010,", ++" __ss0h = 0x0,", ++" esp1 = 0xdcf4bff8,", ++" ss1 = 0x69,", ++" __ss1h = 0x0,", ++" esp2 = 0x0,", ++" ss2 = 0x0,", ++" __ss2h = 0x0,", ++" __cr3 = 0x0,", ++" eip = 0x0,", ++" eflags = 0x0,", ++" eax = 0x0,", ++" ecx = 0x0,", ++" edx = 0x0,", ++" ebx = 0x0,", ++" esp = 0x0,", ++" ebp = 0x0,", ++" esi = 0x0,", ++" edi = 0x0,", ++" es = 0x0,", ++" __esh = 0x0,", ++" cs = 0x0,", ++" __csh = 0x0,", ++" ss = 0x0,", ++" __ssh = 0x0,", ++" ds = 0x0,", ++" __dsh = 0x0,", ++" fs = 0x0,", ++" __fsh = 0x0,", ++" gs = 0x0,", ++" __gsh = 0x0,", ++" ldt = 0x0,", ++" __ldth = 0x0,", ++" trace = 0x0,", ++" bitmap = 0x8000,", ++" __cacheline_filler = \"\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\"", ++" }", ++NULL ++}; ++ ++char *xen_hyper_help_sched[] = { ++"pcpus", ++"display scheduler information", ++"[-v] [pcpu-id] ...", ++" This command displays scheduler information for selected, or all, cpus" , ++" pcpu-id a physical cpu id.", ++" -v display verbosely scheduler information.", ++" ", ++NULL ++}; ++ ++char *xen_hyper_help_sys[] = { ++"sys", ++"system data", ++"[-c [name|number]] config", ++" This command displays system-specific data. If no arguments are entered,\n" ++" the same system data shown during %s invocation is shown.\n", ++"\nEXAMPLES", ++" Display essential system information:\n", ++" %s> sys", ++" DEBUG KERNEL: xen-syms", ++" DUMPFILE: vmcore", ++" CPUS: 2", ++" DOMAINS: 2", ++" MACHINE: Pentium III (Coppermine) (866 Mhz)", ++" MEMORY: 2 GB", ++" %s>", ++NULL ++}; ++ ++char *xen_hyper_help_vcpu[] = { ++"vcpu", ++"display contents of vcpu struct", ++"[vcpup] ...", ++" This command displays contents of vcpu struct for selected, or all, vcpus", ++" vcpu-id a virtual cpu id.", ++" vcpup a virtual cpu pointer.", ++NULL ++}; ++ ++char *xen_hyper_help_vcpus[] = { ++"vcpus", ++"display vcpu status information", ++"[-i domain-id vcpu-id | vcpup] ...", ++" This command displays vcpu status for selected, or all, vcpus" , ++" domain-id a domain id.", ++" vcpu-id a VCPU-ID.", ++" vcpup a hexadecimal struct vcpu pointer.", ++" -i specify vcpu id as an argument.", ++" ", ++" 1. the VCPU-ID.", ++" 2. the physical CPU-ID.", ++" 3. the struct vcpu pointer.", ++" 4. the vcpu state (RU, BL, OF).", ++" 5. the TYPE of domain that vcpu is assigned(I, 0, G).", ++" 6. the DOMAIN-ID of domain that vcpu is assigned.", ++" 7. the struct domain pointer of domain that vcpu is assigned.", ++" ", ++" The active vcpu on each CPU will be highlighted by an angle ", ++" bracket (\">\") preceding its information.", ++" The crashing vcpu on each CPU will be highlighted by an aster ", ++" (\"*\") preceding its information.", ++"\nEXAMPLES", ++" Show the vcpu status of all:\n", ++" %s> vcpus", ++" VCID PCID VCPU ST T DOMID DOMAIN", ++" 0 0 ffbfe080 RU I 32767 ffbfc080", ++" 1 1 ff1df080 RU I 32767 ffbfc080", ++" >* 0 0 ff195180 RU 0 0 ff198080", ++" > 1 1 ff190080 BL 0 0 ff198080", ++" 0 1 ff18a080 BL G 4 ffbee080", ++" 1 0 ff189080 BL G 4 ffbee080", ++" 0 1 ff1f3080 BL G 5 ff186080", ++" 1 0 ff1f2080 BL G 5 ff186080", ++" %s>", ++NULL ++}; ++ ++struct task_context fake_tc = { 0 }; ++ ++#endif +--- crash/xen_hyper_dump_tables.c.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/xen_hyper_dump_tables.c 2007-08-23 17:02:54.000000000 -0400 +@@ -0,0 +1,948 @@ ++/* ++ * xen_hyper_dump_tables.c ++ * ++ * Portions Copyright (C) 2006-2007 Fujitsu Limited ++ * Portions Copyright (C) 2006-2007 VA Linux Systems Japan K.K. ++ * ++ * Authors: Itsuro Oda ++ * Fumihiko Kakuma ++ * ++ * This file is part of Xencrash. ++ * ++ * Xencrash 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 (version 2 of the License). ++ * ++ * Xencrash 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with Xencrash; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include "defs.h" ++ ++#ifdef XEN_HYPERVISOR_ARCH ++#include "xen_hyper_defs.h" ++ ++static void xen_hyper_dump_xen_hyper_table(int verbose); ++static void xen_hyper_dump_xen_hyper_dumpinfo_table(int verbose); ++static void xen_hyper_dump_xen_hyper_domain_table(int verbose); ++static void xen_hyper_dump_xen_hyper_vcpu_table(int verbose); ++static void xen_hyper_dump_xen_hyper_pcpu_table(int verbose); ++static void xen_hyper_dump_xen_hyper_sched_table(int verbose); ++static void xen_hyper_dump_xen_hyper_size_table(char *spec, ulong makestruct); ++static void xen_hyper_dump_xen_hyper_offset_table(char *spec, ulong makestruct); ++ ++static void xen_hyper_dump_mem(void *mem, ulong len, int dsz); ++ ++/* ++ * Get help for a command, to dump an internal table, or the GNU public ++ * license copying/warranty information. ++ */ ++void ++xen_hyper_cmd_help(void) ++{ ++ int c; ++ int oflag; ++ ++ oflag = 0; ++ ++ while ((c = getopt(argcnt, args, ++ "aBbcDgHhM:mnOopszX:")) != EOF) { ++ switch(c) ++ { ++ case 'a': ++ dump_alias_data(); ++ return; ++ case 'b': ++ dump_shared_bufs(); ++ return; ++ case 'B': ++ dump_build_data(); ++ return; ++ case 'c': ++ dump_numargs_cache(); ++ return; ++ case 'n': ++ case 'D': ++ dumpfile_memory(DUMPFILE_MEM_DUMP); ++ return; ++ case 'g': ++ dump_gdb_data(); ++ return; ++ case 'H': ++ dump_hash_table(VERBOSE); ++ return; ++ case 'h': ++ dump_hash_table(!VERBOSE); ++ return; ++ case 'M': ++ dump_machdep_table(stol(optarg, FAULT_ON_ERROR, NULL)); ++ return; ++ case 'm': ++ dump_machdep_table(0); ++ return; ++ case 'O': ++ dump_offset_table(NULL, TRUE); ++ return; ++ case 'o': ++ oflag = TRUE; ++ break; ++ case 'p': ++ dump_program_context(); ++ return; ++ case 's': ++ dump_symbol_table(); ++ return; ++ case 'X': ++ if (strlen(optarg) != 3) { ++ argerrs++; ++ break; ++ } ++ if (!strncmp("Xen", optarg, strlen(optarg))) ++ xen_hyper_dump_xen_hyper_table(VERBOSE); ++ else if (!strncmp("xen", optarg, strlen(optarg))) ++ xen_hyper_dump_xen_hyper_table(!VERBOSE); ++ else if (!strncmp("Dmp", optarg, strlen(optarg))) ++ xen_hyper_dump_xen_hyper_dumpinfo_table(VERBOSE); ++ else if (!strncmp("dmp", optarg, strlen(optarg))) ++ xen_hyper_dump_xen_hyper_dumpinfo_table(!VERBOSE); ++ else if (!strncmp("Dom", optarg, strlen(optarg))) ++ xen_hyper_dump_xen_hyper_domain_table(VERBOSE); ++ else if (!strncmp("dom", optarg, strlen(optarg))) ++ xen_hyper_dump_xen_hyper_domain_table(!VERBOSE); ++ else if (!strncmp("Vcp", optarg, strlen(optarg))) ++ xen_hyper_dump_xen_hyper_vcpu_table(VERBOSE); ++ else if (!strncmp("vcp", optarg, strlen(optarg))) ++ xen_hyper_dump_xen_hyper_vcpu_table(!VERBOSE); ++ else if (!strncmp("Pcp", optarg, strlen(optarg))) ++ xen_hyper_dump_xen_hyper_pcpu_table(VERBOSE); ++ else if (!strncmp("pcp", optarg, strlen(optarg))) ++ xen_hyper_dump_xen_hyper_pcpu_table(!VERBOSE); ++ else if (!strncmp("Sch", optarg, strlen(optarg))) ++ xen_hyper_dump_xen_hyper_sched_table(VERBOSE); ++ else if (!strncmp("sch", optarg, strlen(optarg))) ++ xen_hyper_dump_xen_hyper_sched_table(!VERBOSE); ++ else if (!strncmp("siz", optarg, strlen(optarg))) ++ xen_hyper_dump_xen_hyper_size_table(NULL, TRUE); ++ else if (!strncmp("ofs", optarg, strlen(optarg))) ++ xen_hyper_dump_xen_hyper_offset_table(NULL, TRUE); ++ else { ++ argerrs++; ++ break; ++ } ++ return; ++ case 'z': ++ fprintf(fp, "help options:\n"); ++ fprintf(fp, " -a - alias data\n"); ++ fprintf(fp, " -b - shared buffer data\n"); ++ fprintf(fp, " -B - build data\n"); ++ fprintf(fp, " -c - numargs cache\n"); ++ fprintf(fp, " -M machine specific\n"); ++ fprintf(fp, " -m - machdep_table\n"); ++ fprintf(fp, " -s - symbol table data\n"); ++ fprintf(fp, " -o - offset_table and size_table\n"); ++ fprintf(fp, " -p - program_context\n"); ++ fprintf(fp, " -h - hash_table data\n"); ++ fprintf(fp, " -H - hash_table data (verbose)\n"); ++ fprintf(fp, " -X Xen - xen table data (verbose)\n"); ++ fprintf(fp, " -X xen - xen table data\n"); ++ fprintf(fp, " -X Dmp - dumpinfo table data (verbose)\n"); ++ fprintf(fp, " -X dmp - dumpinfo table data\n"); ++ fprintf(fp, " -X Dom - domain table data (verbose)\n"); ++ fprintf(fp, " -X dom - domain table data\n"); ++ fprintf(fp, " -X Vcp - vcpu table data (verbose)\n"); ++ fprintf(fp, " -X vcp - vcpu table data\n"); ++ fprintf(fp, " -X Pcp - pcpu table data (verbose)\n"); ++ fprintf(fp, " -X pcp - pcpu table data\n"); ++ fprintf(fp, " -X Sch - schedule table data (verbose)\n"); ++ fprintf(fp, " -X sch - schedule table data\n"); ++ fprintf(fp, " -X siz - size table data\n"); ++ fprintf(fp, " -X ofs - offset table data\n"); ++ return; ++ default: ++ argerrs++; ++ break; ++ } ++ } ++ ++ if (argerrs) ++ cmd_usage(pc->curcmd, COMPLETE_HELP); ++ ++ if (!args[optind]) { ++ if (oflag) ++ dump_offset_table(NULL, FALSE); ++ else ++ display_help_screen(""); ++ return; ++ } ++ ++ do { ++ if (oflag) ++ dump_offset_table(args[optind], FALSE); ++ else ++ cmd_usage(args[optind], COMPLETE_HELP); ++ optind++; ++ } while (args[optind]); ++} ++ ++/* ++ * "help -x xen" output ++ */ ++static void ++xen_hyper_dump_xen_hyper_table(int verbose) ++{ ++ char buf[XEN_HYPER_CMD_BUFSIZE]; ++ uint cpuid; ++ int len, flag, i; ++ ++ len = 14; ++ flag = XEN_HYPER_PRI_R; ++ ++ XEN_HYPER_PRI(fp, len, "cpu_data_address: ", buf, flag, ++ (buf, "%lu\n", xht->cpu_data_address)); ++ XEN_HYPER_PRI(fp, len, "cpu_curr: ", buf, flag, ++ (buf, "%u\n", xht->cpu_curr)); ++ XEN_HYPER_PRI(fp, len, "max_cpus: ", buf, flag, ++ (buf, "%u\n", xht->max_cpus)); ++ XEN_HYPER_PRI(fp, len, "cores: ", buf, flag, ++ (buf, "%d\n", xht->cores)); ++ XEN_HYPER_PRI(fp, len, "pcpus: ", buf, flag, ++ (buf, "%d\n", xht->pcpus)); ++ XEN_HYPER_PRI(fp, len, "vcpus: ", buf, flag, ++ (buf, "%d\n", xht->vcpus)); ++ XEN_HYPER_PRI(fp, len, "domains: ", buf, flag, ++ (buf, "%d\n", xht->domains)); ++ XEN_HYPER_PRI(fp, len, "sys_pages: ", buf, flag, ++ (buf, "%lu\n", xht->sys_pages)); ++ XEN_HYPER_PRI(fp, len, "crashing_cpu: ", buf, flag, ++ (buf, "%d\n", xht->crashing_cpu)); ++ XEN_HYPER_PRI(fp, len, "crashing_vcc: ", buf, flag, ++ (buf, "%p\n", xht->crashing_vcc)); ++ XEN_HYPER_PRI(fp, len, "max_page: ", buf, flag, ++ (buf, "%lu\n", xht->max_page)); ++ XEN_HYPER_PRI(fp, len, "total_pages: ", buf, flag, ++ (buf, "%lu\n", xht->total_pages)); ++ XEN_HYPER_PRI(fp, len, "cpumask: ", buf, flag, ++ (buf, "%p\n", xht->cpumask)); ++ if (verbose && xht->cpumask) { ++ xen_hyper_dump_mem(xht->cpumask, ++ XEN_HYPER_SIZE(cpumask_t), sizeof(long)); ++ } ++ XEN_HYPER_PRI(fp, len, "cpu_idxs: ", buf, flag, ++ (buf, "%p\n", xht->cpu_idxs)); ++ if (verbose) { ++ for_cpu_indexes(i, cpuid) ++ fprintf(fp, "%03d : %d\n", i, cpuid); ++ } ++} ++ ++/* ++ * "help -x dmp" output ++ */ ++static void ++xen_hyper_dump_xen_hyper_dumpinfo_table(int verbose) ++{ ++ char buf[XEN_HYPER_CMD_BUFSIZE]; ++ int len, flag; ++ ++ len = 25; ++ flag = XEN_HYPER_PRI_R; ++ ++ XEN_HYPER_PRI(fp, len, "note_ver: ", buf, flag, ++ (buf, "%u\n", xhdit->note_ver)); ++ XEN_HYPER_PRI(fp, len, "context_array: ", buf, flag, ++ (buf, "%p\n", xhdit->context_array)); ++ if (verbose && xhdit->context_array) { ++ xen_hyper_dump_mem((long *)xhdit->context_array, ++ sizeof(struct xen_hyper_dumpinfo_context) * ++ XEN_HYPER_MAX_CPUS(), sizeof(long)); ++ } ++ XEN_HYPER_PRI(fp, len, "context_xen_core_array: ", buf, flag, ++ (buf, "%p\n", xhdit->context_xen_core_array)); ++ if (verbose && xhdit->context_xen_core_array) { ++ xen_hyper_dump_mem((long *)xhdit->context_xen_core_array, ++ sizeof(struct xen_hyper_dumpinfo_context_xen_core) * ++ XEN_HYPER_MAX_CPUS(), sizeof(long)); ++ } ++ XEN_HYPER_PRI_CONST(fp, len, "context_xen_info: ", flag|XEN_HYPER_PRI_LF); ++ XEN_HYPER_PRI(fp, len, "note: ", buf, flag, ++ (buf, "%lx\n", xhdit->context_xen_info.note)); ++ XEN_HYPER_PRI(fp, len, "pcpu_id: ", buf, flag, ++ (buf, "%u\n", xhdit->context_xen_info.pcpu_id)); ++ XEN_HYPER_PRI(fp, len, "crash_xen_info_ptr: ", buf, flag, ++ (buf, "%p\n", xhdit->context_xen_info.crash_xen_info_ptr)); ++ XEN_HYPER_PRI(fp, len, "crash_note_core_array: ", buf, flag, ++ (buf, "%p\n", xhdit->crash_note_core_array)); ++ if (verbose && xhdit->crash_note_core_array) { ++ xen_hyper_dump_mem((long *)xhdit->crash_note_core_array, ++ xhdit->core_size * XEN_HYPER_NR_PCPUS(), ++ sizeof(long)); ++ } ++ XEN_HYPER_PRI(fp, len, "crash_note_xen_core_array: ", buf, flag, ++ (buf, "%p\n", xhdit->crash_note_xen_core_array)); ++ if (verbose && xhdit->crash_note_xen_core_array) { ++ xen_hyper_dump_mem( ++ xhdit->crash_note_xen_core_array, ++ xhdit->xen_core_size * XEN_HYPER_NR_PCPUS(), ++ sizeof(long)); ++ } ++ XEN_HYPER_PRI(fp, len, "crash_note_xen_info_ptr: ", buf, flag, ++ (buf, "%p\n", xhdit->crash_note_xen_info_ptr)); ++ if (verbose && xhdit->crash_note_xen_info_ptr) { ++ xen_hyper_dump_mem( ++ xhdit->crash_note_xen_info_ptr, ++ xhdit->xen_info_size, sizeof(long)); ++ } ++ XEN_HYPER_PRI(fp, len, "xen_info_cpu: ", buf, flag, ++ (buf, "%u\n", xhdit->xen_info_cpu)); ++ XEN_HYPER_PRI(fp, len, "note_size: ", buf, flag, ++ (buf, "%u\n", xhdit->note_size)); ++ XEN_HYPER_PRI(fp, len, "core_offset: ", buf, flag, ++ (buf, "%u\n", xhdit->core_offset)); ++ XEN_HYPER_PRI(fp, len, "core_size: ", buf, flag, ++ (buf, "%u\n", xhdit->core_size)); ++ XEN_HYPER_PRI(fp, len, "xen_core_offset: ", buf, flag, ++ (buf, "%u\n", xhdit->xen_core_offset)); ++ XEN_HYPER_PRI(fp, len, "xen_core_size: ", buf, flag, ++ (buf, "%u\n", xhdit->xen_core_size)); ++ XEN_HYPER_PRI(fp, len, "xen_info_offset: ", buf, flag, ++ (buf, "%u\n", xhdit->xen_info_offset)); ++ XEN_HYPER_PRI(fp, len, "xen_info_size: ", buf, flag, ++ (buf, "%u\n", xhdit->xen_info_size)); ++} ++ ++/* ++ * "help -x dom" output ++ */ ++static void ++xen_hyper_dump_xen_hyper_domain_table(int verbose) ++{ ++ char buf[XEN_HYPER_CMD_BUFSIZE]; ++ struct xen_hyper_domain_context *dcca; ++ int len, flag, i; ++ ++ len = 22; ++ flag = XEN_HYPER_PRI_R; ++ ++ XEN_HYPER_PRI(fp, len, "context_array: ", buf, flag, ++ (buf, "%p\n", xhdt->context_array)); ++ if (verbose) { ++ char buf1[XEN_HYPER_CMD_BUFSIZE]; ++ int j; ++ for (i = 0, dcca = xhdt->context_array; ++ i < xhdt->context_array_cnt; i++, dcca++) { ++ snprintf(buf, XEN_HYPER_CMD_BUFSIZE, "context_array[%d]: ", i); ++ XEN_HYPER_PRI_CONST(fp, len, buf, flag|XEN_HYPER_PRI_LF); ++ XEN_HYPER_PRI(fp, len, "domain: ", buf, flag, ++ (buf, "%lx\n", dcca->domain)); ++ XEN_HYPER_PRI(fp, len, "domain_id: ", buf, flag, ++ (buf, "%d\n", dcca->domain_id)); ++ XEN_HYPER_PRI(fp, len, "tot_pages: ", buf, flag, ++ (buf, "%x\n", dcca->tot_pages)); ++ XEN_HYPER_PRI(fp, len, "max_pages: ", buf, flag, ++ (buf, "%x\n", dcca->max_pages)); ++ XEN_HYPER_PRI(fp, len, "xenheap_pages: ", buf, flag, ++ (buf, "%x\n", dcca->xenheap_pages)); ++ XEN_HYPER_PRI(fp, len, "shared_info: ", buf, flag, ++ (buf, "%lx\n", dcca->shared_info)); ++ XEN_HYPER_PRI(fp, len, "sched_priv: ", buf, flag, ++ (buf, "%lx\n", dcca->sched_priv)); ++ XEN_HYPER_PRI(fp, len, "next_in_list: ", buf, flag, ++ (buf, "%lx\n", dcca->next_in_list)); ++ XEN_HYPER_PRI(fp, len, "domain_flags: ", buf, flag, ++ (buf, "%lx\n", dcca->domain_flags)); ++ XEN_HYPER_PRI(fp, len, "evtchn: ", buf, flag, ++ (buf, "%lx\n", dcca->evtchn)); ++ XEN_HYPER_PRI(fp, len, "vcpu_cnt: ", buf, flag, ++ (buf, "%d\n", dcca->vcpu_cnt)); ++ for (j = 0; j < XEN_HYPER_MAX_VIRT_CPUS; j++) { ++ snprintf(buf1, XEN_HYPER_CMD_BUFSIZE, "vcpu[%d]: ", j); ++ XEN_HYPER_PRI(fp, len, buf1, buf, flag, ++ (buf, "%lx\n", dcca->vcpu[j])); ++ } ++ XEN_HYPER_PRI(fp, len, "vcpu_context_array: ", buf, flag, ++ (buf, "%p\n", dcca->vcpu_context_array)); ++ } ++ } ++ XEN_HYPER_PRI(fp, len, "context_array_cnt: ", buf, flag, ++ (buf, "%d\n", xhdt->context_array_cnt)); ++ XEN_HYPER_PRI(fp, len, "running_domains: ", buf, flag, ++ (buf, "%lu\n", xhdt->running_domains)); ++ XEN_HYPER_PRI(fp, len, "dom_io: ", buf, flag, ++ (buf, "%p\n", xhdt->dom_io)); ++ XEN_HYPER_PRI(fp, len, "dom_xen: ", buf, flag, ++ (buf, "%p\n", xhdt->dom_xen)); ++ XEN_HYPER_PRI(fp, len, "dom0: ", buf, flag, ++ (buf, "%p\n", xhdt->dom0)); ++ XEN_HYPER_PRI(fp, len, "idle_domain: ", buf, flag, ++ (buf, "%p\n", xhdt->idle_domain)); ++ XEN_HYPER_PRI(fp, len, "curr_domain: ", buf, flag, ++ (buf, "%p\n", xhdt->curr_domain)); ++ XEN_HYPER_PRI(fp, len, "last: ", buf, flag, ++ (buf, "%p\n", xhdt->last)); ++ XEN_HYPER_PRI(fp, len, "domain_struct: ", buf, flag, ++ (buf, "%p\n", xhdt->domain_struct)); ++ XEN_HYPER_PRI(fp, len, "domain_struct_verify: ", buf, flag, ++ (buf, "%p\n", xhdt->domain_struct_verify)); ++} ++ ++/* ++ * "help -x vcp" output ++ */ ++static void ++xen_hyper_dump_xen_hyper_vcpu_table(int verbose) ++{ ++ char buf[XEN_HYPER_CMD_BUFSIZE]; ++ int len, flag; ++ ++ len = 25; ++ flag = XEN_HYPER_PRI_R; ++ ++ XEN_HYPER_PRI(fp, len, "vcpu_context_arrays: ", buf, flag, ++ (buf, "%p\n", xhvct->vcpu_context_arrays)); ++ XEN_HYPER_PRI(fp, len, "vcpu_context_arrays_cnt: ", buf, flag, ++ (buf, "%d\n", xhvct->vcpu_context_arrays_cnt)); ++ if (verbose) { ++ struct xen_hyper_vcpu_context_array *vcca; ++ struct xen_hyper_vcpu_context *vca; ++ int i, j; ++ ++ for (i = 0, vcca = xhvct->vcpu_context_arrays; ++ i < xhvct->vcpu_context_arrays_cnt; i++, vcca++) { ++ snprintf(buf, XEN_HYPER_CMD_BUFSIZE, "vcpu_context_arrays[%d]: ", i); ++ XEN_HYPER_PRI_CONST(fp, len, buf, flag|XEN_HYPER_PRI_LF); ++ if (vcca->context_array) { ++ XEN_HYPER_PRI(fp, len, "context_array: ", buf, flag, ++ (buf, "%p\n", vcca->context_array)); ++ } else { ++ XEN_HYPER_PRI(fp, len, "context_array: ", buf, flag, ++ (buf, "NULL\n")); ++ } ++ XEN_HYPER_PRI(fp, len, "context_array_cnt: ", buf, flag, ++ (buf, "%d\n", vcca->context_array_cnt)); ++ XEN_HYPER_PRI(fp, len, "context_array_valid: ", buf, flag, ++ (buf, "%d\n", vcca->context_array_valid)); ++ for (j = 0, vca = vcca->context_array; ++ j < vcca->context_array_cnt; j++, vca++) { ++ snprintf(buf, XEN_HYPER_CMD_BUFSIZE, "context_array[%d]: ", j); ++ XEN_HYPER_PRI_CONST(fp, len, buf, flag|XEN_HYPER_PRI_LF); ++ XEN_HYPER_PRI(fp, len, "vcpu: ", buf, flag, ++ (buf, "%lx\n", vca->vcpu)); ++ XEN_HYPER_PRI(fp, len, "vcpu_id: ", buf, flag, ++ (buf, "%d\n", vca->vcpu_id)); ++ XEN_HYPER_PRI(fp, len, "processor: ", buf, flag, ++ (buf, "%d\n", vca->processor)); ++ XEN_HYPER_PRI(fp, len, "vcpu_info: ", buf, flag, ++ (buf, "%lx\n", vca->vcpu_info)); ++ XEN_HYPER_PRI(fp, len, "domain: ", buf, flag, ++ (buf, "%lx\n", vca->domain)); ++ XEN_HYPER_PRI(fp, len, "next_in_list: ", buf, flag, ++ (buf, "%lx\n", vca->next_in_list)); ++ XEN_HYPER_PRI(fp, len, "sleep_tick: ", buf, flag, ++ (buf, "%lx\n", vca->sleep_tick)); ++ XEN_HYPER_PRI(fp, len, "sched_priv: ", buf, flag, ++ (buf, "%lx\n", vca->sched_priv)); ++ XEN_HYPER_PRI(fp, len, "state: ", buf, flag, ++ (buf, "%d\n", vca->state)); ++ XEN_HYPER_PRI(fp, len, "state_entry_time: ", buf, flag, ++ (buf, "%llux\n", (unsigned long long)(vca->state_entry_time))); ++ XEN_HYPER_PRI(fp, len, "runstate_guest: ", buf, flag, ++ (buf, "%lx\n", vca->runstate_guest)); ++ XEN_HYPER_PRI(fp, len, "vcpu_flags: ", buf, flag, ++ (buf, "%lx\n", vca->vcpu_flags)); ++ } ++ } ++ } ++ XEN_HYPER_PRI(fp, len, "idle_vcpu: ", buf, flag, ++ (buf, "%lx\n", xhvct->idle_vcpu)); ++ XEN_HYPER_PRI(fp, len, "idle_vcpu_context_array: ", buf, flag, ++ (buf, "%p\n", xhvct->idle_vcpu_context_array)); ++ XEN_HYPER_PRI(fp, len, "last: ", buf, flag, ++ (buf, "%p\n", xhvct->last)); ++ XEN_HYPER_PRI(fp, len, "vcpu_struct: ", buf, flag, ++ (buf, "%p\n", xhvct->vcpu_struct)); ++ XEN_HYPER_PRI(fp, len, "vcpu_struct_verify: ", buf, flag, ++ (buf, "%p\n", xhvct->vcpu_struct_verify)); ++} ++ ++/* ++ * "help -x pcp" output ++ */ ++static void ++xen_hyper_dump_xen_hyper_pcpu_table(int verbose) ++{ ++ char buf[XEN_HYPER_CMD_BUFSIZE]; ++ struct xen_hyper_pcpu_context *pcca; ++ int len, flag, i; ++#ifdef X86_64 ++ uint64_t *ist_p; ++ int j; ++#endif ++ ++ len = 21; ++ flag = XEN_HYPER_PRI_R; ++ ++ XEN_HYPER_PRI(fp, len, "context_array: ", buf, flag, ++ (buf, "%p\n", xhpct->context_array)); ++ if (verbose) { ++ for (i = 0, pcca = xhpct->context_array; ++ i < XEN_HYPER_MAX_CPUS(); i++, pcca++) { ++ snprintf(buf, XEN_HYPER_CMD_BUFSIZE, "context_array %d: ", i); ++ XEN_HYPER_PRI_CONST(fp, len, buf, flag|XEN_HYPER_PRI_LF); ++ XEN_HYPER_PRI(fp, len, "pcpu: ", buf, flag, ++ (buf, "%lx\n", pcca->pcpu)); ++ XEN_HYPER_PRI(fp, len, "processor_id: ", buf, flag, ++ (buf, "%u\n", pcca->processor_id)); ++ XEN_HYPER_PRI(fp, len, "guest_cpu_user_regs: ", buf, flag, ++ (buf, "%lx\n", pcca->guest_cpu_user_regs)); ++ XEN_HYPER_PRI(fp, len, "current_vcpu: ", buf, flag, ++ (buf, "%lx\n", pcca->current_vcpu)); ++ XEN_HYPER_PRI(fp, len, "init_tss: ", buf, flag, ++ (buf, "%lx\n", pcca->init_tss)); ++#ifdef X86 ++ XEN_HYPER_PRI(fp, len, "sp.esp0: ", buf, flag, ++ (buf, "%x\n", pcca->sp.esp0)); ++#endif ++#ifdef X86_64 ++ XEN_HYPER_PRI(fp, len, "sp.rsp0: ", buf, flag, ++ (buf, "%lx\n", pcca->sp.rsp0)); ++ for (j = 0, ist_p = pcca->ist; ++ j < XEN_HYPER_TSS_IST_MAX; j++, ist_p++) { ++ XEN_HYPER_PRI(fp, len, "ist: ", buf, flag, ++ (buf, "%lx\n", *ist_p)); ++ } ++#endif ++ } ++ } ++ XEN_HYPER_PRI(fp, len, "last: ", buf, flag, ++ (buf, "%p\n", xhpct->last)); ++ XEN_HYPER_PRI(fp, len, "pcpu_struct: ", buf, flag, ++ (buf, "%p\n", xhpct->pcpu_struct)); ++} ++ ++/* ++ * "help -x sch" output ++ */ ++static void ++xen_hyper_dump_xen_hyper_sched_table(int verbose) ++{ ++ struct xen_hyper_sched_context *schc; ++ char buf[XEN_HYPER_CMD_BUFSIZE]; ++ int len, flag, i; ++ ++ len = 21; ++ flag = XEN_HYPER_PRI_R; ++ ++ XEN_HYPER_PRI(fp, len, "name: ", buf, flag, ++ (buf, "%s\n", xhscht->name)); ++ XEN_HYPER_PRI(fp, len, "opt_sched: ", buf, flag, ++ (buf, "%s\n", xhscht->opt_sched)); ++ XEN_HYPER_PRI(fp, len, "sched_id: ", buf, flag, ++ (buf, "%d\n", xhscht->sched_id)); ++ XEN_HYPER_PRI(fp, len, "scheduler: ", buf, flag, ++ (buf, "%lx\n", xhscht->scheduler)); ++ XEN_HYPER_PRI(fp, len, "scheduler_struct: ", buf, flag, ++ (buf, "%p\n", xhscht->scheduler_struct)); ++ XEN_HYPER_PRI(fp, len, "sched_context_array: ", buf, flag, ++ (buf, "%p\n", xhscht->sched_context_array)); ++ if (verbose) { ++ for (i = 0, schc = xhscht->sched_context_array; ++ i < xht->pcpus; i++, schc++) { ++ XEN_HYPER_PRI(fp, len, "sched_context_array[", buf, ++ flag, (buf, "%d]\n", i)); ++ XEN_HYPER_PRI(fp, len, "schedule_data: ", buf, flag, ++ (buf, "%lx\n", schc->schedule_data)); ++ XEN_HYPER_PRI(fp, len, "curr: ", buf, flag, ++ (buf, "%lx\n", schc->curr)); ++ XEN_HYPER_PRI(fp, len, "idle: ", buf, flag, ++ (buf, "%lx\n", schc->idle)); ++ XEN_HYPER_PRI(fp, len, "sched_priv: ", buf, flag, ++ (buf, "%lx\n", schc->sched_priv)); ++ XEN_HYPER_PRI(fp, len, "tick: ", buf, flag, ++ (buf, "%lx\n", schc->tick)); ++ } ++ } ++} ++ ++/* ++ * "help -x siz" output ++ */ ++static void ++xen_hyper_dump_xen_hyper_size_table(char *spec, ulong makestruct) ++{ ++ char buf[XEN_HYPER_CMD_BUFSIZE]; ++ int len, flag; ++ ++ len = 23; ++ flag = XEN_HYPER_PRI_R; ++ ++ XEN_HYPER_PRI(fp, len, "ELF_Prstatus: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.ELF_Prstatus)); ++ XEN_HYPER_PRI(fp, len, "ELF_Signifo: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.ELF_Signifo)); ++ XEN_HYPER_PRI(fp, len, "ELF_Gregset: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.ELF_Gregset)); ++ XEN_HYPER_PRI(fp, len, "ELF_Timeval: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.ELF_Timeval)); ++ XEN_HYPER_PRI(fp, len, "arch_domain: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.arch_domain)); ++ XEN_HYPER_PRI(fp, len, "arch_shared_info: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.arch_shared_info)); ++ XEN_HYPER_PRI(fp, len, "cpu_info: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.cpu_info)); ++ XEN_HYPER_PRI(fp, len, "cpu_time: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.cpu_time)); ++ XEN_HYPER_PRI(fp, len, "cpu_user_regs: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.cpu_user_regs)); ++ XEN_HYPER_PRI(fp, len, "cpumask_t: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.cpumask_t)); ++ XEN_HYPER_PRI(fp, len, "cpuinfo_ia64: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.cpuinfo_ia64)); ++ XEN_HYPER_PRI(fp, len, "cpuinfo_x86: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.cpuinfo_x86)); ++ XEN_HYPER_PRI(fp, len, "crash_note_t: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.crash_note_t)); ++ XEN_HYPER_PRI(fp, len, "crash_note_core_t: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.crash_note_core_t)); ++ XEN_HYPER_PRI(fp, len, "crash_note_xen_t: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.crash_note_xen_t)); ++ XEN_HYPER_PRI(fp, len, "crash_note_xen_core_t: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.crash_note_xen_core_t)); ++ XEN_HYPER_PRI(fp, len, "crash_note_xen_info_t: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.crash_note_xen_info_t)); ++ XEN_HYPER_PRI(fp, len, "crash_xen_core_t: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.crash_xen_core_t)); ++ XEN_HYPER_PRI(fp, len, "crash_xen_info_t: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.crash_xen_info_t)); ++ XEN_HYPER_PRI(fp, len, "domain: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.domain)); ++#ifdef IA64 ++ XEN_HYPER_PRI(fp, len, "mm_struct: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.mm_struct)); ++#endif ++ XEN_HYPER_PRI(fp, len, "note_buf_t: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.note_buf_t)); ++ XEN_HYPER_PRI(fp, len, "schedule_data: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.schedule_data)); ++ XEN_HYPER_PRI(fp, len, "scheduler: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.scheduler)); ++ XEN_HYPER_PRI(fp, len, "shared_info: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.shared_info)); ++ XEN_HYPER_PRI(fp, len, "timer: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.timer)); ++ XEN_HYPER_PRI(fp, len, "tss_struct: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.tss_struct)); ++ XEN_HYPER_PRI(fp, len, "vcpu: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.vcpu)); ++ XEN_HYPER_PRI(fp, len, "vcpu_runstate_info: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.vcpu_runstate_info)); ++ XEN_HYPER_PRI(fp, len, "xen_crash_xen_regs_t: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_size_table.xen_crash_xen_regs_t)); ++} ++ ++/* ++ * "help -x ofs" output ++ */ ++static void ++xen_hyper_dump_xen_hyper_offset_table(char *spec, ulong makestruct) ++{ ++ char buf[XEN_HYPER_CMD_BUFSIZE]; ++ int len, flag; ++ ++ len = 45; ++ flag = XEN_HYPER_PRI_R; ++ ++ XEN_HYPER_PRI(fp, len, "ELF_Prstatus_pr_info: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.ELF_Prstatus_pr_info)); ++ XEN_HYPER_PRI(fp, len, "ELF_Prstatus_pr_cursig: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.ELF_Prstatus_pr_cursig)); ++ XEN_HYPER_PRI(fp, len, "ELF_Prstatus_pr_sigpend: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.ELF_Prstatus_pr_sigpend)); ++ XEN_HYPER_PRI(fp, len, "ELF_Prstatus_pr_sighold: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.ELF_Prstatus_pr_sighold)); ++ XEN_HYPER_PRI(fp, len, "ELF_Prstatus_pr_pid: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.ELF_Prstatus_pr_pid)); ++ XEN_HYPER_PRI(fp, len, "ELF_Prstatus_pr_ppid: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.ELF_Prstatus_pr_ppid)); ++ XEN_HYPER_PRI(fp, len, "ELF_Prstatus_pr_pgrp: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.ELF_Prstatus_pr_pgrp)); ++ XEN_HYPER_PRI(fp, len, "ELF_Prstatus_pr_sid: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.ELF_Prstatus_pr_sid)); ++ XEN_HYPER_PRI(fp, len, "ELF_Prstatus_pr_stime: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.ELF_Prstatus_pr_stime)); ++ XEN_HYPER_PRI(fp, len, "ELF_Prstatus_pr_cutime: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.ELF_Prstatus_pr_cutime)); ++ XEN_HYPER_PRI(fp, len, "ELF_Prstatus_pr_cstime: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.ELF_Prstatus_pr_cstime)); ++ XEN_HYPER_PRI(fp, len, "ELF_Prstatus_pr_reg: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.ELF_Prstatus_pr_reg)); ++ XEN_HYPER_PRI(fp, len, "ELF_Prstatus_pr_fpvalid: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.ELF_Prstatus_pr_fpvalid)); ++ XEN_HYPER_PRI(fp, len, "ELF_Timeval_tv_sec: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.ELF_Timeval_tv_sec)); ++ XEN_HYPER_PRI(fp, len, "ELF_Timeval_tv_usec: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.ELF_Timeval_tv_usec)); ++ ++#ifdef IA64 ++ XEN_HYPER_PRI(fp, len, "arch_domain_mm: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.arch_domain_mm)); ++#endif ++ ++ XEN_HYPER_PRI(fp, len, "arch_shared_info_max_pfn: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.arch_shared_info_max_pfn)); ++ XEN_HYPER_PRI(fp, len, "arch_shared_info_pfn_to_mfn_frame_list_list: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.arch_shared_info_pfn_to_mfn_frame_list_list)); ++ XEN_HYPER_PRI(fp, len, "arch_shared_info_nmi_reason: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.arch_shared_info_nmi_reason)); ++ ++ XEN_HYPER_PRI(fp, len, "cpu_info_guest_cpu_user_regs: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.cpu_info_guest_cpu_user_regs)); ++ XEN_HYPER_PRI(fp, len, "cpu_info_processor_id: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.cpu_info_processor_id)); ++ XEN_HYPER_PRI(fp, len, "cpu_info_current_vcpu: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.cpu_info_current_vcpu)); ++ ++ XEN_HYPER_PRI(fp, len, "cpu_time_local_tsc_stamp: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.cpu_time_local_tsc_stamp)); ++ XEN_HYPER_PRI(fp, len, "cpu_time_stime_local_stamp: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.cpu_time_stime_local_stamp)); ++ XEN_HYPER_PRI(fp, len, "cpu_time_stime_master_stamp: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.cpu_time_stime_master_stamp)); ++ XEN_HYPER_PRI(fp, len, "cpu_time_tsc_scale: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.cpu_time_tsc_scale)); ++ XEN_HYPER_PRI(fp, len, "cpu_time_calibration_timer: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.cpu_time_calibration_timer)); ++ ++ XEN_HYPER_PRI(fp, len, "crash_note_t_core: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.crash_note_t_core)); ++ XEN_HYPER_PRI(fp, len, "crash_note_t_xen: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.crash_note_t_xen)); ++ XEN_HYPER_PRI(fp, len, "crash_note_t_xen_regs: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.crash_note_t_xen_regs)); ++ XEN_HYPER_PRI(fp, len, "crash_note_t_xen_info: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.crash_note_t_xen_info)); ++ ++ XEN_HYPER_PRI(fp, len, "crash_note_core_t_note: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.crash_note_core_t_note)); ++ XEN_HYPER_PRI(fp, len, "crash_note_core_t_desc: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.crash_note_core_t_desc)); ++ ++ XEN_HYPER_PRI(fp, len, "crash_note_xen_t_note: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.crash_note_xen_t_note)); ++ XEN_HYPER_PRI(fp, len, "crash_note_xen_t_desc: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.crash_note_xen_t_desc)); ++ ++ XEN_HYPER_PRI(fp, len, "crash_note_xen_core_t_note: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.crash_note_xen_core_t_note)); ++ XEN_HYPER_PRI(fp, len, "crash_note_xen_core_t_desc: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.crash_note_xen_core_t_desc)); ++ ++ XEN_HYPER_PRI(fp, len, "crash_note_xen_info_t_note: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.crash_note_xen_info_t_note)); ++ XEN_HYPER_PRI(fp, len, "crash_note_xen_info_t_desc: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.crash_note_xen_info_t_desc)); ++ ++ XEN_HYPER_PRI(fp, len, "domain_page_list: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_page_list)); ++ XEN_HYPER_PRI(fp, len, "domain_xenpage_list: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_xenpage_list)); ++ XEN_HYPER_PRI(fp, len, "domain_domain_id: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_domain_id)); ++ XEN_HYPER_PRI(fp, len, "domain_tot_pages: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_tot_pages)); ++ XEN_HYPER_PRI(fp, len, "domain_max_pages: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_max_pages)); ++ XEN_HYPER_PRI(fp, len, "domain_xenheap_pages: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_xenheap_pages)); ++ XEN_HYPER_PRI(fp, len, "domain_shared_info: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_shared_info)); ++ XEN_HYPER_PRI(fp, len, "domain_sched_priv: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_sched_priv)); ++ XEN_HYPER_PRI(fp, len, "domain_next_in_list: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_next_in_list)); ++ XEN_HYPER_PRI(fp, len, "domain_domain_flags: ", buf, flag, ++ (buf, "%lx\n", xen_hyper_offset_table.domain_domain_flags)); ++ XEN_HYPER_PRI(fp, len, "domain_evtchn: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_evtchn)); ++ XEN_HYPER_PRI(fp, len, "domain_is_hvm: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_is_hvm)); ++ XEN_HYPER_PRI(fp, len, "domain_is_privileged: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_is_privileged)); ++ XEN_HYPER_PRI(fp, len, "domain_debugger_attached: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_debugger_attached)); ++ XEN_HYPER_PRI(fp, len, "domain_is_polling: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_is_polling)); ++ XEN_HYPER_PRI(fp, len, "domain_is_dying: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_is_dying)); ++ XEN_HYPER_PRI(fp, len, "domain_is_paused_by_controller: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_is_paused_by_controller)); ++ XEN_HYPER_PRI(fp, len, "domain_is_shutting_down: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_is_shutting_down)); ++ XEN_HYPER_PRI(fp, len, "domain_is_shut_down: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_is_shut_down)); ++ XEN_HYPER_PRI(fp, len, "domain_vcpu: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_vcpu)); ++ XEN_HYPER_PRI(fp, len, "domain_arch: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.domain_arch)); ++ ++#ifdef IA64 ++ XEN_HYPER_PRI(fp, len, "mm_struct_pgd: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.mm_struct_pgd)); ++#endif ++ ++ XEN_HYPER_PRI(fp, len, "schedule_data_schedule_lock: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.schedule_data_schedule_lock)); ++ XEN_HYPER_PRI(fp, len, "schedule_data_curr: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.schedule_data_curr)); ++ XEN_HYPER_PRI(fp, len, "schedule_data_idle: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.schedule_data_idle)); ++ XEN_HYPER_PRI(fp, len, "schedule_data_sched_priv: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.schedule_data_sched_priv)); ++ XEN_HYPER_PRI(fp, len, "schedule_data_s_timer: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.schedule_data_s_timer)); ++ XEN_HYPER_PRI(fp, len, "schedule_data_tick: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.schedule_data_tick)); ++ ++ XEN_HYPER_PRI(fp, len, "scheduler_name: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.scheduler_name)); ++ XEN_HYPER_PRI(fp, len, "scheduler_opt_name: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.scheduler_opt_name)); ++ XEN_HYPER_PRI(fp, len, "scheduler_sched_id: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.scheduler_sched_id)); ++ XEN_HYPER_PRI(fp, len, "scheduler_init: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.scheduler_init)); ++ XEN_HYPER_PRI(fp, len, "scheduler_tick: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.scheduler_tick)); ++ XEN_HYPER_PRI(fp, len, "scheduler_init_vcpu: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.scheduler_init_vcpu)); ++ XEN_HYPER_PRI(fp, len, "scheduler_destroy_domain: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.scheduler_destroy_domain)); ++ XEN_HYPER_PRI(fp, len, "scheduler_sleep: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.scheduler_sleep)); ++ XEN_HYPER_PRI(fp, len, "scheduler_wake: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.scheduler_wake)); ++ XEN_HYPER_PRI(fp, len, "scheduler_set_affinity: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.scheduler_set_affinity)); ++ XEN_HYPER_PRI(fp, len, "scheduler_do_schedule: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.scheduler_do_schedule)); ++ XEN_HYPER_PRI(fp, len, "scheduler_adjust: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.scheduler_adjust)); ++ XEN_HYPER_PRI(fp, len, "scheduler_dump_settings: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.scheduler_dump_settings)); ++ XEN_HYPER_PRI(fp, len, "scheduler_dump_cpu_state: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.scheduler_dump_cpu_state)); ++ ++ XEN_HYPER_PRI(fp, len, "shared_info_vcpu_info: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.shared_info_vcpu_info)); ++ XEN_HYPER_PRI(fp, len, "shared_info_evtchn_pending: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.shared_info_evtchn_pending)); ++ XEN_HYPER_PRI(fp, len, "shared_info_evtchn_mask: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.shared_info_evtchn_mask)); ++ XEN_HYPER_PRI(fp, len, "shared_info_arch: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.shared_info_arch)); ++ ++ XEN_HYPER_PRI(fp, len, "timer_expires: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.timer_expires)); ++ XEN_HYPER_PRI(fp, len, "timer_cpu: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.timer_cpu)); ++ XEN_HYPER_PRI(fp, len, "timer_function: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.timer_function)); ++ XEN_HYPER_PRI(fp, len, "timer_data: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.timer_data)); ++ XEN_HYPER_PRI(fp, len, "timer_heap_offset: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.timer_heap_offset)); ++ XEN_HYPER_PRI(fp, len, "timer_killed: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.timer_killed)); ++ ++ XEN_HYPER_PRI(fp, len, "tss_struct_rsp0: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.tss_struct_rsp0)); ++ XEN_HYPER_PRI(fp, len, "tss_struct_esp0: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.tss_struct_esp0)); ++ ++ XEN_HYPER_PRI(fp, len, "vcpu_vcpu_id: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_vcpu_id)); ++ XEN_HYPER_PRI(fp, len, "vcpu_processor: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_processor)); ++ XEN_HYPER_PRI(fp, len, "vcpu_vcpu_info: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_vcpu_info)); ++ XEN_HYPER_PRI(fp, len, "vcpu_domain: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_domain)); ++ XEN_HYPER_PRI(fp, len, "vcpu_next_in_list: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_next_in_list)); ++ XEN_HYPER_PRI(fp, len, "vcpu_timer: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_timer)); ++ XEN_HYPER_PRI(fp, len, "vcpu_sleep_tick: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_sleep_tick)); ++ XEN_HYPER_PRI(fp, len, "vcpu_poll_timer: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_poll_timer)); ++ XEN_HYPER_PRI(fp, len, "vcpu_sched_priv: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_sched_priv)); ++ XEN_HYPER_PRI(fp, len, "vcpu_runstate: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_runstate)); ++ XEN_HYPER_PRI(fp, len, "vcpu_runstate_guest: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_runstate_guest)); ++ XEN_HYPER_PRI(fp, len, "vcpu_vcpu_flags: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_vcpu_flags)); ++ XEN_HYPER_PRI(fp, len, "vcpu_pause_count: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_pause_count)); ++ XEN_HYPER_PRI(fp, len, "vcpu_virq_to_evtchn: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_virq_to_evtchn)); ++ XEN_HYPER_PRI(fp, len, "vcpu_cpu_affinity: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_cpu_affinity)); ++ XEN_HYPER_PRI(fp, len, "vcpu_nmi_addr: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_nmi_addr)); ++ XEN_HYPER_PRI(fp, len, "vcpu_vcpu_dirty_cpumask: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_vcpu_dirty_cpumask)); ++ XEN_HYPER_PRI(fp, len, "vcpu_arch: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_arch)); ++ XEN_HYPER_PRI(fp, len, "vcpu_runstate_info_state: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_runstate_info_state)); ++ XEN_HYPER_PRI(fp, len, "vcpu_runstate_info_state_entry_time: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_runstate_info_state_entry_time)); ++ XEN_HYPER_PRI(fp, len, "vcpu_runstate_info_time: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_runstate_info_time)); ++#ifdef IA64 ++ XEN_HYPER_PRI(fp, len, "vcpu_thread_ksp: ", buf, flag, ++ (buf, "%ld\n", xen_hyper_offset_table.vcpu_thread_ksp)); ++#endif ++} ++ ++/* ++ * dump specified memory with specified size. ++ */ ++#define DSP_BYTE_SIZE 16 ++ ++static void ++xen_hyper_dump_mem(void *mem, ulong len, int dsz) ++{ ++ long i, max; ++ void *mem_w = mem; ++ ++ if (!len || ++ (dsz != SIZEOF_8BIT && dsz != SIZEOF_16BIT && ++ dsz != SIZEOF_32BIT && dsz != SIZEOF_64BIT)) ++ return; ++ max = len / dsz + (len % dsz ? 1 : 0); ++ for (i = 0; i < max; i++) { ++ if (i != 0 && !(i % (DSP_BYTE_SIZE / dsz))) ++ fprintf(fp, "\n"); ++ if (i == 0 || !(i % (DSP_BYTE_SIZE / dsz))) ++ fprintf(fp, "%p : ", mem_w); ++ if (dsz == SIZEOF_8BIT) ++ fprintf(fp, "%02x ", *(uint8_t *)mem_w); ++ else if (dsz == SIZEOF_16BIT) ++ fprintf(fp, "%04x ", *(uint16_t *)mem_w); ++ else if (dsz == SIZEOF_32BIT) ++ fprintf(fp, "%08x ", *(uint32_t *)mem_w); ++ else if (dsz == SIZEOF_64BIT) ++ fprintf(fp, "%016llx ", *(unsigned long long *)mem_w); ++ mem_w = (char *)mem_w + dsz; ++ } ++ fprintf(fp, "\n"); ++} ++#endif +--- crash/defs.h.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/defs.h 2007-08-27 11:50:30.000000000 -0400 @@ -1,8 +1,8 @@ /* defs.h - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002, 2003, 2004, 2005 David Anderson - * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. -+ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson -+ * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. All rights reserved. * Copyright (C) 2002 Silicon Graphics, Inc. * * This program is free software; you can redistribute it and/or modify @@ -22146,12 +45498,17 @@ #define NETDUMP (0x20000000000ULL) #define REM_NETDUMP (0x40000000000ULL) #define SYSMAP (0x80000000000ULL) -@@ -169,11 +172,13 @@ +@@ -169,11 +172,18 @@ #define VERSION_QUERY (0x4000000000000ULL) #define READNOW (0x8000000000000ULL) #define NOCRASHRC (0x10000000000000ULL) +#define INIT_IFILE (0x20000000000000ULL) +#define XENDUMP (0x40000000000000ULL) ++#define XEN_HYPER (0x80000000000000ULL) ++#define XEN_CORE (0x100000000000000ULL) ++#define PLEASE_WAIT (0x200000000000000ULL) ++#define IFILE_ERROR (0x400000000000000ULL) ++#define KERNTYPES (0x800000000000000ULL) #define ACTIVE() (pc->flags & LIVE_SYSTEM) #define DUMPFILE() (!(pc->flags & LIVE_SYSTEM)) @@ -22162,13 +45519,16 @@ #define REMOTE() (pc->flags & REMOTE_DAEMON) #define REMOTE_ACTIVE() (pc->flags & REM_LIVE_SYSTEM) #define REMOTE_DUMPFILE() \ -@@ -182,17 +187,30 @@ +@@ -182,16 +192,35 @@ #define LKCD_DUMPFILE() (pc->flags & (LKCD|REM_LKCD)) #define NETDUMP_DUMPFILE() (pc->flags & (NETDUMP|REM_NETDUMP)) #define DISKDUMP_DUMPFILE() (pc->flags & DISKDUMP) +#define KDUMP_DUMPFILE() (pc->flags & KDUMP) +#define XENDUMP_DUMPFILE() (pc->flags & XENDUMP) ++#define XEN_HYPER_MODE() (pc->flags & XEN_HYPER) +#define SYSRQ_TASK(X) ((pc->flags & SYSRQ) && is_task_active(X)) ++#define XEN_CORE_DUMPFILE() (pc->flags & XEN_CORE) ++#define LKCD_KERNTYPES() (pc->flags & KERNTYPES) #define NETDUMP_LOCAL (0x1) /* netdump_data flags */ #define NETDUMP_REMOTE (0x2) @@ -22180,37 +45540,101 @@ +#define KDUMP_ELF32 (0x20) +#define KDUMP_ELF64 (0x40) +#define KDUMP_LOCAL (0x80) -+#define KDUMP_XEN_HV (0x100) + +#define DUMPFILE_FORMAT(flags) ((flags) & \ + (NETDUMP_ELF32|NETDUMP_ELF64|KDUMP_ELF32|KDUMP_ELF64)) ++ ++#define DISKDUMP_LOCAL (0x1) ++#define KDUMP_CMPRS_LOCAL (0x2) ++#define ERROR_EXCLUDED (0x4) ++#define ZERO_EXCLUDED (0x8) ++#define DISKDUMP_VALID() (dd->flags & DISKDUMP_LOCAL) ++#define KDUMP_CMPRS_VALID() (dd->flags & KDUMP_CMPRS_LOCAL) - #define DISKDUMP_LOCAL (0x1) - #define DISKDUMP_VALID() (dd->flags & DISKDUMP_LOCAL) - +-#define DISKDUMP_LOCAL (0x1) +-#define DISKDUMP_VALID() (dd->flags & DISKDUMP_LOCAL) +#define XENDUMP_LOCAL (0x1) +#define XENDUMP_VALID() (xd->flags & XENDUMP_LOCAL) -+ + #define CRASHDEBUG(x) (pc->debug >= (x)) - #define CRASHDEBUG_SUSPEND(X) { pc->debug_save = pc->debug; pc->debug = X; } -@@ -328,6 +346,9 @@ +@@ -210,6 +239,7 @@ + #define SEEK_ERROR (-1) + #define READ_ERROR (-2) + #define WRITE_ERROR (-3) ++#define PAGE_EXCLUDED (-4) + + #define RESTART() (longjmp(pc->main_loop_env, 1)) + #define RESUME_FOREACH() (longjmp(pc->foreach_loop_env, 1)) +@@ -319,15 +349,28 @@ + #define SCROLL_NONE 0 + #define SCROLL_LESS 1 + #define SCROLL_MORE 2 ++#define SCROLL_CRASHPAGER 3 + ulong redirect; /* per-cmd origin and output flags */ + pid_t stdpipe_pid; /* per-cmd standard output pipe's pid */ + pid_t pipe_pid; /* per-cmd output pipe's pid */ + pid_t pipe_shell_pid; /* per-cmd output pipe's shell pid */ + char pipe_command[BUFSIZE]; /* pipe command line */ ++ struct command_table_entry *cmd_table; /* linux/xen command table */ + char *curcmd; /* currently-executing command */ char *lastcmd; /* previously-executed command */ ulong cmdgencur; /* current command generation number */ - ulong cmdgenspec; /* specified command generation num */ +- ulong cmdgenspec; /* specified command generation num */ + ulong curcmd_flags; /* general purpose per-command flag */ -+#define XEN_MACHINE_ADDR (0x1) -+#define REPEAT (0x2) ++#define XEN_MACHINE_ADDR (0x1) ++#define REPEAT (0x2) ++#define IDLE_TASK_SHOWN (0x4) ++#define TASK_SPECIFIED (0x8) ++#define MEMTYPE_UVADDR (0x10) ++#define MEMTYPE_FILEADDR (0x20) ++#define HEADER_PRINTED (0x40) ++#define BAD_INSTRUCTION (0x80) ++#define UD2A_INSTRUCTION (0x100) ++#define IRQ_IN_USE (0x200) ++ ulonglong curcmd_private; /* general purpose per-command info */ int cur_gdb_cmd; /* current gdb command */ int last_gdb_cmd; /* previously-executed gdb command */ int sigint_cnt; /* number of ignored SIGINTs */ -@@ -407,9 +428,23 @@ +@@ -347,11 +390,11 @@ + struct extension_table *curext; /* extension being loaded */ + int (*readmem)(int, void *, int, ulong, physaddr_t); /* memory access */ + int (*writemem)(int, void *, int, ulong, physaddr_t);/* memory access */ ++ ulong ifile_in_progress; /* original xxx_IFILE flags */ ++ off_t ifile_offset; /* current offset into input file */ ++ char *runtime_ifile_cmd; /* runtime command using input file */ + }; + +-#define UNIQUE_COMMAND(s) \ +- (STREQ(pc->curcmd, s) && (pc->cmdgencur == pc->cmdgenspec)) +- + #define READMEM pc->readmem + + typedef void (*cmd_func_t)(void); +@@ -365,6 +408,7 @@ + + #define REFRESH_TASK_TABLE (0x1) /* command_table_entry flags */ + #define HIDDEN_COMMAND (0x2) ++#define CLEANUP (0x4) /* for extensions only */ + + /* + * A linked list of extension table structures keeps track of the current +@@ -407,9 +451,32 @@ #define KALLSYMS_V2 (0x2000) #define TVEC_BASES_V2 (0x4000) #define GCC_3_3_3 (0x8000) +#define USE_OLD_BT (0x10000) +#define ARCH_XEN (0x20000) +#define NO_IKCONFIG (0x40000) ++#define DWARF_UNWIND (0x80000) ++#define NO_DWARF_UNWIND (0x100000) ++#define DWARF_UNWIND_MEMORY (0x200000) ++#define DWARF_UNWIND_EH_FRAME (0x400000) ++#define DWARF_UNWIND_CAPABLE (DWARF_UNWIND_MEMORY|DWARF_UNWIND_EH_FRAME) ++#define DWARF_UNWIND_MODULES (0x800000) ++#define BUGVERBOSE_OFF (0x1000000) ++#define RELOC_SET (0x2000000) ++#define RELOC_FORCE (0x4000000) #define GCC_VERSION_DEPRECATED (GCC_3_2|GCC_3_2_3|GCC_2_96|GCC_3_3_2|GCC_3_3_3) @@ -22228,7 +45652,7 @@ struct kernel_table { /* kernel data */ ulong flags; ulong stext; -@@ -420,6 +455,7 @@ +@@ -420,6 +487,7 @@ ulong init_end; ulong end; int cpus; @@ -22236,7 +45660,7 @@ void (*display_bh)(void); ulong module_list; ulong kernel_module; -@@ -430,11 +466,32 @@ +@@ -430,11 +498,36 @@ uint kernel_version[3]; uint gcc_version[3]; int runq_siblings; @@ -22246,6 +45670,7 @@ long __per_cpu_offset[NR_CPUS]; - long cpu_flags[NR_CPUS]; + ulong cpu_flags[NR_CPUS]; ++ int BUG_bytes; #define NMI 0x1 + ulong xen_flags; +#define WRITABLE_PAGE_TABLES (0x1) @@ -22258,7 +45683,8 @@ +#define P2M_MAPPING_CACHE (512) + struct p2m_mapping_cache { + ulong mapping; -+ ulong mfn; ++ ulong start; ++ ulong end; + } p2m_mapping_cache[P2M_MAPPING_CACHE]; +#define P2M_MAPPING_TO_PAGE_INDEX(c) \ + (((kt->p2m_mapping_cache[c].mapping - kt->phys_to_machine_mapping)/PAGESIZE()) \ @@ -22266,11 +45692,21 @@ + ulong last_mapping_read; + ulong p2m_cache_index; + ulong p2m_pages_searched; -+ ulong p2m_cache_hits; ++ ulong p2m_mfn_cache_hits; ++ ulong p2m_page_cache_hits; ++ ulong relocate; }; /* -@@ -602,6 +659,8 @@ +@@ -578,6 +671,7 @@ + ulonglong flags; + ulong instptr; + ulong stkptr; ++ ulong bptr; + ulong stackbase; + ulong stacktop; + char *stackbuf; +@@ -602,6 +696,8 @@ (void *)(&bt->stackbuf[(ulong)STACK_OFFSET_TYPE(OFF)]), (size_t)(SZ)) struct machine_specific; /* uniquely defined below each machine's area */ @@ -22279,7 +45715,7 @@ struct machdep_table { ulong flags; -@@ -645,14 +704,24 @@ +@@ -645,14 +741,24 @@ char **file; } *line_number_hooks; ulong last_pgd_read; @@ -22304,7 +45740,7 @@ }; /* -@@ -660,19 +729,23 @@ +@@ -660,19 +766,25 @@ * as defined in their processor-specific files below. (see KSYMS_START defs). */ #define HWRESET (0x80000000) @@ -22321,6 +45757,8 @@ +#define DEVMEMRD (0x8000000) +#define INIT (0x4000000) +#define VM_4_LEVEL (0x2000000) ++#define MCA (0x1000000) ++#define PAE (0x800000) extern struct machdep_table *machdep; @@ -22335,7 +45773,7 @@ #define FILL_PGD(PGD, TYPE, SIZE) \ if (!IS_LAST_PGD_READ(PGD)) { \ -@@ -681,6 +754,13 @@ +@@ -681,6 +793,13 @@ machdep->last_pgd_read = (ulong)(PGD); \ } @@ -22349,7 +45787,20 @@ #define FILL_PMD(PMD, TYPE, SIZE) \ if (!IS_LAST_PMD_READ(PMD)) { \ readmem((ulonglong)(PMD), TYPE, machdep->pmd, \ -@@ -737,6 +817,7 @@ +@@ -695,10 +814,12 @@ + machdep->last_ptbl_read = (ulong)(PTBL); \ + } + ++#define SETUP_ENV (0) + #define PRE_SYMTAB (1) + #define PRE_GDB (2) + #define POST_GDB (3) + #define POST_INIT (4) ++#define POST_VM (5) + + #define FOREACH_BT (1) + #define FOREACH_VM (2) +@@ -737,6 +858,7 @@ #define FOREACH_c_FLAG (0x40000) #define FOREACH_f_FLAG (0x80000) #define FOREACH_o_FLAG (0x100000) @@ -22357,16 +45808,72 @@ struct foreach_data { ulong flags; -@@ -875,6 +956,7 @@ +@@ -810,10 +932,15 @@ + long task_struct_last_run; + long task_struct_timestamp; + long task_struct_thread_info; ++ long task_struct_nsproxy; ++ long task_struct_rlim; + long thread_info_task; + long thread_info_cpu; + long thread_info_previous_esp; + long thread_info_flags; ++ long nsproxy_mnt_ns; ++ long mnt_namespace_root; ++ long mnt_namespace_list; + long pid_link_pid; + long pid_hash_chain; + long hlist_node_next; +@@ -830,6 +957,8 @@ + long tms_tms_stime; + long signal_struct_count; + long signal_struct_action; ++ long signal_struct_shared_pending; ++ long signal_struct_rlim; + long k_sigaction_sa; + long sigaction_sa_handler; + long sigaction_sa_flags; +@@ -875,8 +1004,13 @@ long mm_struct_mmap; long mm_struct_pgd; long mm_struct_rss; + long mm_struct_anon_rss; long mm_struct_total_vm; long mm_struct_start_code; ++ long mm_struct_arg_start; ++ long mm_struct_arg_end; ++ long mm_struct_env_start; ++ long mm_struct_env_end; long vm_area_struct_vm_mm; -@@ -970,6 +1052,11 @@ + long vm_area_struct_vm_next; + long vm_area_struct_vm_end; +@@ -948,6 +1082,7 @@ + long block_device_bd_disk; + long irq_desc_t_status; + long irq_desc_t_handler; ++ long irq_desc_t_chip; + long irq_desc_t_action; + long irq_desc_t_depth; + long irqdesc_action; +@@ -968,8 +1103,28 @@ + long hw_interrupt_type_ack; + long hw_interrupt_type_end; long hw_interrupt_type_set_affinity; ++ long irq_chip_typename; ++ long irq_chip_startup; ++ long irq_chip_shutdown; ++ long irq_chip_enable; ++ long irq_chip_disable; ++ long irq_chip_ack; ++ long irq_chip_end; ++ long irq_chip_set_affinity; ++ long irq_chip_mask; ++ long irq_chip_mask_ack; ++ long irq_chip_unmask; ++ long irq_chip_eoi; ++ long irq_chip_retrigger; ++ long irq_chip_set_type; ++ long irq_chip_set_wake; long irq_cpustat_t___softirq_active; long irq_cpustat_t___softirq_mask; + long fdtable_max_fds; @@ -22377,7 +45884,17 @@ long files_struct_max_fds; long files_struct_max_fdset; long files_struct_open_fds; -@@ -1088,6 +1175,8 @@ +@@ -978,6 +1133,9 @@ + long file_f_dentry; + long file_f_vfsmnt; + long file_f_count; ++ long file_f_path; ++ long path_mnt; ++ long path_dentry; + long fs_struct_root; + long fs_struct_pwd; + long fs_struct_rootmnt; +@@ -1088,6 +1246,8 @@ long inet_opt_dport; long inet_opt_sport; long inet_opt_num; @@ -22386,7 +45903,7 @@ long timer_list_list; long timer_list_next; long timer_list_entry; -@@ -1123,6 +1212,7 @@ +@@ -1123,6 +1283,7 @@ long zone_struct_name; long zone_struct_size; long zone_struct_memsize; @@ -22394,7 +45911,15 @@ long zone_struct_zone_start_paddr; long zone_struct_zone_start_mapnr; long zone_struct_zone_mem_map; -@@ -1210,7 +1300,14 @@ +@@ -1143,6 +1304,7 @@ + long zone_pages_min; + long zone_pages_low; + long zone_pages_high; ++ long zone_vm_stat; + long neighbour_next; + long neighbour_primary_key; + long neighbour_ha; +@@ -1210,7 +1372,29 @@ long x8664_pda_irqstackptr; long x8664_pda_level4_pgt; long x8664_pda_cpunumber; @@ -22406,10 +45931,25 @@ + long cpu_user_regs_esp; + long cpu_user_regs_rip; + long cpu_user_regs_rsp; ++ long unwind_table_core; ++ long unwind_table_init; ++ long unwind_table_address; ++ long unwind_table_size; ++ long unwind_table_link; ++ long unwind_table_name; ++ long rq_cfs; ++ long rq_rt; ++ long rq_nr_running; ++ long cfs_rq_rb_leftmost; ++ long cfs_rq_nr_running; ++ long cfs_rq_tasks_timeline; ++ long task_struct_se; ++ long sched_entity_run_node; ++ long rt_rq_active; }; struct size_table { /* stash of commonly-used sizes */ -@@ -1239,6 +1336,7 @@ +@@ -1239,6 +1423,7 @@ long umode_t; long dentry; long files_struct; @@ -22417,7 +45957,15 @@ long fs_struct; long file; long inode; -@@ -1292,15 +1390,19 @@ +@@ -1264,6 +1449,7 @@ + long net_device; + long sock; + long signal_struct; ++ long sigpending_signal; + long signal_queue; + long sighand_struct; + long sigqueue; +@@ -1292,15 +1478,21 @@ long address_space; long char_device_struct; long inet_sock; @@ -22434,10 +45982,28 @@ long cputime_t; + long mem_section; + long pid_link; ++ long unwind_table; ++ long rlimit; }; struct array_table { -@@ -1389,6 +1491,7 @@ +@@ -1327,6 +1519,7 @@ + int free_area_DIMENSION; + int prio_array_queue; + int height_to_maxindex; ++ int pid_hash; + }; + + /* +@@ -1365,6 +1558,7 @@ + #define MEMBER_OFFSET_INIT(X, Y, Z) (ASSIGN_OFFSET(X) = MEMBER_OFFSET(Y, Z)) + #define STRUCT_SIZE_INIT(X, Y) (ASSIGN_SIZE(X) = STRUCT_SIZE(Y)) + #define ARRAY_LENGTH_INIT(A, B, C, D, E) ((A) = get_array_length(C, D, E)) ++#define ARRAY_LENGTH_INIT_ALT(A, B, C, D, E) ((A) = get_array_length_alt(B, C, D, E)) + #define MEMBER_SIZE_INIT(X, Y, Z) (ASSIGN_SIZE(X) = MEMBER_SIZE(Y, Z)) + + /* +@@ -1389,6 +1583,7 @@ #define ULONGLONG(ADDR) *((ulonglong *)((char *)(ADDR))) #define ULONG_PTR(ADDR) *((ulong **)((char *)(ADDR))) #define USHORT(ADDR) *((ushort *)((char *)(ADDR))) @@ -22445,7 +46011,15 @@ #define VOID_PTR(ADDR) *((void **)((char *)(ADDR))) struct node_table { -@@ -1420,6 +1523,7 @@ +@@ -1396,6 +1591,7 @@ + ulong pgdat; + ulong mem_map; + ulong size; ++ ulong present; + ulonglong start_paddr; + ulong start_mapnr; + }; +@@ -1420,6 +1616,7 @@ ulong kmem_max_limit; ulong kmem_max_cpus; ulong kmem_cache_count; @@ -22453,7 +46027,7 @@ ulong PG_reserved; ulong PG_slab; int kmem_cache_namelen; -@@ -1441,17 +1545,35 @@ +@@ -1441,17 +1638,36 @@ ulong cached_vma_hits[VMA_CACHE]; int vma_cache_index; ulong vma_cache_fills; @@ -22492,6 +46066,7 @@ +#define KMEM_CACHE_DELAY (0x2000) +#define NODES_ONLINE (0x4000) +#define VM_STAT (0x8000) ++#define KMALLOC_SLUB (0x10000) + +#define IS_FLATMEM() (vt->flags & FLATMEM) +#define IS_DISCONTIGMEM() (vt->flags & DISCONTIGMEM) @@ -22500,23 +46075,56 @@ #define COMMON_VADDR_SPACE() (vt->flags & COMMON_VADDR) #define PADDR_PRLEN (vt->paddr_prlen) -@@ -1596,6 +1718,7 @@ +@@ -1478,7 +1694,8 @@ + long list_head_offset; + ulong end; + ulong searchfor; +- char *structname; ++ char **structname; ++ int structname_args; + char *header; + }; + #define LIST_OFFSET_ENTERED (VERBOSE << 1) +@@ -1584,8 +1801,11 @@ + int mods_installed; + struct load_module *current; + struct load_module *load_modules; ++ off_t dwarf_eh_frame_file_offset; ++ ulong dwarf_eh_frame_size; + }; + ++/* flags for st */ + #define KERNEL_SYMS (0x1) + #define MODULE_SYMS (0x2) + #define LOAD_MODULE_SYMS (0x4) +@@ -1596,6 +1816,8 @@ #define NO_SEC_CONTENTS (0x40) #define FORCE_DEBUGINFO (0x80) #define CRC_MATCHES (0x100) +#define ADD_SYMBOL_FILE (0x200) ++#define USE_OLD_ADD_SYM (0x400) #endif /* !GDB_COMMON */ -@@ -1659,6 +1782,7 @@ +@@ -1611,6 +1833,8 @@ + #define MOD_KALLSYMS (0x8) + #define MOD_INITRD (0x10) + ++#define SEC_FOUND (0x10000) ++ + struct mod_section_data { + #if defined(GDB_6_1) + struct bfd_section *section; +@@ -1659,6 +1883,8 @@ #define KVADDR (0x1) #define UVADDR (0x2) #define PHYSADDR (0x4) +#define XENMACHADDR (0x8) ++#define FILEADDR (0x10) #define AMBIGUOUS (~0) #define USE_USER_PGD (UVADDR << 2) -@@ -1680,6 +1804,33 @@ +@@ -1680,6 +1906,33 @@ #define VIRTPAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) #define PHYSPAGEBASE(X) (((physaddr_t)(X)) & (physaddr_t)machdep->pagemask) @@ -22550,7 +46158,7 @@ /* * Machine specific stuff */ -@@ -1689,8 +1840,8 @@ +@@ -1689,8 +1942,8 @@ #define MACHINE_TYPE "X86" #define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) #define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) @@ -22561,7 +46169,18 @@ #define PGDIR_SHIFT_2LEVEL (22) #define PTRS_PER_PTE_2LEVEL (1024) -@@ -1724,22 +1875,68 @@ +@@ -1721,25 +1974,86 @@ + + #define SWP_TYPE(entry) (((entry) >> 1) & 0x3f) + #define SWP_OFFSET(entry) ((entry) >> 8) ++#define __swp_type_PAE(entry) (((entry) >> 32) & 0x1f) ++#define __swp_type_nonPAE(entry) (((entry) >> 1) & 0x1f) ++#define __swp_offset_PAE(entry) (((entry) >> 32) >> 5) ++#define __swp_offset_nonPAE(entry) ((entry) >> 8) ++#define __swp_type(entry) (machdep->flags & PAE ? \ ++ __swp_type_PAE(entry) : __swp_type_nonPAE(entry)) ++#define __swp_offset(entry) (machdep->flags & PAE ? \ ++ __swp_offset_PAE(entry) : __swp_offset_nonPAE(entry)) #define TIF_SIGPENDING (2) @@ -22634,11 +46253,18 @@ +#define VMALLOC_END_XEN 0xffffe1ffffffffff +#define MODULES_VADDR_XEN 0xffffffff88000000 +#define MODULES_END_XEN 0xfffffffffff00000 ++ ++#define USERSPACE_TOP_XEN_RHEL4 0x0000008000000000 ++#define PAGE_OFFSET_XEN_RHEL4 0xffffff8000000000 ++#define VMALLOC_START_ADDR_XEN_RHEL4 0xffffff0000000000 ++#define VMALLOC_END_XEN_RHEL4 0xffffff7fffffffff ++#define MODULES_VADDR_XEN_RHEL4 0xffffffffa0000000 ++#define MODULES_END_XEN_RHEL4 0xffffffffafffffff + #define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) #define VTOP(X) x86_64_VTOP((ulong)(X)) #define IS_VMALLOC_ADDR(X) x86_64_IS_VMALLOC_ADDR((ulong)(X)) -@@ -1757,12 +1954,25 @@ +@@ -1757,12 +2071,34 @@ #define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) #define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) @@ -22653,6 +46279,15 @@ + machdep->machspec->last_pml4_read = (ulong)(vt->kernel_pgd[0]); \ } ++#define FILL_PML4_HYPER() { \ ++ if (!machdep->machspec->last_pml4_read) { \ ++ readmem(symbol_value("idle_pg_table_4"), KVADDR, \ ++ machdep->machspec->pml4, PAGESIZE(), "idle_pg_table_4", \ ++ FAULT_ON_ERROR); \ ++ machdep->machspec->last_pml4_read = symbol_value("idle_pg_table_4"); \ ++ }\ ++} ++ +#define IS_LAST_UPML_READ(pml) ((ulong)(pml) == machdep->machspec->last_upml_read) + +#define FILL_UPML(PML, TYPE, SIZE) \ @@ -22665,7 +46300,14 @@ /* * PHYSICAL_PAGE_MASK changed (enlarged) between 2.4 and 2.6, so * for safety, use the 2.6 values to generate it. -@@ -1796,6 +2006,15 @@ +@@ -1791,11 +2127,22 @@ + + #define SWP_TYPE(entry) (((entry) >> 1) & 0x3f) + #define SWP_OFFSET(entry) ((entry) >> 8) ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) + + #define TIF_SIGPENDING (2) #define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) @@ -22681,7 +46323,7 @@ #define CPU_PDA_READ(CPU, BUFFER) \ (STRNEQ("cpu_pda", closest_symbol((symbol_value("cpu_pda") + \ ((CPU) * SIZE(x8664_pda))))) && \ -@@ -1806,6 +2025,9 @@ +@@ -1806,6 +2153,9 @@ #define VALID_LEVEL4_PGT_ADDR(X) \ (((X) == VIRTPAGEBASE(X)) && IS_KVADDR(X) && !IS_VMALLOC_ADDR(X)) @@ -22691,7 +46333,7 @@ #endif /* X86_64 */ #ifdef ALPHA -@@ -1816,7 +2038,7 @@ +@@ -1816,7 +2166,7 @@ #define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) #define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) @@ -22700,7 +46342,16 @@ #define KSEG_BASE_48_BIT (0xffff800000000000) #define KSEG_BASE (0xfffffc0000000000) #define _PFN_MASK (0xFFFFFFFF00000000) -@@ -1861,7 +2083,7 @@ +@@ -1848,6 +2198,8 @@ + + #define SWP_TYPE(entry) (((entry) >> 32) & 0xff) + #define SWP_OFFSET(entry) ((entry) >> 40) ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) + + #define TIF_SIGPENDING (2) + +@@ -1861,7 +2213,7 @@ #define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) #define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) @@ -22709,7 +46360,12 @@ #define PGDIR_SHIFT (22) #define PTRS_PER_PTE (1024) -@@ -1884,6 +2106,9 @@ +@@ -1881,9 +2233,14 @@ + + #define SWP_TYPE(entry) (((entry) >> 1) & 0x7f) + #define SWP_OFFSET(entry) ((entry) >> 8) ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) #define TIF_SIGPENDING (2) @@ -22719,7 +46375,7 @@ #endif /* PPC */ #ifdef IA64 -@@ -1908,6 +2133,9 @@ +@@ -1908,6 +2265,9 @@ #define KERNEL_UNCACHED_BASE ((ulong)KERNEL_UNCACHED_REGION << REGION_SHIFT) #define KERNEL_CACHED_BASE ((ulong)KERNEL_CACHED_REGION << REGION_SHIFT) @@ -22729,7 +46385,7 @@ /* * As of 2.6, these are no longer straight forward. */ -@@ -1917,16 +2145,57 @@ +@@ -1917,16 +2277,57 @@ #define SWITCH_STACK_ADDR(X) (ia64_get_switch_stack((ulong)(X))) @@ -22793,7 +46449,7 @@ * First, define the various bits in a PTE. Note that the PTE format * matches the VHPT short format, the firt doubleword of the VHPD long * format, and the first doubleword of the TLB insertion format. -@@ -1978,6 +2247,7 @@ +@@ -1978,6 +2379,7 @@ #define __DIRTY_BITS _PAGE_ED | __DIRTY_BITS_NO_ED #define EFI_PAGE_SHIFT (12) @@ -22801,7 +46457,23 @@ /* * NOTE: #include'ing creates too many compiler problems, so * this stuff is hardwired here; it's probably etched in stone somewhere. -@@ -2042,7 +2312,7 @@ +@@ -2020,6 +2422,8 @@ + + #define SWP_TYPE(entry) (((entry) >> 1) & 0xff) + #define SWP_OFFSET(entry) ((entry) >> 9) ++#define __swp_type(entry) ((entry >> 2) & 0x7f) ++#define __swp_offset(entry) ((entry << 1) >> 10) + + #define TIF_SIGPENDING (1) + +@@ -2038,11 +2442,14 @@ + #define _64BIT_ + #define MACHINE_TYPE "PPC64" + ++#define PPC64_64K_PAGE_SIZE 65536 ++#define PPC64_STACK_SIZE 16384 ++ + #define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) #define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) #define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) @@ -22810,7 +46482,7 @@ #define KERNELBASE machdep->pageoffset #define PGDIR_SHIFT (machdep->pageshift + (machdep->pageshift -3) + (machdep->pageshift - 2)) -@@ -2067,6 +2337,32 @@ +@@ -2067,6 +2474,32 @@ #define PGD_OFFSET(vaddr) ((vaddr >> PGDIR_SHIFT) & 0x7ff) #define PMD_OFFSET(vaddr) ((vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) @@ -22843,7 +46515,16 @@ #define _PAGE_PRESENT 0x001UL /* software: pte contains a translation */ #define _PAGE_USER 0x002UL /* matches one of the PP bits */ #define _PAGE_RW 0x004UL /* software: user write access allowed */ -@@ -2087,6 +2383,9 @@ +@@ -2080,6 +2513,8 @@ + + #define SWP_TYPE(entry) (((entry) >> 1) & 0x7f) + #define SWP_OFFSET(entry) ((entry) >> 8) ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) + + #define MSR_PR_LG 14 /* Problem State / Privilege Level */ + /* Used to find the user or kernel-mode frame*/ +@@ -2087,6 +2522,9 @@ #define STACK_FRAME_OVERHEAD 112 #define EXCP_FRAME_MARKER 0x7265677368657265 @@ -22853,7 +46534,7 @@ #endif /* PPC64 */ #ifdef S390 -@@ -2095,7 +2394,7 @@ +@@ -2095,7 +2533,7 @@ #define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) #define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) @@ -22862,7 +46543,16 @@ #define PTRS_PER_PTE 1024 #define PTRS_PER_PMD 1 -@@ -2116,7 +2415,7 @@ +@@ -2105,6 +2543,8 @@ + #define SWP_TYPE(entry) (((entry) >> 2) & 0x1f) + #define SWP_OFFSET(entry) ((((entry) >> 11) & 0xfffffffe) | \ + (((entry) >> 7) & 0x1)) ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) + + #define TIF_SIGPENDING (2) + +@@ -2116,7 +2556,7 @@ #define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) #define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) @@ -22871,15 +46561,93 @@ #define PTRS_PER_PTE 512 #define PTRS_PER_PMD 1024 #define PTRS_PER_PGD 2048 -@@ -2186,6 +2485,7 @@ +@@ -2125,6 +2565,8 @@ + #define SWP_TYPE(entry) (((entry) >> 2) & 0x1f) + #define SWP_OFFSET(entry) ((((entry) >> 11) & 0xfffffffffffffffe) | \ + (((entry) >> 7) & 0x1)) ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) + + #define TIF_SIGPENDING (2) + +@@ -2134,6 +2576,8 @@ + + #define SWP_TYPE(entry) (error("PLATFORM_SWP_TYPE: TBD\n")) + #define SWP_OFFSET(entry) (error("PLATFORM_SWP_OFFSET: TBD\n")) ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) + + #endif /* PLATFORM */ + +@@ -2185,7 +2629,10 @@ + #define BADVAL ((ulong)(-1)) #define UNUSED (-1) ++#define UNINITIALIZED (BADVAL) ++ #define BITS_PER_BYTE (8) +#define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) /* * precision lengths for fprintf -@@ -2534,6 +2834,9 @@ +@@ -2199,9 +2646,10 @@ + + #define MINSPACE (-100) + +-#define SYNOPSIS (0x1) +-#define COMPLETE_HELP (0x2) +-#define PIPE_TO_LESS (0x4) ++#define SYNOPSIS (0x1) ++#define COMPLETE_HELP (0x2) ++#define PIPE_TO_SCROLL (0x4) ++#define MUST_HELP (0x8) + + #define LEFT_JUSTIFY (1) + #define RIGHT_JUSTIFY (2) +@@ -2419,17 +2867,22 @@ + /* + * ps command options. + */ +-#define PS_BY_PID (0x1) +-#define PS_BY_TASK (0x2) +-#define PS_BY_CMD (0x4) +-#define PS_SHOW_ALL (0x8) +-#define PS_PPID_LIST (0x10) +-#define PS_CHILD_LIST (0x20) +-#define PS_KERNEL (0x40) +-#define PS_USER (0x80) +-#define PS_TIMES (0x100) +-#define PS_KSTACKP (0x200) +-#define PS_LAST_RUN (0x400) ++#define PS_BY_PID (0x1) ++#define PS_BY_TASK (0x2) ++#define PS_BY_CMD (0x4) ++#define PS_SHOW_ALL (0x8) ++#define PS_PPID_LIST (0x10) ++#define PS_CHILD_LIST (0x20) ++#define PS_KERNEL (0x40) ++#define PS_USER (0x80) ++#define PS_TIMES (0x100) ++#define PS_KSTACKP (0x200) ++#define PS_LAST_RUN (0x400) ++#define PS_ARGV_ENVP (0x800) ++#define PS_TGID_LIST (0x1000) ++#define PS_RLIMIT (0x2000) ++ ++#define PS_EXCLUSIVE (PS_TGID_LIST|PS_ARGV_ENVP|PS_TIMES|PS_CHILD_LIST|PS_PPID_LIST|PS_LAST_RUN|PS_RLIMIT) + + #define MAX_PS_ARGS (100) /* maximum command-line specific requests */ + +@@ -2461,7 +2914,7 @@ + extern struct program_context program_context, *pc; + extern struct task_table task_table, *tt; + extern struct kernel_table kernel_table, *kt; +-extern struct command_table_entry base_command_table[]; ++extern struct command_table_entry linux_command_table[]; + extern char *args[MAXARGS]; + extern int argcnt; + extern int argerrs; +@@ -2534,6 +2987,9 @@ void cmd_gdb(void); /* gdb_interface.c */ void cmd_net(void); /* net.c */ void cmd_extend(void); /* extensions.c */ @@ -22889,17 +46657,35 @@ /* * main.c -@@ -2685,6 +2988,9 @@ +@@ -2591,6 +3047,8 @@ + int interruptible(void); + int received_SIGINT(void); + void debug_redirect(char *); ++int CRASHPAGER_valid(void); ++char *setup_scroll_command(void); + + /* + * tools.c +@@ -2658,6 +3116,7 @@ + int hq_open(void); + int hq_close(void); + int hq_enter(ulong); ++int hq_entry_exists(ulong); + long get_embedded(void); + void dump_embedded(char *); + char *ordinal(ulong, char *); +@@ -2685,6 +3144,10 @@ int machine_type(char *); void command_not_supported(void); void option_not_supported(int); +void please_wait(char *); +void please_wait_done(void); +int pathcmp(char *, char *); ++int calculate(char *, ulong *, ulonglong *, ulong); /* -@@ -2721,6 +3027,7 @@ +@@ -2721,9 +3184,11 @@ struct syment *next_symbol(char *, struct syment *); struct syment *prev_symbol(char *, struct syment *); void get_symbol_data(char *, long, void *); @@ -22907,7 +46693,31 @@ char *value_to_symstr(ulong, char *, ulong); char *value_symbol(ulong); ulong symbol_value(char *); -@@ -2807,6 +3114,7 @@ ++ulong symbol_value_module(char *, char *); + int symbol_exists(char *s); + int kernel_symbol_exists(char *s); + int get_syment_array(char *, struct syment **, int); +@@ -2738,9 +3203,11 @@ + void dump_struct_table(ulong); + void dump_offset_table(char *, ulong); + int is_elf_file(char *); ++int file_elf_version(char *); + int is_system_map(char *); + int select_namelist(char *); + int get_array_length(char *, int *, long); ++int get_array_length_alt(char *, char *, int *, long); + int builtin_array_length(char *, int, int *); + char *get_line_number(ulong, char *, int); + char *get_build_directory(char *); +@@ -2768,6 +3235,7 @@ + long OFFSET_option(long, long, char *, char *, int, char *, char *); + long SIZE_option(long, long, char *, char *, int, char *, char *); + void dump_trace(ulong *); ++int enumerator_value(char *, long *); + + /* + * memory.c +@@ -2807,6 +3275,7 @@ char *swap_location(ulonglong, char *); void clear_swap_info_cache(void); uint memory_page_size(void); @@ -22915,7 +46725,7 @@ ulong first_vmalloc_address(void); int l1_cache_size(void); int dumpfile_memory(int); -@@ -2838,6 +3146,7 @@ +@@ -2838,6 +3307,7 @@ void open_files_dump(ulong, int, struct reference *); void get_pathname(ulong, char *, int, int, ulong); ulong file_to_dentry(ulong); @@ -22923,7 +46733,15 @@ void nlm_files_dump(void); int get_proc_version(void); int file_checksum(char *, long *); -@@ -2945,6 +3254,9 @@ +@@ -2874,6 +3344,7 @@ + void help_init(void); + void cmd_usage(char *, int); + void display_version(void); ++void display_help_screen(char *); + #ifdef X86 + #define dump_machdep_table(X) x86_dump_machdep_table(X) + #endif +@@ -2945,6 +3416,9 @@ extern char *help_waitq[]; extern char *help_whatis[]; extern char *help_wr[]; @@ -22933,7 +46751,20 @@ /* * task.c -@@ -3005,11 +3317,13 @@ +@@ -2962,10 +3436,12 @@ + ulong task_flags(ulong); + ulong task_state(ulong); + ulong task_mm(ulong, int); ++ulong task_tgid(ulong); + ulonglong task_last_run(ulong); + int comm_exists(char *); + struct task_context *task_to_context(ulong); + struct task_context *pid_to_context(ulong); ++struct task_context *tgid_to_context(ulong); + ulong stkptr_to_task(ulong); + ulong task_to_thread_info(ulong); + ulong task_to_stackbase(ulong); +@@ -3005,11 +3481,13 @@ */ void register_extension(struct command_table_entry *); void dump_extension_table(int); @@ -22948,17 +46779,41 @@ void module_init(void); void verify_version(void); void verify_spinlock(void); -@@ -3020,7 +3334,8 @@ +@@ -3019,14 +3497,18 @@ + int is_system_call(char *, ulong); void generic_dump_irq(int); int generic_dis_filter(ulong, char *); ++int kernel_BUG_encoding_bytes(void); void display_sys_stats(void); -void dump_kernel_table(void); +char *get_uptime(char *, ulonglong *); ++void clone_bt_info(struct bt_info *, struct bt_info *, struct task_context *); +void dump_kernel_table(int); void dump_bt_info(struct bt_info *); void dump_log(int); void set_cpu(int); -@@ -3069,6 +3384,8 @@ + void clear_machdep_cache(void); + struct stack_hook *gather_text_list(struct bt_info *); + int get_cpus_online(void); ++int get_cpus_possible(void); + void print_stack_text_syms(struct bt_info *, ulong, ulong); + void back_trace(struct bt_info *); + #define BT_RAW (0x1ULL) +@@ -3039,11 +3521,13 @@ + #define BT_EXCEPTION_FRAME (0x80ULL) + #define BT_LINE_NUMBERS (0x100ULL) + #define BT_USER_EFRAME (0x200ULL) ++#define BT_INCOMPLETE_USER_EFRAME (BT_USER_EFRAME) + #define BT_SAVE_LASTSP (0x400ULL) + #define BT_FROM_EXCEPTION (0x800ULL) + #define BT_FROM_CALLFRAME (0x1000ULL) + #define BT_EFRAME_SEARCH (0x2000ULL) + #define BT_SPECULATE (0x4000ULL) ++#define BT_FRAMESIZE_DISABLE (BT_SPECULATE) + #define BT_RESCHEDULE (0x8000ULL) + #define BT_SCHEDULE (BT_RESCHEDULE) + #define BT_RET_FROM_SMP_FORK (0x10000ULL) +@@ -3069,6 +3553,8 @@ #define BT_DUMPFILE_SEARCH (0x800000000ULL) #define BT_EFRAME_SEARCH2 (0x1000000000ULL) #define BT_START (0x2000000000ULL) @@ -22967,7 +46822,7 @@ #define BT_REF_HEXVAL (0x1) #define BT_REF_SYMBOL (0x2) -@@ -3101,6 +3418,17 @@ +@@ -3101,6 +3587,17 @@ #define TYPE_S390D (REMOTE_VERBOSE << 6) #define TYPE_NETDUMP (REMOTE_VERBOSE << 7) @@ -22985,7 +46840,15 @@ /* * dev.c */ -@@ -3140,6 +3468,8 @@ +@@ -3129,7 +3626,6 @@ + void x86_display_idt_table(void); + #define display_idt_table() x86_display_idt_table() + #define KSYMS_START (0x1) +-#define PAE (0x2) + void x86_dump_eframe_common(struct bt_info *bt, ulong *, int); + char *x86_function_called_by(ulong); + struct syment *x86_jmp_error_code(ulong); +@@ -3140,6 +3636,8 @@ ulong entry_tramp_start; ulong entry_tramp_end; physaddr_t entry_tramp_start_phys; @@ -22994,7 +46857,7 @@ }; struct syment *x86_is_entry_tramp_address(ulong, ulong *); -@@ -3194,7 +3524,17 @@ +@@ -3194,19 +3692,51 @@ #define NMI_STACK 2 /* ebase[] offset to NMI exception stack */ struct machine_specific { @@ -23010,9 +46873,10 @@ + ulong last_upml_read; + ulong last_pml4_read; char *irqstack; ++ ulong irq_eframe_link; struct x86_64_pt_regs_offsets pto; struct x86_64_stkinfo stkinfo; -@@ -3202,6 +3542,12 @@ + }; #define KSYMS_START (0x1) #define PT_REGS_INIT (0x2) @@ -23022,10 +46886,31 @@ +#define NO_TSS (0x20) +#define SCHED_TEXT (0x40) +#define PHYS_BASE (0x80) ++#define VM_XEN_RHEL4 (0x100) ++ ++#define VM_FLAGS (VM_ORIG|VM_2_6_11|VM_XEN|VM_XEN_RHEL4) #define _2MB_PAGE_MASK (~((MEGABYTES(2))-1)) ++ ++#endif ++ ++#if defined(X86) || defined(X86_64) ++ ++/* ++ * unwind_x86_32_64.c ++ */ ++void init_unwind_table(void); ++int dwarf_backtrace(struct bt_info *, int, ulong); ++void dwarf_debug(struct bt_info *); ++int dwarf_print_stack_entry(struct bt_info *, int); ++ #endif -@@ -3240,13 +3586,42 @@ + +-void x86_64_backtrace_notice(ulong); + + /* + * ppc64.c +@@ -3240,13 +3770,42 @@ ulong hwintrstack[NR_CPUS]; char *hwstackbuf; uint hwstacksize; @@ -23069,7 +46954,25 @@ #endif /* -@@ -3396,10 +3771,24 @@ +@@ -3258,6 +3817,8 @@ + #define display_idt_table() \ + error(FATAL, "-d option is not applicable to PowerPC architecture\n") + #define KSYMS_START (0x1) ++/* This should match PPC_FEATURE_BOOKE from include/asm-powerpc/cputable.h */ ++#define CPU_BOOKE (0x00008000) + #endif + + /* +@@ -3283,6 +3844,8 @@ + #define display_idt_table() \ + error(FATAL, "-d option TBD on ia64 architecture\n"); + int ia64_in_init_stack(ulong addr); ++int ia64_in_mca_stack_hyper(ulong addr, struct bt_info *bt); ++physaddr_t ia64_xen_kdump_p2m(struct xen_kdump_data *xkd, physaddr_t pseudo); + + #define OLD_UNWIND (0x1) /* CONFIG_IA64_NEW_UNWIND not turned on */ + #define NEW_UNWIND (0x2) /* CONFIG_IA64_NEW_UNWIND turned on */ +@@ -3396,10 +3959,26 @@ int netdump_init(char *, FILE *); ulong get_netdump_panic_task(void); ulong get_netdump_switch_stack(ulong); @@ -23092,13 +46995,20 @@ +int kdump_memory_used(void); +int kdump_memory_dump(FILE *); +void get_kdump_regs(struct bt_info *, ulong *, ulong *); ++void xen_kdump_p2m_mfn(char *); ++int is_sadump_xen(void); /* * diskdump.c -@@ -3418,6 +3807,23 @@ +@@ -3416,6 +3995,27 @@ + int diskdump_memory_dump(FILE *); + FILE *set_diskdump_fp(FILE *); void get_diskdump_regs(struct bt_info *, ulong *, ulong *); - - /* ++int diskdump_phys_base(unsigned long *); ++ulong *diskdump_flags; ++int is_partial_diskdump(void); ++ ++/* + * xendump.c + */ +int is_xendump(char *); @@ -23114,12 +47024,11 @@ +char *xc_core_mfn_to_page(ulong, char *); +int xc_core_mfn_to_page_index(ulong); +void xendump_panic_hook(char *); -+ -+/* ++int read_xendump_hyper(int, void *, int, ulong, physaddr_t); + + /* * net.c - */ - void net_init(void); -@@ -3560,6 +3966,7 @@ +@@ -3560,6 +4160,7 @@ #define LKCD_DUMP_V7 (0x7) /* DUMP_VERSION_NUMBER */ #define LKCD_DUMP_V8 (0x8) /* DUMP_VERSION_NUMBER */ #define LKCD_DUMP_V9 (0x9) /* DUMP_VERSION_NUMBER */ @@ -23127,8 +47036,1009 @@ #define LKCD_DUMP_VERSION_NUMBER_MASK (0xf) #define LKCD_DUMP_RAW (0x1) /* DUMP_[DH_]RAW */ ---- crash/vas_crash.h.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/vas_crash.h 2006-05-15 16:51:28.000000000 -0400 +@@ -3764,7 +4365,6 @@ + extern int prettyprint_structs; + extern int prettyprint_arrays; + extern int repeat_count_threshold; +-extern int repeat_count_threshold; + extern unsigned int print_max; + + /* +@@ -3814,4 +4414,8 @@ + extern int have_partial_symbols(void); + extern int have_full_symbols(void); + ++#if defined(X86) || defined(X86_64) || defined(IA64) ++#define XEN_HYPERVISOR_ARCH ++#endif ++ + #endif /* !GDB_COMMON */ +--- crash/xen_hyper_defs.h.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/xen_hyper_defs.h 2007-08-23 17:02:54.000000000 -0400 +@@ -0,0 +1,970 @@ ++/* ++ * xen_hyper_defs.h ++ * ++ * Portions Copyright (C) 2006-2007 Fujitsu Limited ++ * Portions Copyright (C) 2006-2007 VA Linux Systems Japan K.K. ++ * ++ * Authors: Itsuro Oda ++ * Fumihiko Kakuma ++ * ++ * This file is part of Xencrash. ++ * ++ * Xencrash 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 (version 2 of the License). ++ * ++ * Xencrash 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with Xencrash; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#ifdef XEN_HYPERVISOR_ARCH ++ ++#include ++#include ++ ++#ifdef X86 ++/* Xen Hypervisor address space layout */ ++#define IOREMAP_VIRT_END (0UL) ++#define IOREMAP_VIRT_START (0xFFC00000UL) ++#define DIRECTMAP_VIRT_END IOREMAP_VIRT_START ++#define DIRECTMAP_VIRT_START (0xFF000000UL) ++#define MAPCACHE_VIRT_END DIRECTMAP_VIRT_START ++#define MAPCACHE_VIRT_START (0xFFC00000UL) ++#define PERDOMAIN_VIRT_END DIRECTMAP_VIRT_START ++#define PERDOMAIN_VIRT_START (0xFE800000UL) ++#define SH_LINEAR_PT_VIRT_END PERDOMAIN_VIRT_START ++#define SH_LINEAR_PT_VIRT_START (0xFE400000UL) ++#define SH_LINEAR_PT_VIRT_START_PAE (0xFE000000UL) ++#define LINEAR_PT_VIRT_END SH_LINEAR_PT_VIRT_START ++#define LINEAR_PT_VIRT_START (0xFE000000UL) ++#define LINEAR_PT_VIRT_START_PAE (0xFD800000UL) ++#define RDWR_MPT_VIRT_END LINEAR_PT_VIRT_START ++#define RDWR_MPT_VIRT_START (0xFDC00000UL) ++#define RDWR_MPT_VIRT_START_PAE (0xFC800000UL) ++#define FRAMETABLE_VIRT_END RDWR_MPT_VIRT_START ++#define FRAMETABLE_VIRT_START (0xFC400000UL) ++#define FRAMETABLE_VIRT_START_PAE (0xF6800000UL) ++#define RO_MPT_VIRT_END FRAMETABLE_VIRT_START ++#define RO_MPT_VIRT_START (0xFC000000UL) ++#define RO_MPT_VIRT_START_PAE (0xF5800000UL) ++ ++#define HYPERVISOR_VIRT_START RO_MPT_VIRT_START ++#define HYPERVISOR_VIRT_START_PAE RO_MPT_VIRT_START_PAE ++#endif ++ ++#ifdef X86_64 ++#define HYPERVISOR_VIRT_START (0xffff800000000000) ++#define HYPERVISOR_VIRT_END (0xffff880000000000) ++#define DIRECTMAP_VIRT_START (0xffff830000000000) ++#define DIRECTMAP_VIRT_END (0xffff840000000000) ++#define PAGE_OFFSET_XEN_HYPER DIRECTMAP_VIRT_START ++#endif ++ ++#ifdef IA64 ++#define HYPERVISOR_VIRT_START (0xe800000000000000) ++#define HYPERVISOR_VIRT_END (0xf800000000000000) ++#define DEFAULT_SHAREDINFO_ADDR (0xf100000000000000) ++#define PERCPU_PAGE_SIZE 65536 ++#define PERCPU_ADDR (DEFAULT_SHAREDINFO_ADDR - PERCPU_PAGE_SIZE) ++#define DIRECTMAP_VIRT_START (0xf000000000000000) ++#define DIRECTMAP_VIRT_END PERCPU_ADDR ++#define VIRT_FRAME_TABLE_SIZE (0x0100000000000000) ++ ++#define PERCPU_VIRT_ADDR(vaddr) \ ++ (((vaddr) >= PERCPU_ADDR) && ((vaddr) < PERCPU_ADDR + PERCPU_PAGE_SIZE)) ++ ++#define FRAME_TABLE_VIRT_ADDR(vaddr) \ ++ ((vaddr) >= xhmachdep->frame_table && (vaddr) < xhmachdep->frame_table + VIRT_FRAME_TABLE_SIZE) ++ ++#undef IA64_RBS_OFFSET ++#define IA64_RBS_OFFSET ((XEN_HYPER_SIZE(vcpu) + 15) & ~15) ++ ++#endif /* IA64 */ ++ ++#define DIRECTMAP_VIRT_ADDR(vaddr) \ ++ (((vaddr) >= DIRECTMAP_VIRT_START) && ((vaddr) < DIRECTMAP_VIRT_END)) ++ ++typedef uint16_t domid_t; ++typedef uint32_t Elf_Word; ++ ++/* ++ * NOTE kakuma: The following defines are temporary version for ++ * elf note format which is used only in crash. ++ */ ++#define XEN_HYPER_ELF_NOTE_V1 1 ++#define XEN_HYPER_ELF_NOTE_V2 2 ++#define XEN_HYPER_ELF_NOTE_V3 3 ++#define XEN_HYPER_ELF_NOTE_V4 4 ++ ++#ifdef X86 ++#define XEN_HYPER_ELF_NOTE_V4_NOTE_SIZE 0x100 ++#endif ++#if defined(X86_64) || defined(IA64) ++#define XEN_HYPER_ELF_NOTE_V4_NOTE_SIZE 0x200 ++#endif ++ ++/* ++ * Xen Hyper ++ */ ++#define XEN_HYPER_SMP (0x400) ++ ++#ifdef X86 ++#define XEN_HYPER_MAX_VIRT_CPUS (32) ++#define XEN_HYPER_HZ 100 ++#endif ++#ifdef X86_64 ++#define XEN_HYPER_MAX_VIRT_CPUS (32) ++#define XEN_HYPER_HZ 100 ++#endif ++#ifdef IA64 ++#define XEN_HYPER_MAX_VIRT_CPUS (64) ++#define XEN_HYPER_HZ 100 ++#endif ++#ifndef XEN_HYPER_MAX_VIRT_CPUS ++#define XEN_HYPER_MAX_VIRT_CPUS (1) ++#endif ++ ++#if defined(X86) || defined(X86_64) ++#define XEN_HYPER_PERCPU_SHIFT 12 ++#define xen_hyper_per_cpu(var, cpu) \ ++ ((ulong)(var) + (((ulong)(cpu))<flags & XEN_HYPER_SMP) ? \ ++ (ulong)(var) + (xht->__per_cpu_offset[cpu]) : \ ++ (ulong)(var)) ++#endif ++ ++#if defined(X86) || defined(X86_64) ++#define XEN_HYPER_STACK_ORDER 2 ++#if 0 ++#define XEN_HYPER_STACK_SIZE (machdep->pagesize << XEN_HYPER_STACK_ORDER) ++#endif ++#define XEN_HYPER_GET_CPU_INFO(sp) \ ++ ((sp & ~(STACKSIZE()-1)) | \ ++ (STACKSIZE() - XEN_HYPER_SIZE(cpu_info))) ++#endif ++ ++#define XEN_HYPER_CONRING_SIZE 16384 ++ ++/* system time */ ++#define XEN_HYPER_NANO_TO_SEC(ns) ((ulonglong)((ns) / 1000000000ULL)) ++#define XEN_HYPER_MICR_TO_SEC(us) ((ulonglong)((us) / 1000000ULL)) ++#define XEN_HYPER_MILI_TO_SEC(ms) ((ulonglong)((ms) / 1000ULL)) ++ ++/* ++ * Domain ++ */ ++/* Prepared domain ID. */ ++#define XEN_HYPER_DOMID_IO (0x7FF1U) ++#define XEN_HYPER_DOMID_XEN (0x7FF2U) ++ ++/* Domain flags (domain_flags). */ ++ /* Is this domain privileged? */ ++#define XEN_HYPER__DOMF_privileged 0 ++#define XEN_HYPER_DOMF_privileged (1UL<= 0) ++#define XEN_HYPER_VALID_STRUCT(X) (xen_hyper_size_table.X >= 0) ++#define XEN_HYPER_VALID_MEMBER(X) (xen_hyper_offset_table.X >= 0) ++ ++#define XEN_HYPER_ASSIGN_SIZE(X) (xen_hyper_size_table.X) ++#define XEN_HYPER_ASSIGN_OFFSET(X) (xen_hyper_offset_table.X) ++ ++#define XEN_HYPER_STRUCT_SIZE_INIT(X, Y) (XEN_HYPER_ASSIGN_SIZE(X) = STRUCT_SIZE(Y)) ++#define XEN_HYPER_MEMBER_SIZE_INIT(X, Y, Z) (XEN_HYPER_ASSIGN_SIZE(X) = MEMBER_SIZE(Y, Z)) ++#define XEN_HYPER_MEMBER_OFFSET_INIT(X, Y, Z) (XEN_HYPER_ASSIGN_OFFSET(X) = MEMBER_OFFSET(Y, Z)) ++ ++/* ++ * System ++ */ ++#define XEN_HYPER_MAX_CPUS() (xht->max_cpus) ++#define XEN_HYPER_CRASHING_CPU() (xht->crashing_cpu) ++ ++/* ++ * Dump information ++ */ ++#define XEN_HYPER_X86_NOTE_EIP(regs) (regs[12]) ++#define XEN_HYPER_X86_NOTE_ESP(regs) (regs[15]) ++#define XEN_HYPER_X86_64_NOTE_RIP(regs) (regs[16]) ++#define XEN_HYPER_X86_64_NOTE_RSP(regs) (regs[19]) ++ ++/* ++ * Domain ++ */ ++#define XEN_HYPER_DOMAIN_F_INIT 0x1 ++ ++#define XEN_HYPER_NR_DOMAINS() (xht->domains) ++#define XEN_HYPER_RUNNING_DOMAINS() (xhdt->running_domains) ++ ++/* ++ * Phisycal CPU ++ */ ++#define XEN_HYPER_NR_PCPUS() (xht->pcpus) ++#define for_cpu_indexes(i, cpuid) \ ++ for (i = 0, cpuid = xht->cpu_idxs[i]; \ ++ i < XEN_HYPER_NR_PCPUS(); \ ++ cpuid = xht->cpu_idxs[++i]) ++#define XEN_HYPER_CURR_VCPU(pcpuid) \ ++ (xen_hyper_get_active_vcpu_from_pcpuid(pcpuid)) ++ ++/* ++ * VCPU ++ */ ++#define XEN_HYPER_VCPU_F_INIT 0x1 ++ ++#define XEN_HYPER_NR_VCPUS_IN_DOM(domain_context) (domain_context->vcpu_cnt) ++#define XEN_HYPER_VCPU_LAST_CONTEXT() (xhvct->last) ++ ++/* ++ * tools ++ */ ++#define XEN_HYPER_PRI(fp, len, str, buf, flag, args) \ ++ sprintf args; \ ++ xen_hyper_fpr_indent(fp, len, str, buf, flag); ++#define XEN_HYPER_PRI_CONST(fp, len, str, flag) \ ++ xen_hyper_fpr_indent(fp, len, str, NULL, flag); ++ ++#define XEN_HYPER_PRI_L (0x0) ++#define XEN_HYPER_PRI_R (0x1) ++#define XEN_HYPER_PRI_LF (0x2) ++ ++/* ++ * Global data ++ */ ++extern struct xen_hyper_machdep_table *xhmachdep; ++extern struct xen_hyper_table *xht; ++extern struct xen_hyper_dumpinfo_table *xhdit; ++extern struct xen_hyper_domain_table *xhdt; ++extern struct xen_hyper_vcpu_table *xhvct; ++extern struct xen_hyper_pcpu_table *xhpct; ++extern struct xen_hyper_sched_table *xhscht; ++extern struct xen_hyper_symbol_table_data *xhsymt; ++ ++extern struct xen_hyper_offset_table xen_hyper_offset_table; ++extern struct xen_hyper_size_table xen_hyper_size_table; ++ ++extern struct command_table_entry xen_hyper_command_table[]; ++extern struct task_context fake_tc; ++ ++/* ++ * Xen Hyper command help ++ */ ++extern char *xen_hyper_help_domain[]; ++extern char *xen_hyper_help_doms[]; ++extern char *xen_hyper_help_dumpinfo[]; ++extern char *xen_hyper_help_log[]; ++extern char *xen_hyper_help_pcpus[]; ++extern char *xen_hyper_help_sched[]; ++extern char *xen_hyper_help_sys[]; ++extern char *xen_hyper_help_vcpu[]; ++extern char *xen_hyper_help_vcpus[]; ++ ++/* ++ * Prototype ++ */ ++ulonglong xen_hyper_get_uptime_hyper(void); ++ ++/* ++ * x86 ++ */ ++int xen_hyper_x86_get_smp_cpus(void); ++uint64_t xen_hyper_x86_memory_size(void); ++ ++/* ++ * IA64 ++ */ ++int xen_hyper_ia64_get_smp_cpus(void); ++uint64_t xen_hyper_ia64_memory_size(void); ++ulong xen_hyper_ia64_processor_speed(void); ++ ++/* ++ * Xen Hyper ++ */ ++void xen_hyper_init(void); ++void xen_hyper_domain_init(void); ++void xen_hyper_vcpu_init(void); ++void xen_hyper_dumpinfo_init(void); ++void xen_hyper_misc_init(void); ++void xen_hyper_post_init(void); ++struct xen_hyper_dumpinfo_context *xen_hyper_id_to_dumpinfo_context(uint id); ++struct xen_hyper_dumpinfo_context *xen_hyper_note_to_dumpinfo_context(ulong note); ++char *xen_hyper_fill_elf_notes(ulong note, char *note_buf, int type); ++ ++/* domain */ ++void xen_hyper_refresh_domain_context_space(void); ++int xen_hyper_get_domains(void); ++char *xen_hyper_get_domain_next(int mod, ulong *next); ++domid_t xen_hyper_domain_to_id(ulong domain); ++char *xen_hyper_id_to_domain_struct(domid_t id); ++struct xen_hyper_domain_context * ++xen_hyper_domain_to_domain_context(ulong domain); ++struct xen_hyper_domain_context * ++xen_hyper_id_to_domain_context(domid_t id); ++struct xen_hyper_domain_context * ++xen_hyper_store_domain_context(struct xen_hyper_domain_context *dc, ++ ulong domain, char *dp); ++char *xen_hyper_read_domain_from_context(struct xen_hyper_domain_context *dc); ++char *xen_hyper_read_domain(ulong domain); ++char *xen_hyper_read_domain_verify(ulong domain); ++char *xen_hyper_fill_domain_struct(ulong domain, char *domain_struct); ++void xen_hyper_alloc_domain_context_space(int domains); ++ulong xen_hyper_domain_state(struct xen_hyper_domain_context *dc); ++ ++/* vcpu */ ++void xen_hyper_refresh_vcpu_context_space(void); ++struct xen_hyper_vcpu_context * ++xen_hyper_vcpu_to_vcpu_context(ulong vcpu); ++struct xen_hyper_vcpu_context * ++xen_hyper_id_to_vcpu_context(ulong domain, domid_t did, int vcid); ++struct xen_hyper_vcpu_context_array * ++xen_hyper_domain_to_vcpu_context_array(ulong domain); ++struct xen_hyper_vcpu_context_array * ++xen_hyper_domid_to_vcpu_context_array(domid_t id); ++struct xen_hyper_vcpu_context * ++xen_hyper_store_vcpu_context(struct xen_hyper_vcpu_context *vcc, ++ ulong vcpu, char *vcp); ++char * ++xen_hyper_read_vcpu_from_context(struct xen_hyper_vcpu_context *vcc); ++char *xen_hyper_read_vcpu(ulong vcpu); ++char *xen_hyper_read_vcpu_verify(ulong vcpu); ++char *xen_hyper_fill_vcpu_struct(ulong vcpu, char *vcpu_struct); ++void xen_hyper_alloc_vcpu_context_arrays_space(int domains); ++void xen_hyper_alloc_vcpu_context_space(struct xen_hyper_vcpu_context_array *vcca, int vcpus); ++int xen_hyper_vcpu_state(struct xen_hyper_vcpu_context *vcc); ++ ++/* pcpu */ ++#if defined(X86) || defined(X86_64) ++void xen_hyper_x86_pcpu_init(void); ++#elif defined(IA64) ++void xen_hyper_ia64_pcpu_init(void); ++#endif ++struct xen_hyper_pcpu_context *xen_hyper_id_to_pcpu_context(uint id); ++struct xen_hyper_pcpu_context *xen_hyper_pcpu_to_pcpu_context(ulong pcpu); ++struct xen_hyper_pcpu_context *xen_hyper_store_pcpu_context(struct xen_hyper_pcpu_context *pcc, ++ ulong pcpu, char *pcp); ++struct xen_hyper_pcpu_context *xen_hyper_store_pcpu_context_tss(struct xen_hyper_pcpu_context *pcc, ++ ulong init_tss, char *tss); ++char *xen_hyper_read_pcpu(ulong pcpu); ++char *xen_hyper_fill_pcpu_struct(ulong pcpu, char *pcpu_struct); ++void xen_hyper_alloc_pcpu_context_space(int pcpus); ++ ++/* others */ ++char *xen_hyper_x86_fill_cpu_data(int idx, char *cpuinfo_x86); ++char *xen_hyper_ia64_fill_cpu_data(int idx, char *cpuinfo_ia64); ++int xen_hyper_is_vcpu_crash(struct xen_hyper_vcpu_context *vcc); ++void xen_hyper_print_bt_header(FILE *out, ulong pcpu, int newline); ++ulong xen_hyper_get_active_vcpu_from_pcpuid(ulong pcpu); ++ulong xen_hyper_pcpu_to_active_vcpu(ulong pcpu); ++void xen_hyper_get_cpu_info(void); ++int xen_hyper_test_pcpu_id(uint pcpu_id); ++ ++/* ++ * Xen Hyper command ++ */ ++void xen_hyper_cmd_help(void); ++void xen_hyper_cmd_domain(void); ++void xen_hyper_cmd_doms(void); ++void xen_hyper_cmd_dumpinfo(void); ++void xen_hyper_cmd_log(void); ++void xen_hyper_dump_log(void); ++void xen_hyper_cmd_pcpus(void); ++void xen_hyper_cmd_sched(void); ++void xen_hyper_cmd_sys(void); ++void xen_hyper_cmd_vcpu(void); ++void xen_hyper_cmd_vcpus(void); ++void xen_hyper_display_sys_stats(void); ++ ++void xen_hyper_show_vcpu_context(struct xen_hyper_vcpu_context *vcc); ++char *xen_hyper_domain_state_string(struct xen_hyper_domain_context *dc, ++ char *buf, int verbose); ++char *xen_hyper_vcpu_state_string(struct xen_hyper_vcpu_context *vcc, ++ char *buf, int verbose); ++ ++/* tools */ ++void xen_hyper_fpr_indent(FILE *fp, int len, char *str1, char *str2, int flag); ++ ++#else ++ ++#define XEN_HYPERVISOR_NOT_SUPPORTED \ ++ "Xen hypervisor mode not supported on this architecture\n" ++ ++#endif +--- crash/vas_crash.h.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/vas_crash.h 2006-10-11 09:14:36.000000000 -0400 +@@ -1,8 +1,8 @@ + /* vas_crash.h - kernel crash dump file format (on swap) + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 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 @@ -19,7 +19,7 @@ */ @@ -23138,9 +48048,9 @@ void save_core(void); ---- crash/netdump.h.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/netdump.h 2006-08-31 15:59:44.000000000 -0400 -@@ -24,3 +24,68 @@ +--- crash/netdump.h.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/netdump.h 2007-05-15 15:04:36.000000000 -0400 +@@ -24,3 +24,95 @@ #define NT_TASKSTRUCT 4 #define NT_DISKDUMP 0x70000001 @@ -23160,6 +48070,7 @@ + off_t file_offset; + physaddr_t phys_start; + physaddr_t phys_end; ++ physaddr_t zero_fill; +}; + +struct vmcore_data { @@ -23188,7 +48099,32 @@ +}; + +/* -+ * Proposed ELF note for Xen (writable pagetable) per-vcpu CR3. ++ * ELF note types for Xen dom0/hypervisor kdumps. ++ * The comments below are from xen/include/public/elfnote.h. ++ */ ++ ++/* ++ * System information exported through crash notes. ++ * ++ * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_INFO ++ * note in case of a system crash. This note will contain various ++ * information about the system, see xen/include/xen/elfcore.h. ++ */ ++#define XEN_ELFNOTE_CRASH_INFO 0x1000001 ++ ++/* ++ * System registers exported through crash notes. ++ * ++ * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_REGS ++ * note per cpu in case of a system crash. This note is architecture ++ * specific and will contain registers not saved in the "CORE" note. ++ * See xen/include/xen/elfcore.h for more information. ++ */ ++#define XEN_ELFNOTE_CRASH_REGS 0x1000002 ++ ++ ++/* ++ * For (temporary) backwards compatibility. + */ +#define NT_XEN_KDUMP_CR3 0x10000001 + @@ -23198,6 +48134,7 @@ + ulong p2m_mfn; + char *page; + ulong last_mfn_read; ++ ulong last_pmd_read; + ulong cache_hits; + ulong accesses; + int p2m_frames; @@ -23209,18 +48146,22 @@ +#define KDUMP_MFN_LIST (0x4) + +#define P2M_FAILURE ((physaddr_t)(0xffffffffffffffffLL)) ---- crash/diskdump.h.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/diskdump.h 2005-11-30 15:50:28.000000000 -0500 -@@ -3,6 +3,8 @@ +--- crash/diskdump.h.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/diskdump.h 2007-04-09 12:15:02.000000000 -0400 +@@ -1,8 +1,10 @@ + /* + * diskdump.h * - * Copyright (C) 2004, 2005 David Anderson - * Copyright (C) 2004, 2005 Red Hat, Inc. All rights reserved. +- * Copyright (C) 2004, 2005 David Anderson +- * Copyright (C) 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2004, 2005, 2006 Red Hat, Inc. All rights reserved. + * Copyright (C) 2005 FUJITSU LIMITED + * Copyright (C) 2005 NEC Corporation * * This software may be freely redistributed under the terms of the * GNU General Public License. -@@ -10,7 +12,59 @@ +@@ -10,7 +12,65 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. @@ -23236,6 +48177,7 @@ +#define DUMP_PARTITION_SIGNATURE "diskdump" +#define SIG_LEN (sizeof(DUMP_PARTITION_SIGNATURE) - 1) +#define DISK_DUMP_SIGNATURE "DISKDUMP" ++#define KDUMP_SIGNATURE "KDUMP " + +#define DUMP_HEADER_COMPLETED 0 +#define DUMP_HEADER_INCOMPLETED 1 @@ -23267,6 +48209,11 @@ + long elf_regs; +}; + ++struct kdump_sub_header { ++ unsigned long phys_base; ++ int dump_level; /* header_version 1 and later */ ++}; ++ +/* page flags */ +#define DUMP_DH_COMPRESSED 0x1 /* page is compressed */ + @@ -23282,14 +48229,14 @@ +#define PAGE_VALID (0x1) /* flags */ +#define DISKDUMP_VALID_PAGE(flags) ((flags) & PAGE_VALID) + ---- crash/xendump.h.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/xendump.h 2006-06-09 16:55:17.000000000 -0400 -@@ -0,0 +1,97 @@ +--- crash/xendump.h.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/xendump.h 2007-03-14 10:16:41.000000000 -0500 +@@ -0,0 +1,177 @@ +/* + * xendump.h + * -+ * Copyright (C) 2006 David Anderson -+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2006, 2007 David Anderson ++ * Copyright (C) 2006, 2007 Red Hat, Inc. All rights reserved. + * + * This software may be freely redistributed under the terms of the + * GNU General Public License. @@ -23299,9 +48246,11 @@ + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include ++#include + +#define XC_SAVE_SIGNATURE "LinuxGuestRecord" +#define XC_CORE_MAGIC 0xF00FEBED ++#define XC_CORE_MAGIC_HVM 0xF00FEBEE + +/* + * From xenctrl.h, but probably not on most host machines. @@ -23320,8 +48269,21 @@ + ulong pfn; + ulong cnt; +}; ++#define PFN_TO_OFFSET_CACHE_ENTRIES (5000) + -+#define PFN_TO_OFFSET_CACHE_ENTRIES (1024) ++struct elf_index_pfn { ++ ulong index; ++ ulong pfn; ++}; ++#define INDEX_PFN_COUNT (128) ++ ++struct last_batch { ++ ulong index; ++ ulong start; ++ ulong end; ++ ulong accesses; ++ ulong duplicates; ++}; + +struct xendump_data { + ulong flags; /* XENDUMP_LOCAL, plus anything else... */ @@ -23340,6 +48302,15 @@ + int p2m_frames; + ulong *p2m_frame_index_list; + struct xc_core_header header; ++ int elf_class; ++ uint64_t format_version; ++ off_t elf_strtab_offset; ++ off_t shared_info_offset; ++ off_t ia64_mapped_regs_offset; ++ struct elf_index_pfn elf_index_pfn[INDEX_PFN_COUNT]; ++ struct last_batch last_batch; ++ Elf32_Ehdr *elf32; ++ Elf64_Ehdr *elf64; + } xc_core; + + struct xc_save_data { @@ -23354,15 +48325,22 @@ + off_t *batch_offsets; + ulong batch_count; + ulong *region_pfn_type; ++ ulong ia64_version; ++ ulong *ia64_page_offsets; + } xc_save; + + ulong panic_pc; + ulong panic_sp; +}; + -+#define XC_SAVE (XENDUMP_LOCAL << 1) -+#define XC_CORE (XENDUMP_LOCAL << 2) -+#define XC_CORE_P2M_INIT (XENDUMP_LOCAL << 3) ++#define XC_SAVE (XENDUMP_LOCAL << 1) ++#define XC_CORE_ORIG (XENDUMP_LOCAL << 2) ++#define XC_CORE_P2M_CREATE (XENDUMP_LOCAL << 3) ++#define XC_CORE_PFN_CREATE (XENDUMP_LOCAL << 4) ++#define XC_CORE_NO_P2M (XENDUMP_LOCAL << 5) ++#define XC_SAVE_IA64 (XENDUMP_LOCAL << 6) ++#define XC_CORE_64BIT_HOST (XENDUMP_LOCAL << 7) ++#define XC_CORE_ELF (XENDUMP_LOCAL << 8) + +#define MACHINE_BYTE_ORDER() \ + (machine_type("X86") || \ @@ -23382,8 +48360,168 @@ + +#define MFN_NOT_FOUND (-1) +#define PFN_NOT_FOUND (-1) ---- crash/lkcd_vmdump_v1.h.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/lkcd_vmdump_v1.h 2006-08-07 13:51:35.000000000 -0400 ++ ++#define INVALID_MFN (~0UL) ++ ++/* ++ * ia64 "xm save" format is completely different than the others. ++ */ ++typedef struct xen_domctl_arch_setup { ++ uint64_t flags; /* XEN_DOMAINSETUP_* */ ++/* #ifdef __ia64__ */ ++ uint64_t bp; /* mpaddr of boot param area */ ++ uint64_t maxmem; /* Highest memory address for MDT. */ ++ uint64_t xsi_va; /* Xen shared_info area virtual address. */ ++ uint32_t hypercall_imm; /* Break imm for Xen hypercalls. */ ++/* #endif */ ++} xen_domctl_arch_setup_t; ++ ++/* ++ * xc_core ELF note, which differs from the standard Elf[32|64]_Nhdr ++ * structure by the additional name field. ++ */ ++struct elfnote { ++ uint32_t namesz; ++ uint32_t descsz; ++ uint32_t type; ++ char name[4]; ++}; ++ ++#define XEN_ELFNOTE_DUMPCORE_NONE 0x2000000 ++#define XEN_ELFNOTE_DUMPCORE_HEADER 0x2000001 ++#define XEN_ELFNOTE_DUMPCORE_XEN_VERSION 0x2000002 ++#define XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION 0x2000003 ++ ++struct xen_dumpcore_elfnote_header_desc { ++ uint64_t xch_magic; ++ uint64_t xch_nr_vcpus; ++ uint64_t xch_nr_pages; ++ uint64_t xch_page_size; ++}; ++ ++#define FORMAT_VERSION_0000000000000001 0x0000000000000001ULL ++ ++struct xen_dumpcore_elfnote_format_version_desc { ++ uint64_t version; ++}; ++ ++struct xen_dumpcore_p2m { ++ uint64_t pfn; ++ uint64_t gmfn; ++}; +--- crash/unwind_x86.h.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/unwind_x86.h 2006-10-20 15:42:08.000000000 -0400 +@@ -0,0 +1,2 @@ ++ ++ +--- crash/unwind_x86_64.h.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/unwind_x86_64.h 2006-10-20 15:42:08.000000000 -0400 +@@ -0,0 +1,92 @@ ++#define CONFIG_64BIT 1 ++#define NULL ((void *)0) ++ ++typedef unsigned long size_t; ++typedef unsigned char u8; ++typedef signed short s16; ++typedef unsigned short u16; ++typedef signed int s32; ++typedef unsigned int u32; ++typedef unsigned long long u64; ++ ++struct pt_regs { ++ unsigned long r15; ++ unsigned long r14; ++ unsigned long r13; ++ unsigned long r12; ++ unsigned long rbp; ++ unsigned long rbx; ++/* arguments: non interrupts/non tracing syscalls only save upto here*/ ++ unsigned long r11; ++ unsigned long r10; ++ unsigned long r9; ++ unsigned long r8; ++ unsigned long rax; ++ unsigned long rcx; ++ unsigned long rdx; ++ unsigned long rsi; ++ unsigned long rdi; ++ unsigned long orig_rax; ++/* end of arguments */ ++/* cpu exception frame or undefined */ ++ unsigned long rip; ++ unsigned long cs; ++ unsigned long eflags; ++ unsigned long rsp; ++ unsigned long ss; ++/* top of stack page */ ++}; ++ ++struct unwind_frame_info ++{ ++ struct pt_regs regs; ++}; ++ ++extern int unwind(struct unwind_frame_info *); ++extern void init_unwind_table(void); ++extern void free_unwind_table(void); ++ ++#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) ++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) ++#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) ++#define BUILD_BUG_ON_ZERO(e) (sizeof(char[1 - 2 * !!(e)]) - 1) ++#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) ++#define get_unaligned(ptr) (*(ptr)) ++//#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr))) ++#define THREAD_ORDER 1 ++#define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER) ++ ++#define UNW_PC(frame) (frame)->regs.rip ++#define UNW_SP(frame) (frame)->regs.rsp ++#ifdef CONFIG_FRAME_POINTER ++ #define UNW_FP(frame) (frame)->regs.rbp ++ #define FRAME_RETADDR_OFFSET 8 ++ #define FRAME_LINK_OFFSET 0 ++ #define STACK_BOTTOM(tsk) (((tsk)->thread.rsp0 - 1) & ~(THREAD_SIZE - 1)) ++ #define STACK_TOP(tsk) ((tsk)->thread.rsp0) ++#endif ++ ++ ++#define EXTRA_INFO(f) { BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) % FIELD_SIZEOF(struct unwind_frame_info, f)) + offsetof(struct unwind_frame_info, f)/ FIELD_SIZEOF(struct unwind_frame_info, f), FIELD_SIZEOF(struct unwind_frame_info, f) } ++ ++#define PTREGS_INFO(f) EXTRA_INFO(regs.f) ++ ++#define UNW_REGISTER_INFO \ ++ PTREGS_INFO(rax),\ ++ PTREGS_INFO(rdx),\ ++ PTREGS_INFO(rcx),\ ++ PTREGS_INFO(rbx), \ ++ PTREGS_INFO(rsi), \ ++ PTREGS_INFO(rdi), \ ++ PTREGS_INFO(rbp), \ ++ PTREGS_INFO(rsp), \ ++ PTREGS_INFO(r8), \ ++ PTREGS_INFO(r9), \ ++ PTREGS_INFO(r10),\ ++ PTREGS_INFO(r11), \ ++ PTREGS_INFO(r12), \ ++ PTREGS_INFO(r13), \ ++ PTREGS_INFO(r14), \ ++ PTREGS_INFO(r15), \ ++ PTREGS_INFO(rip) ++ +--- crash/lkcd_vmdump_v1.h.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/lkcd_vmdump_v1.h 2006-10-11 09:14:35.000000000 -0400 +@@ -1,8 +1,8 @@ + /* lkcd_vmdump_v1.h - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 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 @@ -114,8 +114,12 @@ /* the dump registers */ @@ -23397,8 +48535,19 @@ /* the address of the current task */ struct task_struct *dh_current_task; ---- crash/lkcd_vmdump_v2_v3.h.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/lkcd_vmdump_v2_v3.h 2006-08-07 15:00:27.000000000 -0400 +--- crash/lkcd_vmdump_v2_v3.h.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/lkcd_vmdump_v2_v3.h 2006-10-11 09:14:35.000000000 -0400 +@@ -1,8 +1,8 @@ + /* lkcd_vmdump_v2_v3.h - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 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 @@ -81,7 +81,11 @@ uint32_t dha_eip; @@ -23411,8 +48560,19 @@ } dump_header_asm_t; ---- crash/lkcd_dump_v5.h.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/lkcd_dump_v5.h 2006-03-22 09:11:11.000000000 -0500 +--- crash/lkcd_dump_v5.h.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/lkcd_dump_v5.h 2006-10-11 09:14:35.000000000 -0400 +@@ -1,8 +1,8 @@ + /* lkcd_dump_v5.h - core analysis suite + * + * Copyright (C) 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 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 @@ -35,7 +35,7 @@ #ifndef _DUMP_H #define _DUMP_H @@ -23422,8 +48582,19 @@ /* define TRUE and FALSE for use in our dump modules */ #ifndef FALSE ---- crash/lkcd_dump_v7.h.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/lkcd_dump_v7.h 2006-03-22 09:11:11.000000000 -0500 +--- crash/lkcd_dump_v7.h.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/lkcd_dump_v7.h 2006-10-11 09:14:35.000000000 -0400 +@@ -1,8 +1,8 @@ + /* lkcd_dump_v5.h - core analysis suite + * + * Copyright (C) 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson +- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson ++ * Copyright (C) 2002, 2003, 2004, 2005, 2006 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 @@ -35,7 +35,7 @@ #ifndef _DUMP_H #define _DUMP_H @@ -23433,16 +48604,16 @@ /* define TRUE and FALSE for use in our dump modules */ #ifndef FALSE ---- crash/Makefile.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/Makefile 2006-09-13 11:10:22.000000000 -0400 +--- crash/Makefile.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/Makefile 2007-08-27 15:02:36.000000000 -0400 @@ -3,8 +3,8 @@ # Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. # www.missioncriticallinux.com, info@missioncriticallinux.com # -# Copyright (C) 2002, 2003, 2004, 2005 David Anderson -# Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. -+# Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson -+# Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. ++# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson ++# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 @@ -23461,16 +48632,21 @@ # # Default installation directory # -@@ -62,7 +64,7 @@ +@@ -60,22 +62,25 @@ + # (2) Or invoke make like so: + # make LDFLAGS=-static NAT_CLIBS="-lc -lresolv" GDBSERVER_LIBS="-lc -lresolv" - GENERIC_HFILES=defs.h +-GENERIC_HFILES=defs.h ++GENERIC_HFILES=defs.h xen_hyper_defs.h MCORE_HFILES=va_server.h vas_crash.h -REDHAT_HFILES=netdump.h diskdump.h +REDHAT_HFILES=netdump.h diskdump.h xendump.h LKCD_DUMP_HFILES=lkcd_vmdump_v1.h lkcd_vmdump_v2_v3.h lkcd_dump_v5.h \ lkcd_dump_v7.h lkcd_dump_v8.h lkcd_fix_mem.h LKCD_TRACE_HFILES=lkcd_x86_trace.h -@@ -71,11 +73,11 @@ + IBM_HFILES=ibm_common.h +-UNWIND_HFILES=unwind.h unwind_i.h rse.h ++UNWIND_HFILES=unwind.h unwind_i.h rse.h unwind_x86.h unwind_x86_64.h CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \ kernel.c test.c gdb_interface.c configure.c net.c dev.c \ @@ -23480,11 +48656,14 @@ lkcd_common.c lkcd_v1.c lkcd_v2_v3.c lkcd_v5.c lkcd_v7.c lkcd_v8.c\ lkcd_fix_mem.c s390_dump.c lkcd_x86_trace.c \ - netdump.c diskdump.c unwind.c unwind_decoder.c -+ netdump.c diskdump.c xendump.c unwind.c unwind_decoder.c ++ netdump.c diskdump.c xendump.c unwind.c unwind_decoder.c \ ++ unwind_x86_32_64.c \ ++ xen_hyper.c xen_hyper_command.c xen_hyper_global_data.c \ ++ xen_hyper_dump_tables.c SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \ ${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \ -@@ -83,12 +85,21 @@ +@@ -83,11 +88,23 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \ build_data.o kernel.o test.o gdb_interface.o net.o dev.o \ @@ -23493,9 +48672,13 @@ extensions.o remote.o va_server.o va_server_v1.o symbols.o cmdline.o \ lkcd_common.o lkcd_v1.o lkcd_v2_v3.o lkcd_v5.o lkcd_v7.o lkcd_v8.o \ - lkcd_fix_mem.o s390_dump.o netdump.o diskdump.o \ +- lkcd_x86_trace.o unwind_v1.o unwind_v2.o unwind_v3.o + lkcd_fix_mem.o s390_dump.o netdump.o diskdump.o xendump.o \ - lkcd_x86_trace.o unwind_v1.o unwind_v2.o unwind_v3.o - ++ lkcd_x86_trace.o unwind_v1.o unwind_v2.o unwind_v3.o \ ++ unwind_x86_32_64.o \ ++ xen_hyper.o xen_hyper_command.o xen_hyper_global_data.o \ ++ xen_hyper_dump_tables.o ++ +# These are the current set of crash extensions sources. They are not built +# by default unless the third command line of the "all:" stanza is uncommented. +# Alternatively, they can be built by entering "make extensions" from this @@ -23504,11 +48687,10 @@ +EXTENSIONS=extensions +EXTENSION_SOURCE_FILES=${EXTENSIONS}/Makefile ${EXTENSIONS}/echo.c ${EXTENSIONS}/dminfo.c +EXTENSION_OBJECT_FILES=echo.so dminfo.so -+ + DAEMON_OBJECT_FILES=remote_daemon.o va_server.o va_server_v1.o \ lkcd_common.o lkcd_v1.o lkcd_v2_v3.o lkcd_v5.o lkcd_v7.o lkcd_v8.o \ - s390_dump.o netdump_daemon.o -@@ -150,10 +161,11 @@ +@@ -150,10 +167,11 @@ ${GDB}/gdb/main.c ${GDB}/gdb/symtab.c ${GDB}/gdb/target.c \ ${GDB}/gdb/symfile.c ${GDB}/gdb/elfread.c \ ${GDB}/gdb/ui-file.c ${GDB}/gdb/utils.c ${GDB}/gdb/dwarf2read.c \ @@ -23522,7 +48704,7 @@ # # GDB_FLAGS is passed up from the gdb Makefile. -@@ -175,7 +187,8 @@ +@@ -175,7 +193,8 @@ CFLAGS=-g -D${TARGET} ${TARGET_CFLAGS} @@ -23532,7 +48714,7 @@ CSCOPE_FILES=${SOURCE_FILES} READLINE_DIRECTORY=./${GDB}/readline -@@ -184,9 +197,13 @@ +@@ -184,9 +203,13 @@ REDHATFLAGS=-DREDHAT @@ -23546,7 +48728,7 @@ gdb_merge: force @if [ ! -f ${GDB}/README ]; then \ -@@ -206,6 +223,11 @@ +@@ -206,6 +229,11 @@ @for FILE in ${GDB_FILES}; do\ echo $$FILE >> gdb.files; done @tar --exclude-from gdb.files -xvzmf ${GDB}.tar.gz @@ -23558,7 +48740,7 @@ library: make_build_data ${OBJECT_FILES} ar -rs ${PROGRAM}lib.a ${OBJECT_FILES} -@@ -318,7 +340,7 @@ +@@ -318,7 +346,7 @@ remote_daemon.o: ${GENERIC_HFILES} remote.c cc -c ${CFLAGS} -DDAEMON remote.c -o remote_daemon.o ${WARNING_OPTIONS} ${WARNING_ERROR} @@ -23567,7 +48749,23 @@ cc -c ${CFLAGS} -DMCLX x86.c ${WARNING_OPTIONS} ${WARNING_ERROR} alpha.o: ${GENERIC_HFILES} alpha.c -@@ -342,6 +364,9 @@ +@@ -327,13 +355,13 @@ + ppc.o: ${GENERIC_HFILES} ppc.c + cc -c ${CFLAGS} ppc.c ${WARNING_OPTIONS} ${WARNING_ERROR} + +-ia64.o: ${GENERIC_HFILES} ia64.c ++ia64.o: ${GENERIC_HFILES} ${REDHAT_HFILES} ia64.c + cc -c ${CFLAGS} ia64.c ${WARNING_OPTIONS} ${WARNING_ERROR} + + ppc64.o: ${GENERIC_HFILES} ppc64.c + cc -c ${CFLAGS} ppc64.c ${WARNING_OPTIONS} ${WARNING_ERROR} + +-x86_64.o: ${GENERIC_HFILES} x86_64.c ++x86_64.o: ${GENERIC_HFILES} ${REDHAT_HFILES} x86_64.c + cc -c ${CFLAGS} x86_64.c ${WARNING_OPTIONS} ${WARNING_ERROR} + + s390.o: ${GENERIC_HFILES} ${IBM_HFILES} s390.c +@@ -342,6 +370,9 @@ s390x.o: ${GENERIC_HFILES} ${IBM_HFILES} s390x.c cc -c ${CFLAGS} s390x.c ${WARNING_OPTIONS} ${WARNING_ERROR} @@ -23577,7 +48775,7 @@ s390_dump.o: ${GENERIC_HFILES} ${IBM_HFILES} s390_dump.c cc -c ${CFLAGS} s390_dump.c ${WARNING_OPTIONS} ${WARNING_ERROR} -@@ -353,6 +378,9 @@ +@@ -353,12 +384,18 @@ diskdump.o: ${GENERIC_HFILES} ${REDHAT_HFILES} diskdump.c cc -c ${CFLAGS} diskdump.c ${WARNING_OPTIONS} ${WARNING_ERROR} @@ -23587,7 +48785,35 @@ extensions.o: ${GENERIC_HFILES} extensions.c cc -c ${CFLAGS} extensions.c ${WARNING_OPTIONS} ${WARNING_ERROR} -@@ -393,13 +421,13 @@ + lkcd_x86_trace.o: ${GENERIC_HFILES} ${LKCD_TRACE_HFILES} lkcd_x86_trace.c + cc -c ${CFLAGS} -DREDHAT lkcd_x86_trace.c ${WARNING_OPTIONS} ${WARNING_ERROR} + ++unwind_x86_32_64.o: ${GENERIC_HFILES} ${UNWIND_HFILES} unwind_x86_32_64.c ++ cc -c ${CFLAGS} unwind_x86_32_64.c -o unwind_x86_32_64.o ${WARNING_OPTIONS} ${WARNING_ERROR} ++ + unwind_v1.o: ${GENERIC_HFILES} ${UNWIND_HFILES} unwind.c unwind_decoder.c + cc -c ${CFLAGS} -DREDHAT -DUNWIND_V1 unwind.c -o unwind_v1.o ${WARNING_OPTIONS} ${WARNING_ERROR} + +@@ -371,6 +408,18 @@ + lkcd_fix_mem.o: ${GENERIC_HFILES} ${LKCD_HFILES} lkcd_fix_mem.c + cc -c ${CFLAGS} lkcd_fix_mem.c ${WARNING_OPTIONS} ${WARNING_ERROR} + ++xen_hyper.o: ${GENERIC_HFILES} xen_hyper.c ++ cc -c ${CFLAGS} xen_hyper.c ${WARNING_OPTIONS} ${WARNING_ERROR} ++ ++xen_hyper_command.o: ${GENERIC_HFILES} xen_hyper_command.c ++ cc -c ${CFLAGS} xen_hyper_command.c ${WARNING_OPTIONS} ${WARNING_ERROR} ++ ++xen_hyper_global_data.o: ${GENERIC_HFILES} xen_hyper_global_data.c ++ cc -c ${CFLAGS} xen_hyper_global_data.c ${WARNING_OPTIONS} ${WARNING_ERROR} ++ ++xen_hyper_dump_tables.o: ${GENERIC_HFILES} xen_hyper_dump_tables.c ++ cc -c ${CFLAGS} xen_hyper_dump_tables.c ${WARNING_OPTIONS} ${WARNING_ERROR} ++ + ${PROGRAM}: force + @make --no-print-directory all + +@@ -393,13 +442,13 @@ gdb_files: make_configure @./configure -q -b @@ -23596,24 +48822,27 @@ show_files: @if [ -f ${PROGRAM} ]; then \ - ./${PROGRAM} --no_crashrc -h README > README; fi +- ./${PROGRAM} --no_crashrc -h README > README; fi - @echo ${SOURCE_FILES} Makefile ${GDB_FILES} COPYING README \ - .rh_rpm_package crash.8 ++ ./${PROGRAM} --no_scroll --no_crashrc -h README > README; echo $?; fi + @echo ${SOURCE_FILES} Makefile ${GDB_FILES} ${GDB_PATCH_FILES} COPYING README \ + .rh_rpm_package crash.8 ${EXTENSION_SOURCE_FILES} ctags: ctags ${SOURCE_FILES} -@@ -411,7 +439,7 @@ +@@ -410,8 +459,8 @@ + do_tar: @if [ -f ${PROGRAM} ]; then \ - ./${PROGRAM} --no_crashrc -h README > README; fi +- ./${PROGRAM} --no_crashrc -h README > README; fi - tar cvzf ${PROGRAM}.tar.gz ${TAR_FILES} ${GDB_FILES} ++ ./${PROGRAM} --no_scroll --no_crashrc -h README > README; fi + tar cvzf ${PROGRAM}.tar.gz ${TAR_FILES} ${GDB_FILES} ${GDB_PATCH_FILES} @echo; ls -l ${PROGRAM}.tar.gz # To create a base tar file for Red Hat RPM packaging, pass the base RPM -@@ -421,7 +449,7 @@ +@@ -421,12 +470,12 @@ # spec file will have its own release number, which will in turn get passed # to the "all" target upon the initial build. @@ -23622,7 +48851,13 @@ release: make_configure @if [ "`id --user`" != "0" ]; then \ -@@ -446,8 +474,8 @@ + echo "make release: must be super-user"; exit 1; fi +- @./configure -p "RPMPKG=${RPMPKG}" -u -g ++ @./configure -P "RPMPKG=${RPMPKG}" -u -g + @make --no-print-directory release_configure + @echo + @echo "cvs tag this release if necessary" +@@ -446,10 +495,10 @@ @rm -f ${PROGRAM}-${RELEASE}.tar.gz @rm -f ${PROGRAM}-${RELEASE}.src.rpm @chown root ./RELDIR/${PROGRAM}-${RELEASE} @@ -23631,9 +48866,21 @@ + @tar cf - ${SOURCE_FILES} Makefile ${GDB_FILES} ${GDB_PATCH_FILES} COPYING \ + .rh_rpm_package crash.8 ${EXTENSION_SOURCE_FILES} | (cd ./RELDIR/${PROGRAM}-${RELEASE}; tar xf -) @cp ${GDB}.tar.gz ./RELDIR/${PROGRAM}-${RELEASE} - @./${PROGRAM} --no_crashrc -h README > ./RELDIR/${PROGRAM}-${RELEASE}/README +- @./${PROGRAM} --no_crashrc -h README > ./RELDIR/${PROGRAM}-${RELEASE}/README ++ @./${PROGRAM} --no_scroll --no_crashrc -h README > ./RELDIR/${PROGRAM}-${RELEASE}/README @(cd ./RELDIR; find . -exec chown root {} ";") -@@ -488,3 +516,10 @@ + @(cd ./RELDIR; find . -exec chgrp root {} ";") + @(cd ./RELDIR; find . -exec touch {} ";") +@@ -464,7 +513,7 @@ + cp ${PROGRAM}-${RELEASE}.tar.gz /usr/src/redhat/SOURCES; \ + /usr/bin/rpmbuild -bs ${PROGRAM}.spec > /dev/null; \ + rm -f /usr/src/redhat/SOURCES/${PROGRAM}-${RELEASE}.tar.gz; \ +- cp /usr/src/redhat/SRPMS/${PROGRAM}-${RELEASE}.src.rpm . ; \ ++ mv /usr/src/redhat/SRPMS/${PROGRAM}-${RELEASE}.src.rpm . ; \ + ls -l ${PROGRAM}-${RELEASE}.src.rpm; \ + exit 0; fi + +@@ -488,3 +537,11 @@ dis: objdump --disassemble --line-numbers ${PROGRAM} > ${PROGRAM}.dis @@ -23643,11 +48890,12 @@ + @make --no-print-directory do_extensions + +do_extensions: -+ @(cd extensions; make -i OBJECTS="$(EXTENSION_OBJECT_FILES)" TARGET=$(TARGET)) ---- crash/gdb-6.1.patch.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/gdb-6.1.patch 2006-01-03 14:48:26.000000000 -0500 -@@ -0,0 +1,11 @@ -+--- gdb-6.1/bfd/coff-alpha.c.orig ++ @(cd extensions; make -i OBJECTS="$(EXTENSION_OBJECT_FILES)" \ ++ TARGET=$(TARGET) TARGET_CFLAGS=$(TARGET_CFLAGS)) +--- crash/gdb-6.1.patch.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/gdb-6.1.patch 2007-04-03 11:43:05.000000000 -0400 +@@ -0,0 +1,87 @@ ++--- gdb-6.1.orig/bfd/coff-alpha.c ++++ gdb-6.1/bfd/coff-alpha.c +@@ -1455,7 +1455,7 @@ alpha_relocate_section (output_bfd, info + amt = sizeof (struct ecoff_section_tdata); @@ -23658,18 +48906,94 @@ + } + + if (lita_sec_data->gp != 0) ---- crash/README.orig 2006-09-13 11:10:23.000000000 -0400 -+++ crash/README 2006-09-13 11:10:21.000000000 -0400 ++--- gdb-6.1.orig/sim/ppc/debug.c +++++ gdb-6.1/sim/ppc/debug.c ++@@ -28,6 +28,7 @@ ++ #ifdef HAVE_STDLIB_H ++ #include ++ #endif +++#include ++ ++ int ppc_trace[nr_trace_options]; ++ ++--- gdb-6.1.orig/gdb/remote.c +++++ gdb-6.1/gdb/remote.c ++@@ -3445,7 +3445,7 @@ remote_store_registers (int regnum) ++ { ++ int i; ++ regs = alloca (rs->sizeof_g_packet); ++- memset (regs, rs->sizeof_g_packet, 0); +++ memset (regs, 0, rs->sizeof_g_packet); ++ for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++) ++ { ++ struct packet_reg *r = &rs->regs[i]; ++--- gdb-6.1.orig/gdb/std-regs.c +++++ gdb-6.1/gdb/std-regs.c ++@@ -61,7 +61,7 @@ value_of_builtin_frame_reg (struct frame ++ val = allocate_value (builtin_type_frame_reg); ++ VALUE_LVAL (val) = not_lval; ++ buf = VALUE_CONTENTS_RAW (val); ++- memset (buf, TYPE_LENGTH (VALUE_TYPE (val)), 0); +++ memset (buf, 0, TYPE_LENGTH (VALUE_TYPE (val))); ++ /* frame.base. */ ++ if (frame != NULL) ++ ADDRESS_TO_POINTER (builtin_type_void_data_ptr, buf, ++@@ -87,7 +87,7 @@ value_of_builtin_frame_fp_reg (struct fr ++ struct value *val = allocate_value (builtin_type_void_data_ptr); ++ char *buf = VALUE_CONTENTS_RAW (val); ++ if (frame == NULL) ++- memset (buf, TYPE_LENGTH (VALUE_TYPE (val)), 0); +++ memset (buf, 0, TYPE_LENGTH (VALUE_TYPE (val))); ++ else ++ ADDRESS_TO_POINTER (builtin_type_void_data_ptr, buf, ++ get_frame_base_address (frame)); ++@@ -105,7 +105,7 @@ value_of_builtin_frame_pc_reg (struct fr ++ struct value *val = allocate_value (builtin_type_void_data_ptr); ++ char *buf = VALUE_CONTENTS_RAW (val); ++ if (frame == NULL) ++- memset (buf, TYPE_LENGTH (VALUE_TYPE (val)), 0); +++ memset (buf, 0, TYPE_LENGTH (VALUE_TYPE (val))); ++ else ++ ADDRESS_TO_POINTER (builtin_type_void_data_ptr, buf, ++ get_frame_pc (frame)); ++--- gdb-6.1.orig/gdb/dwarf2-frame.c +++++ gdb-6.1/gdb/dwarf2-frame.c ++@@ -1353,7 +1353,9 @@ decode_frame_entry_1 (struct comp_unit * ++ else if (*augmentation == 'P') ++ { ++ /* Skip. */ ++- buf += size_of_encoded_value (*buf++); +++// buf += size_of_encoded_value (*buf++); +++ buf += size_of_encoded_value(*buf); +++ buf++; ++ augmentation++; ++ } ++ ++--- gdb-6.1/opcodes/i386-dis.c.orig +++++ gdb-6.1/opcodes/i386-dis.c ++@@ -2092,6 +2092,10 @@ print_insn (bfd_vma pc, disassemble_info ++ dp = &dis386_twobyte[*++codep]; ++ need_modrm = twobyte_has_modrm[*codep]; ++ uses_SSE_prefix = twobyte_uses_SSE_prefix[*codep]; +++ if (dp->name && strcmp(dp->name, "ud2a") == 0) { +++ extern int kernel_BUG_encoding_bytes(void); +++ codep += kernel_BUG_encoding_bytes(); +++ } ++ } ++ else ++ { +--- crash/README.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/README 2007-08-27 15:02:34.000000000 -0400 @@ -69,7 +69,7 @@ After the kernel is re-compiled, the uncompressed "vmlinux" kernel that is created in the top-level kernel build directory must be saved. - To build this utility, simply uncompress the tar file, enter the crash-4.0 -+ To build this utility, simply uncompress the tar file, enter the crash-4.0-3.3 ++ To build this utility, simply uncompress the tar file, enter the crash-4.0-4.6 subdirectory, and type "make". The initial build will take several minutes because the gdb module must be configured and and built. Alternatively, the crash source RPM file may be installed and built, and the resultant crash -@@ -89,10 +89,12 @@ +@@ -89,11 +89,14 @@ $ crash @@ -23677,34 +49001,37 @@ - Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. - Copyright (C) 2004, 2005 IBM Corporation - Copyright (C) 1999-2005 Hewlett-Packard Co -+ crash 4.0-3.3 -+ Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. +- Copyright (C) 1999, 2002 Silicon Graphics, Inc. ++ crash 4.0-4.6 ++ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. + Copyright (C) 2004, 2005, 2006 IBM Corporation + Copyright (C) 1999-2006 Hewlett-Packard Co -+ Copyright (C) 2005 Fujitsu Limited ++ Copyright (C) 2005, 2006 Fujitsu Limited ++ Copyright (C) 2006, 2007 VA Linux Systems Japan K.K. + Copyright (C) 2005 NEC Corporation - Copyright (C) 1999, 2002 Silicon Graphics, Inc. ++ Copyright (C) 1999, 2002, 2007 Silicon Graphics, Inc. Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. This program is free software, covered by the GNU General Public License, -@@ -111,7 +113,7 @@ + and you are welcome to change it and/or distribute copies of it under +@@ -111,7 +114,7 @@ KERNEL: /boot/vmlinux DUMPFILE: /dev/mem CPUS: 1 - DATE: Wed Jul 13 13:26:00 2005 -+ DATE: Wed Sep 13 11:10:21 2006 ++ DATE: Mon Aug 27 15:02:34 2007 UPTIME: 10 days, 22:55:18 LOAD AVERAGE: 0.08, 0.03, 0.01 TASKS: 42 -@@ -139,7 +141,7 @@ +@@ -139,7 +142,7 @@ exit log rd task extend mach repeat timer - crash version: 4.0 gdb version: 6.1 -+ crash version: 4.0-3.3 gdb version: 6.1 ++ crash version: 4.0-4.6 gdb version: 6.1 For help on any command above, enter "help ". For help on input options, enter "help input". For help on output options, enter "help output". -@@ -152,10 +154,12 @@ +@@ -152,11 +155,14 @@ $ crash vmlinux vmcore @@ -23712,16 +49039,19 @@ - Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. - Copyright (C) 2004, 2005 IBM Corporation - Copyright (C) 1999-2005 Hewlett-Packard Co -+ crash 4.0-3.3 -+ Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. +- Copyright (C) 1999, 2002 Silicon Graphics, Inc. ++ crash 4.0-4.6 ++ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. + Copyright (C) 2004, 2005, 2006 IBM Corporation + Copyright (C) 1999-2006 Hewlett-Packard Co -+ Copyright (C) 2005 Fujitsu Limited ++ Copyright (C) 2005, 2006 Fujitsu Limited ++ Copyright (C) 2006, 2007 VA Linux Systems Japan K.K. + Copyright (C) 2005 NEC Corporation - Copyright (C) 1999, 2002 Silicon Graphics, Inc. ++ Copyright (C) 1999, 2002, 2007 Silicon Graphics, Inc. Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. This program is free software, covered by the GNU General Public License, -@@ -196,10 +200,12 @@ + and you are welcome to change it and/or distribute copies of it under +@@ -196,11 +202,14 @@ $ crash vmlinux.17 lcore.cr.17 @@ -23729,12 +49059,169 @@ - Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. - Copyright (C) 2004, 2005 IBM Corporation - Copyright (C) 1999-2005 Hewlett-Packard Co -+ crash 4.0-3.3 -+ Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. +- Copyright (C) 1999, 2002 Silicon Graphics, Inc. ++ crash 4.0-4.6 ++ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. + Copyright (C) 2004, 2005, 2006 IBM Corporation + Copyright (C) 1999-2006 Hewlett-Packard Co -+ Copyright (C) 2005 Fujitsu Limited ++ Copyright (C) 2005, 2006 Fujitsu Limited ++ Copyright (C) 2006, 2007 VA Linux Systems Japan K.K. + Copyright (C) 2005 NEC Corporation - Copyright (C) 1999, 2002 Silicon Graphics, Inc. ++ Copyright (C) 1999, 2002, 2007 Silicon Graphics, Inc. Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. This program is free software, covered by the GNU General Public License, + and you are welcome to change it and/or distribute copies of it under +--- crash/crash.8.orig 2007-08-27 15:02:36.000000000 -0400 ++++ crash/crash.8 2007-07-13 16:57:38.000000000 -0400 +@@ -5,7 +5,7 @@ + .TH CRASH 8 + .SH NAME + crash \- Analyze Linux crash data or a live system +-.SH SYNAPSIS ++.SH SYNOPSIS + .B crash + [ + .B -h +@@ -42,9 +42,13 @@ + is a tool for interactively analyzing the state of the Linux system + while it is running, or after a kernel crash has occurred and a + core dump has been created by the Red Hat +-.I netdump +-facility. It is loosely based on the SVR4 UNIX crash +-command, but has been signficantly enhanced ++.I netdump, ++.I diskdump, ++.I kdump, ++or ++.I xendump ++facilities. It is loosely based on the SVR4 UNIX crash ++command, but has been significantly enhanced + by completely merging it with the + .I gdb + debugger. The marriage of the two effectively combines the +@@ -207,15 +211,15 @@ + .I dis + disassembles memory, either entire kernel functions, from a + location for a specified number of instructions, or from the start of a +-fuction up to a specified memory location. ++function up to a specified memory location. + .TP + .I eval + evalues an expression or numeric type and displays the result +-in hexidecimal, decimal, octal and binary. ++in hexadecimal, decimal, octal and binary. + .TP + .I exit + causes +-.I crash ++.B crash + to exit. + .TP + .I extend +@@ -230,7 +234,7 @@ + in the system. + .TP + .I fuser +-displays the tasks using the specifed file or socket. ++displays the tasks using the specified file or socket. + .TP + .I gdb + passes its argument to the underlying +@@ -274,7 +278,7 @@ + display various network related data. + .TP + .I p +-passes its argumnts to the ++passes its arguments to the + .I gdb + "print" command for evaluation and display. + .TP +@@ -361,11 +365,85 @@ + .I wr + modifies the contents of memory. When writing to memory on + a live system, this command should obviously be used with great care. ++.SH FILES ++.TP ++.I .crashrc ++Initialization commands. The file can be located in the user's ++.B HOME ++directory and/or the current directory. Commands found in the ++.I .crashrc ++file in the ++.B HOME ++directory are executed before those in the current directory's ++.I .crashrc ++file. ++.SH ENVIRONMENT ++.TP ++.B EDITOR ++Command input is read using ++.BR readline(3). ++If ++.B EDITOR ++is set to ++.I emacs ++or ++.I vi ++then suitable keybindings are used. If ++.B EDITOR ++is not set, then ++.I vi ++is used. This can be overridden by ++.B set vi ++or ++.B set emacs ++commands located in a ++.IR .crashrc ++file, or by entering ++.B -e emacs ++on the ++.B crash ++command line. ++.TP ++.B CRASHPAGER ++If ++.B CRASHPAGER ++is set, its value is used as the name of the program to which command output will be sent. ++If not, then command output is sent to ++.B /usr/bin/less -E -X ++by default. ++.SH NOTES ++.PP ++If ++.B crash ++does not work, look for a newer version: kernel evolution frequently makes ++.B crash ++updates necessary. ++.PP ++The command ++.B set scroll off ++will cause output to be sent directly to ++the terminal rather than through a paging program. This is useful, ++for example, if you are running ++.B crash ++in a window of ++.BR emacs . + .SH AUTHOR + Dave Anderson wrote +-.B Crash ++.B crash + .TP + Jay Fenlason wrote this man page. + .SH "SEE ALSO" +-netdump(8) +-gdb(1) ++.PP ++The ++.I help ++command within ++.B crash ++provides more complete and accurate documentation than this man page. ++.PP ++.I http://people.redhat.com/anderson ++- the home page of the ++.B crash ++utility. ++.PP ++.BR netdump (8), ++.BR gdb (1) diff --git a/crash.spec b/crash.spec index d93fa50..242b552 100644 --- a/crash.spec +++ b/crash.spec @@ -1,10 +1,10 @@ # # crash core analysis suite # -Summary: crash utility for live systems; netdump, diskdump, LKCD or mcore dumpfiles +Summary: crash utility for live systems; netdump, diskdump, kdump, LKCD or mcore dumpfiles Name: crash Version: 4.0 -Release: 3.3 +Release: 4.6.2 License: GPL Group: Development/Debuggers Source: %{name}-%{version}.tar.gz @@ -46,6 +46,9 @@ rm -rf %{buildroot} %doc README %changelog +* Wed Aug 29 2007 Dave Anderson - 4.0-4.6.2 +- Updated crash.patch to match upstream version 4.0-4.6. + * Wed Sep 13 2006 Dave Anderson - 4.0-3.3 - Updated crash.patch to match upstream version 4.0-3.3. - Support for x86_64 relocatable kernels. BZ #204557