commit 60873327298c09cf437e47e509244134be1cd4de Author: CentOS Sources Date: Tue May 7 09:44:18 2019 -0400 import crash-7.2.3-18.el8 diff --git a/.crash.metadata b/.crash.metadata new file mode 100644 index 0000000..d966af7 --- /dev/null +++ b/.crash.metadata @@ -0,0 +1 @@ +1a9fa8cd6869da42314ec47df6a750e053f4bece SOURCES/crash-7.2.3.tar.gz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..32212ef --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/crash-7.2.3.tar.gz diff --git a/SOURCES/github_0f65ae0c_readline.patch b/SOURCES/github_0f65ae0c_readline.patch new file mode 100644 index 0000000..73d317a --- /dev/null +++ b/SOURCES/github_0f65ae0c_readline.patch @@ -0,0 +1,154 @@ +commit 0f65ae0c36bf04e22219f28c32c3ae0cdee5acfe +Author: Dave Anderson +Date: Fri Dec 7 15:17:37 2018 -0500 + + Implemented a new plugin function for the readline library's tab + completion feature. Without the patch, the use of the default plugin + from the embedded gdb module has been seen to cause segmentation + violations or other fatal malloc/free/corruption assertions. The new + plugin takes gdb out of the picture entirely, and also restricts the + matching options to just symbol names, so as not to clutter the + results with irrelevant filenames. + (anderson@redhat.com) + +diff --git a/cmdline.c b/cmdline.c +index cf3e150..665f48c 100644 +--- a/cmdline.c ++++ b/cmdline.c +@@ -40,6 +40,8 @@ int shell_command(char *); + static void modify_orig_line(char *, struct args_input_file *); + static void modify_expression_arg(char *, char **, struct args_input_file *); + static int verify_args_input_file(char *); ++static char *crash_readline_completion_generator(const char *, int); ++static char **crash_readline_completer(const char *, int, int); + + #define READLINE_LIBRARY + +@@ -2073,6 +2075,9 @@ readline_init(void) + if (STREQ(pc->editing_mode, "emacs")) { + rl_editing_mode = emacs_mode; + } ++ ++ rl_attempted_completion_function = crash_readline_completer; ++ rl_attempted_completion_over = 1; + } + + /* +@@ -2610,3 +2615,27 @@ exec_args_input_file(struct command_table_entry *ct, struct args_input_file *aif + fclose(pc->args_ifile); + pc->args_ifile = NULL; + } ++ ++static char * ++crash_readline_completion_generator(const char *match, int state) ++{ ++ static struct syment *sp_match; ++ ++ if (state == 0) ++ sp_match = NULL; ++ ++ sp_match = symbol_complete_match(match, sp_match); ++ ++ if (sp_match) ++ return(strdup(sp_match->name)); ++ else ++ return NULL; ++} ++ ++static char ** ++crash_readline_completer(const char *match, int start, int end) ++{ ++ rl_attempted_completion_over = 1; ++ return rl_completion_matches(match, crash_readline_completion_generator); ++} ++ +diff --git a/defs.h b/defs.h +index 9ce32c1..a3cb5a4 100644 +--- a/defs.h ++++ b/defs.h +@@ -5153,6 +5153,7 @@ void parse_for_member_extended(struct datatype_member *, ulong); + void add_to_downsized(char *); + int is_downsized(char *); + int is_string(char *, char *); ++struct syment *symbol_complete_match(const char *, struct syment *); + + /* + * memory.c +diff --git a/symbols.c b/symbols.c +index 05628ff..0769294 100644 +--- a/symbols.c ++++ b/symbols.c +@@ -13108,3 +13108,73 @@ is_downsized(char *name) + + return FALSE; + } ++ ++struct syment * ++symbol_complete_match(const char *match, struct syment *sp_last) ++{ ++ int i; ++ struct syment *sp, *sp_end, *sp_start; ++ struct load_module *lm; ++ int search_init; ++ ++ if (sp_last) { ++ sp_start = next_symbol(NULL, sp_last); ++ if (!sp_start) ++ return NULL; ++ } else ++ sp_start = st->symtable; ++ ++ if ((sp_start >= st->symtable) && (sp_start < st->symend)) { ++ for (sp = sp_start; sp < st->symend; sp++) { ++ if (STRNEQ(sp->name, match)) ++ return sp; ++ } ++ sp_start = NULL; ++ } ++ ++ search_init = FALSE; ++ ++ for (i = 0; i < st->mods_installed; i++) { ++ lm = &st->load_modules[i]; ++ if (lm->mod_flags & MOD_INIT) ++ search_init = TRUE; ++ sp_end = lm->mod_symend; ++ if (!sp_start) ++ sp_start = lm->mod_symtable; ++ ++ if ((sp_start >= lm->mod_symtable) && (sp_start < sp_end)) { ++ for (sp = sp_start; sp < sp_end; sp++) { ++ if (MODULE_START(sp)) ++ continue; ++ ++ if (STRNEQ(sp->name, match)) ++ return sp; ++ } ++ sp_start = NULL; ++ } ++ } ++ ++ if (!search_init) ++ return NULL; ++ ++ for (i = 0; i < st->mods_installed; i++) { ++ lm = &st->load_modules[i]; ++ if (!lm->mod_init_symtable) ++ continue; ++ sp_end = lm->mod_init_symend; ++ if (!sp_start) ++ sp_start = lm->mod_init_symtable; ++ ++ if ((sp_start >= lm->mod_init_symtable) && (sp_start < sp_end)) { ++ for (sp = sp_start; sp < sp_end; sp++) { ++ if (MODULE_START(sp)) ++ continue; ++ ++ if (STRNEQ(sp->name, match)) ++ return sp; ++ } ++ } ++ } ++ ++ return NULL; ++} diff --git a/SOURCES/github_1926150e_ppc64_stacksize.patch b/SOURCES/github_1926150e_ppc64_stacksize.patch new file mode 100644 index 0000000..5da09da --- /dev/null +++ b/SOURCES/github_1926150e_ppc64_stacksize.patch @@ -0,0 +1,27 @@ +commit 1926150ee350e17fee2aeabb8ef781222d94366e +Author: Dave Anderson +Date: Mon Jun 11 13:46:41 2018 -0400 + + Fix for the ppc64/ppc64le "bt" command on Linux 4.7 and later kernels + that contain commit d8bff643d81a58181356c0aa3ab771ac10da6894, + titled "[x86] asm: Make sure verify_cpu() has a good stack", which + inadvertently breaks the ppc64/ppc64le kernel stack size calculation + when running with crash-7.2.2 or later. Without the patch, "bt" may + fail with a filtered kdump dumpfile with the two error messages + "bt: page excluded: kernel virtual address:
type: stack + contents" and "bt: read of stack at
failed". + (anderson@redhat.com) + +diff --git a/task.c b/task.c +index f6956d5..1b32629 100644 +--- a/task.c ++++ b/task.c +@@ -440,7 +440,7 @@ task_init(void) + } else if (VALID_SIZE(thread_union) && + ((len = SIZE(thread_union)) != STACKSIZE())) { + machdep->stacksize = len; +- } else { ++ } else if (!VALID_SIZE(thread_union) && !VALID_SIZE(task_union)) { + if (kernel_symbol_exists("__start_init_task") && + kernel_symbol_exists("__end_init_task")) { + len = symbol_value("__end_init_task"); diff --git a/SOURCES/github_27a6ebd0_dev-p.patch b/SOURCES/github_27a6ebd0_dev-p.patch new file mode 100644 index 0000000..0cbafcc --- /dev/null +++ b/SOURCES/github_27a6ebd0_dev-p.patch @@ -0,0 +1,412 @@ +commit 27a6ebd0cda386b1dfb7b0fffb4d8b489b391ccf +Author: Dave Anderson +Date: Mon Sep 24 16:33:57 2018 -0400 + + Resurrection of the the "dev -p" option for displaying PCI device + data on Linux 2.6.26 and later kernels. The option was deprecated + as of Linux 2.6.26, and without the patch, the option would indicate + "dev: -p option not supported or applicable on this architecture + or kernel" when running against the newer kernel versions. PCI Bus + information will also be displayed with this patch. + (m.mizuma@jp.fujitsu.com) + +diff --git a/defs.h b/defs.h +index d6492c5..80c61ef 100644 +--- a/defs.h ++++ b/defs.h +@@ -2032,6 +2032,17 @@ struct offset_table { + long bpf_prog_aux_user; + long user_struct_uid; + long idr_cur; ++ long pci_dev_dev; ++ long pci_dev_hdr_type; ++ long pci_dev_pcie_flags_reg; ++ long pci_bus_node; ++ long pci_bus_devices; ++ long pci_bus_dev; ++ long pci_bus_children; ++ long pci_bus_parent; ++ long pci_bus_self; ++ long device_kobj; ++ long kobject_name; + }; + + struct size_table { /* stash of commonly-used sizes */ +diff --git a/dev.c b/dev.c +index 3db898a..7ce2422 100644 +--- a/dev.c ++++ b/dev.c +@@ -24,6 +24,7 @@ static void dump_blkdevs_v3(ulong); + static ulong search_cdev_map_probes(char *, int, int, ulong *); + static ulong search_bdev_map_probes(char *, int, int, ulong *); + static void do_pci(void); ++static void do_pci2(void); + static void do_io(void); + static void do_resource_list(ulong, char *, int); + +@@ -51,11 +52,23 @@ dev_init(void) + MEMBER_OFFSET_INIT(pci_dev_global_list, "pci_dev", "global_list"); + MEMBER_OFFSET_INIT(pci_dev_next, "pci_dev", "next"); + MEMBER_OFFSET_INIT(pci_dev_bus, "pci_dev", "bus"); ++ MEMBER_OFFSET_INIT(pci_dev_dev, "pci_dev", "dev"); + MEMBER_OFFSET_INIT(pci_dev_devfn, "pci_dev", "devfn"); + MEMBER_OFFSET_INIT(pci_dev_class, "pci_dev", "class"); + MEMBER_OFFSET_INIT(pci_dev_device, "pci_dev", "device"); ++ MEMBER_OFFSET_INIT(pci_dev_hdr_type, "pci_dev", "hdr_type"); ++ MEMBER_OFFSET_INIT(pci_dev_pcie_flags_reg, "pci_dev", "pcie_flags_reg"); + MEMBER_OFFSET_INIT(pci_dev_vendor, "pci_dev", "vendor"); + MEMBER_OFFSET_INIT(pci_bus_number, "pci_bus", "number"); ++ MEMBER_OFFSET_INIT(pci_bus_node, "pci_bus", "node"); ++ MEMBER_OFFSET_INIT(pci_bus_devices, "pci_bus", "devices"); ++ MEMBER_OFFSET_INIT(pci_bus_dev, "pci_bus", "dev"); ++ MEMBER_OFFSET_INIT(pci_bus_children, "pci_bus", "children"); ++ MEMBER_OFFSET_INIT(pci_bus_parent, "pci_bus", "parent"); ++ MEMBER_OFFSET_INIT(pci_bus_self, "pci_bus", "self"); ++ ++ MEMBER_OFFSET_INIT(device_kobj, "device", "kobj"); ++ MEMBER_OFFSET_INIT(kobject_name, "kobject", "name"); + + STRUCT_SIZE_INIT(resource, "resource"); + if ((VALID_STRUCT(resource) && symbol_exists("do_resource_list")) || +@@ -114,10 +127,14 @@ cmd_dev(void) + return; + + case 'p': +- if (machine_type("S390X") || +- (THIS_KERNEL_VERSION >= LINUX(2,6,26))) ++ if (machine_type("S390X")) ++ option_not_supported(c); ++ if (symbol_exists("pci_devices")) ++ do_pci(); ++ else if (symbol_exists("pci_root_buses")) ++ do_pci2(); ++ else + option_not_supported(c); +- do_pci(); + return; + + default: +@@ -2217,6 +2234,313 @@ do_resource_list(ulong first_entry, char *resource_buf, int size) + + #endif /* USE_2_2_17_PCI_H */ + ++#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ ++#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */ ++#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */ ++#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ ++#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */ ++#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ ++#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCIe to PCI/PCI-X Bridge */ ++#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIe Bridge */ ++#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */ ++#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */ ++ ++static void ++fill_dev_name(ulong pci_dev, char *name) ++{ ++ ulong kobj, value; ++ ++ memset(name, 0, sizeof(*name) * BUFSIZE); ++ ++ kobj = pci_dev + OFFSET(pci_dev_dev) + OFFSET(device_kobj); ++ ++ readmem(kobj + OFFSET(kobject_name), ++ KVADDR, &value, sizeof(void *), "kobject name", ++ FAULT_ON_ERROR); ++ ++ read_string(value, name, BUFSIZE-1); ++} ++ ++static void ++fill_bus_name(ulong pci_bus, char *name) ++{ ++ ulong kobj, value; ++ ++ memset(name, 0, sizeof(*name) * BUFSIZE); ++ ++ kobj = pci_bus + OFFSET(pci_bus_dev) + OFFSET(device_kobj); ++ ++ readmem(kobj + OFFSET(kobject_name), ++ KVADDR, &value, sizeof(void *), "kobject name", ++ FAULT_ON_ERROR); ++ ++ read_string(value, name, BUFSIZE-1); ++} ++ ++static void ++fill_dev_id(ulong pci_dev, char *id) ++{ ++ unsigned short device, vendor; ++ ++ memset(id, 0, sizeof(*id) * BUFSIZE); ++ ++ readmem(pci_dev + OFFSET(pci_dev_device), ++ KVADDR, &device, sizeof(short), "pci dev device", ++ FAULT_ON_ERROR); ++ readmem(pci_dev + OFFSET(pci_dev_vendor), KVADDR, ++ &vendor, sizeof(short), "pci dev vendor", FAULT_ON_ERROR); ++ ++ sprintf(id, "%x:%x", vendor, device); ++} ++ ++static void ++fill_dev_class(ulong pci_dev, char *c) ++{ ++ unsigned int class; ++ ++ memset(c, 0, sizeof(*c) * BUFSIZE); ++ readmem(pci_dev + OFFSET(pci_dev_class), KVADDR, ++ &class, sizeof(int), "pci class", FAULT_ON_ERROR); ++ ++ class >>= 8; ++ ++ sprintf(c, "%04x", class); ++} ++ ++static int ++pci_pcie_type(ulong cap) ++{ ++ return (cap & PCI_EXP_FLAGS_TYPE) >> 4; ++} ++ ++static int ++pci_is_bridge(unsigned char hdr_type) ++{ ++ return hdr_type == PCI_HEADER_TYPE_BRIDGE || ++ hdr_type == PCI_HEADER_TYPE_CARDBUS; ++} ++ ++static void ++fill_pcie_type(ulong pcidev, char *t) ++{ ++ int type, bufidx = 0; ++ unsigned short pciecap; ++ unsigned char hdr_type; ++ ++ memset(t, 0, sizeof(*t) * BUFSIZE); ++ ++ readmem(pcidev + OFFSET(pci_dev_hdr_type), KVADDR, &hdr_type, ++ sizeof(char), "pci dev hdr_type", FAULT_ON_ERROR); ++ ++ if (!VALID_MEMBER(pci_dev_pcie_flags_reg)) ++ goto bridge_chk; ++ ++ readmem(pcidev + OFFSET(pci_dev_pcie_flags_reg), KVADDR, &pciecap, ++ sizeof(unsigned short), "pci dev pcie_flags_reg", FAULT_ON_ERROR); ++ ++ type = pci_pcie_type(pciecap); ++ ++ if (type == PCI_EXP_TYPE_ENDPOINT) ++ bufidx = sprintf(t, "ENDPOINT"); ++ else if (type == PCI_EXP_TYPE_LEG_END) ++ bufidx = sprintf(t, "LEG_END"); ++ else if (type == PCI_EXP_TYPE_ROOT_PORT) ++ bufidx = sprintf(t, "ROOT_PORT"); ++ else if (type == PCI_EXP_TYPE_UPSTREAM) ++ bufidx = sprintf(t, "UPSTREAM"); ++ else if (type == PCI_EXP_TYPE_DOWNSTREAM) ++ bufidx = sprintf(t, "DOWNSTREAM"); ++ else if (type == PCI_EXP_TYPE_PCI_BRIDGE) ++ bufidx = sprintf(t, "PCI_BRIDGE"); ++ else if (type == PCI_EXP_TYPE_PCIE_BRIDGE) ++ bufidx = sprintf(t, "PCIE_BRIDGE"); ++ else if (type == PCI_EXP_TYPE_RC_END) ++ bufidx = sprintf(t, "RC_END"); ++ else if (type == PCI_EXP_TYPE_RC_EC) ++ bufidx = sprintf(t, "RC_EC"); ++ ++bridge_chk: ++ if (pci_is_bridge(hdr_type)) ++ sprintf(t + bufidx, " [BRIDGE]"); ++} ++ ++static void ++walk_devices(ulong pci_bus) ++{ ++ struct list_data list_data, *ld; ++ int devcnt, i; ++ ulong *devlist, self; ++ char name[BUFSIZE], class[BUFSIZE], id[BUFSIZE], type[BUFSIZE]; ++ char pcidev_hdr[BUFSIZE]; ++ char buf1[BUFSIZE]; ++ char buf2[BUFSIZE]; ++ char buf3[BUFSIZE]; ++ char buf4[BUFSIZE]; ++ char buf5[BUFSIZE]; ++ ++ ld = &list_data; ++ ++ BZERO(ld, sizeof(struct list_data)); ++ ++ readmem(pci_bus + OFFSET(pci_bus_devices), KVADDR, ++ &ld->start, sizeof(void *), "pci bus devices", ++ FAULT_ON_ERROR); ++ ++ if (VALID_MEMBER(pci_dev_pcie_flags_reg)) ++ snprintf(pcidev_hdr, sizeof(pcidev_hdr), "%s %s %s %s %s\n", ++ mkstring(buf1, VADDR_PRLEN, CENTER, "PCI DEV"), ++ mkstring(buf2, strlen("0000:00:00.0"), CENTER, "DO:BU:SL.FN"), ++ mkstring(buf3, strlen("0000") + 2, CENTER, "CLASS"), ++ mkstring(buf4, strlen("0000:0000"), CENTER, "PCI_ID"), ++ mkstring(buf5, 10, CENTER, "TYPE")); ++ else ++ snprintf(pcidev_hdr, sizeof(pcidev_hdr), "%s %s %s %s\n", ++ mkstring(buf1, VADDR_PRLEN, CENTER, "PCI DEV"), ++ mkstring(buf2, strlen("0000:00:00.0"), CENTER, "DO:BU:SL.FN"), ++ mkstring(buf3, strlen("0000") + 2, CENTER, "CLASS"), ++ mkstring(buf4, strlen("0000:0000"), CENTER, "PCI_ID")); ++ ++ fprintf(fp, " %s", pcidev_hdr); ++ ++ readmem(pci_bus + OFFSET(pci_bus_self), KVADDR, &self, ++ sizeof(void *), "pci bus self", FAULT_ON_ERROR); ++ if (self) { ++ fill_dev_name(self, name); ++ fill_dev_class(self, class); ++ fill_dev_id(self, id); ++ fill_pcie_type(self, type); ++ fprintf(fp, " %s %s %s %s %s\n", ++ mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX, ++ MKSTR(self)), ++ mkstring(buf2, strlen("0000:00:00.0"), CENTER, name), ++ mkstring(buf3, strlen("0000") + 2, CENTER, class), ++ mkstring(buf4, strlen("0000:0000"), CENTER, id), ++ mkstring(buf5, 10, CENTER, type)); ++ } ++ ++ if (ld->start == (pci_bus + OFFSET(pci_bus_devices))) ++ return; ++ ++ ld->end = pci_bus + OFFSET(pci_bus_devices); ++ hq_open(); ++ devcnt = do_list(ld); ++ devlist = (ulong *)GETBUF(devcnt * sizeof(ulong)); ++ devcnt = retrieve_list(devlist, devcnt); ++ hq_close(); ++ ++ for (i = 0; i < devcnt; i++) { ++ fill_dev_name(devlist[i], name); ++ fill_dev_class(devlist[i], class); ++ fill_dev_id(devlist[i], id); ++ fill_pcie_type(devlist[i], type); ++ fprintf(fp, " %s %s %s %s %s\n", ++ mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX, ++ MKSTR(devlist[i])), ++ mkstring(buf2, strlen("0000:00:00.0"), CENTER, name), ++ mkstring(buf3, strlen("0000") + 2, CENTER, class), ++ mkstring(buf4, strlen("0000:0000"), CENTER, id), ++ mkstring(buf5, 10, CENTER, type)); ++ } ++ FREEBUF(devlist); ++} ++ ++static void ++walk_buses(ulong pci_bus) ++{ ++ struct list_data list_data, *ld; ++ int buscnt, i; ++ ulong *buslist, parent; ++ char pcibus_hdr[BUFSIZE]; ++ char buf1[BUFSIZE]; ++ char buf2[BUFSIZE]; ++ ++ ld = &list_data; ++ ++ BZERO(ld, sizeof(struct list_data)); ++ ++ readmem(pci_bus + OFFSET(pci_bus_children), KVADDR, ++ &ld->start, sizeof(void *), "pci bus children", ++ FAULT_ON_ERROR); ++ ++ if (ld->start == (pci_bus + OFFSET(pci_bus_children))) ++ return; ++ ++ ld->end = pci_bus + OFFSET(pci_bus_children); ++ hq_open(); ++ buscnt = do_list(ld); ++ buslist = (ulong *)GETBUF(buscnt * sizeof(ulong)); ++ buscnt = retrieve_list(buslist, buscnt); ++ hq_close(); ++ ++ snprintf(pcibus_hdr, sizeof(pcibus_hdr), "%s %s\n", ++ mkstring(buf1, VADDR_PRLEN, CENTER, "PCI BUS"), ++ mkstring(buf2, VADDR_PRLEN, CENTER, "PARENT BUS")); ++ ++ for (i = 0; i < buscnt; i++) { ++ readmem(buslist[i] + OFFSET(pci_bus_parent), KVADDR, &parent, ++ sizeof(void *), "pci bus parent", FAULT_ON_ERROR); ++ ++ fprintf(fp, " %s", pcibus_hdr); ++ ++ fprintf(fp, " %s %s\n", ++ mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX, ++ MKSTR(buslist[i])), ++ mkstring(buf2, VADDR_PRLEN, LJUST|LONG_HEX, ++ MKSTR(parent))); ++ walk_devices(buslist[i]); ++ fprintf(fp, "\n"); ++ walk_buses(buslist[i]); ++ } ++ FREEBUF(buslist); ++} ++ ++static void ++do_pci2(void) ++{ ++ struct list_data list_data, *ld; ++ int rootbuscnt, i; ++ ulong *rootbuslist; ++ unsigned long pci_root_bus_addr = symbol_value("pci_root_buses"); ++ char name[BUFSIZE]; ++ char pcirootbus_hdr[BUFSIZE]; ++ char buf1[BUFSIZE]; ++ char buf2[BUFSIZE]; ++ ++ ld = &list_data; ++ BZERO(ld, sizeof(struct list_data)); ++ ++ get_symbol_data("pci_root_buses", sizeof(void *), &ld->start); ++ ++ if (ld->start == pci_root_bus_addr) ++ error(FATAL, "no PCI devices found on this system.\n"); ++ ++ ld->end = pci_root_bus_addr; ++ ++ hq_open(); ++ rootbuscnt = do_list(ld); ++ rootbuslist = (ulong *)GETBUF(rootbuscnt * sizeof(ulong)); ++ rootbuscnt = retrieve_list(rootbuslist, rootbuscnt); ++ hq_close(); ++ ++ snprintf(pcirootbus_hdr, sizeof(pcirootbus_hdr), "%s %s\n", ++ mkstring(buf1, VADDR_PRLEN, CENTER, "ROOT BUS"), ++ mkstring(buf2, strlen("0000:00"), CENTER, "BUSNAME")); ++ ++ for (i = 0; i < rootbuscnt; i++) { ++ fprintf(fp, "%s", pcirootbus_hdr); ++ fill_bus_name(rootbuslist[i], name); ++ fprintf(fp, "%s %s\n", ++ mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX, ++ MKSTR(rootbuslist[i])), ++ mkstring(buf2, strlen("0000:00"), CENTER, name)); ++ walk_devices(rootbuslist[i]); ++ walk_buses(rootbuslist[i]); ++ ++ fprintf(fp, "\n"); ++ } ++ FREEBUF(rootbuslist); ++} ++ + static void + do_pci(void) + { +@@ -2230,9 +2554,6 @@ do_pci(void) + char buf2[BUFSIZE]; + char buf3[BUFSIZE]; + +- 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)) { diff --git a/SOURCES/github_28fa7bd0_to_02efd083.patch b/SOURCES/github_28fa7bd0_to_02efd083.patch new file mode 100644 index 0000000..177c106 --- /dev/null +++ b/SOURCES/github_28fa7bd0_to_02efd083.patch @@ -0,0 +1,174 @@ +commit 28fa7bd09013455b5ddc020dea4706278cda0d65 +Author: Dave Anderson +Date: Tue Jun 19 16:31:54 2018 -0400 + + Fix for PPC64 kernel virtual address translation in Linux 4.17 and + later kernels with commit c2b4d8b7417a59b7f9a52d0d8402f5257cbbd398, + titled "powerpc/mm/hash64: Increase the VA range", in which the + maximum virtual address value has been increased to 4PB. Without + the patch, the translation/access of high vmalloc space addresses + fails; for example, the "kmem -[sS]" option fails the translation + of per-cpu kmem_cache_cpu addresses located in vmalloc space, with + the error messages "kmem: invalid kernel virtual address:
+ type: kmem_cache_cpu.freelist" and "kmem: invalid kernel virtual + address:
type: kmem_cache_cpu.page", and the "vtop" + command shows the addresses as "(not mapped)". + (hbathini@linux.ibm.com) + +diff --git a/defs.h b/defs.h +index 6e6f6be..e6e3850 100644 +--- a/defs.h ++++ b/defs.h +@@ -3977,6 +3977,7 @@ struct efi_memory_desc_t { + #define PMD_INDEX_SIZE_L4_64K_4_12 10 + #define PUD_INDEX_SIZE_L4_64K_4_12 7 + #define PGD_INDEX_SIZE_L4_64K_4_12 8 ++#define PUD_INDEX_SIZE_L4_64K_4_17 10 + #define PTE_INDEX_SIZE_RADIX_64K 5 + #define PMD_INDEX_SIZE_RADIX_64K 9 + #define PUD_INDEX_SIZE_RADIX_64K 9 +diff --git a/ppc64.c b/ppc64.c +index 0dd8a2a..f5d0dac 100644 +--- a/ppc64.c ++++ b/ppc64.c +@@ -451,7 +451,10 @@ ppc64_init(int when) + + if (THIS_KERNEL_VERSION >= LINUX(4,12,0)) { + m->l2_index_size = PMD_INDEX_SIZE_L4_64K_4_12; +- m->l3_index_size = PUD_INDEX_SIZE_L4_64K_4_12; ++ if (THIS_KERNEL_VERSION >= LINUX(4,17,0)) ++ m->l3_index_size = PUD_INDEX_SIZE_L4_64K_4_17; ++ else ++ m->l3_index_size = PUD_INDEX_SIZE_L4_64K_4_12; + m->l4_index_size = PGD_INDEX_SIZE_L4_64K_4_12; + } else { + m->l2_index_size = PMD_INDEX_SIZE_L4_64K_4_6; + +commit e5df29d54bbdb8b84cb1661233ed186b153be746 +Author: Dave Anderson +Date: Wed Jun 20 11:15:38 2018 -0400 + + Fix for the x86_64 "bt" command in which a legitimate exception + frame is appended with the message "bt: WARNING: possibly bogus + exception frame". This only happens in KASLR-enabled kernels when + the text address that was executing when the exception occurred + is marked as a "weak" symbol (type "W") instead of a text symbol + (type "T" or "t"). As a result, the exception frame's RIP is not + recognized as a text symbol, and the warning message is displayed. + (anderson@redhat.com) + +diff --git a/symbols.c b/symbols.c +index bb4ae3a..bf55319 100644 +--- a/symbols.c ++++ b/symbols.c +@@ -2755,9 +2755,14 @@ is_kernel_text(ulong value) + section); + end = start + (ulong)bfd_section_size(st->bfd, + section); ++ ++ if (kt->flags2 & KASLR) { ++ start += (kt->relocate * -1); ++ end += (kt->relocate * -1); ++ } + +- if ((value >= start) && (value < end)) +- return TRUE; ++ if ((value >= start) && (value < end)) ++ return TRUE; + } + } + } +@@ -2833,7 +2838,16 @@ is_kernel_text_offset(ulong value) + int + is_symbol_text(struct syment *sp) + { +- return ((sp->type == 'T') || (sp->type == 't')); ++ if ((sp->type == 'T') || (sp->type == 't')) ++ return TRUE; ++ ++ if ((sp->type == 'W') || (sp->type == 'w')) { ++ if ((sp->value >= kt->stext) && ++ (sp->value < kt->etext)) ++ return TRUE; ++ } ++ ++ return FALSE; + } + + /* + +commit a7e5b90757bb41ad5e148177c5b3aaf5d892243d +Author: Dave Anderson +Date: Wed Jun 20 16:33:43 2018 -0400 + + Fix for the x86_64 "bt" command in Linux 4.16 and later kernels + containing commit 3aa99fc3e708b9cd9b4cfe2df0b7a66cf293e3cf, titled + "x86/entry/64: Remove 'interrupt' macro". Without the patch, the + exception frame display generated by an interrupt exception will + show incorrect contents, and be followed by the message "bt: WARNING: + possibly bogus exception frame". + (anderson@redhat.com) + +diff --git a/x86_64.c b/x86_64.c +index e01082b..6d1ae2f 100644 +--- a/x86_64.c ++++ b/x86_64.c +@@ -4285,6 +4285,12 @@ x86_64_exception_frame(ulong flags, ulong kvaddr, char *local, + long err; + char buf[BUFSIZE]; + ++ if (flags == EFRAME_VERIFY) { ++ if (!accessible(kvaddr) || ++ !accessible(kvaddr + SIZE(pt_regs) - sizeof(long))) ++ return FALSE; ++ } ++ + ms = machdep->machspec; + sp = NULL; + +@@ -6283,6 +6289,9 @@ x86_64_irq_eframe_link(ulong stkref, struct bt_info *bt, FILE *ofp) + { + ulong irq_eframe; + ++ if (x86_64_exception_frame(EFRAME_VERIFY, stkref, 0, bt, ofp)) ++ return stkref; ++ + irq_eframe = stkref - machdep->machspec->irq_eframe_link; + + if (x86_64_exception_frame(EFRAME_VERIFY, irq_eframe, 0, bt, ofp)) + +commit 02efd0838f05ef8a7fe21b0b8ba6cad729270645 +Author: Dave Anderson +Date: Fri Jun 22 11:00:01 2018 -0400 + + Fix for the failure of several "kmem" command options, most notably + seen if the command is piped directly into a crash session, or if + the command is contained in an input file. For examples: + $ echo "kmem -i" | crash ... + $ crash -i ... + Without the patch, the kmem command may fail with the error message + "". While the bug is due to a buffer + overflow that has always existed, it only is triggered by certain + kernel configurations. + (anderson@redhat.com) + +diff --git a/memory.c b/memory.c +index 2f568d5..5c0a853 100644 +--- a/memory.c ++++ b/memory.c +@@ -17498,13 +17498,12 @@ vm_stat_init(void) + STREQ(arglist[0], "NR_VM_ZONE_STAT_ITEMS")) { + continue; + } else { +- stringlen += strlen(arglist[0]); ++ stringlen += strlen(arglist[0]) + 1; + count++; + } + } + +- total = stringlen + vt->nr_vm_stat_items + +- (sizeof(void *) * vt->nr_vm_stat_items); ++ total = stringlen + (sizeof(void *) * vt->nr_vm_stat_items); + if (!(vt->vm_stat_items = (char **)malloc(total))) { + close_tmpfile(); + error(FATAL, "cannot malloc vm_stat_items cache\n"); diff --git a/SOURCES/github_2f57a96c_files-c-p.patch b/SOURCES/github_2f57a96c_files-c-p.patch new file mode 100644 index 0000000..18c9255 --- /dev/null +++ b/SOURCES/github_2f57a96c_files-c-p.patch @@ -0,0 +1,58 @@ +commit 2f57a96ce27d8b121c2822de2a66c71b83bdad21 +Author: Dave Anderson +Date: Tue Sep 4 14:29:45 2018 -0400 + + Fix for the "files" command in Linux 4.17 and later kernels that + contain commit b93b016313b3ba8003c3b8bb71f569af91f19fc7, titled + "page cache: use xa_lock". Without the patch, the "files -c" option + fails with the message "files: -c option not supported or applicable + on this architecture or kernel", and the "files -p <inode>" option + fails in a similar manner. + (k-hagio@ab.jp.nec.com) + +diff --git a/filesys.c b/filesys.c +index 47f5a24..32daa5a 100644 +--- a/filesys.c ++++ b/filesys.c +@@ -2207,6 +2207,11 @@ dump_inode_page_cache_info(ulong inode) + RJUST|LONG_DEC, + MKSTR(nrpages))); + ++ FREEBUF(inode_buf); ++ ++ if (!nrpages) ++ return; ++ + root_rnode = i_mapping + OFFSET(address_space_page_tree); + rtp.index = 0; + rtp.value = (void *)&dump_inode_page; +@@ -2217,7 +2222,6 @@ dump_inode_page_cache_info(ulong inode) + error(INFO, "page_tree count: %ld nrpages: %ld\n", + count, nrpages); + +- FREEBUF(inode_buf); + return; + } + +@@ -2275,7 +2279,7 @@ cmd_files(void) + return; + + case 'c': +- if (VALID_MEMBER(address_space_page_tree) && ++ if (VALID_MEMBER(address_space_nrpages) && + VALID_MEMBER(inode_i_mapping)) + open_flags |= PRINT_NRPAGES; + else +diff --git a/memory.c b/memory.c +index 24fce5e..ea25047 100644 +--- a/memory.c ++++ b/memory.c +@@ -485,6 +485,8 @@ vm_init(void) + MEMBER_OFFSET_INIT(block_device_bd_disk, "block_device", "bd_disk"); + MEMBER_OFFSET_INIT(inode_i_mapping, "inode", "i_mapping"); + MEMBER_OFFSET_INIT(address_space_page_tree, "address_space", "page_tree"); ++ if (INVALID_MEMBER(address_space_page_tree)) ++ MEMBER_OFFSET_INIT(address_space_page_tree, "address_space", "i_pages"); + MEMBER_OFFSET_INIT(address_space_nrpages, "address_space", "nrpages"); + if (INVALID_MEMBER(address_space_nrpages)) + MEMBER_OFFSET_INIT(address_space_nrpages, "address_space", "__nrpages"); diff --git a/SOURCES/github_3141bba9.patch b/SOURCES/github_3141bba9.patch new file mode 100644 index 0000000..4629517 --- /dev/null +++ b/SOURCES/github_3141bba9.patch @@ -0,0 +1,45 @@ +commit 3141bba98af302e2a7c5e2a19203bb8a40b6aa63 +Author: Dave Anderson +Date: Wed Oct 10 09:15:42 2018 -0400 + + Fix the calculation of the vmalloc memory region size to account for + Linux 4.17 commit a7412546d8cb5ad578805060b4006f2a021b5868, titled + "x86/mm: Adjust vmalloc base and size at boot-time", which increases + the region's size from 32TB to 1280TB when 5-level pagetables are + enabled. Also presume that virtual addresses above the end of the + vmalloc space up to the beginning of vmemmap space are translatable + via 5-level page tables. Without the patch, mapped virtual addresses + may fail translation in whatever command accesses them, with errors + indicating "seek error: kernel virtual address: + type: " + (anderson@redhat.com) + +diff --git a/x86_64.c b/x86_64.c +index 6f547e8..345122c 100644 +--- a/x86_64.c ++++ b/x86_64.c +@@ -393,8 +393,12 @@ x86_64_init(int when) + readmem(symbol_value("vmalloc_base"), KVADDR, + &machdep->machspec->vmalloc_start_addr, + sizeof(ulong), "vmalloc_base", FAULT_ON_ERROR); +- machdep->machspec->vmalloc_end = +- machdep->machspec->vmalloc_start_addr + TERABYTES(32) - 1; ++ if (machdep->flags & VM_5LEVEL) ++ machdep->machspec->vmalloc_end = ++ machdep->machspec->vmalloc_start_addr + TERABYTES(1280) - 1; ++ else ++ machdep->machspec->vmalloc_end = ++ machdep->machspec->vmalloc_start_addr + TERABYTES(32) - 1; + if (kernel_symbol_exists("vmemmap_base")) { + readmem(symbol_value("vmemmap_base"), KVADDR, + &machdep->machspec->vmemmap_vaddr, sizeof(ulong), +@@ -1626,7 +1630,8 @@ x86_64_IS_VMALLOC_ADDR(ulong vaddr) + (vaddr >= VSYSCALL_START && vaddr < VSYSCALL_END) || + (machdep->machspec->cpu_entry_area_start && + vaddr >= machdep->machspec->cpu_entry_area_start && +- vaddr <= machdep->machspec->cpu_entry_area_end)); ++ vaddr <= machdep->machspec->cpu_entry_area_end) || ++ ((machdep->flags & VM_5LEVEL) && vaddr > VMALLOC_END && vaddr < VMEMMAP_VADDR)); + } + + static int diff --git a/SOURCES/github_361f050e_dev-d.patch b/SOURCES/github_361f050e_dev-d.patch new file mode 100644 index 0000000..0091f96 --- /dev/null +++ b/SOURCES/github_361f050e_dev-d.patch @@ -0,0 +1,196 @@ +commit 361f050e3148c6188afb45942e06d4a509852b86 +Author: Dave Anderson +Date: Mon Jan 7 13:56:15 2019 -0500 + + Fix for the "dev -[dD]" options in kernels containing Linux 5.0-rc1 + commit 7ff4f8035695984c513598e2d49c8277d5d234ca, titled "block: + remove dead queue members", in which the number of I/Os issued to + a disk driver are no longer stored in the request_queue structure. + Without the patch, the options indicate "dev: -d option not supported + or applicable on this architecture or kernel". With the patch, the + "DRV" column is not shown. + (m.mizuma@jp.fujitsu.com) + +diff --git a/defs.h b/defs.h +index a3cb5a4..9ebdde6 100644 +--- a/defs.h ++++ b/defs.h +@@ -2043,6 +2043,8 @@ struct offset_table { + long pci_bus_self; + long device_kobj; + long kobject_name; ++ long hd_struct_dkstats; ++ long disk_stats_in_flight; + }; + + struct size_table { /* stash of commonly-used sizes */ +diff --git a/dev.c b/dev.c +index 7ce2422..24efea2 100644 +--- a/dev.c ++++ b/dev.c +@@ -3974,7 +3974,7 @@ struct iter { + * this function reads request_list.count[2], and the first argument + * is the address of request_queue. + */ +- void (*get_diskio)(unsigned long , struct diskio *); ++ void (*get_diskio)(unsigned long , unsigned long, struct diskio *); + + /* + * check if device.type == &disk_type +@@ -4187,24 +4187,55 @@ get_mq_diskio(unsigned long q, unsigned long *mq_count) + } + } + ++static void ++get_one_diskio_from_dkstats(unsigned long dkstats, unsigned long *count) ++{ ++ int cpu; ++ unsigned long dkstats_addr; ++ unsigned long in_flight[2]; ++ ++ for (cpu = 0; cpu < kt->cpus; cpu++) { ++ if ((kt->flags & SMP) && (kt->flags & PER_CPU_OFF)) { ++ dkstats_addr = dkstats + kt->__per_cpu_offset[cpu]; ++ readmem(dkstats_addr + OFFSET(disk_stats_in_flight), ++ KVADDR, in_flight, sizeof(long) * 2, ++ "disk_stats.in_flight", FAULT_ON_ERROR); ++ count[0] += in_flight[0]; ++ count[1] += in_flight[1]; ++ } ++ } ++} ++ ++ + /* read request_queue.rq.count[2] */ + static void +-get_diskio_1(unsigned long rq, struct diskio *io) ++get_diskio_1(unsigned long rq, unsigned long gendisk, struct diskio *io) + { + int count[2]; +- unsigned long mq_count[2] = { 0 }; ++ unsigned long io_counts[2] = { 0 }; ++ unsigned long dkstats; + + if (!use_mq_interface(rq)) { +- readmem(rq + OFFSET(request_queue_rq) + +- OFFSET(request_list_count), KVADDR, count, +- sizeof(int) * 2, "request_list.count", FAULT_ON_ERROR); ++ if (VALID_MEMBER(request_queue_rq)) { ++ readmem(rq + OFFSET(request_queue_rq) + ++ OFFSET(request_list_count), KVADDR, count, ++ sizeof(int) * 2, "request_list.count", FAULT_ON_ERROR); ++ ++ io->read = count[0]; ++ io->write = count[1]; ++ } else { ++ readmem(gendisk + OFFSET(gendisk_part0) + ++ OFFSET(hd_struct_dkstats), KVADDR, &dkstats, ++ sizeof(ulong), "gendisk.part0.dkstats", FAULT_ON_ERROR); ++ get_one_diskio_from_dkstats(dkstats, io_counts); + +- io->read = count[0]; +- io->write = count[1]; ++ io->read = io_counts[0]; ++ io->write = io_counts[1]; ++ } + } else { +- get_mq_diskio(rq, mq_count); +- io->read = mq_count[0]; +- io->write = mq_count[1]; ++ get_mq_diskio(rq, io_counts); ++ io->read = io_counts[0]; ++ io->write = io_counts[1]; + } + } + +@@ -4250,9 +4281,6 @@ init_iter(struct iter *i) + i->get_in_flight = get_in_flight_1; + } else if (SIZE(rq_in_flight) == sizeof(int) * 2) { + i->get_in_flight = get_in_flight_2; +- } else { +- option_not_supported('d'); +- return; + } + i->get_diskio = get_diskio_1; + +@@ -4354,7 +4382,7 @@ display_one_diskio(struct iter *i, unsigned long gendisk, ulong flags) + sizeof(ulong), "gen_disk.queue", FAULT_ON_ERROR); + readmem(gendisk + OFFSET(gendisk_major), KVADDR, &major, sizeof(int), + "gen_disk.major", FAULT_ON_ERROR); +- i->get_diskio(queue_addr, &io); ++ i->get_diskio(queue_addr, gendisk, &io); + + if ((flags & DIOF_NONZERO) + && (io.read + io.write == 0)) +@@ -4379,11 +4407,14 @@ display_one_diskio(struct iter *i, unsigned long gendisk, ulong flags) + (char *)(unsigned long)io.write), + space(MINSPACE)); + +- if (!use_mq_interface(queue_addr)) { +- in_flight = i->get_in_flight(queue_addr); +- fprintf(fp, "%5u\n", in_flight); ++ if (VALID_MEMBER(request_queue_in_flight)) { ++ if (!use_mq_interface(queue_addr)) { ++ in_flight = i->get_in_flight(queue_addr); ++ fprintf(fp, "%5u\n", in_flight); ++ } else ++ fprintf(fp, "%s\n", "N/A(MQ)"); + } else +- fprintf(fp, "%s\n", "N/A(MQ)"); ++ fprintf(fp, "\n"); + } + + static void +@@ -4418,7 +4449,7 @@ display_all_diskio(ulong flags) + i.sync_count ? mkstring(buf4, 5, RJUST, "SYNC") : + mkstring(buf4, 5, RJUST, "WRITE"), + space(MINSPACE), +- mkstring(buf5, 5, RJUST, "DRV")); ++ VALID_MEMBER(request_queue_in_flight) ? mkstring(buf5, 5, RJUST, "DRV") : ""); + + while ((gendisk = i.next_disk(&i)) != 0) + display_one_diskio(&i, gendisk, flags); +@@ -4446,6 +4477,7 @@ void diskio_init(void) + MEMBER_OFFSET_INIT(gendisk_part0, "gendisk", "part0"); + MEMBER_OFFSET_INIT(gendisk_queue, "gendisk", "queue"); + MEMBER_OFFSET_INIT(hd_struct_dev, "hd_struct", "__dev"); ++ MEMBER_OFFSET_INIT(hd_struct_dkstats, "hd_struct", "dkstats"); + MEMBER_OFFSET_INIT(klist_k_list, "klist", "k_list"); + MEMBER_OFFSET_INIT(klist_node_n_klist, "klist_node", "n_klist"); + MEMBER_OFFSET_INIT(klist_node_n_node, "klist_node", "n_node"); +@@ -4476,6 +4508,7 @@ void diskio_init(void) + MEMBER_SIZE_INIT(rq_in_flight, "request_queue", "in_flight"); + MEMBER_SIZE_INIT(class_private_devices, "class_private", + "class_devices"); ++ MEMBER_OFFSET_INIT(disk_stats_in_flight, "disk_stats", "in_flight"); + + dt->flags |= DISKIO_INIT; + } +diff --git a/help.c b/help.c +index aadd2ed..1593e82 100644 +--- a/help.c ++++ b/help.c +@@ -3218,7 +3218,7 @@ char *help_dev[] = { + " WRITE: I/O requests that are writes (older kernels)", + " DRV: I/O requests that are in-flight in the device driver.", + " If the device driver uses blk-mq interface, this field", +-" shows N/A(MQ).", ++" shows N/A(MQ). If not available, this column is not shown.", + " -D same as -d, but filter out disks with no in-progress I/O requests.", + "\nEXAMPLES", + " Display character and block device data:\n", +diff --git a/symbols.c b/symbols.c +index ef6f934..5f77e27 100644 +--- a/symbols.c ++++ b/symbols.c +@@ -10021,6 +10021,10 @@ dump_offset_table(char *spec, ulong makestruct) + OFFSET(gendisk_queue)); + fprintf(fp, " hd_struct_dev: %ld\n", + OFFSET(hd_struct_dev)); ++ fprintf(fp, " hd_struct_dkstats: %ld\n", ++ OFFSET(hd_struct_dkstats)); ++ fprintf(fp, " disk_stats_in_flight: %ld\n", ++ OFFSET(disk_stats_in_flight)); + fprintf(fp, " klist_k_list: %ld\n", + OFFSET(klist_k_list)); + fprintf(fp, " klist_node_n_klist: %ld\n", diff --git a/SOURCES/github_46d21219_to_9446958f.patch b/SOURCES/github_46d21219_to_9446958f.patch new file mode 100644 index 0000000..c871403 --- /dev/null +++ b/SOURCES/github_46d21219_to_9446958f.patch @@ -0,0 +1,414 @@ +commit 46d2121960d81354facf4e2558c81f82257b740e +Author: Dave Anderson +Date: Tue May 29 14:04:03 2018 -0400 + + Fix for the "timer -r" command on Linux 4.10 and later kernels that + contain commit 2456e855354415bfaeb7badaa14e11b3e02c8466, titled + "ktime: Get rid of the union". Without the patch, the command fails + with the error message "timer: invalid structure member offset: + ktime_t_sec". + (k-hagio@ab.jp.nec.com) + +diff --git a/kernel.c b/kernel.c +index b1886ce..138a47f 100644 +--- a/kernel.c ++++ b/kernel.c +@@ -7740,7 +7740,7 @@ ktime_to_ns(const void *ktime) + if (VALID_MEMBER(ktime_t_tv64)) { + readmem((ulong)ktime + OFFSET(ktime_t_tv64), KVADDR, &ns, + sizeof(ns), "ktime_t tv64", QUIET|RETURN_ON_ERROR); +- } else { ++ } else if (VALID_MEMBER(ktime_t_sec) && VALID_MEMBER(ktime_t_nsec)) { + uint32_t sec, nsec; + + sec = 0; +@@ -7753,6 +7753,9 @@ ktime_to_ns(const void *ktime) + sizeof(nsec), "ktime_t nsec", QUIET|RETURN_ON_ERROR); + + ns = sec * 1000000000L + nsec; ++ } else { ++ readmem((ulong)ktime, KVADDR, &ns, ++ sizeof(ns), "ktime_t", QUIET|RETURN_ON_ERROR); + } + + return ns; + +commit a6cd8408d1d214a67ed0c4b09343fec77a8e2ae7 +Author: Dave Anderson +Date: Thu May 31 11:43:14 2018 -0400 + + Fix for the x86 and x86_64 "mach -m" option on Linux 4.12 and later + kernels to account for the structure name changes "e820map" to + "e820_table", and "e820entry" to "e820_entry", and for the symbol + name change from "e820" to "e820_table". Also updated the display + output to properly translate E820_PRAM and E820_RESERVED_KERN entries. + Without the patch on all kernels, E820_PRAM and E820_RESERVED_KERN + entries show "type 12" and "type 128" respectively. Without the + patch on Linux 4.12 and later kernels, the command fails with the + error message "mach: cannot resolve e820". + (anderson@redhat.com) + +diff --git a/x86.c b/x86.c +index 47767b6..88562b6 100644 +--- a/x86.c ++++ b/x86.c +@@ -1,8 +1,8 @@ + /* x86.c - core analysis suite + * + * Portions Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002-2014,2017 David Anderson +- * Copyright (C) 2002-2014,2017 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002-2014,2017-2018 David Anderson ++ * Copyright (C) 2002-2014,2017-2018 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 +@@ -1967,15 +1967,27 @@ x86_init(int when) + } + MEMBER_OFFSET_INIT(thread_struct_cr3, "thread_struct", "cr3"); + STRUCT_SIZE_INIT(cpuinfo_x86, "cpuinfo_x86"); +- STRUCT_SIZE_INIT(e820map, "e820map"); +- STRUCT_SIZE_INIT(e820entry, "e820entry"); + STRUCT_SIZE_INIT(irq_ctx, "irq_ctx"); ++ if (STRUCT_EXISTS("e820map")) { ++ STRUCT_SIZE_INIT(e820map, "e820map"); ++ MEMBER_OFFSET_INIT(e820map_nr_map, "e820map", "nr_map"); ++ } else { ++ STRUCT_SIZE_INIT(e820map, "e820_table"); ++ MEMBER_OFFSET_INIT(e820map_nr_map, "e820_table", "nr_entries"); ++ } ++ if (STRUCT_EXISTS("e820entry")) { ++ STRUCT_SIZE_INIT(e820entry, "e820entry"); ++ MEMBER_OFFSET_INIT(e820entry_addr, "e820entry", "addr"); ++ MEMBER_OFFSET_INIT(e820entry_size, "e820entry", "size"); ++ MEMBER_OFFSET_INIT(e820entry_type, "e820entry", "type"); ++ } else { ++ STRUCT_SIZE_INIT(e820entry, "e820_entry"); ++ MEMBER_OFFSET_INIT(e820entry_addr, "e820_entry", "addr"); ++ MEMBER_OFFSET_INIT(e820entry_size, "e820_entry", "size"); ++ MEMBER_OFFSET_INIT(e820entry_type, "e820_entry", "type"); ++ } + if (!VALID_STRUCT(irq_ctx)) + STRUCT_SIZE_INIT(irq_ctx, "irq_stack"); +- MEMBER_OFFSET_INIT(e820map_nr_map, "e820map", "nr_map"); +- MEMBER_OFFSET_INIT(e820entry_addr, "e820entry", "addr"); +- MEMBER_OFFSET_INIT(e820entry_size, "e820entry", "size"); +- MEMBER_OFFSET_INIT(e820entry_type, "e820entry", "type"); + if (KVMDUMP_DUMPFILE()) + set_kvm_iohole(NULL); + if (symbol_exists("irq_desc")) +@@ -4415,33 +4427,54 @@ static char *e820type[] = { + static void + x86_display_memmap(void) + { +- ulong e820; +- int nr_map, i; +- char *buf, *e820entry_ptr; +- ulonglong addr, size; +- ulong type; ++ ulong e820; ++ int nr_map, i; ++ char *buf, *e820entry_ptr; ++ ulonglong addr, size; ++ uint type; ++ ++ if (kernel_symbol_exists("e820")) { ++ if (get_symbol_type("e820", NULL, NULL) == TYPE_CODE_PTR) ++ get_symbol_data("e820", sizeof(void *), &e820); ++ else ++ e820 = symbol_value("e820"); ++ ++ } else if (kernel_symbol_exists("e820_table")) ++ get_symbol_data("e820_table", sizeof(void *), &e820); ++ else ++ error(FATAL, "neither e820 or e820_table symbols exist\n"); + +- e820 = symbol_value("e820"); +- buf = (char *)GETBUF(SIZE(e820map)); ++ if (CRASHDEBUG(1)) { ++ if (STRUCT_EXISTS("e820map")) ++ dump_struct("e820map", e820, RADIX(16)); ++ else if (STRUCT_EXISTS("e820_table")) ++ dump_struct("e820_table", e820, RADIX(16)); ++ } ++ buf = (char *)GETBUF(SIZE(e820map)); + +- readmem(e820, KVADDR, &buf[0], SIZE(e820map), +- "e820map", FAULT_ON_ERROR); ++ readmem(e820, KVADDR, &buf[0], SIZE(e820map), ++ "e820map", FAULT_ON_ERROR); + +- nr_map = INT(buf + OFFSET(e820map_nr_map)); ++ nr_map = INT(buf + OFFSET(e820map_nr_map)); + +- fprintf(fp, " PHYSICAL ADDRESS RANGE TYPE\n"); ++ 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 = ULONG(e820entry_ptr + OFFSET(e820entry_type)); ++ 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 ", addr, addr+size); +- if (type >= (sizeof(e820type)/sizeof(char *))) +- fprintf(fp, "type %ld\n", type); +- else ++ if (type >= (sizeof(e820type)/sizeof(char *))) { ++ if (type == 12) ++ fprintf(fp, "E820_PRAM\n"); ++ else if (type == 128) ++ fprintf(fp, "E820_RESERVED_KERN\n"); ++ else ++ fprintf(fp, "type %d\n", type); ++ } else + fprintf(fp, "%s\n", e820type[type]); +- } ++ } + } + + /* +diff --git a/x86_64.c b/x86_64.c +index 921552b..1d5e155 100644 +--- a/x86_64.c ++++ b/x86_64.c +@@ -415,12 +415,26 @@ x86_64_init(int when) + STRUCT_SIZE_INIT(gate_struct, "gate_desc"); + else + STRUCT_SIZE_INIT(gate_struct, "gate_struct"); +- STRUCT_SIZE_INIT(e820map, "e820map"); +- STRUCT_SIZE_INIT(e820entry, "e820entry"); +- MEMBER_OFFSET_INIT(e820map_nr_map, "e820map", "nr_map"); +- MEMBER_OFFSET_INIT(e820entry_addr, "e820entry", "addr"); +- MEMBER_OFFSET_INIT(e820entry_size, "e820entry", "size"); +- MEMBER_OFFSET_INIT(e820entry_type, "e820entry", "type"); ++ ++ if (STRUCT_EXISTS("e820map")) { ++ STRUCT_SIZE_INIT(e820map, "e820map"); ++ MEMBER_OFFSET_INIT(e820map_nr_map, "e820map", "nr_map"); ++ } else { ++ STRUCT_SIZE_INIT(e820map, "e820_table"); ++ MEMBER_OFFSET_INIT(e820map_nr_map, "e820_table", "nr_entries"); ++ } ++ if (STRUCT_EXISTS("e820entry")) { ++ STRUCT_SIZE_INIT(e820entry, "e820entry"); ++ MEMBER_OFFSET_INIT(e820entry_addr, "e820entry", "addr"); ++ MEMBER_OFFSET_INIT(e820entry_size, "e820entry", "size"); ++ MEMBER_OFFSET_INIT(e820entry_type, "e820entry", "type"); ++ } else { ++ STRUCT_SIZE_INIT(e820entry, "e820_entry"); ++ MEMBER_OFFSET_INIT(e820entry_addr, "e820_entry", "addr"); ++ MEMBER_OFFSET_INIT(e820entry_size, "e820_entry", "size"); ++ MEMBER_OFFSET_INIT(e820entry_type, "e820_entry", "type"); ++ } ++ + if (KVMDUMP_DUMPFILE()) + set_kvm_iohole(NULL); + MEMBER_OFFSET_INIT(thread_struct_rip, "thread_struct", "rip"); +@@ -5643,12 +5657,23 @@ x86_64_display_memmap(void) + ulonglong addr, size; + uint type; + +- if (get_symbol_type("e820", NULL, NULL) == TYPE_CODE_PTR) +- get_symbol_data("e820", sizeof(void *), &e820); ++ if (kernel_symbol_exists("e820")) { ++ if (get_symbol_type("e820", NULL, NULL) == TYPE_CODE_PTR) ++ get_symbol_data("e820", sizeof(void *), &e820); ++ else ++ e820 = symbol_value("e820"); ++ ++ } else if (kernel_symbol_exists("e820_table")) ++ get_symbol_data("e820_table", sizeof(void *), &e820); + else +- e820 = symbol_value("e820"); +- if (CRASHDEBUG(1)) +- dump_struct("e820map", e820, RADIX(16)); ++ error(FATAL, "neither e820 or e820_table symbols exist\n"); ++ ++ if (CRASHDEBUG(1)) { ++ if (STRUCT_EXISTS("e820map")) ++ dump_struct("e820map", e820, RADIX(16)); ++ else if (STRUCT_EXISTS("e820_table")) ++ dump_struct("e820_table", e820, RADIX(16)); ++ } + buf = (char *)GETBUF(SIZE(e820map)); + + readmem(e820, KVADDR, &buf[0], SIZE(e820map), +@@ -5664,9 +5689,14 @@ x86_64_display_memmap(void) + size = ULONGLONG(e820entry_ptr + OFFSET(e820entry_size)); + type = UINT(e820entry_ptr + OFFSET(e820entry_type)); + fprintf(fp, "%016llx - %016llx ", addr, addr+size); +- if (type >= (sizeof(e820type)/sizeof(char *))) +- fprintf(fp, "type %d\n", type); +- else ++ if (type >= (sizeof(e820type)/sizeof(char *))) { ++ if (type == 12) ++ fprintf(fp, "E820_PRAM\n"); ++ else if (type == 128) ++ fprintf(fp, "E820_RESERVED_KERN\n"); ++ else ++ fprintf(fp, "type %d\n", type); ++ } else + fprintf(fp, "%s\n", e820type[type]); + } + } + +commit da49e2010b3cb88b4755d69d38fe90af6ba218b2 +Author: Dave Anderson +Date: Fri Jun 1 10:58:00 2018 -0400 + + Update for the recognition of the new x86_64 CPU_ENTRY_AREA virtual + address range introduced in Linux 4.15. The memory range exists + above the vmemmap range and below the mapped kernel static text/data + region, and where all of the x86_64 exception stacks have been moved. + Without the patch, reads from the new memory region fail because the + address range is not recognized as a legitimate virtual address. + Most notable is the failure of "bt" on tasks whose backtraces + originate from any of the exception stacks, which fail with the two + error messages "bt: seek error: kernel virtual address:
+ type: stack contents" followed by "bt: read of stack at
+ failed". + (anderson@redhat.com) + +diff --git a/defs.h b/defs.h +index 931be07..6e6f6be 100644 +--- a/defs.h ++++ b/defs.h +@@ -3391,6 +3391,9 @@ struct arm64_stackframe { + #define VSYSCALL_START 0xffffffffff600000 + #define VSYSCALL_END 0xffffffffff601000 + ++#define CPU_ENTRY_AREA_START 0xfffffe0000000000 ++#define CPU_ENTRY_AREA_END 0xfffffe7fffffffff ++ + #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)) +@@ -5829,6 +5832,8 @@ struct machine_specific { + ulong kpti_entry_stack; + ulong kpti_entry_stack_size; + ulong ptrs_per_pgd; ++ ulong cpu_entry_area_start; ++ ulong cpu_entry_area_end; + }; + + #define KSYMS_START (0x1) +diff --git a/x86_64.c b/x86_64.c +index 1d5e155..54b6539 100644 +--- a/x86_64.c ++++ b/x86_64.c +@@ -407,6 +407,11 @@ x86_64_init(int when) + machdep->machspec->modules_end = MODULES_END_2_6_31; + } + } ++ if (STRUCT_EXISTS("cpu_entry_area")) { ++ machdep->machspec->cpu_entry_area_start = CPU_ENTRY_AREA_START; ++ machdep->machspec->cpu_entry_area_end = CPU_ENTRY_AREA_END; ++ } ++ + STRUCT_SIZE_INIT(cpuinfo_x86, "cpuinfo_x86"); + /* + * Before 2.6.25 the structure was called gate_struct +@@ -879,20 +884,21 @@ x86_64_dump_machdep_table(ulong arg) + + /* pml4 and upml is legacy for extension modules */ + if (ms->pml4) { +- fprintf(fp, " pml4: %lx\n", (ulong)ms->pml4); +- fprintf(fp, " last_pml4_read: %lx\n", (ulong)ms->last_pml4_read); ++ fprintf(fp, " pml4: %lx\n", (ulong)ms->pml4); ++ fprintf(fp, " last_pml4_read: %lx\n", (ulong)ms->last_pml4_read); + + } else { +- fprintf(fp, " pml4: (unused)\n"); +- fprintf(fp, " last_pml4_read: (unused)\n"); ++ fprintf(fp, " pml4: (unused)\n"); ++ fprintf(fp, " last_pml4_read: (unused)\n"); + } + + if (ms->upml) { +- fprintf(fp, " upml: %lx\n", (ulong)ms->upml); +- fprintf(fp, " last_upml_read: %lx\n", (ulong)ms->last_upml_read); ++ fprintf(fp, " upml: %lx\n", (ulong)ms->upml); ++ fprintf(fp, " last_upml_read: %lx\n", (ulong)ms->last_upml_read); + } else { +- fprintf(fp, " upml: (unused)\n"); +- fprintf(fp, " last_upml_read: (unused)\n"); ++ fprintf(fp, " GART_end: %lx\n", ms->GART_end); ++ fprintf(fp, " upml: (unused)\n"); ++ fprintf(fp, " last_upml_read: (unused)\n"); + } + + if (ms->p4d) { +@@ -1016,10 +1022,14 @@ x86_64_dump_machdep_table(ulong arg) + fprintf(fp, "\n "); + fprintf(fp, "%016lx ", ms->stkinfo.ibase[c]); + } +- fprintf(fp, "\n kpti_entry_stack_size: %ld", ms->kpti_entry_stack_size); +- fprintf(fp, "\n kpti_entry_stack: "); ++ fprintf(fp, "\n kpti_entry_stack_size: "); ++ if (ms->kpti_entry_stack_size) ++ fprintf(fp, "%ld", ms->kpti_entry_stack_size); ++ else ++ fprintf(fp, "(unused)"); ++ fprintf(fp, "\n kpti_entry_stack: "); + if (machdep->flags & KPTI) { +- fprintf(fp, "%lx\n ", ms->kpti_entry_stack); ++ fprintf(fp, "(percpu: %lx):\n ", ms->kpti_entry_stack); + for (c = 0; c < cpus; c++) { + if (c && !(c%4)) + fprintf(fp, "\n "); +@@ -1028,6 +1038,16 @@ x86_64_dump_machdep_table(ulong arg) + fprintf(fp, "\n"); + } else + fprintf(fp, "(unused)\n"); ++ fprintf(fp, " cpu_entry_area_start: "); ++ if (ms->cpu_entry_area_start) ++ fprintf(fp, "%016lx\n", (ulong)ms->cpu_entry_area_start); ++ else ++ fprintf(fp, "(unused)\n"); ++ fprintf(fp, " cpu_entry_area_end: "); ++ if (ms->cpu_entry_area_end) ++ fprintf(fp, "%016lx\n", (ulong)ms->cpu_entry_area_end); ++ else ++ fprintf(fp, "(unused)\n"); + } + + /* +@@ -1586,7 +1606,10 @@ x86_64_IS_VMALLOC_ADDR(ulong vaddr) + ((machdep->flags & VMEMMAP) && + (vaddr >= VMEMMAP_VADDR && vaddr <= VMEMMAP_END)) || + (vaddr >= MODULES_VADDR && vaddr <= MODULES_END) || +- (vaddr >= VSYSCALL_START && vaddr < VSYSCALL_END)); ++ (vaddr >= VSYSCALL_START && vaddr < VSYSCALL_END) || ++ (machdep->machspec->cpu_entry_area_start && ++ vaddr >= machdep->machspec->cpu_entry_area_start && ++ vaddr <= machdep->machspec->cpu_entry_area_end)); + } + + static int + +commit 9446958fe211825ed5524317b05d5ea020bb00d6 +Author: Dave Anderson +Date: Fri Jun 1 14:01:01 2018 -0400 + + Fix to address a "__builtin___snprintf_chk" compiler warning if bpf.c + is compiled with -D_FORTIFY_SOURCE=2. + (anderson@redhat.com) + +diff --git a/bpf.c b/bpf.c +index 305d49f..ee1986f 100644 +--- a/bpf.c ++++ b/bpf.c +@@ -362,7 +362,7 @@ do_bpf(ulong flags, ulong prog_id, ulong map_id, int radix) + fprintf(fp, " LOAD_TIME: "); + if (VALID_MEMBER(bpf_prog_aux_load_time)) { + load_time = ULONGLONG(bpf->bpf_prog_aux_buf + OFFSET(bpf_prog_aux_load_time)); +- print_boot_time(load_time, buf5, BUFSIZE); ++ print_boot_time(load_time, buf5, BUFSIZE/2); + fprintf(fp, "%s\n", buf5); + } else + fprintf(fp, "(unknown)\n"); diff --git a/SOURCES/github_64dad6d0.patch b/SOURCES/github_64dad6d0.patch new file mode 100644 index 0000000..7f41a57 --- /dev/null +++ b/SOURCES/github_64dad6d0.patch @@ -0,0 +1,34 @@ + +commit 64dad6d0d60514498252e6071738fa1b4c12db8c +Author: Dave Anderson +Date: Thu Nov 29 14:21:19 2018 -0500 + + Fix for the "ps -s" option on ARM64 if the number of tasks exceeds + 2000. Without the patch, the command ultimately fails with a + dump of the internal buffer allocation stats, followed by the + message "ps: cannot allocate any more memory!". + (anderson@redhat.com) + +diff -up crash-7.2.3/task.c.orig crash-7.2.3/task.c +--- crash-7.2.3/task.c.orig 2018-11-29 13:54:39.108320730 -0500 ++++ crash-7.2.3/task.c 2018-11-29 13:54:48.598279086 -0500 +@@ -4133,6 +4133,10 @@ task_pointer_string(struct task_context + readmem(tc->task + OFFSET(task_struct_thread_ksp), + KVADDR, &bt->stkptr, sizeof(void *), + "thread_struct ksp", FAULT_ON_ERROR); ++ } else if (VALID_MEMBER(task_struct_thread_context_sp)) { ++ readmem(tc->task + OFFSET(task_struct_thread_context_sp), ++ KVADDR, &bt->stkptr, sizeof(void *), ++ "cpu_context sp", FAULT_ON_ERROR); + } else { + if ((bt->stackbase = GET_STACKBASE(tc->task))) { + bt->stacktop = GET_STACKTOP(tc->task); +@@ -4140,6 +4144,8 @@ task_pointer_string(struct task_context + bt->tc = tc; + bt->flags |= BT_KSTACKP; + back_trace(bt); ++ if (bt->stackbuf) ++ FREEBUF(bt->stackbuf); + } else + bt->stkptr = 0; + } diff --git a/SOURCES/github_6b93714b_cmdline.patch b/SOURCES/github_6b93714b_cmdline.patch new file mode 100644 index 0000000..0fe9a66 --- /dev/null +++ b/SOURCES/github_6b93714b_cmdline.patch @@ -0,0 +1,39 @@ +commit 6b93714b83d59ae4147b8ec3887261aca7fd6f65 +Author: Dave Anderson +Date: Mon Jan 7 10:44:29 2019 -0500 + + Prevent a SIGSEGV if a user attempts to input a command line that + exceeds the maximum length of 1500 bytes. The patch displays an + error message and ignores the command line. + (anderson@redhat.com) + +diff --git a/cmdline.c b/cmdline.c +index 665f48c..796f7c5 100644 +--- a/cmdline.c ++++ b/cmdline.c +@@ -1,8 +1,8 @@ + /* cmdline.c - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002-2015,2018 David Anderson +- * Copyright (C) 2002-2015,2018 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002-2015,2019 David Anderson ++ * Copyright (C) 2002-2015,2019 Red Hat, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -121,9 +121,11 @@ process_command_line(void) + args[0] = NULL; + fprintf(fp, "\n"); + return; +- } +- +- strcpy(pc->command_line, pc->readline); ++ } ++ if (strlen(pc->readline) >= BUFSIZE) ++ error(FATAL, "input line exceeds maximum of 1500 bytes\n"); ++ else ++ strcpy(pc->command_line, pc->readline); + free(pc->readline); + + clean_line(pc->command_line); diff --git a/SOURCES/github_8618ddd8_CONFIG_ARM64_USER_VA_BITS_52 b/SOURCES/github_8618ddd8_CONFIG_ARM64_USER_VA_BITS_52 new file mode 100644 index 0000000..c15eddc --- /dev/null +++ b/SOURCES/github_8618ddd8_CONFIG_ARM64_USER_VA_BITS_52 @@ -0,0 +1,212 @@ +commit 8618ddd817621c40c1f44f0ab6df7c7805234416 +Author: Dave Anderson +Date: Fri Feb 1 15:01:29 2019 -0500 + + First phase of support for ARM64 kernels that are configured with + CONFIG_ARM64_USER_VA_BITS_52, which causes the PTRS_PER_PGD count + to increase from 64 to 1024. Without the patch, "WARNING: cannot + access vmalloc'd module memory" will be displayed during session + initialization, and the translation of any mapped kernel virtual + address that requires a page table walk will fail, leading to a + myriad of other errors. + (anderson@redhat.com) + +diff --git a/arm64.c b/arm64.c +index 45c7313..2308612 100644 +--- a/arm64.c ++++ b/arm64.c +@@ -1,8 +1,8 @@ + /* + * arm64.c - core analysis suite + * +- * Copyright (C) 2012-2018 David Anderson +- * Copyright (C) 2012-2018 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2012-2019 David Anderson ++ * Copyright (C) 2012-2019 Red Hat, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -209,6 +209,8 @@ arm64_init(int when) + ms->page_offset = ARM64_PAGE_OFFSET; + machdep->identity_map_base = ARM64_PAGE_OFFSET; + machdep->kvbase = ARM64_VA_START; ++ machdep->is_kvaddr = generic_is_kvaddr; ++ machdep->kvtop = arm64_kvtop; + ms->userspace_top = ARM64_USERSPACE_TOP; + if (machdep->flags & NEW_VMEMMAP) { + struct syment *sp; +@@ -262,11 +264,17 @@ arm64_init(int when) + break; + + case 65536: ++ if (kernel_symbol_exists("idmap_ptrs_per_pgd") && ++ readmem(symbol_value("idmap_ptrs_per_pgd"), KVADDR, ++ &value, sizeof(ulong), "idmap_ptrs_per_pgd", RETURN_ON_ERROR)) ++ machdep->ptrs_per_pgd = value; ++ + if (machdep->machspec->VA_BITS > PGDIR_SHIFT_L3_64K) { + machdep->flags |= VM_L3_64K; +- machdep->ptrs_per_pgd = PTRS_PER_PGD_L3_64K; ++ if (!machdep->ptrs_per_pgd) ++ machdep->ptrs_per_pgd = PTRS_PER_PGD_L3_64K; + if ((machdep->pgd = +- (char *)malloc(PTRS_PER_PGD_L3_64K * 8)) == NULL) ++ (char *)malloc(machdep->ptrs_per_pgd * 8)) == NULL) + error(FATAL, "cannot malloc pgd space."); + if ((machdep->pmd = + (char *)malloc(PTRS_PER_PMD_L3_64K * 8)) == NULL) +@@ -276,9 +284,10 @@ arm64_init(int when) + error(FATAL, "cannot malloc ptbl space."); + } else { + machdep->flags |= VM_L2_64K; +- machdep->ptrs_per_pgd = PTRS_PER_PGD_L2_64K; ++ if (!machdep->ptrs_per_pgd) ++ machdep->ptrs_per_pgd = PTRS_PER_PGD_L2_64K; + if ((machdep->pgd = +- (char *)malloc(PTRS_PER_PGD_L2_64K * 8)) == NULL) ++ (char *)malloc(machdep->ptrs_per_pgd * 8)) == NULL) + error(FATAL, "cannot malloc pgd space."); + if ((machdep->ptbl = + (char *)malloc(PTRS_PER_PTE_L2_64K * 8)) == NULL) +@@ -306,9 +315,11 @@ arm64_init(int when) + machdep->flags |= VMEMMAP; + + machdep->uvtop = arm64_uvtop; +- machdep->kvtop = arm64_kvtop; +- machdep->is_kvaddr = generic_is_kvaddr; + machdep->is_uvaddr = arm64_is_uvaddr; ++ if (kernel_symbol_exists("vabits_user") && ++ readmem(symbol_value("vabits_user"), KVADDR, ++ &value, sizeof(ulong), "vabits_user", RETURN_ON_ERROR)) ++ machdep->machspec->vabits_user = value; + machdep->eframe_search = arm64_eframe_search; + machdep->back_trace = arm64_back_trace_cmd; + machdep->in_alternate_stack = arm64_in_alternate_stack; +@@ -350,10 +361,14 @@ arm64_init(int when) + case POST_GDB: + arm64_calc_virtual_memory_ranges(); + machdep->section_size_bits = _SECTION_SIZE_BITS; +- if (THIS_KERNEL_VERSION >= LINUX(3,17,0)) +- machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_3_17; +- else +- machdep->max_physmem_bits = _MAX_PHYSMEM_BITS; ++ if (!machdep->max_physmem_bits) { ++ if (machdep->machspec->VA_BITS == 52) /* guess */ ++ machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_52; ++ else if (THIS_KERNEL_VERSION >= LINUX(3,17,0)) ++ machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_3_17; ++ else ++ machdep->max_physmem_bits = _MAX_PHYSMEM_BITS; ++ } + ms = machdep->machspec; + + if (THIS_KERNEL_VERSION >= LINUX(4,0,0)) { +@@ -601,6 +616,11 @@ arm64_dump_machdep_table(ulong arg) + + fprintf(fp, " machspec: %lx\n", (ulong)ms); + fprintf(fp, " VA_BITS: %ld\n", ms->VA_BITS); ++ fprintf(fp, " vabits_user: "); ++ if (ms->vabits_user) ++ fprintf(fp, "%ld\n", ms->vabits_user); ++ else ++ fprintf(fp, "(unused)\n"); + fprintf(fp, " userspace_top: %016lx\n", ms->userspace_top); + fprintf(fp, " page_offset: %016lx\n", ms->page_offset); + fprintf(fp, " vmalloc_start_addr: %016lx\n", ms->vmalloc_start_addr); +@@ -691,6 +711,8 @@ arm64_parse_machdep_arg_l(char *argstring, char *param, ulong *value) + *value = dtol(p, flags, &err); + if (!err) + *value = MEGABYTES(*value); ++ } else if (STRNEQ(argstring, "max_physmem_bits")) { ++ *value = dtol(p, flags, &err); + } else { + *value = htol(p, flags, &err); + } +@@ -750,6 +772,12 @@ arm64_parse_cmdline_args(void) + "setting kimage_voffset to: 0x%lx\n\n", + machdep->machspec->kimage_voffset); + continue; ++ } else if (arm64_parse_machdep_arg_l(arglist[i], "max_physmem_bits", ++ &machdep->max_physmem_bits)) { ++ error(NOTE, ++ "setting max_physmem_bits to: %ld\n\n", ++ machdep->max_physmem_bits); ++ continue; + } + + error(WARNING, "ignoring --machdep option: %s\n", +@@ -1065,8 +1093,8 @@ arm64_vtop_2level_64k(ulong pgd, ulong vaddr, physaddr_t *paddr, int verbose) + fprintf(fp, "PAGE DIRECTORY: %lx\n", pgd); + + pgd_base = (ulong *)pgd; +- FILL_PGD(pgd_base, KVADDR, PTRS_PER_PGD_L2_64K * sizeof(ulong)); +- pgd_ptr = pgd_base + (((vaddr) >> PGDIR_SHIFT_L2_64K) & (PTRS_PER_PGD_L2_64K - 1)); ++ FILL_PGD(pgd_base, KVADDR, machdep->ptrs_per_pgd * sizeof(ulong)); ++ pgd_ptr = pgd_base + (((vaddr) >> PGDIR_SHIFT_L2_64K) & (machdep->ptrs_per_pgd - 1)); + pgd_val = ULONG(machdep->pgd + PAGEOFFSET(pgd_ptr)); + if (verbose) + fprintf(fp, " PGD: %lx => %lx\n", (ulong)pgd_ptr, pgd_val); +@@ -1129,8 +1157,8 @@ arm64_vtop_3level_64k(ulong pgd, ulong vaddr, physaddr_t *paddr, int verbose) + fprintf(fp, "PAGE DIRECTORY: %lx\n", pgd); + + pgd_base = (ulong *)pgd; +- FILL_PGD(pgd_base, KVADDR, PTRS_PER_PGD_L3_64K * sizeof(ulong)); +- pgd_ptr = pgd_base + (((vaddr) >> PGDIR_SHIFT_L3_64K) & (PTRS_PER_PGD_L3_64K - 1)); ++ FILL_PGD(pgd_base, KVADDR, machdep->ptrs_per_pgd * sizeof(ulong)); ++ pgd_ptr = pgd_base + (((vaddr) >> PGDIR_SHIFT_L3_64K) & (machdep->ptrs_per_pgd - 1)); + pgd_val = ULONG(machdep->pgd + PGDIR_OFFSET_L3_64K(pgd_ptr)); + if (verbose) + fprintf(fp, " PGD: %lx => %lx\n", (ulong)pgd_ptr, pgd_val); +diff --git a/crash.8 b/crash.8 +index 8c11615..f9de36d 100644 +--- a/crash.8 ++++ b/crash.8 +@@ -278,6 +278,7 @@ ARM: + ARM64: + phys_offset= + kimage_voffset= ++ max_physmem_bits= + X86: + page_offset= + .fi +diff --git a/defs.h b/defs.h +index b473972..05f2d17 100644 +--- a/defs.h ++++ b/defs.h +@@ -3049,7 +3049,7 @@ typedef signed int s32; + #define PMD_SHIFT_L3_64K (29) + #define PMD_SIZE_L3_64K (1UL << PMD_SHIFT_L3_64K) + #define PMD_MASK_L3_64K (~(PMD_SIZE_L3_64K-1)) +-#define PGDIR_OFFSET_L3_64K(X) (((ulong)(X)) & ((PTRS_PER_PGD_L3_64K * 8) - 1)) ++#define PGDIR_OFFSET_L3_64K(X) (((ulong)(X)) & ((machdep->ptrs_per_pgd * 8) - 1)) + + /* + * 2-levels / 64K pages +@@ -3136,6 +3136,7 @@ typedef signed int s32; + #define _SECTION_SIZE_BITS 30 + #define _MAX_PHYSMEM_BITS 40 + #define _MAX_PHYSMEM_BITS_3_17 48 ++#define _MAX_PHYSMEM_BITS_52 52 + + typedef unsigned long long __u64; + typedef unsigned long long u64; +@@ -3215,6 +3216,7 @@ struct machine_specific { + ulong kern_eframe_offset; + ulong machine_kexec_start; + ulong machine_kexec_end; ++ ulong vabits_user; + }; + + struct arm64_stackframe { +diff --git a/help.c b/help.c +index ff0c80b..ba15dec 100644 +--- a/help.c ++++ b/help.c +@@ -179,6 +179,7 @@ char *program_usage_info[] = { + " ARM64:", + " phys_offset=", + " kimage_voffset=", ++ " max_physmem_bits=", + " X86:", + " page_offset=", + "", diff --git a/SOURCES/github_95daa11b.patch b/SOURCES/github_95daa11b.patch new file mode 100644 index 0000000..b36d5ab --- /dev/null +++ b/SOURCES/github_95daa11b.patch @@ -0,0 +1,23 @@ +commit 95daa11b82dfa6aa3e68ffc92e1282abc1b2b62a +Author: Dave Anderson +Date: Fri Jun 1 15:28:55 2018 -0400 + + Fix for the "bpf -t" option. Although highly unlikely, without the + patch, the target function name of a BPF bytecode call instruction + may fail to be resolved correctly. + (anderson@redhat.com) + +diff --git a/bpf.c b/bpf.c +index ee1986f..427263d 100644 +--- a/bpf.c ++++ b/bpf.c +@@ -1060,8 +1060,7 @@ static char *__func_get_name(const struct bpf_insn *insn, + return buff; + + if (insn->src_reg != BPF_PSEUDO_CALL && +- insn->imm >= 0 && insn->imm < __BPF_FUNC_MAX_ID && +- func_id_str[insn->imm]) { ++ insn->imm >= 0 && insn->imm < __BPF_FUNC_MAX_ID) { + // return func_id_str[insn->imm]; + if (!readmem(symbol_value("func_id_str") + (insn->imm * sizeof(void *)), + KVADDR, &func_id_ptr, sizeof(void *), "func_id_str pointer", diff --git a/SOURCES/github_9b494b70_to_eb823b79.patch b/SOURCES/github_9b494b70_to_eb823b79.patch new file mode 100644 index 0000000..5723118 --- /dev/null +++ b/SOURCES/github_9b494b70_to_eb823b79.patch @@ -0,0 +1,1233 @@ + +commit 9b494b7006bcc7f3f0bf3be9e3c6d3a5e703a728 +Author: Dave Anderson +Date: Tue Jun 26 16:00:28 2018 -0400 + + Update for the "kmem -V" option to also dump the global entries that + are contained in the "vm_numa_stat" array that was introduced in + Linux 4.14. Also, the command output separates the "vm_zone_stat", + "vm_node_stat" and "vm_numa_stat" entries into separate sections with + "VM_ZONE_STAT", "VM_NODE_STAT" and "VM_NUMA_STAT" headers. Without + the patch, the "vm_zone_stat" and "vm_node_stat" entries are listed + together under a "VM_STAT" header. + (anderson@redhat.com) + +diff --git a/help.c b/help.c +index 5a52650..638c6ec 100644 +--- a/help.c ++++ b/help.c +@@ -6451,9 +6451,10 @@ char *help_kmem[] = { + " -C same as -c, but also dumps all pages in the page_hash_table.", + " -i displays general memory usage information", + " -v displays the mapped virtual memory regions allocated by vmalloc().", +-" -V displays the kernel vm_stat table if it exists, the cumulative", +-" page_states counter values if they exist, and/or the cumulative", +-" vm_event_states counter values if they exist.", ++" -V displays the kernel vm_stat table if it exists, or in more recent", ++" kernels, the vm_zone_stat, vm_node_stat and vm_numa_stat tables,", ++" the cumulative page_states counter values if they exist, and/or ", ++" the cumulative, vm_event_states counter values if they exist.", + " -n display memory node data (if supported).", + " -z displays per-zone memory statistics.", + " -o displays each cpu's offset value that is added to per-cpu symbol", +@@ -6761,24 +6762,69 @@ char *help_kmem[] = { + " f63d5cc0 f6287b80 f83c2000 - f84c3000 1052672", + " ...", + " ", +-" Dump the vm_table contents:\n", ++" Dump the virtual memory statistics:\n", + " %s> kmem -V", +-" NR_ANON_PAGES: 38989", +-" NR_FILE_MAPPED: 3106", +-" NR_FILE_PAGES: 169570", +-" NR_SLAB: 32439", +-" NR_PAGETABLE: 1181", +-" NR_FILE_DIRTY: 4633", +-" NR_WRITEBACK: 0", +-" NR_UNSTABLE_NFS: 0", +-" NR_BOUNCE: 0", +-" NUMA_HIT: 63545992", +-" NUMA_MISS: 0", +-" NUMA_FOREIGN: 0", +-" NUMA_INTERLEAVE_HIT: 24002", +-" NUMA_LOCAL: 63545992", +-" NUMA_OTHER: 0", +-" ", ++" VM_ZONE_STAT:", ++" NR_FREE_PAGES: 30085", ++" NR_ZONE_INACTIVE_ANON: 1985", ++" NR_ZONE_ACTIVE_ANON: 338275", ++" NR_ZONE_INACTIVE_FILE: 19760", ++" NR_ZONE_ACTIVE_FILE: 12018", ++" NR_ZONE_UNEVICTABLE: 0", ++" NR_ZONE_WRITE_PENDING: 4", ++" NR_MLOCK: 0", ++" NR_PAGETABLE: 1562", ++" NR_KERNEL_STACK_KB: 1728", ++" NR_BOUNCE: 0", ++" NR_FREE_CMA_PAGES: 0", ++" ", ++" VM_NODE_STAT:", ++" NR_INACTIVE_ANON: 1985", ++" NR_ACTIVE_ANON: 338275", ++" NR_INACTIVE_FILE: 19760", ++" NR_ACTIVE_FILE: 12018", ++" NR_UNEVICTABLE: 0", ++" NR_SLAB_RECLAIMABLE: 3111", ++" NR_SLAB_UNRECLAIMABLE: 3039", ++" NR_ISOLATED_ANON: 0", ++" NR_ISOLATED_FILE: 0", ++" WORKINGSET_REFAULT: 0", ++" WORKINGSET_ACTIVATE: 0", ++" WORKINGSET_NODERECLAIM: 0", ++" NR_ANON_MAPPED: 338089", ++" NR_FILE_MAPPED: 8102", ++" NR_FILE_PAGES: 33949", ++" NR_FILE_DIRTY: 4", ++" NR_WRITEBACK: 0", ++" NR_WRITEBACK_TEMP: 0", ++" NR_SHMEM: 2171", ++" NR_SHMEM_THPS: 0", ++" NR_SHMEM_PMDMAPPED: 0", ++" NR_ANON_THPS: 86", ++" NR_UNSTABLE_NFS: 0", ++" NR_VMSCAN_WRITE: 0", ++" NR_VMSCAN_IMMEDIATE: 0", ++" NR_DIRTIED: 155", ++" NR_WRITTEN: 75", ++" ", ++" VM_NUMA_STAT:", ++" NUMA_HIT: 575409", ++" NUMA_MISS: 0", ++" NUMA_FOREIGN: 0", ++" NUMA_INTERLEAVE_HIT: 12930", ++" NUMA_LOCAL: 575409", ++" NUMA_OTHER: 0", ++" ", ++" VM_EVENT_STATES:", ++" PGPGIN: 282492", ++" PGPGOUT: 6773", ++" PSWPIN: 0", ++" PSWPOUT: 0", ++" PGALLOC_DMA: 0", ++" PGALLOC_DMA32: 693092", ++" PGALLOC_NORMAL: 0", ++" ...", ++" ", + " Display hugepage hstate information: \n", + " %s> kmem -h", + " HSTATE SIZE FREE TOTAL NAME", +diff --git a/memory.c b/memory.c +index 5c0a853..81ed689 100644 +--- a/memory.c ++++ b/memory.c +@@ -17422,7 +17422,7 @@ vm_stat_init(void) + int c ATTRIBUTE_UNUSED; + struct gnu_request *req; + char *start; +- long enum_value, zc = -1; ++ long enum_value, zone_cnt = -1, node_cnt = -1; + int split_vmstat = 0, ni = 0; + + if (vt->flags & VM_STAT) +@@ -17451,11 +17451,21 @@ vm_stat_init(void) + } else if (symbol_exists("vm_zone_stat") && + get_symbol_type("vm_zone_stat", + NULL, NULL) == TYPE_CODE_ARRAY) { +- vt->nr_vm_stat_items = +- get_array_length("vm_zone_stat", NULL, 0) +- + get_array_length("vm_node_stat", NULL, 0); +- split_vmstat = 1; +- enumerator_value("NR_VM_ZONE_STAT_ITEMS", &zc); ++ if (symbol_exists("vm_numa_stat")) { ++ vt->nr_vm_stat_items = ++ get_array_length("vm_zone_stat", NULL, 0) ++ + get_array_length("vm_node_stat", NULL, 0) ++ + get_array_length("vm_numa_stat", NULL, 0); ++ split_vmstat = 2; ++ enumerator_value("NR_VM_ZONE_STAT_ITEMS", &zone_cnt); ++ enumerator_value("NR_VM_NODE_STAT_ITEMS", &node_cnt); ++ } else { ++ vt->nr_vm_stat_items = ++ get_array_length("vm_zone_stat", NULL, 0) ++ + get_array_length("vm_node_stat", NULL, 0); ++ split_vmstat = 1; ++ enumerator_value("NR_VM_ZONE_STAT_ITEMS", &zone_cnt); ++ } + } else { + goto bailout; + } +@@ -17468,13 +17478,20 @@ vm_stat_init(void) + req->flags = GNU_PRINT_ENUMERATORS; + gdb_interface(req); + +- if (split_vmstat) { ++ if (split_vmstat >= 1) { + req->command = GNU_GET_DATATYPE; + req->name = "node_stat_item"; + req->flags = GNU_PRINT_ENUMERATORS; + gdb_interface(req); + } + ++ if (split_vmstat == 2) { ++ req->command = GNU_GET_DATATYPE; ++ req->name = "numa_stat_item"; ++ req->flags = GNU_PRINT_ENUMERATORS; ++ gdb_interface(req); ++ } ++ + FREEBUF(req); + + stringlen = 1; +@@ -17488,15 +17505,20 @@ vm_stat_init(void) + c = parse_line(buf, arglist); + if ((!split_vmstat && + STREQ(arglist[0], "NR_VM_ZONE_STAT_ITEMS")) || +- (split_vmstat && +- STREQ(arglist[0], "NR_VM_NODE_STAT_ITEMS"))) { ++ ((split_vmstat == 1) && ++ STREQ(arglist[0], "NR_VM_NODE_STAT_ITEMS")) || ++ ((split_vmstat == 2) && ++ STREQ(arglist[0], "NR_VM_NUMA_STAT_ITEMS"))) { + if (LKCD_KERNTYPES()) + vt->nr_vm_stat_items = + MAX(atoi(arglist[2]), count); + break; +- } else if (split_vmstat && ++ } else if ((split_vmstat == 1) && + STREQ(arglist[0], "NR_VM_ZONE_STAT_ITEMS")) { + continue; ++ } else if ((split_vmstat == 2) && ++ STREQ(arglist[0], "NR_VM_NODE_STAT_ITEMS")) { ++ continue; + } else { + stringlen += strlen(arglist[0]) + 1; + count++; +@@ -17523,8 +17545,11 @@ vm_stat_init(void) + } + + i = ni + enum_value; +- if (!ni && (enum_value == zc)) { +- ni = zc; ++ if (!ni && (enum_value == zone_cnt)) { ++ ni = zone_cnt; ++ continue; ++ } else if ((ni == zone_cnt) && (enum_value == node_cnt)) { ++ ni += node_cnt; + continue; + } + +@@ -17556,8 +17581,8 @@ dump_vm_stat(char *item, long *retval, ulong zone) + char *buf; + ulong *vp; + ulong location; +- int i, maxlen, len; +- long tc, zc = 0, nc = 0; ++ int i, maxlen, len, node_start = -1, numa_start = 1; ++ long total_cnt, zone_cnt = 0, node_cnt = 0, numa_cnt = 0; + int split_vmstat = 0; + + if (!vm_stat_init()) { +@@ -17570,48 +17595,86 @@ dump_vm_stat(char *item, long *retval, ulong zone) + + buf = GETBUF(sizeof(ulong) * vt->nr_vm_stat_items); + +- if (symbol_exists("vm_node_stat") && symbol_exists("vm_zone_stat")) ++ if (symbol_exists("vm_node_stat") && symbol_exists("vm_zone_stat") && ++ symbol_exists("vm_numa_stat")) ++ split_vmstat = 2; ++ else if (symbol_exists("vm_node_stat") && symbol_exists("vm_zone_stat")) + split_vmstat = 1; + else + location = zone ? zone : symbol_value("vm_stat"); + +- if (split_vmstat) { +- enumerator_value("NR_VM_ZONE_STAT_ITEMS", &zc); ++ if (split_vmstat == 1) { ++ enumerator_value("NR_VM_ZONE_STAT_ITEMS", &zone_cnt); + location = zone ? zone : symbol_value("vm_zone_stat"); + readmem(location, KVADDR, buf, +- sizeof(ulong) * zc, ++ sizeof(ulong) * zone_cnt, + "vm_zone_stat", FAULT_ON_ERROR); + if (!zone) { + location = symbol_value("vm_node_stat"); +- enumerator_value("NR_VM_NODE_STAT_ITEMS", &nc); +- readmem(location, KVADDR, buf + (sizeof(ulong) * zc), +- sizeof(ulong) * nc, ++ enumerator_value("NR_VM_NODE_STAT_ITEMS", &node_cnt); ++ readmem(location, KVADDR, buf + (sizeof(ulong) * zone_cnt), ++ sizeof(ulong) * node_cnt, + "vm_node_stat", FAULT_ON_ERROR); + } +- tc = zc + nc; ++ node_start = zone_cnt; ++ total_cnt = zone_cnt + node_cnt; ++ } else if (split_vmstat == 2) { ++ enumerator_value("NR_VM_ZONE_STAT_ITEMS", &zone_cnt); ++ location = zone ? zone : symbol_value("vm_zone_stat"); ++ readmem(location, KVADDR, buf, ++ sizeof(ulong) * zone_cnt, ++ "vm_zone_stat", FAULT_ON_ERROR); ++ if (!zone) { ++ location = symbol_value("vm_node_stat"); ++ enumerator_value("NR_VM_NODE_STAT_ITEMS", &node_cnt); ++ readmem(location, KVADDR, buf + (sizeof(ulong) * zone_cnt), ++ sizeof(ulong) * node_cnt, ++ "vm_node_stat", FAULT_ON_ERROR); ++ } ++ node_start = zone_cnt; ++ if (!zone) { ++ location = symbol_value("vm_numa_stat"); ++ enumerator_value("NR_VM_NUMA_STAT_ITEMS", &numa_cnt); ++ readmem(location, KVADDR, buf + (sizeof(ulong) * (zone_cnt+node_cnt)), ++ sizeof(ulong) * numa_cnt, ++ "vm_numa_stat", FAULT_ON_ERROR); ++ } ++ numa_start = zone_cnt+node_cnt; ++ total_cnt = zone_cnt + node_cnt + numa_cnt; + } else { + readmem(location, KVADDR, buf, + sizeof(ulong) * vt->nr_vm_stat_items, + "vm_stat", FAULT_ON_ERROR); +- tc = vt->nr_vm_stat_items; ++ total_cnt = vt->nr_vm_stat_items; + } + + if (!item) { +- if (!zone) +- fprintf(fp, " VM_STAT:\n"); +- for (i = maxlen = 0; i < tc; i++) ++ if (!zone) { ++ if (symbol_exists("vm_zone_stat")) ++ fprintf(fp, " VM_ZONE_STAT:\n"); ++ else ++ fprintf(fp, " VM_STAT:\n"); ++ } ++ for (i = maxlen = 0; i < total_cnt; i++) + if ((len = strlen(vt->vm_stat_items[i])) > maxlen) + maxlen = len; + vp = (ulong *)buf; +- for (i = 0; i < tc; i++) ++ for (i = 0; i < total_cnt; i++) { ++ if (!zone) { ++ if ((i == node_start) && symbol_exists("vm_node_stat")) ++ fprintf(fp, "\n VM_NODE_STAT:\n"); ++ if ((i == numa_start) && symbol_exists("vm_numa_stat")) ++ fprintf(fp, "\n VM_NUMA_STAT:\n"); ++ } + fprintf(fp, "%s%s: %ld\n", + space(maxlen - strlen(vt->vm_stat_items[i])), + vt->vm_stat_items[i], vp[i]); ++ } + return TRUE; + } + + vp = (ulong *)buf; +- for (i = 0; i < tc; i++) { ++ for (i = 0; i < total_cnt; i++) { + if (STREQ(vt->vm_stat_items[i], item)) { + *retval = vp[i]; + return TRUE; + +commit f294197b5511537e6b14d5e1db324f4fc4fdd3f8 +Author: Dave Anderson +Date: Fri Jul 6 10:57:50 2018 -0400 + + Support for the "bpf" command on RHEL 3.10.0-913.el7 and later + 3.10-based RHEL7 kernels, which contain a backport of the upstream + eBPF code, but still use the older, pre-4.11, IDR facility that does + not use radix trees for linking the active bpf_prog and bpf_map + structures. Without the patch, the command indicates "bpf: command + not supported or applicable on this architecture or kernel". + (anderson@redhat.com) + +diff --git a/bpf.c b/bpf.c +index 427263d..8871b76 100644 +--- a/bpf.c ++++ b/bpf.c +@@ -45,6 +45,10 @@ static void bpf_prog_gpl_compatible(char *, ulong); + static void dump_xlated_plain(void *, unsigned int, int); + static void print_boot_time(unsigned long long, char *, unsigned int); + ++static int do_old_idr(int, ulong, struct radix_tree_pair *); ++#define OLD_IDR_INIT (1) ++#define OLD_IDR_COUNT (2) ++#define OLD_IDR_GATHER (3) + + #define PROG_ID (0x1) + #define MAP_ID (0x2) +@@ -167,7 +171,6 @@ bpf_init(struct bpf_info *bpf) + !VALID_STRUCT(bpf_map) || + !VALID_STRUCT(bpf_insn) || + INVALID_MEMBER(bpf_prog_aux) || +- INVALID_MEMBER(idr_idr_rt) || + INVALID_MEMBER(bpf_prog_type) || + INVALID_MEMBER(bpf_prog_tag) || + INVALID_MEMBER(bpf_prog_jited_len) || +@@ -210,6 +213,9 @@ bpf_init(struct bpf_info *bpf) + mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "BPF_MAP"), + mkstring(buf3, bpf->bpf_map_map_type_size, CENTER|LJUST, "BPF_MAP_TYPE")); + ++ if (INVALID_MEMBER(idr_idr_rt)) ++ do_old_idr(OLD_IDR_INIT, 0, NULL); ++ + bpf->status = TRUE; + break; + +@@ -220,24 +226,38 @@ bpf_init(struct bpf_info *bpf) + command_not_supported(); + } + +- bpf->progs = do_radix_tree(symbol_value("prog_idr") + OFFSET(idr_idr_rt), +- RADIX_TREE_COUNT, NULL); ++ if (VALID_MEMBER(idr_idr_rt)) ++ bpf->progs = do_radix_tree(symbol_value("prog_idr") + OFFSET(idr_idr_rt), ++ RADIX_TREE_COUNT, NULL); ++ else ++ bpf->progs = do_old_idr(OLD_IDR_COUNT, symbol_value("prog_idr"), NULL); ++ + if (bpf->progs) { + len = sizeof(struct radix_tree_pair) * (bpf->progs+1); + bpf->proglist = (struct radix_tree_pair *)GETBUF(len); + bpf->proglist[0].index = bpf->progs; +- bpf->progs = do_radix_tree(symbol_value("prog_idr") + OFFSET(idr_idr_rt), +- RADIX_TREE_GATHER, bpf->proglist); ++ if (VALID_MEMBER(idr_idr_rt)) ++ bpf->progs = do_radix_tree(symbol_value("prog_idr") + OFFSET(idr_idr_rt), ++ RADIX_TREE_GATHER, bpf->proglist); ++ else ++ bpf->progs = do_old_idr(OLD_IDR_GATHER, symbol_value("prog_idr"), bpf->proglist); + } + +- bpf->maps = do_radix_tree(symbol_value("map_idr") + OFFSET(idr_idr_rt), +- RADIX_TREE_COUNT, NULL); ++ if (VALID_MEMBER(idr_idr_rt)) ++ bpf->maps = do_radix_tree(symbol_value("map_idr") + OFFSET(idr_idr_rt), ++ RADIX_TREE_COUNT, NULL); ++ else ++ bpf->maps = do_old_idr(OLD_IDR_COUNT, symbol_value("map_idr"), NULL); ++ + if (bpf->maps) { + len = sizeof(struct radix_tree_pair) * (bpf->maps+1); + bpf->maplist = (struct radix_tree_pair *)GETBUF(len); + bpf->maplist[0].index = bpf->maps; +- bpf->maps = do_radix_tree(symbol_value("map_idr") + OFFSET(idr_idr_rt), +- RADIX_TREE_GATHER, bpf->maplist); ++ if (VALID_MEMBER(idr_idr_rt)) ++ bpf->maps = do_radix_tree(symbol_value("map_idr") + OFFSET(idr_idr_rt), ++ RADIX_TREE_GATHER, bpf->maplist); ++ else ++ bpf->maps = do_old_idr(OLD_IDR_GATHER, symbol_value("map_idr"), bpf->maplist); + } + + bpf->bpf_prog_buf = GETBUF(SIZE(bpf_prog)); +@@ -538,8 +558,10 @@ do_map_only: + } + + bailout: +- FREEBUF(bpf->proglist); +- FREEBUF(bpf->maplist); ++ if (bpf->proglist) ++ FREEBUF(bpf->proglist); ++ if (bpf->maplist) ++ FREEBUF(bpf->maplist); + FREEBUF(bpf->bpf_prog_buf); + FREEBUF(bpf->bpf_prog_aux_buf); + FREEBUF(bpf->bpf_map_buf); +@@ -1255,3 +1277,50 @@ print_boot_time(unsigned long long nsecs, char *buf, unsigned int size) + sprintf(buf, "(unknown)"); + #endif + } ++ ++/* ++ * Borrow the old (pre-radix_tree) IDR facility code used by ++ * the ipcs command. ++ */ ++static int ++do_old_idr(int cmd, ulong idr, struct radix_tree_pair *rtp) ++{ ++ int i, max, cur, next_id, total = 0; ++ ulong entry; ++ ++ switch (cmd) ++ { ++ case OLD_IDR_INIT: ++ ipcs_init(); ++ break; ++ ++ case OLD_IDR_COUNT: ++ readmem(idr + OFFSET(idr_cur), KVADDR, &cur, ++ sizeof(int), "idr.cur", FAULT_ON_ERROR); ++ for (total = next_id = 0; next_id < cur; next_id++) { ++ entry = idr_find(idr, next_id); ++ if (entry == 0) ++ continue; ++ total++; ++ } ++ break; ++ ++ case OLD_IDR_GATHER: ++ max = rtp[0].index; ++ readmem(idr + OFFSET(idr_cur), KVADDR, &cur, ++ sizeof(int), "idr.cur", FAULT_ON_ERROR); ++ for (i = total = next_id = 0; next_id < cur; next_id++) { ++ entry = idr_find(idr, next_id); ++ if (entry == 0) ++ continue; ++ total++; ++ rtp[i].index = next_id; ++ rtp[i].value = (void *)entry; ++ if (++i == max) ++ break; ++ } ++ break; ++ } ++ ++ return total; ++} +diff --git a/defs.h b/defs.h +index e6e3850..b05aecc 100644 +--- a/defs.h ++++ b/defs.h +@@ -2031,6 +2031,7 @@ struct offset_table { /* stash of commonly-used offsets */ + long bpf_prog_aux_load_time; + long bpf_prog_aux_user; + long user_struct_uid; ++ long idr_cur; + }; + + struct size_table { /* stash of commonly-used sizes */ +@@ -5591,6 +5592,12 @@ enum { + void dev_init(void); + void dump_dev_table(void); + ++/* ++ * ipcs.c ++ */ ++void ipcs_init(void); ++ulong idr_find(ulong, int); ++ + #ifdef ARM + void arm_init(int); + void arm_dump_machdep_table(ulong); +diff --git a/ipcs.c b/ipcs.c +index ef51fdd..80f78e4 100644 +--- a/ipcs.c ++++ b/ipcs.c +@@ -79,13 +79,11 @@ struct ipcs_table { + * function declaration + */ + +-static void ipcs_init(void); + static int dump_shared_memory(int, ulong, int, ulong); + static int dump_semaphore_arrays(int, ulong, int, ulong); + static int dump_message_queues(int, ulong, int, ulong); + static int ipc_search_idr(ulong, int, ulong, int (*)(ulong, int, ulong, int, int), int); + static int ipc_search_array(ulong, int, ulong, int (*)(ulong, int, ulong, int, int), int); +-static ulong idr_find(ulong, int); + static int dump_shm_info(ulong, int, ulong, int, int); + static int dump_sem_info(ulong, int, ulong, int, int); + static int dump_msg_info(ulong, int, ulong, int, int); +@@ -101,7 +99,7 @@ static void gather_radix_tree_entries(ulong); + */ + static struct ipcs_table ipcs_table = { 0 }; + +-static void ++void + ipcs_init(void) + { + if (ipcs_table.init_flags & IPCS_INIT) { +@@ -119,6 +117,7 @@ ipcs_init(void) + MEMBER_OFFSET_INIT(idr_layer_layer, "idr_layer", "layer"); + MEMBER_OFFSET_INIT(idr_layer_ary, "idr_layer", "ary"); + MEMBER_OFFSET_INIT(idr_top, "idr", "top"); ++ MEMBER_OFFSET_INIT(idr_cur, "idr", "cur"); + MEMBER_OFFSET_INIT(ipc_id_ary_p, "ipc_id_ary", "p"); + MEMBER_OFFSET_INIT(ipc_ids_entries, "ipc_ids", "entries"); + MEMBER_OFFSET_INIT(ipc_ids_max_id, "ipc_ids", "max_id"); +@@ -188,7 +187,10 @@ ipcs_init(void) + ipcs_table.shm_f_op_huge_addr = -1; + } + +- if (BITS32()) ++ if (VALID_MEMBER(idr_layer_ary) && ++ get_array_length("idr_layer.ary", NULL, 0) > 64) ++ ipcs_table.idr_bits = 8; ++ else if (BITS32()) + ipcs_table.idr_bits = 5; + else if (BITS64()) + ipcs_table.idr_bits = 6; +@@ -635,7 +637,7 @@ ipc_search_idr(ulong ipc_ids_p, int specified, ulong specified_value, int (*fn)( + /* + * search every idr_layer + */ +-static ulong ++ulong + idr_find(ulong idp, int id) + { + ulong idr_layer_p; +diff --git a/symbols.c b/symbols.c +index bf55319..8ff1430 100644 +--- a/symbols.c ++++ b/symbols.c +@@ -10055,6 +10055,8 @@ dump_offset_table(char *spec, ulong makestruct) + OFFSET(idr_layers)); + fprintf(fp, " idr_top: %ld\n", + OFFSET(idr_top)); ++ fprintf(fp, " idr_cur: %ld\n", ++ OFFSET(idr_cur)); + fprintf(fp, " ipc_id_ary_p: %ld\n", + OFFSET(ipc_id_ary_p)); + fprintf(fp, " ipc_ids_entries: %ld\n", + +commit b21633026a725a10b9394aabc65d8c57d5bbe33a +Author: Dave Anderson +Date: Tue Jul 10 15:24:38 2018 -0400 + + Third phase of support for x86_64 5-level page tables in Linux 4.17 + and later kernels. With this patch, the usage of 5-level page tables + is automatically detected on live systems and when running against + vmcores that contain the new "NUMBER(pgtable_l5_enabled)" VMCOREINFO + entry. Without the patch, the "--machdep vm=5level" command line + option is required. + (douly.fnst@cn.fujitsu.com, anderson@redhat.com) + +diff --git a/x86_64.c b/x86_64.c +index 6d1ae2f..b07d6f2 100644 +--- a/x86_64.c ++++ b/x86_64.c +@@ -294,25 +294,6 @@ x86_64_init(int when) + machdep->machspec->pgdir_shift = PGDIR_SHIFT; + machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD; + break; +- +- case VM_5LEVEL: +- machdep->machspec->userspace_top = USERSPACE_TOP_5LEVEL; +- machdep->machspec->page_offset = PAGE_OFFSET_5LEVEL; +- machdep->machspec->vmalloc_start_addr = VMALLOC_START_ADDR_5LEVEL; +- machdep->machspec->vmalloc_end = VMALLOC_END_5LEVEL; +- machdep->machspec->modules_vaddr = MODULES_VADDR_5LEVEL; +- machdep->machspec->modules_end = MODULES_END_5LEVEL; +- machdep->machspec->vmemmap_vaddr = VMEMMAP_VADDR_5LEVEL; +- machdep->machspec->vmemmap_end = VMEMMAP_END_5LEVEL; +- if (symbol_exists("vmemmap_populate")) +- machdep->flags |= VMEMMAP; +- machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_5LEVEL; +- machdep->machspec->pgdir_shift = PGDIR_SHIFT_5LEVEL; +- machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD_5LEVEL; +- if ((machdep->machspec->p4d = (char *)malloc(PAGESIZE())) == NULL) +- error(FATAL, "cannot malloc p4d space."); +- machdep->machspec->last_p4d_read = 0; +- machdep->uvtop = x86_64_uvtop_level4; /* 5-level is optional per-task */ + } + machdep->kvbase = (ulong)PAGE_OFFSET; + machdep->identity_map_base = (ulong)PAGE_OFFSET; +@@ -346,6 +327,43 @@ x86_64_init(int when) + break; + + case POST_RELOC: ++ /* Check for 5-level paging */ ++ if (!(machdep->flags & VM_5LEVEL)) { ++ int l5_enabled = 0; ++ if ((string = pc->read_vmcoreinfo("NUMBER(pgtable_l5_enabled)"))) { ++ l5_enabled = atoi(string); ++ free(string); ++ } else if (kernel_symbol_exists("__pgtable_l5_enabled")) ++ readmem(symbol_value("__pgtable_l5_enabled"), KVADDR, ++ &l5_enabled, sizeof(int), "__pgtable_l5_enabled", ++ FAULT_ON_ERROR); ++ ++ if (l5_enabled) ++ machdep->flags |= VM_5LEVEL; ++ } ++ if (machdep->flags & VM_5LEVEL) { ++ machdep->machspec->userspace_top = USERSPACE_TOP_5LEVEL; ++ machdep->machspec->page_offset = PAGE_OFFSET_5LEVEL; ++ machdep->machspec->vmalloc_start_addr = VMALLOC_START_ADDR_5LEVEL; ++ machdep->machspec->vmalloc_end = VMALLOC_END_5LEVEL; ++ machdep->machspec->modules_vaddr = MODULES_VADDR_5LEVEL; ++ machdep->machspec->modules_end = MODULES_END_5LEVEL; ++ machdep->machspec->vmemmap_vaddr = VMEMMAP_VADDR_5LEVEL; ++ machdep->machspec->vmemmap_end = VMEMMAP_END_5LEVEL; ++ if (symbol_exists("vmemmap_populate")) ++ machdep->flags |= VMEMMAP; ++ machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_5LEVEL; ++ machdep->machspec->pgdir_shift = PGDIR_SHIFT_5LEVEL; ++ machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD_5LEVEL; ++ if ((machdep->machspec->p4d = (char *)malloc(PAGESIZE())) == NULL) ++ error(FATAL, "cannot malloc p4d space."); ++ machdep->machspec->last_p4d_read = 0; ++ machdep->uvtop = x86_64_uvtop_level4; /* 5-level is optional per-task */ ++ machdep->kvbase = (ulong)PAGE_OFFSET; ++ machdep->identity_map_base = (ulong)PAGE_OFFSET; ++ ++ } ++ + /* + * Check for CONFIG_RANDOMIZE_MEMORY, and set page_offset here. + * The remainder of the virtual address range setups will get + +commit 6596f1121b89162f96d1e1825c2905b83b59bec1 +Author: Dave Anderson +Date: Wed Jul 11 16:25:59 2018 -0400 + + The existing "list" command uses a hash table to detect duplicate + items as it traverses the list. The hash table approach has worked + well for many years. However, with increasing memory sizes and list + sizes, the overhead of the hash table can be substantial, often + leading to commands running for a very long time. For large lists, + we have found that the existing hash based approach may slow the + system to a crawl and possibly never complete. You can turn off + the hash with "set hash off" but then there is no loop detection; in + that case, loop detection must be done manually after dumping the + list to disk or some other method. This patch is an implementation + of the cycle detection algorithm from R. P. Brent as an alternative + algorithm for the "list" command. The algorithm both avoids the + overhead of the hash table and yet is able to detect a loop. In + addition, further loop characteristics are printed, such as the + distance to the start of the loop as well as the loop length. + An excellent description of the algorithm can be found here on + the crash-utility mailing list: + + https://www.redhat.com/archives/crash-utility/2018-July/msg00019.html + + A new "list -B" option has been added to the "list" command to + invoke this new algorithm rather than using the hash table. In + addition to low memory usage, the output of the list command is + slightly different when a loop is detected. In addition to printing + the first duplicate entry, the length of the loop, and the distance + to the loop is output. + (dwysocha@redhat.com) + +diff --git a/defs.h b/defs.h +index b05aecc..5af82be 100644 +--- a/defs.h ++++ b/defs.h +@@ -2491,6 +2491,7 @@ struct list_data { /* generic structure used by do_list() to walk */ + #define CALLBACK_RETURN (VERBOSE << 12) + #define LIST_PARSE_MEMBER (VERBOSE << 13) + #define LIST_READ_MEMBER (VERBOSE << 14) ++#define LIST_BRENT_ALGO (VERBOSE << 15) + + struct tree_data { + ulong flags; +@@ -4944,6 +4945,7 @@ char *shift_string_right(char *, int); + int bracketed(char *, char *, int); + void backspace(int); + int do_list(struct list_data *); ++int do_list_no_hash(struct list_data *); + struct radix_tree_ops { + void (*entry)(ulong node, ulong slot, const char *path, + ulong index, void *private); +diff --git a/help.c b/help.c +index 638c6ec..54bf9b4 100644 +--- a/help.c ++++ b/help.c +@@ -5724,7 +5724,7 @@ char *help__list[] = { + "list", + "linked list", + "[[-o] offset][-e end][-[s|S] struct[.member[,member] [-l offset]] -[x|d]]" +-"\n [-r|-h|-H] start", ++"\n [-r|-B] [-h|-H] start", + " ", + " This command dumps the contents of a linked list. The entries in a linked", + " list are typically data structures that are tied together in one of two", +@@ -5822,6 +5822,12 @@ char *help__list[] = { + " -r For a list linked with list_head structures, traverse the list", + " in the reverse order by using the \"prev\" pointer instead", + " of \"next\".", ++" -B Use the algorithm from R. P. Brent to detect loops instead of", ++" using a hash table. This algorithm uses a tiny fixed amount of", ++" memory and so is especially helpful for longer lists. The output", ++" is slightly different than the normal list output as it will", ++" print the length of the loop, the start of the loop, and the", ++" first duplicate in the list.", + " ", + " The meaning of the \"start\" argument, which can be expressed symbolically,", + " in hexadecimal format, or an expression evaluating to an address, depends", +diff --git a/tools.c b/tools.c +index 1a83643..634aec6 100644 +--- a/tools.c ++++ b/tools.c +@@ -3266,9 +3266,12 @@ cmd_list(void) + BZERO(ld, sizeof(struct list_data)); + struct_list_offset = 0; + +- while ((c = getopt(argcnt, args, "Hhrs:S:e:o:xdl:")) != EOF) { ++ while ((c = getopt(argcnt, args, "BHhrs:S:e:o:xdl:")) != EOF) { + switch(c) + { ++ case 'B': ++ ld->flags |= LIST_BRENT_ALGO; ++ break; + case 'H': + ld->flags |= LIST_HEAD_FORMAT; + ld->flags |= LIST_HEAD_POINTER; +@@ -3516,9 +3519,13 @@ next_arg: + ld->flags &= ~(LIST_OFFSET_ENTERED|LIST_START_ENTERED); + ld->flags |= VERBOSE; + +- hq_open(); +- c = do_list(ld); +- hq_close(); ++ if (ld->flags & LIST_BRENT_ALGO) ++ c = do_list_no_hash(ld); ++ else { ++ hq_open(); ++ c = do_list(ld); ++ hq_close(); ++ } + + if (ld->structname_args) + FREEBUF(ld->structname); +@@ -3862,6 +3869,283 @@ do_list(struct list_data *ld) + return count; + } + ++static void ++do_list_debug_entry(struct list_data *ld) ++{ ++ int i, others; ++ ++ if (CRASHDEBUG(1)) { ++ others = 0; ++ console(" flags: %lx (", ld->flags); ++ if (ld->flags & VERBOSE) ++ console("%sVERBOSE", others++ ? "|" : ""); ++ if (ld->flags & LIST_OFFSET_ENTERED) ++ console("%sLIST_OFFSET_ENTERED", others++ ? "|" : ""); ++ if (ld->flags & LIST_START_ENTERED) ++ console("%sLIST_START_ENTERED", others++ ? "|" : ""); ++ if (ld->flags & LIST_HEAD_FORMAT) ++ console("%sLIST_HEAD_FORMAT", others++ ? "|" : ""); ++ if (ld->flags & LIST_HEAD_POINTER) ++ console("%sLIST_HEAD_POINTER", others++ ? "|" : ""); ++ if (ld->flags & RETURN_ON_DUPLICATE) ++ console("%sRETURN_ON_DUPLICATE", others++ ? "|" : ""); ++ if (ld->flags & RETURN_ON_LIST_ERROR) ++ console("%sRETURN_ON_LIST_ERROR", others++ ? "|" : ""); ++ if (ld->flags & RETURN_ON_LIST_ERROR) ++ console("%sRETURN_ON_LIST_ERROR", others++ ? "|" : ""); ++ if (ld->flags & LIST_STRUCT_RADIX_10) ++ console("%sLIST_STRUCT_RADIX_10", others++ ? "|" : ""); ++ if (ld->flags & LIST_STRUCT_RADIX_16) ++ console("%sLIST_STRUCT_RADIX_16", others++ ? "|" : ""); ++ if (ld->flags & LIST_ALLOCATE) ++ console("%sLIST_ALLOCATE", others++ ? "|" : ""); ++ if (ld->flags & LIST_CALLBACK) ++ console("%sLIST_CALLBACK", others++ ? "|" : ""); ++ if (ld->flags & CALLBACK_RETURN) ++ console("%sCALLBACK_RETURN", others++ ? "|" : ""); ++ console(")\n"); ++ console(" start: %lx\n", ld->start); ++ console(" member_offset: %ld\n", ld->member_offset); ++ console(" list_head_offset: %ld\n", ld->list_head_offset); ++ console(" end: %lx\n", ld->end); ++ console(" searchfor: %lx\n", ld->searchfor); ++ 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); ++ console(" list_ptr: %lx\n", (ulong)ld->list_ptr); ++ console(" callback_func: %lx\n", (ulong)ld->callback_func); ++ console(" callback_data: %lx\n", (ulong)ld->callback_data); ++ console("struct_list_offset: %lx\n", ld->struct_list_offset); ++ } ++} ++ ++ ++static void ++do_list_output_struct(struct list_data *ld, ulong next, ulong offset, ++ unsigned int radix, struct req_entry **e) ++{ ++ int i; ++ ++ for (i = 0; i < ld->structname_args; i++) { ++ switch (count_chars(ld->structname[i], '.')) ++ { ++ case 0: ++ dump_struct(ld->structname[i], ++ next - offset, radix); ++ break; ++ default: ++ if (ld->flags & LIST_PARSE_MEMBER) ++ dump_struct_members(ld, i, next); ++ else if (ld->flags & LIST_READ_MEMBER) ++ dump_struct_members_fast(e[i], ++ radix, next - offset); ++ break; ++ } ++ } ++} ++ ++static int ++do_list_no_hash_readmem(struct list_data *ld, ulong *next_ptr, ++ ulong readflag) ++{ ++ if (!readmem(*next_ptr + ld->member_offset, KVADDR, next_ptr, ++ sizeof(void *), "list entry", readflag)) { ++ error(INFO, "\ninvalid list entry: %lx\n", *next_ptr); ++ return -1; ++ } ++ return 0; ++} ++ ++static ulong brent_x; /* tortoise */ ++static ulong brent_y; /* hare */ ++static ulong brent_r; /* power */ ++static ulong brent_lambda; /* loop length */ ++static ulong brent_mu; /* distance to start of loop */ ++static ulong brent_loop_detect; ++static ulong brent_loop_exit; ++/* ++ * 'ptr': representative of x or y; modified on return ++ */ ++static int ++brent_f(ulong *ptr, struct list_data *ld, ulong readflag) ++{ ++ return do_list_no_hash_readmem(ld, ptr, readflag); ++} ++ ++/* ++ * Similar to do_list() but without the hash_table or LIST_ALLOCATE. ++ * Useful for the 'list' command and other callers needing faster list ++ * enumeration. ++ */ ++int ++do_list_no_hash(struct list_data *ld) ++{ ++ ulong next, last, first, offset; ++ ulong searchfor, readflag; ++ int i, count, ret; ++ unsigned int radix; ++ struct req_entry **e = NULL; ++ ++ do_list_debug_entry(ld); ++ ++ count = 0; ++ searchfor = ld->searchfor; ++ ld->searchfor = 0; ++ if (ld->flags & LIST_STRUCT_RADIX_10) ++ radix = 10; ++ else if (ld->flags & LIST_STRUCT_RADIX_16) ++ radix = 16; ++ else ++ radix = 0; ++ next = ld->start; ++ ++ readflag = ld->flags & RETURN_ON_LIST_ERROR ? ++ (RETURN_ON_ERROR|QUIET) : FAULT_ON_ERROR; ++ ++ if (!readmem(next + ld->member_offset, KVADDR, &first, sizeof(void *), ++ "first list entry", readflag)) { ++ error(INFO, "\ninvalid list entry: %lx\n", next); ++ return -1; ++ } ++ ++ if (ld->header) ++ fprintf(fp, "%s", ld->header); ++ ++ offset = ld->list_head_offset + ld->struct_list_offset; ++ ++ if (ld->structname && (ld->flags & LIST_READ_MEMBER)) { ++ e = (struct req_entry **)GETBUF(sizeof(*e) * ld->structname_args); ++ for (i = 0; i < ld->structname_args; i++) ++ e[i] = fill_member_offsets(ld->structname[i]); ++ } ++ ++ brent_loop_detect = brent_loop_exit = 0; ++ brent_lambda = 0; ++ brent_r = 2; ++ brent_x = brent_y = next; ++ ret = brent_f(&brent_y, ld, readflag); ++ if (ret == -1) ++ return -1; ++ while (1) { ++ if (!brent_loop_detect && ld->flags & VERBOSE) { ++ fprintf(fp, "%lx\n", next - ld->list_head_offset); ++ if (ld->structname) { ++ do_list_output_struct(ld, next, offset, radix, e); ++ } ++ } ++ ++ if (next && brent_loop_exit) { ++ if (ld->flags & ++ (RETURN_ON_DUPLICATE|RETURN_ON_LIST_ERROR)) { ++ error(INFO, "\nduplicate list entry: %lx\n", ++ brent_x); ++ return -1; ++ } ++ error(FATAL, "\nduplicate list entry: %lx\n", brent_x); ++ } ++ ++ if ((searchfor == next) || ++ (searchfor == (next - ld->list_head_offset))) ++ ld->searchfor = searchfor; ++ ++ count++; ++ last = next; ++ ++ if ((ld->flags & LIST_CALLBACK) && ++ ld->callback_func((void *)(next - ld->list_head_offset), ++ ld->callback_data) && (ld->flags & CALLBACK_RETURN)) ++ break; ++ ++ ret = do_list_no_hash_readmem(ld, &next, readflag); ++ if (ret == -1) ++ return -1; ++ ++ if (!brent_loop_detect) { ++ if (brent_x == brent_y) { ++ brent_loop_detect = 1; ++ error(INFO, "loop detected, loop length: %lx\n", brent_lambda); ++ /* reset x and y to start; advance y loop length */ ++ brent_mu = 0; ++ brent_x = brent_y = ld->start; ++ while (brent_lambda--) { ++ ret = brent_f(&brent_y, ld, readflag); ++ if (ret == -1) ++ return -1; ++ } ++ } else { ++ if (brent_r == brent_lambda) { ++ brent_x = brent_y; ++ brent_r *= 2; ++ brent_lambda = 0; ++ } ++ brent_y = next; ++ brent_lambda++; ++ } ++ } else { ++ if (!brent_loop_exit && brent_x == brent_y) { ++ brent_loop_exit = 1; ++ error(INFO, "length from start to loop: %lx", ++ brent_mu); ++ } else { ++ ret = brent_f(&brent_x, ld, readflag); ++ if (ret == -1) ++ return -1; ++ ret = brent_f(&brent_y, ld, readflag); ++ if (ret == -1) ++ return -1; ++ brent_mu++; ++ } ++ } ++ ++ if (next == 0) { ++ if (ld->flags & LIST_HEAD_FORMAT) { ++ error(INFO, "\ninvalid list entry: 0\n"); ++ return -1; ++ } ++ if (CRASHDEBUG(1)) ++ console("do_list end: next:%lx\n", next); ++ ++ break; ++ } ++ ++ if (next == ld->end) { ++ if (CRASHDEBUG(1)) ++ console("do_list end: next:%lx == end:%lx\n", ++ next, ld->end); ++ break; ++ } ++ ++ if (next == ld->start) { ++ if (CRASHDEBUG(1)) ++ console("do_list end: next:%lx == start:%lx\n", ++ next, ld->start); ++ break; ++ } ++ ++ if (next == last) { ++ if (CRASHDEBUG(1)) ++ console("do_list end: next:%lx == last:%lx\n", ++ next, last); ++ break; ++ } ++ ++ if ((next == first) && (count != 1)) { ++ if (CRASHDEBUG(1)) ++ console("do_list end: next:%lx == first:%lx (count %d)\n", ++ next, last, count); ++ break; ++ } ++ } ++ ++ if (CRASHDEBUG(1)) ++ console("do_list count: %d\n", count); ++ ++ return count; ++} ++ + /* + * Issue a dump_struct_member() call for one or more structure + * members. Multiple members are passed in a comma-separated + +commit 582f8b1ea4bb843f996d5285288e7a12b519ee73 +Author: Dave Anderson +Date: Thu Jul 12 14:06:22 2018 -0400 + + Fix for x86_64 "bt" command to prevent an in-kernel exception frame + from not being displayed. Without the patch, if the RIP in a pt_regs + structure on the stack is not a kernel text address, such as a NULL + pointer, it is not recognized as an exception frame and the register + set is not displayed. + (anderson@redhat.com) + +diff --git a/x86_64.c b/x86_64.c +index b07d6f2..15800fb 100644 +--- a/x86_64.c ++++ b/x86_64.c +@@ -4662,6 +4662,8 @@ x86_64_eframe_verify(struct bt_info *bt, long kvaddr, long cs, long ss, + STREQ(sp->name, "page_fault")) + return TRUE; + ++ if ((kvaddr + SIZE(pt_regs)) == rsp) ++ return TRUE; + } + + if ((cs == 0x10) && kvaddr) { +@@ -8393,7 +8395,7 @@ x86_64_get_framesize(struct bt_info *bt, ulong textaddr, ulong rsp) + *p1 = NULLCHAR; + p2 = arglist[arg]; + reterror = 0; +- offset = htol(p2+1, RETURN_ON_ERROR, &reterror); ++ offset = htol(p2+1, RETURN_ON_ERROR|QUIET, &reterror); + if (reterror) + continue; + framesize += offset; + +commit 528849c15a02d9162c2dd17f4551390763711ad5 +Author: Dave Anderson +Date: Fri Jul 13 13:50:44 2018 -0400 + + Fix for the "repeat" command when the argument consists of an input + file construct, for example, "repeat -1 < input_file". Without the + patch, only the first command line in the input file is executed + each time. + (anderson@redhat.com) + +diff --git a/cmdline.c b/cmdline.c +index aab37ce..ee08f06 100644 +--- a/cmdline.c ++++ b/cmdline.c +@@ -1,8 +1,8 @@ + /* cmdline.c - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002-2015,2017 David Anderson +- * Copyright (C) 2002-2015,2017 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002-2015,2018 David Anderson ++ * Copyright (C) 2002-2015,2018 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 +@@ -2324,6 +2324,9 @@ is_args_input_file(struct command_table_entry *ct, struct args_input_file *aif) + if (pc->curcmd_flags & NO_MODIFY) + return FALSE; + ++ if (STREQ(ct->name, "repeat")) ++ return FALSE; ++ + BZERO(aif, sizeof(struct args_input_file)); + retval = FALSE; + + +commit 61fcad549faa479e6831d5283387f8f2e4ec9202 +Author: Dave Anderson +Date: Mon Jul 16 09:32:57 2018 -0400 + + Fourth phase of support for x86_64 5-level page tables in Linux 4.17 + and later kernels. This patch adds support for user virtual address + translation when the kernel is configured with CONFIG_X86_5LEVEL. + (douly.fnst@cn.fujitsu.com) + +diff --git a/x86_64.c b/x86_64.c +index 15800fb..4073acb 100644 +--- a/x86_64.c ++++ b/x86_64.c +@@ -24,7 +24,6 @@ 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 int x86_64_task_uses_5level(struct task_context *); + 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); +@@ -341,6 +340,7 @@ x86_64_init(int when) + if (l5_enabled) + machdep->flags |= VM_5LEVEL; + } ++ + if (machdep->flags & VM_5LEVEL) { + machdep->machspec->userspace_top = USERSPACE_TOP_5LEVEL; + machdep->machspec->page_offset = PAGE_OFFSET_5LEVEL; +@@ -361,7 +361,6 @@ x86_64_init(int when) + machdep->uvtop = x86_64_uvtop_level4; /* 5-level is optional per-task */ + machdep->kvbase = (ulong)PAGE_OFFSET; + machdep->identity_map_base = (ulong)PAGE_OFFSET; +- + } + + /* +@@ -812,7 +811,7 @@ x86_64_dump_machdep_table(ulong arg) + else if (machdep->uvtop == x86_64_uvtop_level4) { + fprintf(fp, " uvtop: x86_64_uvtop_level4()"); + if (machdep->flags & VM_5LEVEL) +- fprintf(fp, " or x86_64_uvtop_5level()"); ++ fprintf(fp, " (uses 5-level page tables)"); + fprintf(fp, "\n"); + } else if (machdep->uvtop == x86_64_uvtop_level4_xen_wpt) + fprintf(fp, " uvtop: x86_64_uvtop_level4_xen_wpt()\n"); +@@ -1915,7 +1914,7 @@ x86_64_uvtop_level4(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, in + goto no_upage; + + /* If the VM is in 5-level page table */ +- if (machdep->flags & VM_5LEVEL && x86_64_task_uses_5level(tc)) { ++ if (machdep->flags & VM_5LEVEL) { + ulong p4d_pte; + /* + * p4d = p4d_offset(pgd, address); +@@ -1987,12 +1986,6 @@ no_upage: + } + + static int +-x86_64_task_uses_5level(struct task_context *tc) +-{ +- return FALSE; +-} +- +-static int + x86_64_uvtop_level4_xen_wpt(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int verbose) + { + ulong pgd_pte; + +commit eb823b79385f61be97411a06dd57b6fc0973d280 +Author: Dave Anderson +Date: Mon Jul 16 10:50:19 2018 -0400 + + Fix to prevent an unnecessary "read error" message during session + initialization on live systems running a kernel that is configured + with CONFIG_X86_5LEVEL. Without the patch, a message indicating + "crash: read error: kernel virtual address: <address> type: + __pgtable_l5_enabled" will be displayed if /proc/kcore gets + selected as the live memory source after /dev/mem is determined + to be unusable. + (anderson@redhat.com) + +diff --git a/x86_64.c b/x86_64.c +index 4073acb..0574041 100644 +--- a/x86_64.c ++++ b/x86_64.c +@@ -335,7 +335,7 @@ x86_64_init(int when) + } else if (kernel_symbol_exists("__pgtable_l5_enabled")) + readmem(symbol_value("__pgtable_l5_enabled"), KVADDR, + &l5_enabled, sizeof(int), "__pgtable_l5_enabled", +- FAULT_ON_ERROR); ++ QUIET|FAULT_ON_ERROR); + + if (l5_enabled) + machdep->flags |= VM_5LEVEL; diff --git a/SOURCES/github_a10917ba_to_e9532aea.patch b/SOURCES/github_a10917ba_to_e9532aea.patch new file mode 100644 index 0000000..0a858bd --- /dev/null +++ b/SOURCES/github_a10917ba_to_e9532aea.patch @@ -0,0 +1,894 @@ +commit a10917ba3203aa8b20e2aa1b84dc12c1e17445e1 +Author: Dave Anderson +Date: Thu Jul 19 13:43:07 2018 -0400 + + Update for "ps" and "foreach" commands to display and recognize two + new process states, "ID" for the TASK_IDLE macro introduced in + Linux 4.2, and "NE" for the TASK_NEW bit introduced in Linux 4.8. + (k-hagio@ab.jp.nec.com) + +diff --git a/help.c b/help.c +index 54bf9b4..83cda7c 100644 +--- a/help.c ++++ b/help.c +@@ -837,7 +837,7 @@ char *help_foreach[] = { + " kernel perform the command(s) on all kernel threads.", + " active perform the command(s) on the active thread on each CPU.", + " state perform the command(s) on all tasks in the specified state, which", +-" may be one of: RU, IN, UN, ST, ZO, TR, SW, DE, WA or PA.\n", ++" may be one of: RU, IN, UN, ST, ZO, TR, SW, DE, WA, PA, ID or NE.\n", + " If none of the task-identifying arguments above are entered, the command", + " will be performed on all tasks.\n", + " command select one or more of the following commands to be run on the tasks", +@@ -1292,7 +1292,7 @@ char *help_ps[] = { + " 3. the CPU number that the task ran on last.", + " 4. the task_struct address or the kernel stack pointer of the process.", + " (see -s option below)", +-" 5. the task state (RU, IN, UN, ZO, ST, TR, DE, SW, WA, PA).", ++" 5. the task state (RU, IN, UN, ZO, ST, TR, DE, SW, WA, PA, ID, NE).", + " 6. the percentage of physical memory being used by this task.", + " 7. the virtual address size of this task in kilobytes.", + " 8. the resident set size of this task in kilobytes.", +diff --git a/task.c b/task.c +index 1b32629..39fb0de 100644 +--- a/task.c ++++ b/task.c +@@ -5172,6 +5172,7 @@ static long _WAKING_ = TASK_STATE_UNINITIALIZED; + static long _NONINTERACTIVE_ = TASK_STATE_UNINITIALIZED; + static long _PARKED_ = TASK_STATE_UNINITIALIZED; + static long _NOLOAD_ = TASK_STATE_UNINITIALIZED; ++static long _NEW_ = TASK_STATE_UNINITIALIZED; + + #define valid_task_state(X) ((X) != TASK_STATE_UNINITIALIZED) + +@@ -5249,6 +5250,10 @@ dump_task_states(void) + if (valid_task_state(_NOLOAD_)) + fprintf(fp, " NOLOAD: %3ld (0x%lx)\n", + _NOLOAD_, _NOLOAD_); ++ ++ if (valid_task_state(_NEW_)) ++ fprintf(fp, " NEW: %3ld (0x%lx)\n", ++ _NEW_, _NEW_); + } + + +@@ -5282,6 +5287,7 @@ old_defaults: + /* + * If the later version of stat_nam[] array exists that contains + * WAKING, WAKEKILL and PARKED, use it instead of task_state_array[]. ++ * Available since kernel version 2.6.33 to 4.13. + */ + if (((len = get_array_length("stat_nam", NULL, 0)) > 0) && + read_string(symbol_value("stat_nam"), buf, BUFSIZE-1) && +@@ -5331,6 +5337,9 @@ old_defaults: + case 'N': + _NOLOAD_ = (1 << (i-1)); + break; ++ case 'n': ++ _NEW_ = (1 << (i-1)); ++ break; + } + } + +@@ -5393,7 +5402,16 @@ old_defaults: + _NONINTERACTIVE_ = 64; + } + +- if (THIS_KERNEL_VERSION >= LINUX(2,6,32)) { ++ if (THIS_KERNEL_VERSION >= LINUX(4,14,0)) { ++ if (valid_task_state(_PARKED_)) { ++ bitpos = _PARKED_; ++ _DEAD_ |= (bitpos << 1); /* TASK_DEAD */ ++ _WAKEKILL_ = (bitpos << 2); /* TASK_WAKEKILL */ ++ _WAKING_ = (bitpos << 3); /* TASK_WAKING */ ++ _NOLOAD_ = (bitpos << 4); /* TASK_NOLOAD */ ++ _NEW_ = (bitpos << 5); /* TASK_NEW */ ++ } ++ } else if (THIS_KERNEL_VERSION >= LINUX(2,6,32)) { + /* + * Account for states not listed in task_state_array[] + */ +@@ -5481,6 +5499,10 @@ task_state_string_verbose(ulong task, char *buf) + sprintf(&buf[strlen(buf)], "%sTASK_NOLOAD", + count++ ? "|" : ""); + ++ if (valid_task_state(_NEW_) && (state & _NEW_)) ++ sprintf(&buf[strlen(buf)], "%sTASK_NEW", ++ count++ ? "|" : ""); ++ + if (valid_task_state(_NONINTERACTIVE_) && + (state & _NONINTERACTIVE_)) + sprintf(&buf[strlen(buf)], "%sTASK_NONINTERACTIVE", +@@ -5530,7 +5552,11 @@ task_state_string(ulong task, char *buf, int verbose) + } + + if (state & _UNINTERRUPTIBLE_) { +- sprintf(buf, "UN"); ++ if (valid_task_state(_NOLOAD_) && ++ (state & _NOLOAD_)) ++ sprintf(buf, "ID"); ++ else ++ sprintf(buf, "UN"); + valid++; + set++; + } +@@ -5576,6 +5602,11 @@ task_state_string(ulong task, char *buf, int verbose) + valid++; + } + ++ if (state == _NEW_) { ++ sprintf(buf, "NE"); ++ valid++; ++ } ++ + if (valid && exclusive) + strcat(buf, "EX"); + +@@ -6273,6 +6304,8 @@ cmd_foreach(void) + STREQ(args[optind], "DE") || + STREQ(args[optind], "PA") || + STREQ(args[optind], "WA") || ++ STREQ(args[optind], "ID") || ++ STREQ(args[optind], "NE") || + STREQ(args[optind], "SW")) { + + if (fd->flags & FOREACH_STATE) +@@ -6298,6 +6331,10 @@ cmd_foreach(void) + fd->state = _PARKED_; + else if (STREQ(args[optind], "WA")) + fd->state = _WAKING_; ++ else if (STREQ(args[optind], "ID")) ++ fd->state = _UNINTERRUPTIBLE_|_NOLOAD_; ++ else if (STREQ(args[optind], "NE")) ++ fd->state = _NEW_; + + if (fd->state == TASK_STATE_UNINITIALIZED) + error(FATAL, +@@ -6678,6 +6715,19 @@ foreach(struct foreach_data *fd) + if (fd->state == _RUNNING_) { + if (task_state(tc->task) != _RUNNING_) + continue; ++ } else if (fd->state & _UNINTERRUPTIBLE_) { ++ if (!(task_state(tc->task) & _UNINTERRUPTIBLE_)) ++ continue; ++ ++ if (valid_task_state(_NOLOAD_)) { ++ if (fd->state & _NOLOAD_) { ++ if (!(task_state(tc->task) & _NOLOAD_)) ++ continue; ++ } else { ++ if ((task_state(tc->task) & _NOLOAD_)) ++ continue; ++ } ++ } + } else if (!(task_state(tc->task) & fd->state)) + continue; + } + +commit 6c39a3d39b799e1f3f26e8017bcfa458d38d3820 +Author: Dave Anderson +Date: Wed Aug 8 11:31:17 2018 -0400 + + Fix for running live on ARM64 kernels against /proc/kcore on kernels + configured with CONFIG_RANDOMIZE_BASE. Without the patch, depending + upon the hardware platform, the session may fail with the error message + "crash: vmlinux and /proc/kcore do not match!". + (anderson@redhat.com) + +diff --git a/arm64.c b/arm64.c +index 150e7d7..4ee53ce 100644 +--- a/arm64.c ++++ b/arm64.c +@@ -125,7 +125,8 @@ arm64_init(int when) + free(string); + } + +- if (ms->kimage_voffset) { ++ if (ms->kimage_voffset || ++ (ACTIVE() && (symbol_value_from_proc_kallsyms("kimage_voffset") != BADVAL))) { + machdep->flags |= NEW_VMEMMAP; + + /* +@@ -771,6 +772,17 @@ arm64_calc_kimage_voffset(void) + char *p1; + int errflag; + FILE *iomem; ++ ulong kimage_voffset, vaddr; ++ ++ if (pc->flags & PROC_KCORE) { ++ kimage_voffset = symbol_value_from_proc_kallsyms("kimage_voffset"); ++ if ((kimage_voffset != BADVAL) && ++ (READMEM(pc->mfd, &vaddr, sizeof(ulong), ++ kimage_voffset, KCORE_USE_VADDR) > 0)) { ++ ms->kimage_voffset = vaddr; ++ return; ++ } ++ } + + if ((iomem = fopen("/proc/iomem", "r")) == NULL) + return; +@@ -838,16 +850,22 @@ arm64_calc_phys_offset(void) + int errflag; + FILE *iomem; + physaddr_t paddr; ++ ulong vaddr; + struct syment *sp; + + if ((machdep->flags & NEW_VMEMMAP) && + ms->kimage_voffset && (sp = kernel_symbol_search("memstart_addr"))) { +- if (pc->flags & PROC_KCORE) ++ if (pc->flags & PROC_KCORE) { ++ vaddr = symbol_value_from_proc_kallsyms("memstart_addr"); ++ if (vaddr == BADVAL) ++ vaddr = sp->value; + paddr = KCORE_USE_VADDR; +- else ++ } else { ++ vaddr = sp->value; + paddr = sp->value - machdep->machspec->kimage_voffset; ++ } + if (READMEM(pc->mfd, &phys_offset, sizeof(phys_offset), +- sp->value, paddr) > 0) { ++ vaddr, paddr) > 0) { + ms->phys_offset = phys_offset; + return; + } +diff --git a/defs.h b/defs.h +index 5af82be..da2ae04 100644 +--- a/defs.h ++++ b/defs.h +@@ -5067,6 +5067,7 @@ struct syment *per_cpu_symbol_search(char *); + int symbol_exists(char *s); + int kernel_symbol_exists(char *s); + struct syment *kernel_symbol_search(char *); ++ulong symbol_value_from_proc_kallsyms(char *); + int get_syment_array(char *, struct syment **, int); + void set_temporary_radix(unsigned int, unsigned int *); + void restore_current_radix(unsigned int); +diff --git a/symbols.c b/symbols.c +index 8ff1430..df84ee2 100644 +--- a/symbols.c ++++ b/symbols.c +@@ -28,7 +28,6 @@ static void store_sysmap_symbols(void); + static ulong relocate(ulong, char *, int); + static int relocate_force(ulong, char *); + static void kaslr_init(void); +-static ulong symbol_value_from_proc_kallsyms(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 *); +@@ -997,7 +996,7 @@ relocate_force(ulong symval, char *symname) + /* + * Get a symbol value from /proc/kallsyms. + */ +-static ulong ++ulong + symbol_value_from_proc_kallsyms(char *symname) + { + FILE *kp; + +commit 455da1ae5c7f22ba870aa57e071dad340749bdcd +Author: Dave Anderson +Date: Wed Aug 8 14:20:21 2018 -0400 + + Modify the output of the "kmem -[sS]" header and contents such that + the slab cache name string is moved from the second column to the + the last column. Since the slab cache name strings have become + increasingly longer over time, without the patch, the numerical + column contents may be skewed so far to the right that the output + becomes difficult to read. + (k-hagio@ab.jp.nec.com) + +diff --git a/help.c b/help.c +index 83cda7c..a189038 100644 +--- a/help.c ++++ b/help.c +@@ -6692,8 +6692,8 @@ char *help_kmem[] = { + " Find all of the combined slab/page structures that are used by", + " the kmalloc-8192 slab cache:\n", + " %s> kmem -s kmalloc-8192", +-" CACHE NAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE", +-" ffff880215802e00 kmalloc-8192 8192 65 80 20 32k", ++" CACHE OBJSIZE ALLOCATED TOTAL SLABS SSIZE NAME", ++" ffff880215802e00 8192 65 80 20 32k kmalloc-8192", + " %s> kmem -m slab_cache | grep ffff880215802e00", + " ffffea0004117800 ffff880215802e00 ", + " ffffea00041ca600 ffff880215802e00 ", +@@ -6889,72 +6889,72 @@ char *help_kmem[] = { + " ", + " Display kmalloc() slab data:\n", + " %s> kmem -s", +-" CACHE NAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE", +-" c02eadc0 kmem_cache 232 58 68 4 4k", +-" f79c2888 ip_vs_conn 128 0 0 0 4k", +-" f79c2970 tcp_tw_bucket 96 0 0 0 4k", +-" f79c2a58 tcp_bind_bucket 32 12 565 5 4k", +-" f79c2b40 tcp_open_request 64 0 59 1 4k", +-" f79c2c28 inet_peer_cache 64 1 59 1 4k", +-" f79c2d10 ip_fib_hash 32 11 339 3 4k", +-" f79c2df8 ip_dst_cache 160 8 120 5 4k", +-" f79c2ee0 arp_cache 128 1 30 1 4k", +-" c8402970 blkdev_requests 96 30208 37800 945 4k", +-" c8402a58 nfs_read_data 384 0 0 0 4k", +-" c8402b40 nfs_write_data 384 0 0 0 4k", +-" c8402c28 nfs_page 96 0 0 0 4k", +-" c8402d10 dnotify cache 20 0 0 0 4k", +-" c8402df8 file lock cache 92 3 336 8 4k", +-" c8402ee0 fasync cache 16 0 0 0 4k", +-" c84027a0 uid_cache 32 3 339 3 4k", +-" c84026b8 skbuff_head_cache 160 320 624 26 4k", +-" c84025d0 sock 832 32 180 20 8k", +-" c84024e8 sigqueue 132 0 203 7 4k", +-" c8402400 cdev_cache 64 19 472 8 4k", +-" c8402318 bdev_cache 64 8 236 4 4k", +-" c8402230 mnt_cache 96 11 120 3 4k", +-" c8402148 inode_cache 480 817 848 106 4k", +-" c8402060 dentry_cache 128 1352 1470 49 4k", +-" c8403ee0 filp 96 244 440 11 4k", +-" c8403df8 names_cache 4096 0 12 12 4k", +-" c8403d10 buffer_head 96 14936 16000 400 4k", +-" c8403c28 mm_struct 128 25 240 8 4k", +-" c8403b40 vm_area_struct 64 393 1298 22 4k", +-" c8403a58 fs_cache 64 30 472 8 4k", +-" c8403970 files_cache 416 30 135 15 4k", +-" c8403888 signal_act 1312 32 99 33 4k", +-" c84037a0 size-131072(DMA) 131072 0 0 0 128k", +-" c84036b8 size-131072 131072 1 1 1 128k", +-" c84035d0 size-65536(DMA) 65536 0 0 0 64k", +-" c84034e8 size-65536 65536 0 0 0 64k", +-" c8403400 size-32768(DMA) 32768 0 0 0 32k", +-" c8403318 size-32768 32768 0 1 1 32k", +-" c8403230 size-16384(DMA) 16384 0 0 0 16k", +-" c8403148 size-16384 16384 0 0 0 16k", +-" c8403060 size-8192(DMA) 8192 0 0 0 8k", +-" c8401ee0 size-8192 8192 1 2 2 8k", +-" c8401df8 size-4096(DMA) 4096 0 0 0 4k", +-" c8401d10 size-4096 4096 30 30 30 4k", +-" c8401c28 size-2048(DMA) 2048 0 0 0 4k", +-" c8401b40 size-2048 2048 37 132 66 4k", +-" c8401a58 size-1024(DMA) 1024 0 0 0 4k", +-" c8401970 size-1024 1024 301 328 82 4k", +-" c8401888 size-512(DMA) 512 0 0 0 4k", +-" c84017a0 size-512 512 141 168 21 4k", +-" c84016b8 size-256(DMA) 256 0 0 0 4k", +-" c84015d0 size-256 256 80 435 29 4k", +-" c84014e8 size-128(DMA) 128 0 0 0 4k", +-" c8401400 size-128 128 508 840 28 4k", +-" c8401318 size-64(DMA) 64 0 0 0 4k", +-" c8401230 size-64 64 978 1357 23 4k", +-" c8401148 size-32(DMA) 32 0 0 0 4k", +-" c8401060 size-32 32 1244 1808 16 4k", ++" CACHE OBJSIZE ALLOCATED TOTAL SLABS SSIZE NAME", ++" c02eadc0 232 58 68 4 4k kmem_cache", ++" f79c2888 128 0 0 0 4k ip_vs_conn", ++" f79c2970 96 0 0 0 4k tcp_tw_bucket", ++" f79c2a58 32 12 565 5 4k tcp_bind_bucket", ++" f79c2b40 64 0 59 1 4k tcp_open_request", ++" f79c2c28 64 1 59 1 4k inet_peer_cache", ++" f79c2d10 32 11 339 3 4k ip_fib_hash", ++" f79c2df8 160 8 120 5 4k ip_dst_cache", ++" f79c2ee0 128 1 30 1 4k arp_cache", ++" c8402970 96 30208 37800 945 4k blkdev_requests", ++" c8402a58 384 0 0 0 4k nfs_read_data", ++" c8402b40 384 0 0 0 4k nfs_write_data", ++" c8402c28 96 0 0 0 4k nfs_page", ++" c8402d10 20 0 0 0 4k dnotify cache", ++" c8402df8 92 3 336 8 4k file lock cache", ++" c8402ee0 16 0 0 0 4k fasync cache", ++" c84027a0 32 3 339 3 4k uid_cache", ++" c84026b8 160 320 624 26 4k skbuff_head_cache", ++" c84025d0 832 32 180 20 8k sock", ++" c84024e8 132 0 203 7 4k sigqueue", ++" c8402400 64 19 472 8 4k cdev_cache", ++" c8402318 64 8 236 4 4k bdev_cache", ++" c8402230 96 11 120 3 4k mnt_cache", ++" c8402148 480 817 848 106 4k inode_cache", ++" c8402060 128 1352 1470 49 4k dentry_cache", ++" c8403ee0 96 244 440 11 4k filp", ++" c8403df8 4096 0 12 12 4k names_cache", ++" c8403d10 96 14936 16000 400 4k buffer_head", ++" c8403c28 128 25 240 8 4k mm_struct", ++" c8403b40 64 393 1298 22 4k vm_area_struct", ++" c8403a58 64 30 472 8 4k fs_cache", ++" c8403970 416 30 135 15 4k files_cache", ++" c8403888 1312 32 99 33 4k signal_act", ++" c84037a0 131072 0 0 0 128k size-131072(DMA)", ++" c84036b8 131072 1 1 1 128k size-131072", ++" c84035d0 65536 0 0 0 64k size-65536(DMA)", ++" c84034e8 65536 0 0 0 64k size-65536", ++" c8403400 32768 0 0 0 32k size-32768(DMA)", ++" c8403318 32768 0 1 1 32k size-32768", ++" c8403230 16384 0 0 0 16k size-16384(DMA)", ++" c8403148 16384 0 0 0 16k size-16384", ++" c8403060 8192 0 0 0 8k size-8192(DMA)", ++" c8401ee0 8192 1 2 2 8k size-8192", ++" c8401df8 4096 0 0 0 4k size-4096(DMA)", ++" c8401d10 4096 30 30 30 4k size-4096", ++" c8401c28 2048 0 0 0 4k size-2048(DMA)", ++" c8401b40 2048 37 132 66 4k size-2048", ++" c8401a58 1024 0 0 0 4k size-1024(DMA)", ++" c8401970 1024 301 328 82 4k size-1024", ++" c8401888 512 0 0 0 4k size-512(DMA)", ++" c84017a0 512 141 168 21 4k size-512", ++" c84016b8 256 0 0 0 4k size-256(DMA)", ++" c84015d0 256 80 435 29 4k size-256", ++" c84014e8 128 0 0 0 4k size-128(DMA)", ++" c8401400 128 508 840 28 4k size-128", ++" c8401318 64 0 0 0 4k size-64(DMA)", ++" c8401230 64 978 1357 23 4k size-64", ++" c8401148 32 0 0 0 4k size-32(DMA)", ++" c8401060 32 1244 1808 16 4k size-32", + + " ", + " Display all slab data in the \"arp_cache\" cache:\n", + " %s> kmem -S arp_cache", +-" CACHE NAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE", +-" f79c2ee0 arp_cache 128 1 30 1 4k", ++" CACHE OBJSIZE ALLOCATED TOTAL SLABS SSIZE NAME", ++" f79c2ee0 128 1 30 1 4k arp_cache", + " SLAB MEMORY TOTAL ALLOCATED FREE", + " f729d000 f729d0a0 30 1 29", + " FREE / [ALLOCATED]", +@@ -6991,8 +6991,8 @@ char *help_kmem[] = { + " ", + " Search the kmalloc() slab subsystem for address c3fbdb60:\n", + " %s> kmem -s c3fbdb60", +-" CACHE NAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE", +-" c8402970 blkdev_requests 96 30208 37800 945 4k", ++" CACHE OBJSIZE ALLOCATED TOTAL SLABS SSIZE NAME", ++" c8402970 96 30208 37800 945 4k blkdev_requests", + " SLAB MEMORY TOTAL ALLOCATED FREE", + " c3fbd020 c3fbd0e0 40 40 0", + " FREE / [ALLOCATED]", +@@ -7000,8 +7000,8 @@ char *help_kmem[] = { + " ", + " Make a generic search (no flags) for the same address c3fbdb60:\n", + " %s> kmem c3fbdb60 ", +-" CACHE NAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE", +-" c8402970 blkdev_requests 96 30208 37800 945 4k", ++" CACHE OBJSIZE ALLOCATED TOTAL SLABS SSIZE NAME", ++" c8402970 96 30208 37800 945 4k blkdev_requests", + " SLAB MEMORY TOTAL ALLOCATED FREE", + " c3fbd020 c3fbd0e0 40 40 0 ", + " FREE / [ALLOCATED]", +diff --git a/memory.c b/memory.c +index 81ed689..5bcf09e 100644 +--- a/memory.c ++++ b/memory.c +@@ -172,7 +172,6 @@ static void dump_kmem_cache(struct meminfo *); + static void dump_kmem_cache_percpu_v1(struct meminfo *); + static void dump_kmem_cache_percpu_v2(struct meminfo *); + static void dump_kmem_cache_slub(struct meminfo *); +-static void dump_kmem_cache_info_v2(struct meminfo *); + static void kmem_cache_list_common(void); + static ulong get_cpu_slab_ptr(struct meminfo *, int, ulong *); + static unsigned int oo_order(ulong); +@@ -9379,7 +9378,7 @@ kmem_cache_init(void) + + if (!strlen(kmem_cache_hdr)) + sprintf(kmem_cache_hdr, +- "CACHE%sNAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE\n", ++ "CACHE%s OBJSIZE ALLOCATED TOTAL SLABS SSIZE NAME\n", + space(VADDR_PRLEN > 8 ? 12 : 4)); + + if (!strlen(free_inuse_hdr)) +@@ -9964,55 +9963,36 @@ ignore_cache(struct meminfo *si, char *name) + #define KMEM_SLAB_OVERLOAD_PAGE (8) + #define KMEM_SLAB_FREELIST (9) + +-#define DUMP_KMEM_CACHE_INFO_V1() \ +- { \ +- char b1[BUFSIZE]; \ +- fprintf(fp, "%s %-18s %8ld ", \ +- mkstring(b1, VADDR_PRLEN, LJUST|LONG_HEX, MKSTR(si->cache)), \ +- buf, si->size); \ +- fprintf(fp, "%9ld %8ld %5ld %3ldk\n", \ +- vt->flags & PERCPU_KMALLOC_V1 ? \ +- si->inuse - si->cpucached_cache : \ +- si->inuse, si->num_slabs * si->c_num, \ +- si->num_slabs, si->slabsize/1024); \ +- } +- +-#define DUMP_KMEM_CACHE_INFO_V2() dump_kmem_cache_info_v2(si) ++#define DUMP_KMEM_CACHE_INFO() dump_kmem_cache_info(si) + + static void +-dump_kmem_cache_info_v2(struct meminfo *si) ++dump_kmem_cache_info(struct meminfo *si) + { + char b1[BUFSIZE]; +- char b2[BUFSIZE]; +- int namelen, sizelen, spacelen; +- +- fprintf(fp, "%s ", +- mkstring(b1, VADDR_PRLEN, LJUST|LONG_HEX, MKSTR(si->cache))); +- +- namelen = strlen(si->curname); +- sprintf(b2, "%ld", si->size); +- sizelen = strlen(b2); +- spacelen = 0; +- +- if (namelen++ > 18) { +- spacelen = 29 - namelen - sizelen; +- fprintf(fp, "%s%s%ld ", si->curname, +- space(spacelen <= 0 ? 1 : spacelen), si->size); +- if (spacelen > 0) +- spacelen = 1; +- sprintf(b1, "%c%dld ", '%', 9 + spacelen - 1); ++ ulong objsize, allocated, total; ++ ++ if (si->flags & SLAB_GATHER_FAILURE) ++ error(INFO, "%s: cannot gather relevant slab data\n", si->curname); ++ ++ objsize = (vt->flags & KMALLOC_SLUB) ? si->objsize : si->size; ++ ++ fprintf(fp, "%s %8ld ", ++ mkstring(b1, VADDR_PRLEN, LJUST|LONG_HEX, MKSTR(si->cache)), ++ objsize); ++ ++ if (si->flags & SLAB_GATHER_FAILURE) { ++ fprintf(fp, "%9s %8s %5s ", "?", "?", "?"); + } else { +- fprintf(fp, "%-18s %8ld ", si->curname, si->size); +- sprintf(b1, "%c%dld ", '%', 9); +- } ++ allocated = (vt->flags & (PERCPU_KMALLOC_V1|PERCPU_KMALLOC_V2)) ? ++ si->inuse - si->cpucached_cache : si->inuse; ++ total = (vt->flags & KMALLOC_SLUB) ? ++ si->inuse + si->free : si->num_slabs * si->c_num; + +- fprintf(fp, b1, vt->flags & (PERCPU_KMALLOC_V2) ? +- si->inuse - si->cpucached_cache : si->inuse); ++ fprintf(fp, "%9ld %8ld %5ld ", ++ allocated, total, si->num_slabs); ++ } + +- fprintf(fp, "%8ld %s%5ld %s%3ldk\n", +- si->num_slabs * si->c_num, +- si->num_slabs < 100000 ? " " : "", si->num_slabs, +- (si->slabsize/1024) < 1000 ? " " : "", si->slabsize/1024); ++ fprintf(fp, "%4ldk %s\n", si->slabsize/1024, si->curname); + } + + #define DUMP_SLAB_INFO() \ +@@ -10152,7 +10132,7 @@ dump_kmem_cache(struct meminfo *si) + do_slab_chain(SLAB_GET_COUNTS, si); + + if (!(si->flags & (ADDRESS_SPECIFIED|GET_SLAB_PAGES))) +- DUMP_KMEM_CACHE_INFO_V1(); ++ DUMP_KMEM_CACHE_INFO(); + + if (si->flags == GET_SLAB_PAGES) + si->retval += (si->num_slabs * +@@ -10166,7 +10146,7 @@ dump_kmem_cache(struct meminfo *si) + + if (si->found) { + fprintf(fp, "%s", kmem_cache_hdr); +- DUMP_KMEM_CACHE_INFO_V1(); ++ DUMP_KMEM_CACHE_INFO(); + fprintf(fp, "%s", slab_hdr); + DUMP_SLAB_INFO(); + +@@ -10362,7 +10342,7 @@ dump_kmem_cache_percpu_v1(struct meminfo *si) + do_slab_chain_percpu_v1(SLAB_GET_COUNTS, si); + + if (!(si->flags & (ADDRESS_SPECIFIED|GET_SLAB_PAGES))) { +- DUMP_KMEM_CACHE_INFO_V1(); ++ DUMP_KMEM_CACHE_INFO(); + if (CRASHDEBUG(3)) + dump_struct("kmem_cache_s", si->cache, 0); + } +@@ -10382,7 +10362,7 @@ dump_kmem_cache_percpu_v1(struct meminfo *si) + + if (si->found) { + fprintf(fp, "%s", kmem_cache_hdr); +- DUMP_KMEM_CACHE_INFO_V1(); ++ DUMP_KMEM_CACHE_INFO(); + fprintf(fp, "%s", slab_hdr); + gather_slab_cached_count(si); + DUMP_SLAB_INFO(); +@@ -10617,7 +10597,7 @@ dump_kmem_cache_percpu_v2(struct meminfo *si) + do_slab_chain_percpu_v2(SLAB_GET_COUNTS, si); + + if (!(si->flags & (ADDRESS_SPECIFIED|GET_SLAB_PAGES))) { +- DUMP_KMEM_CACHE_INFO_V2(); ++ DUMP_KMEM_CACHE_INFO(); + if (CRASHDEBUG(3)) + dump_struct("kmem_cache_s", si->cache, 0); + } +@@ -10644,7 +10624,7 @@ dump_kmem_cache_percpu_v2(struct meminfo *si) + + if (si->found) { + fprintf(fp, "%s", kmem_cache_hdr); +- DUMP_KMEM_CACHE_INFO_V2(); ++ DUMP_KMEM_CACHE_INFO(); + fprintf(fp, "%s", slab_hdr); + gather_slab_cached_count(si); + DUMP_SLAB_INFO(); +@@ -18064,56 +18044,6 @@ kmem_cache_list_common(void) + FREEBUF(cache_list); + } + +-#define DUMP_KMEM_CACHE_INFO_SLUB() dump_kmem_cache_info_slub(si) +- +-static void +-dump_kmem_cache_info_slub(struct meminfo *si) +-{ +- char b1[BUFSIZE]; +- char b2[BUFSIZE]; +- int namelen, sizelen, spacelen; +- +- if (si->flags & SLAB_GATHER_FAILURE) +- error(INFO, "%s: cannot gather relevant slab data\n", si->curname); +- +- fprintf(fp, "%s ", +- mkstring(b1, VADDR_PRLEN, LJUST|LONG_HEX, MKSTR(si->cache))); +- +- namelen = strlen(si->curname); +- sprintf(b2, "%ld", si->objsize); +- sizelen = strlen(b2); +- spacelen = 0; +- +- if (namelen++ > 18) { +- spacelen = 29 - namelen - sizelen; +- fprintf(fp, "%s%s%ld ", si->curname, +- space(spacelen <= 0 ? 1 : spacelen), si->objsize); +- if (spacelen > 0) +- spacelen = 1; +- if (si->flags & SLAB_GATHER_FAILURE) +- sprintf(b1, "%c%ds ", '%', 9 + spacelen - 1); +- else +- sprintf(b1, "%c%dld ", '%', 9 + spacelen - 1); +- } else { +- fprintf(fp, "%-18s %8ld ", si->curname, si->objsize); +- if (si->flags & SLAB_GATHER_FAILURE) +- sprintf(b1, "%c%ds ", '%', 9); +- else +- sprintf(b1, "%c%dld ", '%', 9); +- } +- +- if (si->flags & SLAB_GATHER_FAILURE) { +- fprintf(fp, b1, "?"); +- fprintf(fp, "%8s %5s %4ldk\n", +- "?", "?", si->slabsize/1024); +- } else { +- fprintf(fp, b1, si->inuse); +- fprintf(fp, "%8ld %5ld %4ldk\n", +- si->inuse + si->free, +- si->num_slabs, si->slabsize/1024); +- } +-} +- + static void + dump_kmem_cache_slub(struct meminfo *si) + { +@@ -18214,7 +18144,7 @@ dump_kmem_cache_slub(struct meminfo *si) + !get_kmem_cache_slub_data(GET_SLUB_OBJECTS, si)) + si->flags |= SLAB_GATHER_FAILURE; + +- DUMP_KMEM_CACHE_INFO_SLUB(); ++ DUMP_KMEM_CACHE_INFO(); + + if (si->flags & SLAB_GATHER_FAILURE) { + si->flags &= ~SLAB_GATHER_FAILURE; + +commit ba03b66cec24fc0033d4378be08f5f9a96cd4a91 +Author: Dave Anderson +Date: Thu Aug 9 10:54:46 2018 -0400 + + Fix for the "files" and "net -s" commands when a task has an open + files count that exceeds 1024 (FD_SETSIZE) file descriptors. Without + the patch, the commands may omit the display of open file descriptors. + (tan.hu@zte.com.cn) + +diff --git a/filesys.c b/filesys.c +index 0ace8f4..47f5a24 100644 +--- a/filesys.c ++++ b/filesys.c +@@ -2380,7 +2380,8 @@ open_files_dump(ulong task, int flags, struct reference *ref) + int max_fdset = 0; + int max_fds = 0; + ulong open_fds_addr; +- fd_set open_fds; ++ int open_fds_size; ++ ulong *open_fds; + ulong fd; + ulong file; + ulong value; +@@ -2583,16 +2584,25 @@ open_files_dump(ulong task, int flags, struct reference *ref) + open_fds_addr = ULONG(files_struct_buf + + OFFSET(files_struct_open_fds)); + ++ open_fds_size = MAX(max_fdset, max_fds) / BITS_PER_BYTE; ++ open_fds = (ulong *)GETBUF(open_fds_size); ++ if (!open_fds) { ++ if (fdtable_buf) ++ FREEBUF(fdtable_buf); ++ FREEBUF(files_struct_buf); ++ return; ++ } ++ + if (open_fds_addr) { + if (VALID_MEMBER(files_struct_open_fds_init) && + (open_fds_addr == (files_struct_addr + + OFFSET(files_struct_open_fds_init)))) + BCOPY(files_struct_buf + + OFFSET(files_struct_open_fds_init), +- &open_fds, sizeof(fd_set)); ++ open_fds, open_fds_size); + else +- readmem(open_fds_addr, KVADDR, &open_fds, +- sizeof(fd_set), "fdtable open_fds", ++ readmem(open_fds_addr, KVADDR, open_fds, ++ open_fds_size, "fdtable open_fds", + FAULT_ON_ERROR); + } + +@@ -2607,6 +2617,7 @@ open_files_dump(ulong task, int flags, struct reference *ref) + if (fdtable_buf) + FREEBUF(fdtable_buf); + FREEBUF(files_struct_buf); ++ FREEBUF(open_fds); + return; + } + +@@ -2617,11 +2628,11 @@ open_files_dump(ulong task, int flags, struct reference *ref) + j = 0; + for (;;) { + unsigned long set; +- i = j * __NFDBITS; ++ i = j * BITS_PER_LONG; + if (((max_fdset >= 0) && (i >= max_fdset)) || + (i >= max_fds)) + break; +- set = open_fds.__fds_bits[j++]; ++ set = open_fds[j++]; + while (set) { + if (set & 1) { + readmem(fd + i*sizeof(struct file *), KVADDR, +@@ -2665,6 +2676,7 @@ open_files_dump(ulong task, int flags, struct reference *ref) + if (fdtable_buf) + FREEBUF(fdtable_buf); + FREEBUF(files_struct_buf); ++ FREEBUF(open_fds); + } + + /* +diff --git a/net.c b/net.c +index 4199091..f08f22a 100644 +--- a/net.c ++++ b/net.c +@@ -1373,7 +1373,8 @@ dump_sockets_workhorse(ulong task, ulong flag, struct reference *ref) + int max_fdset = 0; + int max_fds = 0; + ulong open_fds_addr = 0; +- fd_set open_fds; ++ ulong *open_fds; ++ int open_fds_size; + ulong fd; + ulong file; + int i, j; +@@ -1446,12 +1447,18 @@ dump_sockets_workhorse(ulong task, ulong flag, struct reference *ref) + sizeof(void *), "files_struct fd addr", FAULT_ON_ERROR); + } + ++ open_fds_size = MAX(max_fdset, max_fds) / BITS_PER_BYTE; ++ open_fds = (ulong *)GETBUF(open_fds_size); ++ if (!open_fds) ++ return; ++ + if (open_fds_addr) +- readmem(open_fds_addr, KVADDR, &open_fds, sizeof(fd_set), ++ readmem(open_fds_addr, KVADDR, open_fds, open_fds_size, + "files_struct open_fds", FAULT_ON_ERROR); + if (!open_fds_addr || !fd) { + if (!NET_REFERENCE_CHECK(ref)) + fprintf(fp, "No open sockets.\n"); ++ FREEBUF(open_fds); + return; + } + +@@ -1479,10 +1486,10 @@ dump_sockets_workhorse(ulong task, ulong flag, struct reference *ref) + j = 0; + for (;;) { + unsigned long set; +- i = j * __NFDBITS; ++ i = j * BITS_PER_LONG; + if (((max_fdset >= 0) && (i >= max_fdset)) || (i >= max_fds)) + break; +- set = open_fds.__fds_bits[j++]; ++ set = open_fds[j++]; + while (set) { + if (set & 1) { + readmem(fd + i*sizeof(struct file *), KVADDR, +@@ -1505,6 +1512,8 @@ dump_sockets_workhorse(ulong task, ulong flag, struct reference *ref) + + if (NET_REFERENCE_FOUND(ref)) + fprintf(fp, "\n"); ++ ++ FREEBUF(open_fds); + } + + + +commit e9532aea6818b347bc0740f39efd4ec844cfb9b0 +Author: Dave Anderson +Date: Thu Aug 9 11:20:26 2018 -0400 + + As an addendum to the new "kmem -[sS]" output format, align the slab + cache name string so that it is beneath the "NAME" header column when + the "kmem -I <slab-cache>" option is used to ignore a slab cache, + or if the scan of the metadata of a slab cache enounters corruption. + Also remove a superfluous line from the "help kmem" description of + the "kmem -I" option. + (k-hagio@ab.jp.nec.com, anderson@redhat.com) + +diff --git a/help.c b/help.c +index a189038..aeeb056 100644 +--- a/help.c ++++ b/help.c +@@ -6495,7 +6495,6 @@ char *help_kmem[] = { + " all slab cache names and addresses are listed.", + " -I slab when used with -s or -S, one or more slab cache names in a", + " comma-separated list may be specified as slab caches to ignore.", +-" their hugepage size, total and free counts, and name.", + " -g displays the enumerator value of all bits in the page structure's", + " \"flags\" field.", + " flags when used with -g, translates all bits in this hexadecimal page", +diff --git a/memory.c b/memory.c +index 5bcf09e..4790cf6 100644 +--- a/memory.c ++++ b/memory.c +@@ -9963,6 +9963,9 @@ ignore_cache(struct meminfo *si, char *name) + #define KMEM_SLAB_OVERLOAD_PAGE (8) + #define KMEM_SLAB_FREELIST (9) + ++#define DUMP_KMEM_CACHE_TAG(addr, name, tag) \ ++ fprintf(fp, "%lx %-43s %s\n", addr, tag, name) ++ + #define DUMP_KMEM_CACHE_INFO() dump_kmem_cache_info(si) + + static void +@@ -10094,7 +10097,7 @@ dump_kmem_cache(struct meminfo *si) + goto next_cache; + + if (ignore_cache(si, buf)) { +- fprintf(fp, "%lx %-18s [IGNORED]\n", si->cache, buf); ++ DUMP_KMEM_CACHE_TAG(si->cache, buf, "[IGNORED]"); + goto next_cache; + } + +@@ -10303,7 +10306,7 @@ dump_kmem_cache_percpu_v1(struct meminfo *si) + goto next_cache; + + if (ignore_cache(si, buf)) { +- fprintf(fp, "%lx %-18s [IGNORED]\n", si->cache, buf); ++ DUMP_KMEM_CACHE_TAG(si->cache, buf, "[IGNORED]"); + goto next_cache; + } + +@@ -10547,12 +10550,12 @@ dump_kmem_cache_percpu_v2(struct meminfo *si) + goto next_cache; + + if (ignore_cache(si, buf)) { +- fprintf(fp, "%lx %-18s [IGNORED]\n", si->cache, buf); ++ DUMP_KMEM_CACHE_TAG(si->cache, buf, "[IGNORED]"); + goto next_cache; + } + + if (bad_slab_cache(si->cache)) { +- fprintf(fp, "%lx %-18s [INVALID/CORRUPTED]\n", si->cache, buf); ++ DUMP_KMEM_CACHE_TAG(si->cache, buf, "[INVALID/CORRUPTED]"); + goto next_cache; + } + +@@ -18109,8 +18112,7 @@ dump_kmem_cache_slub(struct meminfo *si) + fprintf(fp, "%s", kmem_cache_hdr); + } + if (ignore_cache(si, buf)) { +- fprintf(fp, "%lx %-18s [IGNORED]\n", +- si->cache_list[i], buf); ++ DUMP_KMEM_CACHE_TAG(si->cache_list[i], buf, "[IGNORED]"); + goto next_cache; + } + diff --git a/SOURCES/github_a89ec821_vmcoreinfo_plugin.patch b/SOURCES/github_a89ec821_vmcoreinfo_plugin.patch new file mode 100644 index 0000000..0c79a31 --- /dev/null +++ b/SOURCES/github_a89ec821_vmcoreinfo_plugin.patch @@ -0,0 +1,193 @@ +commit a89ec821cb5dbb106cb58e8740f84c7e382c0140 +Author: Dave Anderson +Date: Fri Feb 8 11:12:23 2019 -0500 + + For live system analysis where there is no vmcoreinfo ELF note + attached to /proc/kcore, or for dumpfile analysis where there is no + vmcoreinfo ELF note attached to the dumpfile, this patch sets the + internal pc->read_vmcoreinfo() function to a new plugin function + that reads the data directly from the live kernel or dumpfile. + Because the function is set much later during initialization than + if the ELF note is attached to /proc/kcore or the dumpfile, it may + not be available during very early session initialization. + (anderson@redhat.com) + +diff --git a/defs.h b/defs.h +index 05f2d17..5841b1f 100644 +--- a/defs.h ++++ b/defs.h +@@ -4872,6 +4872,7 @@ int clean_exit(int); + int untrusted_file(FILE *, char *); + char *readmem_function_name(void); + char *writemem_function_name(void); ++char *no_vmcoreinfo(const char *); + + /* + * cmdline.c +diff --git a/kernel.c b/kernel.c +index e512da5..9f5ba89 100644 +--- a/kernel.c ++++ b/kernel.c +@@ -93,6 +93,8 @@ static void source_tree_init(void); + static ulong dump_audit_skb_queue(ulong); + static ulong __dump_audit(char *); + static void dump_audit(void); ++static char *vmcoreinfo_read_string(const char *); ++static void check_vmcoreinfo(void); + + + /* +@@ -127,6 +129,8 @@ kernel_init() + kt->end = highest_bss_symbol(); + if ((sp1 = kernel_symbol_search("_end")) && (sp1->value > kt->end)) + kt->end = sp1->value; ++ ++ check_vmcoreinfo(); + + /* + * For the traditional (non-pv_ops) Xen architecture, default to writable +@@ -11117,3 +11121,84 @@ dump_audit(void) + if (!qlen) + error(INFO, "kernel audit log is empty\n"); + } ++ ++/* ++ * Reads a string value from the VMCOREINFO data stored in (live) memory. ++ * ++ * Returns a string (that has to be freed by the caller) that contains the ++ * value for key or NULL if the key has not been found. ++ */ ++static char * ++vmcoreinfo_read_string(const char *key) ++{ ++ char *buf, *value_string, *p1, *p2; ++ size_t value_length; ++ size_t vmcoreinfo_size; ++ ulong vmcoreinfo_data; ++ char keybuf[BUFSIZE]; ++ ++ buf = value_string = NULL; ++ ++ switch (get_symbol_type("vmcoreinfo_data", NULL, NULL)) ++ { ++ case TYPE_CODE_PTR: ++ get_symbol_data("vmcoreinfo_data", sizeof(vmcoreinfo_data), &vmcoreinfo_data); ++ break; ++ case TYPE_CODE_ARRAY: ++ vmcoreinfo_data = symbol_value("vmcoreinfo_data"); ++ break; ++ default: ++ return NULL; ++ } ++ ++ get_symbol_data("vmcoreinfo_size", sizeof(vmcoreinfo_size), &vmcoreinfo_size); ++ ++ sprintf(keybuf, "%s=", key); ++ ++ if ((buf = malloc(vmcoreinfo_size+1)) == NULL) { ++ error(INFO, "cannot malloc vmcoreinfo buffer\n"); ++ goto err; ++ } ++ ++ if (!readmem(vmcoreinfo_data, KVADDR, buf, vmcoreinfo_size, ++ "vmcoreinfo_data", RETURN_ON_ERROR|QUIET)) { ++ error(INFO, "cannot read vmcoreinfo_data\n"); ++ goto err; ++ } ++ ++ buf[vmcoreinfo_size] = '\n'; ++ ++ if ((p1 = strstr(buf, keybuf))) { ++ p2 = p1 + strlen(keybuf); ++ p1 = strstr(p2, "\n"); ++ value_length = p1-p2; ++ value_string = calloc(value_length+1, sizeof(char)); ++ strncpy(value_string, p2, value_length); ++ value_string[value_length] = NULLCHAR; ++ } ++err: ++ if (buf) ++ free(buf); ++ ++ return value_string; ++} ++ ++static void ++check_vmcoreinfo(void) ++{ ++ if (!kernel_symbol_exists("vmcoreinfo_data") || ++ !kernel_symbol_exists("vmcoreinfo_size")) ++ return; ++ ++ if (pc->read_vmcoreinfo == no_vmcoreinfo) { ++ switch (get_symbol_type("vmcoreinfo_data", NULL, NULL)) ++ { ++ case TYPE_CODE_PTR: ++ pc->read_vmcoreinfo = vmcoreinfo_read_string; ++ break; ++ case TYPE_CODE_ARRAY: ++ pc->read_vmcoreinfo = vmcoreinfo_read_string; ++ break; ++ } ++ } ++} +diff --git a/main.c b/main.c +index 7248810..cd282cd 100644 +--- a/main.c ++++ b/main.c +@@ -1,8 +1,8 @@ + /* main.c - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. +- * Copyright (C) 2002-2018 David Anderson +- * Copyright (C) 2002-2018 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002-2019 David Anderson ++ * Copyright (C) 2002-2019 Red Hat, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -29,7 +29,6 @@ static void check_xen_hyper(void); + static void show_untrusted_files(void); + static void get_osrelease(char *); + static void get_log(char *); +-static char *no_vmcoreinfo(const char *); + + static struct option long_options[] = { + {"memory_module", required_argument, 0, 0}, +@@ -1950,7 +1949,7 @@ get_log(char *dumpfile) + } + + +-static char * ++char * + no_vmcoreinfo(const char *unused) + { + return NULL; +diff --git a/netdump.c b/netdump.c +index d0179e0..5aeea6f 100644 +--- a/netdump.c ++++ b/netdump.c +@@ -1,7 +1,7 @@ + /* netdump.c + * +- * Copyright (C) 2002-2018 David Anderson +- * Copyright (C) 2002-2018 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002-2019 David Anderson ++ * Copyright (C) 2002-2019 Red Hat, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -1786,11 +1786,13 @@ vmcoreinfo_read_string(const char *key) + if (STREQ(key, "NUMBER(kimage_voffset)") && nd->arch_data) { + value = calloc(VADDR_PRLEN+1, sizeof(char)); + sprintf(value, "%lx", nd->arch_data); ++ pc->read_vmcoreinfo = no_vmcoreinfo; + return value; + } + if (STREQ(key, "relocate") && nd->arch_data) { + value = calloc(VADDR_PRLEN+1, sizeof(char)); + sprintf(value, "%lx", nd->arch_data); ++ pc->read_vmcoreinfo = no_vmcoreinfo; + return value; + } + } diff --git a/SOURCES/github_ac5a7889_CONFIG_ARM64_PA_BITS.patch b/SOURCES/github_ac5a7889_CONFIG_ARM64_PA_BITS.patch new file mode 100644 index 0000000..2122183 --- /dev/null +++ b/SOURCES/github_ac5a7889_CONFIG_ARM64_PA_BITS.patch @@ -0,0 +1,29 @@ +commit ac5a7889d31bb37aa0687110ecea08837f8a66a8 +Author: Dave Anderson +Date: Fri Feb 8 10:48:30 2019 -0500 + + Support for configurable CONFIG_ARM64_PA_BITS values introduced + in kernel commit 982aa7c5f0861bf56b2412ca341a13f44c238ba4, titled + "arm64: add kconfig symbol to configure physical address size". + Without the patch, it is impossible to determine the value of + CONFIG_ARM64_PA_BITS, and will require a new MAX_PHYSMEM_BITS + vmcoreinfo entry to be exported. This patch reads that entry + during intitialization. + (anderson@redhat.com) + +diff --git a/arm64.c b/arm64.c +index 2308612..b4d9b13 100644 +--- a/arm64.c ++++ b/arm64.c +@@ -362,7 +362,10 @@ arm64_init(int when) + arm64_calc_virtual_memory_ranges(); + machdep->section_size_bits = _SECTION_SIZE_BITS; + if (!machdep->max_physmem_bits) { +- if (machdep->machspec->VA_BITS == 52) /* guess */ ++ if ((string = pc->read_vmcoreinfo("NUMBER(MAX_PHYSMEM_BITS)"))) { ++ machdep->max_physmem_bits = atol(string); ++ free(string); ++ } else if (machdep->machspec->VA_BITS == 52) /* guess */ + machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_52; + else if (THIS_KERNEL_VERSION >= LINUX(3,17,0)) + machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_3_17; diff --git a/SOURCES/github_b9d76838_c79a11fa_proc_kcore.patch b/SOURCES/github_b9d76838_c79a11fa_proc_kcore.patch new file mode 100644 index 0000000..0d84189 --- /dev/null +++ b/SOURCES/github_b9d76838_c79a11fa_proc_kcore.patch @@ -0,0 +1,149 @@ +commit b9d76838372d1b4087bb506ce6da425afad68876 +Author: Dave Anderson +Date: Thu Jun 7 13:20:16 2018 -0400 + + If /proc/kcore gets selected for the live memory source because + /dev/mem was configured with CONFIG_STRICT_DEVMEM, its ELF header + contents are not displayed by "help -[dD]", and are not displayed + when the crash session is invoked with -d". Without the + patch, the ELF contents are only displayed in those two situations + if "/proc/kcore" is explicitly entered on the crash command line. + (anderson@redhat.com) + +diff --git a/netdump.c b/netdump.c +index 25683eb..1f3e26c 100644 +--- a/netdump.c ++++ b/netdump.c +@@ -4334,11 +4334,8 @@ kcore_memory_dump(FILE *ofp) + Elf32_Phdr *lp32; + Elf64_Phdr *lp64; + +- if (!(pkd->flags & KCORE_LOCAL)) +- return FALSE; +- + fprintf(ofp, "proc_kcore_data:\n"); +- fprintf(ofp, " flags: %lx (", nd->flags); ++ fprintf(ofp, " flags: %x (", pkd->flags); + others = 0; + if (pkd->flags & KCORE_LOCAL) + fprintf(ofp, "%sKCORE_LOCAL", others++ ? "|" : ""); +commit c79a11fa10da94b71ddf341ec996c522fbd75237 +Author: Dave Anderson +Date: Fri Jun 8 14:31:08 2018 -0400 + + If the default live memory source /dev/mem is determined to be + unusable because the kernel was configured with CONFIG_STRICT_DEVMEM, + the first memory read during session initialization will fail. The + current behavior results in a readmem() error message, followed by two + notification messages that indicate that /dev/mem is restricted and + a switch to using /proc/kcore will be attempted; the readmem is + reattempted from /proc/kcore, and if successful, the session will + continue initialization. With this patch, the behavior will change + such that if the switch to /proc/kcore and the reattempted readmem() + are successful, no messages will be displayed unless the crash + session is invoked with "crash -d<number>". + (anderson@redhat.com) + +diff --git a/kernel.c b/kernel.c +index 138a47f..3cd5bf1 100644 +--- a/kernel.c ++++ b/kernel.c +@@ -882,7 +882,7 @@ cpu_maps_init(void) + { + int i, c, m, cpu, len; + char *buf; +- ulong *maskptr, addr; ++ ulong *maskptr, addr, error_handle; + struct mapinfo { + ulong cpu_flag; + char *name; +@@ -902,8 +902,9 @@ cpu_maps_init(void) + if (!(addr = cpu_map_addr(mapinfo[m].name))) + continue; + ++ error_handle = pc->flags & DEVMEM ? RETURN_ON_ERROR|QUIET : RETURN_ON_ERROR; + if (!readmem(addr, KVADDR, buf, len, +- mapinfo[m].name, RETURN_ON_ERROR)) { ++ mapinfo[m].name, error_handle)) { + error(WARNING, "cannot read cpu_%s_map\n", + mapinfo[m].name); + continue; +diff --git a/memory.c b/memory.c +index 82f9cbf..2f568d5 100644 +--- a/memory.c ++++ b/memory.c +@@ -2243,9 +2243,11 @@ readmem(ulonglong addr, int memtype, void *buffer, long size, + error(INFO, READ_ERRMSG, memtype_string(memtype, 0), addr, type); + if ((pc->flags & DEVMEM) && (kt->flags & PRE_KERNEL_INIT) && + !(error_handle & NO_DEVMEM_SWITCH) && devmem_is_restricted() && +- switch_to_proc_kcore()) ++ switch_to_proc_kcore()) { ++ error_handle &= ~QUIET; + return(readmem(addr, memtype, bufptr, size, + type, error_handle)); ++ } + goto readmem_error; + + case PAGE_EXCLUDED: +@@ -2457,7 +2459,7 @@ devmem_is_restricted(void) + QUIET|RETURN_ON_ERROR|NO_DEVMEM_SWITCH)) + restricted = TRUE; + +- if (restricted) ++ if (restricted && CRASHDEBUG(1)) + error(INFO, + "this kernel may be configured with CONFIG_STRICT_DEVMEM," + " which\n renders /dev/mem unusable as a live memory " +@@ -2472,9 +2474,10 @@ switch_to_proc_kcore(void) + { + close(pc->mfd); + +- if (file_exists("/proc/kcore", NULL)) +- error(INFO, "trying /proc/kcore as an alternative to /dev/mem\n\n"); +- else ++ if (file_exists("/proc/kcore", NULL)) { ++ if (CRASHDEBUG(1)) ++ error(INFO, "trying /proc/kcore as an alternative to /dev/mem\n\n"); ++ } else + return FALSE; + + if ((pc->mfd = open("/proc/kcore", O_RDONLY)) < 0) { +diff --git a/ppc64.c b/ppc64.c +index 0b04187..0dd8a2a 100644 +--- a/ppc64.c ++++ b/ppc64.c +@@ -1,7 +1,7 @@ + /* ppc64.c -- core analysis suite + * +- * Copyright (C) 2004-2015,2017 David Anderson +- * Copyright (C) 2004-2015,2017 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2004-2015,2018 David Anderson ++ * Copyright (C) 2004-2015,2018 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 +@@ -343,8 +343,9 @@ ppc64_init(int when) + + if (symbol_exists("vmemmap_populate")) { + if (symbol_exists("vmemmap")) { +- get_symbol_data("vmemmap", sizeof(void *), +- &machdep->machspec->vmemmap_base); ++ readmem(symbol_value("vmemmap"), KVADDR, ++ &machdep->machspec->vmemmap_base, ++ sizeof(void *), "vmemmap", QUIET|FAULT_ON_ERROR); + } else + machdep->machspec->vmemmap_base = + VMEMMAP_REGION_ID << REGION_SHIFT; +diff --git a/x86_64.c b/x86_64.c +index 54b6539..e01082b 100644 +--- a/x86_64.c ++++ b/x86_64.c +@@ -356,7 +356,7 @@ x86_64_init(int when) + machdep->flags |= RANDOMIZED; + readmem(symbol_value("page_offset_base"), KVADDR, + &machdep->machspec->page_offset, sizeof(ulong), +- "page_offset_base", FAULT_ON_ERROR); ++ "page_offset_base", QUIET|FAULT_ON_ERROR); + machdep->kvbase = machdep->machspec->page_offset; + machdep->identity_map_base = machdep->machspec->page_offset; + } diff --git a/SOURCES/github_c5f45d6c.patch b/SOURCES/github_c5f45d6c.patch new file mode 100644 index 0000000..c242be1 --- /dev/null +++ b/SOURCES/github_c5f45d6c.patch @@ -0,0 +1,239 @@ +commit c5f45d6cdbe7f01314857a75b2feef25b22adaaa +Author: Dave Anderson +Date: Thu Oct 11 13:28:39 2018 -0400 + + Address several Coverity Scan "RESOURCE_LEAK" issues in the following + top-level source files: cmdline.c, kvmdump.c, lkcd_v8.c, xendump.c, + symbols.c, unwind_x86_32_64.c, va_server.c and va_server_v1.c. + (anderson@redhat.com) + +diff --git a/cmdline.c b/cmdline.c +index c0a9f4f..cf3e150 100644 +--- a/cmdline.c ++++ b/cmdline.c +@@ -1318,8 +1318,10 @@ is_shell_script(char *s) + if ((fd = open(s, O_RDONLY)) < 0) + return FALSE; + +- if (isatty(fd)) ++ if (isatty(fd)) { ++ close(fd); + return FALSE; ++ } + + if (read(fd, interp, 2) != 2) { + close(fd); +diff --git a/kvmdump.c b/kvmdump.c +index 622619c..4db96bd 100644 +--- a/kvmdump.c ++++ b/kvmdump.c +@@ -846,8 +846,10 @@ kvmdump_mapfile_exists(void) + + sprintf(filename, "%s.map", pc->dumpfile); + +- if (!file_exists(filename, &stat) || !S_ISREG(stat.st_mode)) ++ if (!file_exists(filename, &stat) || !S_ISREG(stat.st_mode)) { ++ free(filename); + return FALSE; ++ } + + if (is_kvmdump_mapfile(filename)) { + pc->kvmdump_mapfile = filename; +diff --git a/lkcd_v8.c b/lkcd_v8.c +index 1322250..3b355e0 100644 +--- a/lkcd_v8.c ++++ b/lkcd_v8.c +@@ -184,6 +184,7 @@ lkcd_dump_init_v8_arch(dump_header_t *dh) + + memcpy(&dump_header_asm_v8, &arch_hdr, sizeof(dump_header_asm_t)); + ++ free(hdr_buf); + return 0; + + err: +diff --git a/symbols.c b/symbols.c +index b54b8c0..fb9cd1b 100644 +--- a/symbols.c ++++ b/symbols.c +@@ -3862,12 +3862,10 @@ is_bfd_format(char *filename) + #else + struct bfd *bfd; + #endif +- char **matching; +- + if ((bfd = bfd_openr(filename, NULL)) == NULL) + return FALSE; + +- if (!bfd_check_format_matches(bfd, bfd_object, &matching)) { ++ if (!bfd_check_format_matches(bfd, bfd_object, NULL)) { + bfd_close(bfd); + return FALSE; + } +diff --git a/unwind_x86_32_64.c b/unwind_x86_32_64.c +index c62f92f..c7c30d6 100644 +--- a/unwind_x86_32_64.c ++++ b/unwind_x86_32_64.c +@@ -819,6 +819,7 @@ try_eh_frame: + error(WARNING, "cannot read %s data from %s\n", + is_ehframe ? ".eh_frame" : ".debug_frame", pc->namelist); + free(unwind_table); ++ close(fd); + return; + } + +diff --git a/va_server.c b/va_server.c +index d96287a..96c2b5c 100644 +--- a/va_server.c ++++ b/va_server.c +@@ -313,20 +313,27 @@ int read_map(char *crash_file) + ret = fseek(vas_file_p, (long)0, SEEK_SET); + if(ret == -1) { + printf("va_server: unable to fseek, err = %d\n", ferror(vas_file_p)); ++ free(hdr); + free(disk_hdr); + return -1; + } + items = fread((void *)disk_hdr, 1, Page_Size, vas_file_p); + if(items != Page_Size) { ++ free(hdr); ++ free(disk_hdr); + return -1; + } + if(disk_hdr->magic[0] != CRASH_MAGIC) { ++ free(hdr); ++ free(disk_hdr); + return -1; + } + ret = fseek(vas_file_p, (long)((disk_hdr->map_block) * disk_hdr->blk_size), SEEK_SET); + + if(ret == -1) { + printf("va_server: unable to fseek, err = %d\n", ferror(vas_file_p)); ++ free(hdr); ++ free(disk_hdr); + return -1; + } + +@@ -338,10 +345,13 @@ int read_map(char *crash_file) + vas_file_p); + if(items != disk_hdr->map_blocks) { + printf("unable to read map entries, err = %d\n", errno); ++ free(hdr); ++ free(disk_hdr); + return -1; + } + + vas_map_base = hdr; ++ free(disk_hdr); + return 0; + } + +diff --git a/va_server_v1.c b/va_server_v1.c +index 1924946..88a2a5a 100644 +--- a/va_server_v1.c ++++ b/va_server_v1.c +@@ -253,7 +253,7 @@ u_long vas_find_end_v1(void) + } + int read_maps_v1(char *crash_file) + { +- int *cur_entry_p; ++ int *cur_entry_p, *cp; + int ret, items, blk_pos; + + cur_entry_p = (int *)malloc(Page_Size); +@@ -266,25 +266,32 @@ int read_maps_v1(char *crash_file) + vas_file_p = fopen(crash_file, "r"); + if(vas_file_p == (FILE *)0) { + printf("read_maps: bad ret from fopen for %s: %s\n", crash_file, strerror(errno)); ++ free(cur_entry_p); + return -1; + } + ret = fseek(vas_file_p, (long)0, SEEK_SET); + if(ret == -1) { + printf("read_maps: unable to fseek in %s, errno = %d\n", crash_file, ferror(vas_file_p)); ++ free(cur_entry_p); + return -1; + } + items = fread((void *)cur_entry_p, 1, Page_Size, vas_file_p); + if(items != Page_Size) { + printf("read_maps: unable to read header from %s, errno = %d\n", crash_file, ferror(vas_file_p)); ++ free(cur_entry_p); + return -1; + } + ret = -1; +- while ((blk_pos = *cur_entry_p++)) { +- if (read_map_v1(blk_pos)) ++ cp = cur_entry_p; ++ while ((blk_pos = *cp++)) { ++ if (read_map_v1(blk_pos)) { ++ free(cur_entry_p); + return -1; ++ } + ret = 0; + } + ++ free(cur_entry_p); + return ret; + } + +@@ -308,21 +315,28 @@ int read_map_v1(int blk_pos) + ret = fseek(vas_file_p, (long)(blk_pos*Page_Size), SEEK_SET); + if(ret == -1) { + console("va_server: unable to fseek, err = %d\n", ferror(vas_file_p)); ++ free(hdr); + free(disk_hdr); + return -1; + } + items = fread((void *)disk_hdr, 1, Page_Size, vas_file_p); + if(items != Page_Size) { ++ free(hdr); ++ free(disk_hdr); + return -1; + } + if(disk_hdr->magic[0] != CRASH_MAGIC) { + console("va_server: bad magic 0x%lx\n", disk_hdr->magic[0]); ++ free(hdr); ++ free(disk_hdr); + return -1; + } + ret = fseek(vas_file_p, (long)((blk_pos + disk_hdr->map_block) * disk_hdr->blk_size), SEEK_SET); + + if(ret == -1) { + printf("va_server: unable to fseek, err = %d\n", ferror(vas_file_p)); ++ free(hdr); ++ free(disk_hdr); + return -1; + } + +@@ -338,6 +352,8 @@ int read_map_v1(int blk_pos) + vas_file_p); + if(items != hdr->map_entries) { + printf("unable to read map entries, err = %d\n", errno); ++ free(hdr); ++ free(disk_hdr); + return -1; + } + +diff --git a/xendump.c b/xendump.c +index 4bd59b5..70cf261 100644 +--- a/xendump.c ++++ b/xendump.c +@@ -2775,8 +2775,10 @@ xc_core_dump_elfnote(off_t sh_offset, size_t sh_size, int store) + index += sizeof(struct elfnote) + elfnote->descsz; + } + +- if (!store) ++ if (!store) { ++ free(notes_buffer); + return; ++ } + + if (elfnote_header) { + xd->xc_core.header.xch_magic = elfnote_header->xch_magic; +@@ -2798,6 +2800,7 @@ xc_core_dump_elfnote(off_t sh_offset, size_t sh_size, int store) + xd->xc_core.format_version = format_version->version; + } + ++ free(notes_buffer); + } + + /* diff --git a/SOURCES/github_ced52552_dev-p_offsets.patch b/SOURCES/github_ced52552_dev-p_offsets.patch new file mode 100644 index 0000000..f8ba626 --- /dev/null +++ b/SOURCES/github_ced52552_dev-p_offsets.patch @@ -0,0 +1,41 @@ +commit ced5255233447cc0810965b683657409f798c4a2 +Author: Dave Anderson +Date: Tue Oct 2 11:18:09 2018 -0400 + + As an addendum to the "dev -p" patch above, add the new structure + member offsets for display by the "help -o" option. + (anderson@redhat.com) + +diff --git a/symbols.c b/symbols.c +index cb2174b..bb8a8f4 100644 +--- a/symbols.c ++++ b/symbols.c +@@ -9692,6 +9692,28 @@ dump_offset_table(char *spec, ulong makestruct) + fprintf(fp, " pci_bus_number: %ld\n", + OFFSET(pci_bus_number)); + ++ fprintf(fp, " pci_dev_dev: %ld\n", ++ OFFSET(pci_dev_dev)); ++ fprintf(fp, " pci_dev_hdr_type: %ld\n", ++ OFFSET(pci_dev_hdr_type)); ++ fprintf(fp, " pci_dev_pcie_flags_reg: %ld\n", ++ OFFSET(pci_dev_pcie_flags_reg)); ++ fprintf(fp, " pci_bus_node: %ld\n", ++ OFFSET(pci_bus_node)); ++ fprintf(fp, " pci_bus_devices: %ld\n", ++ OFFSET(pci_bus_devices)); ++ fprintf(fp, " pci_bus_dev: %ld\n", ++ OFFSET(pci_bus_dev)); ++ fprintf(fp, " pci_bus_children: %ld\n", ++ OFFSET(pci_bus_children)); ++ fprintf(fp, " pci_bus_parent: %ld\n", ++ OFFSET(pci_bus_parent)); ++ fprintf(fp, " pci_bus_self: %ld\n", ++ OFFSET(pci_bus_self)); ++ fprintf(fp, " device_kobj: %ld\n", ++ OFFSET(device_kobj)); ++ fprintf(fp, " kobject_name: %ld\n", ++ OFFSET(kobject_name)); + + fprintf(fp, " resource_entry_t_from: %ld\n", + OFFSET(resource_entry_t_from)); diff --git a/SOURCES/github_f3a53059.patch b/SOURCES/github_f3a53059.patch new file mode 100644 index 0000000..f28387c --- /dev/null +++ b/SOURCES/github_f3a53059.patch @@ -0,0 +1,89 @@ +commit f3a5305947077a65aea8091b05cdb542cea0d61a +Author: Dave Anderson +Date: Wed Oct 24 16:25:43 2018 -0400 + + Modify the x86_64 "bt" behavior when a legitimate exception RIP value + cannot be referenced symbolically, such as when the exception occurs + while running in seccomp BPF filter code. Without the patch, the + exception frame register dump is preceded by "[exception RIP: unknown + or invalid address]", and then followed by "bt: WARNING: possibly + bogus exception frame". With the patch applied, the translation of + the exception RIP will show "[exception RIP: no symbolic reference]", + and there will be no warning message. + (anderson@redhat.com) + +diff --git a/x86_64.c b/x86_64.c +index 345122c..d145f96 100644 +--- a/x86_64.c ++++ b/x86_64.c +@@ -3259,6 +3259,18 @@ x86_64_in_alternate_stack(int cpu, ulong + return FALSE; + } + ++static char * ++x86_64_exception_RIP_message(struct bt_info *bt, ulong rip) ++{ ++ physaddr_t phys; ++ ++ if (IS_VMALLOC_ADDR(rip) && ++ machdep->kvtop(bt->tc, rip, &phys, 0)) ++ return ("no symbolic reference"); ++ ++ return ("unknown or invalid address"); ++} ++ + #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 \ +@@ -3370,7 +3382,7 @@ x86_64_low_budget_back_trace_cmd(struct + fprintf(ofp, (*gdb_output_radix == 16) ? + "+0x%lx" : "+%ld", offset); + } else +- fprintf(ofp, "unknown or invalid address"); ++ fprintf(ofp, "%s", x86_64_exception_RIP_message(bt, bt->instptr)); + fprintf(ofp, "]\n"); + if (KVMDUMP_DUMPFILE()) + kvmdump_display_regs(bt->tc->processor, ofp); +@@ -4458,9 +4470,9 @@ x86_64_exception_frame(ulong flags, ulon + (*gdb_output_radix == 16) ? + "+0x%lx" : "+%ld", + offset); +- } else +- fprintf(ofp, +- "unknown or invalid address"); ++ } else ++ fprintf(ofp, "%s", ++ x86_64_exception_RIP_message(bt, rip)); + fprintf(ofp, "]\n"); + } + } else if (!(cs & 3)) { +@@ -4472,7 +4484,7 @@ x86_64_exception_frame(ulong flags, ulon + "+0x%lx" : "+%ld", offset); + bt->eframe_ip = rip; + } else +- fprintf(ofp, "unknown or invalid address"); ++ fprintf(ofp, "%s", x86_64_exception_RIP_message(bt, rip)); + fprintf(ofp, "]\n"); + } + fprintf(ofp, " RIP: %016lx RSP: %016lx RFLAGS: %08lx\n", +@@ -4616,6 +4628,7 @@ x86_64_eframe_verify(struct bt_info *bt, + int estack; + struct syment *sp; + ulong offset, exception; ++ physaddr_t phys; + + if ((rflags & RAZ_MASK) || !(rflags & 0x2)) + return FALSE; +@@ -4682,6 +4695,12 @@ x86_64_eframe_verify(struct bt_info *bt, + return TRUE; + } + ++ if ((cs == 0x10) && kvaddr) { ++ if (IS_KVADDR(rsp) && IS_VMALLOC_ADDR(rip) && ++ machdep->kvtop(bt->tc, rip, &phys, 0)) ++ return TRUE; ++ } ++ + if ((cs == 0x33) && (ss == 0x2b)) { + if (IS_UVADDR(rip, bt->tc) && IS_UVADDR(rsp, bt->tc)) + return TRUE; diff --git a/SOURCES/github_ppc64_5fe78861_7e393689_599a6579_72cc0cba.patch b/SOURCES/github_ppc64_5fe78861_7e393689_599a6579_72cc0cba.patch new file mode 100644 index 0000000..2b3d324 --- /dev/null +++ b/SOURCES/github_ppc64_5fe78861_7e393689_599a6579_72cc0cba.patch @@ -0,0 +1,499 @@ +commit 5fe78861ea1589084f6a2956a6ff63677c9269e1 +Author: Dave Anderson +Date: Fri Sep 7 16:05:52 2018 -0400 + + Commit 3db3d3992d781c1e42587d2d2bf81e785408e0c2 in crash-7.1.8 was + aimed at making the PPC64 "bt" command work for dumpfiles saved + with the FADUMP facility, but it introduced a bit of unwarranted + complexity in "bt" command processing. Reworked the "bt" command + processing for PPC64 arch to make it a little less compilated and + also to print symbols for NIP and LR registers in exception frames. + Without the patch, "bt" on non-panic active tasks may fail with + the message "bt: invalid kernel virtual address:
+ type: Regs NIP value". + (hbathini@linux.ibm.com) + +diff --git a/ppc64.c b/ppc64.c +index f5d0dac..03fecd3 100644 +--- a/ppc64.c ++++ b/ppc64.c +@@ -2093,15 +2093,10 @@ ppc64_print_stack_entry(int frame, + lr); + return; + } +- if (req->pc != lr) { +- fprintf(fp, "\n%s[Link Register] ", +- frame < 10 ? " " : ""); +- fprintf(fp, "[%lx] %s at %lx", +- req->sp, lrname, lr); +- } + req->ra = lr; + } +- if (!req->name || STREQ(req->name,lrname)) ++ if (!req->name || STREQ(req->name, lrname) || ++ !is_kernel_text(req->pc)) + fprintf(fp, " (unreliable)"); + + fprintf(fp, "\n"); +@@ -2219,6 +2214,22 @@ ppc64_print_regs(struct ppc64_pt_regs *regs) + fprintf(fp, " Syscall Result: %016lx\n", regs->result); + } + ++static void ppc64_print_nip_lr(struct ppc64_pt_regs *regs, int print_lr) ++{ ++ char buf[BUFSIZE]; ++ char *sym_buf; ++ ++ sym_buf = value_to_symstr(regs->nip, buf, 0); ++ if (sym_buf[0] != NULLCHAR) ++ fprintf(fp, " [NIP : %s]\n", sym_buf); ++ ++ if (print_lr) { ++ sym_buf = value_to_symstr(regs->link, buf, 0); ++ if (sym_buf[0] != NULLCHAR) ++ fprintf(fp, " [LR : %s]\n", sym_buf); ++ } ++} ++ + /* + * Print the exception frame information + */ +@@ -2231,6 +2242,59 @@ ppc64_print_eframe(char *efrm_str, struct ppc64_pt_regs *regs, + + fprintf(fp, " %s [%lx] exception frame:\n", efrm_str, regs->trap); + ppc64_print_regs(regs); ++ ppc64_print_nip_lr(regs, 1); ++} ++ ++/* ++ * For vmcore typically saved with KDump or FADump, get SP and IP values ++ * from the saved ptregs. ++ */ ++static int ++ppc64_vmcore_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp) ++{ ++ struct ppc64_pt_regs *pt_regs; ++ unsigned long unip; ++ ++ pt_regs = (struct ppc64_pt_regs *)bt_in->machdep; ++ if (!pt_regs || !pt_regs->gpr[1]) { ++ /* ++ * Not collected regs. May be the corresponding CPU not ++ * responded to an IPI in case of KDump OR f/w has not ++ * not provided the register info in case of FADump. ++ */ ++ fprintf(fp, "%0lx: GPR1 register value (SP) was not saved\n", ++ bt_in->task); ++ return FALSE; ++ } ++ *ksp = pt_regs->gpr[1]; ++ if (IS_KVADDR(*ksp)) { ++ readmem(*ksp+16, KVADDR, &unip, sizeof(ulong), "Regs NIP value", ++ FAULT_ON_ERROR); ++ *nip = unip; ++ } else { ++ if (IN_TASK_VMA(bt_in->task, *ksp)) ++ fprintf(fp, "%0lx: Task is running in user space\n", ++ bt_in->task); ++ else ++ fprintf(fp, "%0lx: Invalid Stack Pointer %0lx\n", ++ bt_in->task, *ksp); ++ *nip = pt_regs->nip; ++ } ++ ++ if (bt_in->flags && ++ ((BT_TEXT_SYMBOLS|BT_TEXT_SYMBOLS_PRINT|BT_TEXT_SYMBOLS_NOPRINT))) ++ return TRUE; ++ ++ /* ++ * Print the collected regs for the active task ++ */ ++ ppc64_print_regs(pt_regs); ++ if (!IS_KVADDR(*ksp)) ++ return FALSE; ++ ++ ppc64_print_nip_lr(pt_regs, (unip != pt_regs->link) ? 1 : 0); ++ ++ return TRUE; + } + + /* +@@ -2239,7 +2303,7 @@ ppc64_print_eframe(char *efrm_str, struct ppc64_pt_regs *regs, + static int + ppc64_get_dumpfile_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp) + { +- int i; ++ int i, ret, panic_task; + char *sym; + ulong *up; + struct bt_info bt_local, *bt; +@@ -2251,11 +2315,29 @@ ppc64_get_dumpfile_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp) + struct ppc64_pt_regs *pt_regs; + struct syment *sp; + +- bt = &bt_local; +- BCOPY(bt_in, bt, sizeof(struct bt_info)); +- ms = machdep->machspec; ++ bt = &bt_local; ++ BCOPY(bt_in, bt, sizeof(struct bt_info)); ++ ms = machdep->machspec; ++ ur_nip = ur_ksp = 0; ++ ++ panic_task = tt->panic_task == bt->task ? TRUE : FALSE; + + check_hardirq = check_softirq = tt->flags & IRQSTACKS ? TRUE : FALSE; ++ if (panic_task && bt->machdep) { ++ pt_regs = (struct ppc64_pt_regs *)bt->machdep; ++ ur_nip = pt_regs->nip; ++ ur_ksp = pt_regs->gpr[1]; ++ } else if ((pc->flags & KDUMP) || ++ ((pc->flags & DISKDUMP) && ++ (*diskdump_flags & KDUMP_CMPRS_LOCAL))) { ++ /* ++ * For the KDump or FADump vmcore, use SP and IP values ++ * that are saved in ptregs. ++ */ ++ ret = ppc64_vmcore_stack_frame(bt_in, nip, ksp); ++ if (ret) ++ return TRUE; ++ } + + if (bt->task != tt->panic_task) { + char cpu_frozen = FALSE; +@@ -2385,38 +2467,14 @@ retry: + check_intrstack = FALSE; + goto retry; + } +- + /* +- * We didn't find what we were looking for, so try to use +- * the SP and IP values saved in ptregs. ++ * We didn't find what we were looking for, so just use what was ++ * passed in the ELF header. + */ +- pt_regs = (struct ppc64_pt_regs *)bt_in->machdep; +- if (!pt_regs || !pt_regs->gpr[1]) { +- /* +- * Not collected regs. May be the corresponding CPU did not +- * respond to an IPI. +- */ +- if (CRASHDEBUG(1)) +- fprintf(fp, "%0lx: GPR1(SP) register value not saved\n", +- bt_in->task); +- } else { +- *ksp = pt_regs->gpr[1]; +- if (IS_KVADDR(*ksp)) { +- readmem(*ksp+16, KVADDR, nip, sizeof(ulong), +- "Regs NIP value", FAULT_ON_ERROR); +- ppc64_print_regs(pt_regs); +- return TRUE; +- } else { +- if (IN_TASK_VMA(bt_in->task, *ksp)) +- fprintf(fp, "%0lx: Task is running in user space\n", +- bt_in->task); +- else +- fprintf(fp, "%0lx: Invalid Stack Pointer %0lx\n", +- bt_in->task, *ksp); +- *nip = pt_regs->nip; +- ppc64_print_regs(pt_regs); +- return FALSE; +- } ++ if (ur_nip && ur_ksp) { ++ *nip = ur_nip; ++ *ksp = ur_ksp; ++ return TRUE; + } + + console("ppc64_get_dumpfile_stack_frame: cannot find SP for panic task\n"); +commit 7e3936895386ea6e85a6dc01bc5027f8133d12bb +Author: Dave Anderson +Date: Mon Sep 17 14:33:08 2018 -0400 + + An addendum to crash commit 5fe78861ea1589084f6a2956a6ff63677c9269e1, + this patch for the PPC64 "bt" command prevents an invalid error + message from being displayed when an active non-panic task is + interrupted while running in user space. Without the patch, the + command correctly indicates "Task is running in user space", dumps + the user-space exception frame, but then prints the invalid error + message "bt: invalid kernel virtual address: ffffffffffffff90 type: + Regs NIP value". + (anderson@redhat.com) + +diff --git a/ppc64.c b/ppc64.c +index 03fecd3..8badcde 100644 +--- a/ppc64.c ++++ b/ppc64.c +@@ -2254,6 +2254,7 @@ ppc64_vmcore_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp) + { + struct ppc64_pt_regs *pt_regs; + unsigned long unip; ++ int in_user_space = FALSE; + + pt_regs = (struct ppc64_pt_regs *)bt_in->machdep; + if (!pt_regs || !pt_regs->gpr[1]) { +@@ -2272,10 +2273,11 @@ ppc64_vmcore_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp) + FAULT_ON_ERROR); + *nip = unip; + } else { +- if (IN_TASK_VMA(bt_in->task, *ksp)) ++ if (IN_TASK_VMA(bt_in->task, *ksp)) { + fprintf(fp, "%0lx: Task is running in user space\n", + bt_in->task); +- else ++ in_user_space = TRUE; ++ } else + fprintf(fp, "%0lx: Invalid Stack Pointer %0lx\n", + bt_in->task, *ksp); + *nip = pt_regs->nip; +@@ -2289,6 +2291,8 @@ ppc64_vmcore_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp) + * Print the collected regs for the active task + */ + ppc64_print_regs(pt_regs); ++ if (in_user_space) ++ return TRUE; + if (!IS_KVADDR(*ksp)) + return FALSE; + +commit 599a6579aa916df7800f8e889d68e4287e4520dd +Author: Dave Anderson +Date: Thu Sep 27 14:14:31 2018 -0400 + + With Linux 4.19-rc1 commit 7d4340bb92a9df78e6e28152f3dd89d9bd82146b, + titled "powerpc/mm: Increase MAX_PHYSMEM_BITS to 128TB with + SPARSEMEM_VMEMMAP config", the PPC64 MAX_PHYSMEM_BITS value has + been bumped up to 47. The appropriate update has been made in + this patch. + (hbathini@linux.ibm.com) + +diff --git a/defs.h b/defs.h +index 80c61ef..5b64bb7 100644 +--- a/defs.h ++++ b/defs.h +@@ -4054,6 +4054,7 @@ struct efi_memory_desc_t { + #define _SECTION_SIZE_BITS 24 + #define _MAX_PHYSMEM_BITS 44 + #define _MAX_PHYSMEM_BITS_3_7 46 ++#define _MAX_PHYSMEM_BITS_4_19 47 + + #endif /* PPC64 */ + +diff --git a/ppc64.c b/ppc64.c +index 8badcde..ee2f76f 100644 +--- a/ppc64.c ++++ b/ppc64.c +@@ -554,7 +554,10 @@ ppc64_init(int when) + ppc64_vmemmap_init(); + + machdep->section_size_bits = _SECTION_SIZE_BITS; +- if (THIS_KERNEL_VERSION >= LINUX(3,7,0)) ++ if ((machdep->flags & VMEMMAP) && ++ (THIS_KERNEL_VERSION >= LINUX(4,19,0))) ++ machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_4_19; ++ else if (THIS_KERNEL_VERSION >= LINUX(3,7,0)) + machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_3_7; + else + machdep->max_physmem_bits = _MAX_PHYSMEM_BITS; + + +commit 72cc0cba8a6cab14ca0961dff062d0384d307ce5 +Author: Dave Anderson +Date: Tue Oct 2 10:56:28 2018 -0400 + + Fix for the PPC64 "bt" command to recognize when a thread is running + in OPAL firmware. Without the patch, the "bt" command indicates + : Invalid Stack Pointer " + (hbathini@linux.ibm.com) + +--- a/defs.h ++++ b/defs.h +@@ -5934,6 +5934,12 @@ struct ppc64_elf_prstatus { + + #ifdef PPC64 + ++struct ppc64_opal { ++ uint64_t base; ++ uint64_t entry; ++ uint64_t size; ++}; ++ + struct ppc64_vmemmap { + unsigned long phys; + unsigned long virt; +@@ -5984,6 +5990,7 @@ struct machine_specific { + ulong _page_accessed; + int (*is_kvaddr)(ulong); + int (*is_vmaddr)(ulong); ++ struct ppc64_opal opal; + }; + + void ppc64_init(int); +@@ -6001,6 +6008,7 @@ void ppc64_dump_machdep_table(ulong); + * in the kernel is also 0x40. + */ + #define RADIX_MMU (0x40) ++#define OPAL_FW (0x80) + + #define REGION_SHIFT (60UL) + #define REGION_ID(addr) (((unsigned long)(addr)) >> REGION_SHIFT) +--- a/ppc64.c ++++ b/ppc64.c +@@ -65,8 +65,26 @@ static ulong hugepage_dir(ulong pte); + static ulong pgd_page_vaddr_l4(ulong pgd); + static ulong pud_page_vaddr_l4(ulong pud); + static ulong pmd_page_vaddr_l4(ulong pmd); ++static int is_opal_context(ulong sp, ulong nip); + void opalmsg(void); + ++static int is_opal_context(ulong sp, ulong nip) ++{ ++ uint64_t opal_start, opal_end; ++ ++ if (!(machdep->flags & OPAL_FW)) ++ return FALSE; ++ ++ opal_start = machdep->machspec->opal.base; ++ opal_end = opal_start + machdep->machspec->opal.size; ++ ++ if (((sp >= opal_start) && (sp < opal_end)) || ++ ((nip >= opal_start) && (nip < opal_end))) ++ return TRUE; ++ ++ return FALSE; ++} ++ + static inline int is_hugepage(ulong pte) + { + if ((machdep->flags & BOOK3E) || +@@ -241,6 +259,7 @@ struct machine_specific book3e_machine_s + .is_vmaddr = book3e_is_vmaddr, + }; + ++#define SKIBOOT_BASE 0x30000000 + + /* + * Do all necessary machine-specific setup here. This is called several +@@ -362,6 +381,16 @@ ppc64_init(int when) + struct machine_specific *m = machdep->machspec; + + /* ++ * To determine if the kernel was running on OPAL based platform, ++ * use struct opal, which is populated with relevant values. ++ */ ++ if (symbol_exists("opal")) { ++ get_symbol_data("opal", sizeof(struct ppc64_opal), &(m->opal)); ++ if (m->opal.base == SKIBOOT_BASE) ++ machdep->flags |= OPAL_FW; ++ } ++ ++ /* + * On Power ISA 3.0 based server processors, a kernel can + * run with radix MMU or standard MMU. Set the flag, + * if it is radix MMU. +@@ -712,6 +741,8 @@ ppc64_dump_machdep_table(ulong arg) + fprintf(fp, "%sSWAP_ENTRY_L4", others++ ? "|" : ""); + if (machdep->flags & RADIX_MMU) + fprintf(fp, "%sRADIX_MMU", others++ ? "|" : ""); ++ if (machdep->flags & OPAL_FW) ++ fprintf(fp, "%sOPAL_FW", others++ ? "|" : ""); + fprintf(fp, ")\n"); + + fprintf(fp, " kvbase: %lx\n", machdep->kvbase); +@@ -2257,7 +2288,11 @@ ppc64_vmcore_stack_frame(struct bt_info + { + struct ppc64_pt_regs *pt_regs; + unsigned long unip; +- int in_user_space = FALSE; ++ /* ++ * TRUE: task is running in a different context (userspace, OPAL..) ++ * FALSE: task is probably running in kernel space. ++ */ ++ int out_of_context = FALSE; + + pt_regs = (struct ppc64_pt_regs *)bt_in->machdep; + if (!pt_regs || !pt_regs->gpr[1]) { +@@ -2270,20 +2305,25 @@ ppc64_vmcore_stack_frame(struct bt_info + bt_in->task); + return FALSE; + } ++ + *ksp = pt_regs->gpr[1]; + if (IS_KVADDR(*ksp)) { + readmem(*ksp+16, KVADDR, &unip, sizeof(ulong), "Regs NIP value", + FAULT_ON_ERROR); + *nip = unip; + } else { ++ *nip = pt_regs->nip; + if (IN_TASK_VMA(bt_in->task, *ksp)) { + fprintf(fp, "%0lx: Task is running in user space\n", + bt_in->task); +- in_user_space = TRUE; ++ out_of_context = TRUE; ++ } else if (is_opal_context(*ksp, *nip)) { ++ fprintf(fp, "%0lx: Task is running in OPAL (firmware) context\n", ++ bt_in->task); ++ out_of_context = TRUE; + } else + fprintf(fp, "%0lx: Invalid Stack Pointer %0lx\n", + bt_in->task, *ksp); +- *nip = pt_regs->nip; + } + + if (bt_in->flags && +@@ -2294,7 +2334,8 @@ ppc64_vmcore_stack_frame(struct bt_info + * Print the collected regs for the active task + */ + ppc64_print_regs(pt_regs); +- if (in_user_space) ++ ++ if (out_of_context) + return TRUE; + if (!IS_KVADDR(*ksp)) + return FALSE; +@@ -2828,7 +2869,6 @@ ppc64_get_smp_cpus(void) + */ + #define SKIBOOT_CONSOLE_DUMP_START 0x31000000 + #define SKIBOOT_CONSOLE_DUMP_SIZE 0x100000 +-#define SKIBOOT_BASE 0x30000000 + #define ASCII_UNLIMITED ((ulong)(-1) >> 1) + + void +@@ -2841,10 +2881,6 @@ opalmsg(void) + uint64_t u64; + uint64_t limit64; + }; +- struct opal { +- unsigned long long base; +- unsigned long long entry; +- } opal; + int i, a; + size_t typesz; + void *location; +@@ -2856,25 +2892,13 @@ opalmsg(void) + long count = SKIBOOT_CONSOLE_DUMP_SIZE; + ulonglong addr = SKIBOOT_CONSOLE_DUMP_START; + ++ if (!(machdep->flags & OPAL_FW)) ++ error(FATAL, "dump was not captured on OPAL based system"); ++ + if (CRASHDEBUG(4)) + fprintf(fp, "\n", + addr, count, "PHYSADDR"); + +- /* +- * OPAL based platform check +- * struct opal of BSS section and hence default value will be ZERO(0) +- * opal_init() in the kernel initializes this structure based on +- * the platform. Use it as a key to determine whether the dump +- * was taken on an OPAL based system or not. +- */ +- if (symbol_exists("opal")) { +- get_symbol_data("opal", sizeof(struct opal), &opal); +- if (opal.base != SKIBOOT_BASE) +- error(FATAL, "dump was captured on non-PowerNV machine"); +- } else { +- error(FATAL, "dump was captured on non-PowerNV machine"); +- } +- + BZERO(&mem, sizeof(struct memloc)); + lost = typesz = per_line = 0; + location = NULL; diff --git a/SOURCES/lzo_snappy.patch b/SOURCES/lzo_snappy.patch new file mode 100644 index 0000000..61af0cc --- /dev/null +++ b/SOURCES/lzo_snappy.patch @@ -0,0 +1,22 @@ +--- crash-7.1.5/diskdump.c.orig ++++ crash-7.1.5/diskdump.c +@@ -23,6 +23,8 @@ + * GNU General Public License for more details. + */ + ++#define LZO ++#define SNAPPY + #include "defs.h" + #include "diskdump.h" + #include "xen_dom0.h" +--- crash-7.1.5/Makefile.orig ++++ crash-7.1.5/Makefile +@@ -228,7 +228,7 @@ all: make_configure + gdb_merge: force + @if [ ! -f ${GDB}/README ]; then \ + make --no-print-directory gdb_unzip; fi +- @echo "${LDFLAGS} -lz -ldl -rdynamic" > ${GDB}/gdb/mergelibs ++ @echo "${LDFLAGS} -lz -llzo2 -lsnappy -ldl -rdynamic" > ${GDB}/gdb/mergelibs + @echo "../../${PROGRAM} ../../${PROGRAM}lib.a" > ${GDB}/gdb/mergeobj + @rm -f ${PROGRAM} + @if [ ! -f ${GDB}/config.status ]; then \ diff --git a/SOURCES/rhel8_build.patch b/SOURCES/rhel8_build.patch new file mode 100644 index 0000000..33bdb99 --- /dev/null +++ b/SOURCES/rhel8_build.patch @@ -0,0 +1,32 @@ +--- crash-7.2.3/Makefile.orig ++++ crash-7.2.3/Makefile +@@ -198,7 +198,7 @@ GDB_FLAGS= + # TARGET_CFLAGS will be configured automatically by configure + TARGET_CFLAGS= + +-CRASH_CFLAGS=-g -D${TARGET} ${TARGET_CFLAGS} ${GDB_FLAGS} ${CFLAGS} ++CRASH_CFLAGS=-g -D${TARGET} ${TARGET_CFLAGS} ${GDB_FLAGS} ${CFLAGS} ${CPPFLAGS} -fPIE + + GPL_FILES=COPYING3 + TAR_FILES=${SOURCE_FILES} Makefile ${GPL_FILES} README .rh_rpm_package crash.8 \ +@@ -228,7 +228,7 @@ all: make_configure + gdb_merge: force + @if [ ! -f ${GDB}/README ]; then \ + make --no-print-directory gdb_unzip; fi +- @echo "${LDFLAGS} -lz -llzo2 -lsnappy -ldl -rdynamic" > ${GDB}/gdb/mergelibs ++ @echo "${LDFLAGS} -lz -llzo2 -lsnappy -ldl -rdynamic -Wl,-z,now -fpie" > ${GDB}/gdb/mergelibs + @echo "../../${PROGRAM} ../../${PROGRAM}lib.a" > ${GDB}/gdb/mergeobj + @rm -f ${PROGRAM} + @if [ ! -f ${GDB}/config.status ]; then \ +--- crash-7.2.3/configure.c.orig ++++ crash-7.2.3/configure.c +@@ -780,7 +780,8 @@ build_configure(struct supported_gdb_ver + fprintf(fp2, "%s\n", sp->GDB); + sprintf(target_data.gdb_version, "%s", &sp->GDB[4]); + } else if (strncmp(buf, "LDFLAGS=", strlen("LDFLAGS=")) == 0) { +- fprintf(fp2, "LDFLAGS=%s\n", ldflags ? ldflags : ""); ++ if (ldflags) ++ fprintf(fp2, "LDFLAGS=%s\n", ldflags ? ldflags : ""); + } else + fprintf(fp2, "%s", buf); + diff --git a/SOURCES/rhel8_ppc64_max_physmem_bits.patch b/SOURCES/rhel8_ppc64_max_physmem_bits.patch new file mode 100644 index 0000000..28cd4cf --- /dev/null +++ b/SOURCES/rhel8_ppc64_max_physmem_bits.patch @@ -0,0 +1,15 @@ +--- crash-7.2.3/ppc64.c.orig ++++ crash-7.2.3/ppc64.c +@@ -583,8 +583,11 @@ ppc64_init(int when) + ppc64_vmemmap_init(); + + machdep->section_size_bits = _SECTION_SIZE_BITS; ++ ++#define is_RHEL8() (strstr(kt->proc_version, ".el8.")) ++ + if ((machdep->flags & VMEMMAP) && +- (THIS_KERNEL_VERSION >= LINUX(4,19,0))) ++ ((THIS_KERNEL_VERSION >= LINUX(4,19,0)) || is_RHEL8())) + machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_4_19; + else if (THIS_KERNEL_VERSION >= LINUX(3,7,0)) + machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_3_7; diff --git a/SPECS/crash.spec b/SPECS/crash.spec new file mode 100644 index 0000000..8a25125 --- /dev/null +++ b/SPECS/crash.spec @@ -0,0 +1,617 @@ +# +# crash core analysis suite +# +Summary: Kernel analysis utility for live systems, netdump, diskdump, kdump, LKCD or mcore dumpfiles +Name: crash +Version: 7.2.3 +Release: 18%{?dist} +License: GPLv3 +Group: Development/Debuggers +Source: http://people.redhat.com/anderson/crash-%{version}.tar.gz +URL: http://people.redhat.com/anderson +ExclusiveOS: Linux +ExclusiveArch: %{ix86} ia64 x86_64 ppc ppc64 s390 s390x %{arm} aarch64 ppc64le +Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n) +BuildRequires: ncurses-devel zlib-devel lzo-devel bison snappy-devel +Requires: binutils +Patch0: lzo_snappy.patch +Patch1: github_46d21219_to_9446958f.patch +Patch2: github_95daa11b.patch +Patch3: github_b9d76838_c79a11fa_proc_kcore.patch +Patch4: github_1926150e_ppc64_stacksize.patch +Patch5: github_28fa7bd0_to_02efd083.patch +Patch6: github_9b494b70_to_eb823b79.patch +Patch7: github_a10917ba_to_e9532aea.patch +Patch8: rhel8_build.patch +Patch9: github_ppc64_5fe78861_7e393689_599a6579_72cc0cba.patch +Patch10: github_3141bba9.patch +Patch11: github_c5f45d6c.patch +Patch12: github_f3a53059.patch +Patch13: github_64dad6d0.patch +Patch14: rhel8_ppc64_max_physmem_bits.patch +Patch15: github_27a6ebd0_dev-p.patch +Patch16: github_ced52552_dev-p_offsets.patch +Patch17: github_361f050e_dev-d.patch +Patch18: github_0f65ae0c_readline.patch +Patch19: github_6b93714b_cmdline.patch +Patch20: github_8618ddd8_CONFIG_ARM64_USER_VA_BITS_52 +Patch21: github_ac5a7889_CONFIG_ARM64_PA_BITS.patch +Patch22: github_a89ec821_vmcoreinfo_plugin.patch +Patch23: github_2f57a96c_files-c-p.patch + +%description +The core analysis suite is a self-contained tool that can be used to +investigate either live systems, kernel core dumps created from the +netdump, diskdump and kdump packages from Red Hat Linux, the mcore kernel patch +offered by Mission Critical Linux, or the LKCD kernel patch. + +%package devel +Requires: %{name} = %{version}, zlib-devel lzo-devel snappy-devel +Summary: kernel crash analysis utility for live systems, netdump, diskdump, kdump, LKCD or mcore dumpfiles +Group: Development/Debuggers + +%description devel +The core analysis suite is a self-contained tool that can be used to +investigate either live systems, kernel core dumps created from the +netdump, diskdump and kdump packages from Red Hat Linux, the mcore kernel patch +offered by Mission Critical Linux, or the LKCD kernel patch. + +%prep +%setup -n %{name}-%{version} -q +%patch0 -p1 -b lzo_snappy.patch +%patch1 -p1 -b github_46d21219_to_9446958f.patch +%patch2 -p1 -b github_95daa11b.patch +%patch3 -p1 -b github_b9d76838_c79a11fa_proc_kcore.patch +%patch4 -p1 -b github_1926150e_ppc64_stacksize.patch +%patch5 -p1 -b github_28fa7bd0_to_02efd083.patch +%patch6 -p1 -b github_9b494b70_to_eb823b79.patch +%patch7 -p1 -b github_a10917ba_to_e9532aea.patch +%patch8 -p1 -b rhel8_build.patch +%patch9 -p1 -b github_ppc64_5fe78861_7e393689_599a6579_72cc0cba.patch +%patch10 -p1 -b github_3141bba9.patch +%patch11 -p1 -b github_c5f45d6c.patch +%patch12 -p1 -b github_f3a53059.patch +%patch13 -p1 -b github_64dad6d0.patch +%patch14 -p1 -b rhel8_ppc64_max_physmem_bits.patch +%patch15 -p1 -b github_27a6ebd0_dev-p.patch +%patch16 -p1 -b github_ced52552_dev-p_offsets.patch +%patch17 -p1 -b github_361f050e_dev-d.patch +%patch18 -p1 -b github_0f65ae0c_readline.patch +%patch19 -p1 -b github_6b93714b_cmdline.patch +%patch20 -p1 -b github_8618ddd8_CONFIG_ARM64_USER_VA_BITS_52 +%patch21 -p1 -b github_ac5a7889_CONFIG_ARM64_PA_BITS.patch +%patch22 -p1 -b github_a89ec821_vmcoreinfo_plugin.patch +%patch23 -p1 -b github_2f57a96c_files-c-p.patch + +%build +make RPMPKG="%{version}-%{release}" CFLAGS="%{optflags}" + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot}%{_bindir} +make DESTDIR=%{buildroot} install +mkdir -p %{buildroot}%{_mandir}/man8 +cp -p crash.8 %{buildroot}%{_mandir}/man8/crash.8 +mkdir -p %{buildroot}%{_includedir}/crash +chmod 0644 defs.h +cp -p defs.h %{buildroot}%{_includedir}/crash + +%clean +rm -rf %{buildroot} + +%files +%defattr(-,root,root,-) +%{_bindir}/crash +%{_mandir}/man8/crash.8* +%doc README COPYING3 + +%files devel +%defattr(-,root,root,-) +%{_includedir}/* + +%changelog +* Thu Feb 14 2019 Dave Anderson - 7.2.3-18 +- Fix "files -c" and "files -p" options + Resolves: rhbz#1673285 + +* Mon Feb 11 2019 Dave Anderson - 7.2.3-17 +- Support for CONFIG_ARM64_USER_VA_BITS_52 and CONFIG_ARM64_PA_BITS=52 + Resolves: rhbz#1670099 + +* Tue Jan 8 2019 Dave Anderson - 7.2.3-16 +- Resurrect "dev -p" option. +- Fix "dev -[dD]" options to account for request_queue.in_flight[] removal. + Resolves: rhbz#1662039 +- Command line input fixes + Resolves: rhbz#1664061 + +* Thu Dec 13 2018 Dave Anderson - 7.2.3-15 +- Increase ppc64 MAX_PHYSMEM_BITS to match 4.18.0-35.el8 kernel backport + Resolves: rhbz#1658628 + +* Thu Nov 29 2018 Dave Anderson - 7.2.3-14 +- Fix for ARM64 "ps -s" memory allocation failure + Resolves: rhbz#1654582 + +* Thu Oct 25 2018 Dave Anderson - 7.2.3-13 +- Change "bt" warnings when exception RIP is legitimate mapped address + Resolves: rhbz#1642221 + +* Mon Oct 15 2018 Dave Anderson - 7.2.3-12 +- Address covscan issues + Resolves: rhbz#1602466 +- Fix for x86_64 5-level pagetable vmalloc range expansion + Resolves: rhbz#1637125 + +* Wed Oct 4 2018 Dave Anderson - 7.2.3-11 +- Fix ppc64 backtrace issues + Resolves: rhbz#1633525 + +* Wed Sep 19 2018 Dave Anderson - 7.2.3-10 +- Address annocheck build issues + Resolves: rhbz#1624101 + +* Thu Aug 9 2018 Dave Anderson - 7.2.3-9 +- Fix for live system (/proc/kcore) access when KALSR is in effect + Resolves: rhbz#1611916 + +* Mon Jul 16 2018 Dave Anderson - 7.2.3-8 +- Rebase to github commits 9b494b70_to_eb823b79 + Resolves: rhbz#1563495 + +* Fri Jun 22 2018 Dave Anderson - 7.2.3-7 +- Rebase to github commits 28fa7bd0 to 02efd083 + Resolves: rhbz#1590751 + Resolves: rhbz#1592746 + +* Tue Jun 12 2018 Dave Anderson - 7.2.3-6 +- github commit 1926150e: fix ppc64/ppc6le stacksize calculation + +* Fri Jun 8 2018 Dave Anderson - 7.2.3-5 +- Remove /dev/mem readmem error message and /proc/kcore switch messages + Resolves: rhbz#1585944 + +* Fri Jun 1 2018 Dave Anderson - 7.2.3-4 +- Rebase to latest upstream sources + +* Tue Nov 21 2017 Dave Anderson - 7.2.0-2 +- Rebase to github commits da9bd35a to e2efacdd + Resolves: rhbz#1497316 + +* Wed Nov 1 2017 Dave Anderson - 7.2.0-1 +- Rebase to upstream version 7.2.0 +- Rebase to github commits da9bd35a_to_e2efacdd.patch + Resolves: rhbz#1497316 +- ppc64le: fix for "WARNING: cannot access vmalloc'd module memory" + Resolves: rhbz#1485391 +- Support for analyzing an SADUMP crash dump if KASLR is enabled + Resolves: rhbz#1504467 + +* Wed May 3 2017 Dave Anderson - 7.1.9-2 +- Rebase to github commits 87179026 to ad3b8476 + Resolves: rhbz#1393534 +- Prohibit native gdb disassemble command when KASLR + Resolves: rhbz#1445649 + +* Mon Apr 24 2017 Dave Anderson - 7.1.9-1 +- Rebase to upstream version 7.1.9 + Resolves: rhbz#1393534 +- Fix gdb "set scope" option for KASLR kernels. + Resolves: rhbz#1440725 +- Fix for the determination of the x86_64 "phys_base" value when it is + not passed in the VMCOREINFO data of ELF vmcores + Resolves: rhbz#1439170 + +* Wed Mar 8 2017 Dave Anderson - 7.1.8-2 +- mod [-sS] command may erroneously reassign module symbol addresses + Resolves: rhbz#1430091 + +* Fri Feb 24 2017 Dave Anderson - 7.1.8-1 +- Rebase to upstream version 7.1.8 + Resolves: rhbz#1393534 +- POWER9 - Power ISA 3.0 related support for crash utility + Resolves: rhbz#1368711 +- crash package update - ppc64/ppc64le + Resolves: rhbz#1384944 +- exception RIP: unknown or invalid address + Resolves: rhbz#1350457 +- Crash does not always parse correctly the modules symbol tables + Resolves: rhbz#1360415 +- ARM64: crash live system from: WARNING: cannot read linux_banner string + Resolves: rhbz#1392007 +- kmem: invalid structure member offset: page_count + Resolves: rhbz#1392011 +- Kernel address space randomization [KASLR] support + Resolves: rhbz#1392658 +- invalid structure size: tnt + Resolves: rhbz#1420653 + +* Wed Sep 14 2016 Dave Anderson - 7.1.5-2 +- Fix for kernel module symbol gathering when the ordering of module + symbol name strings does not match the order of the kernel_symbol + structures. +- Resolves: rhbz#1375130 + +* Thu Apr 28 2016 Dave Anderson - 7.1.5-1 +- Rebase to upstream version 7.1.5 + Resolves: rhbz#1292566 +- Decode clflushopt instruction + Resolves: rhbz#1262479 +- Support AArch64 QEMU generated dumps + Resolves: rhbz#1299873 +- crash: zero-size memory allocation (aarch64) + Resolves: rhbz#1312738 + +* Tue Apr 5 2016 Dave Anderson - 7.1.2-4 +- crash: fails to read excluded pages by default on sadump-related format + Resolves: rhbz#1304260 + +* Mon Nov 23 2015 Dave Anderson - 7.1.2-3 +- crash fails to read or wrongly reads some parts of memory in sadump vmcore format + Resolves: rhbz#1282997 + +* Tue Aug 4 2015 Dave Anderson - 7.1.2-2 +- Fix "kmem -s
", "bt -F[F]", and "rd -S[S]" options in kernels + configured with CONFIG_SLUB having multiple-page slabs. + Resolves: rhbz#1244003 +- Fix for SIGSEGV generated by "bt -[f|F]" in ARM64 kernels. + Resolves: rhbz#1248859 + +* Mon Jul 13 2015 Dave Anderson - 7.1.2-1 +- Rebase to upstream version 7.1.2 + Resolves: rhbz#1207696 +- Fix several ppc64 backtrace issues + Resolves: rhbz#1235447 + +* Fri Jun 05 2015 Dave Anderson - 7.1.1-2 +- ARM64 backtrace enhancements + Resolves: rhbz#1227508 + +* Thu May 28 2015 Dave Anderson - 7.1.1-1 +- Rebase to upstream version 7.1.1 + Resolves: rhbz#1207696 +- Display s390x vector registers from a kernel dump. + Resolves: rhbz#1182161 +- Fix date displayed on initial system banner and by the "sys" command on ARM64. + Resolves: rhbz#1223044 +- Fix ARM64 page size calculation on 4.1 and later kernels. + Resolves: rhbz#1222645 + +* Tue Apr 21 2015 Dave Anderson - 7.0.9-6 +- Calculate ARM64 virtual memory layout based upon struct page size + Resolves: rhbz#1204941 + +* Tue Apr 7 2015 Dave Anderson - 7.0.9-5 +- Support new sadump format that can represent more than 16 TB physical memory space + Resolves: rhbz#1182383 + +* Mon Jan 26 2015 Dave Anderson - 7.0.9-4 + Fix ppc64 "bt" command for active tasks in compressed kdumps. + Resolves: rhbz#1184401 + +* Mon Jan 12 2015 Dave Anderson - 7.0.9-3 + Fix "bt" command mislabeling errors. + Resolves: rhbz#1179476 + +* Mon Dec 08 2014 Dave Anderson - 7.0.9-2 +- Use registers from QEMU-generated ELF and compressed kdump headers + for active task backtraces. +- Resolves: rhbz#1169555 + +* Fri Nov 14 2014 Dave Anderson - 7.0.9-1 +- Rebase to upstream version 7.0.9. +- Resolves: rhbz#1110513 + +* Tue Sep 23 2014 Dave Anderson - 7.0.8-2 +- Fix ps performance patch regression on live systems. +- Resolves: rhbz#1134177 +- Minor build-related fixes for ppc64le. +- Resolves: rhbz#1123991 + +* Fri Sep 12 2014 Dave Anderson - 7.0.8-1 +- Rebase to upstream version 7.0.8. +- Resolves: rhbz#1110513 +- Fix to calculate the physical base address of dumpfiles created + by a "virsh dump" of an OVMF guest. +- Resolves: rhbz#1080698 +- Support for aarch64 architecture. +- Resolves: rhbz#1110551 +- Fix to prevent crash from spinning endlessly on a corrupted/truncated + dumpfile whose bitmap data is not wholly contained within the file. +- Resolves: rhbz#1114088 +- Support for ppc64le architecture. +- Resolves: rhbz#1123991 + +* Tue Jan 28 2014 Daniel Mach - 7.0.2-6 +- Mass rebuild 2014-01-24 + +* Fri Jan 24 2014 Dave Anderson - 7.0.2-5 +- Fix for a missing kernel-mode exception frame dump by the x86_64 + "bt" command if a page fault was generated by a bogus RIP. +- Resolves: rhbz#1057353 +- Fix for the x86_64 "bt" command to prevent an unwarranted message + indicating "WARNING: possibly bogus exception frame" generated + from a blocked kernel thread that was in the process of exec'ing + a user process via the call_usermodehelper() facility. +- Resolves: rhbz#1057357 + +* Fri Jan 10 2014 Dave Anderson - 7.0.2-4 +- Fixes for "kmem -S" command for CONFIG_SLUB. +- Resolves: rhbz#1045591 +- Increase S390X NR_CPUS +- Resolves: rhbz#1051156 + +* Fri Dec 27 2013 Daniel Mach - 7.0.2-3 +- Mass rebuild 2013-12-27 + +* Tue Oct 29 2013 Dave Anderson - 7.0.2-2 +- Compressed kdump 46-bit physical memory support + Resolves: rhbz#1015250 +- Fix incorrect backtrace for dumps taken with "virsh dump --memory-only" + Resolves: rhbz#1020469 +- Fix cpu number display on systems with more than 254 cpus + Resolves: rhbz#1020536 + +* Wed Sep 04 2013 Dave Anderson - 7.0.2-1 +- Update to latest upstream release +- Fix for ppc64 embedded gdb NULL pointer translation sigsegv +- Fix for bt -F failure + +* Fri Jul 26 2013 Dave Anderson - 7.0.1-4 +- Add lzo-devel and snappy-devel to crash-devel Requires line + +* Tue Jul 23 2013 Dave Anderson - 7.0.1-3 +- Build with snappy compression support + +* Tue Jul 9 2013 Dave Anderson - 7.0.1-2 +- Fix for ppc64 Linux 3.10 vmalloc/user-space virtual address translation + +* Tue Jun 18 2013 Dave Anderson - 7.0.1-1 +- Update to latest upstream release +- Build with LZO support + +* Tue Apr 9 2013 Dave Anderson - 6.1.6-1 +- Update to latest upstream release + +* Tue Feb 19 2013 Dave Anderson - 6.1.4-1 +- Update to latest upstream release + +* Wed Feb 13 2013 Fedora Release Engineering - 6.1.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Wed Jan 9 2013 Dave Anderson - 6.1.2-1 +- Update to latest upstream release + +* Tue Nov 27 2012 Dave Anderson - 6.1.1-1 +- Update to latest upstream release + +* Mon Sep 1 2012 Dave Anderson - 6.1.0-1 +- Add ppc to ExclusiveArch list +- Update to latest upstream release + +* Tue Aug 21 2012 Dave Anderson - 6.0.9-1 +- Update to latest upstream release + +* Wed Jul 18 2012 Fedora Release Engineering - 6.0.8-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Mon Jul 1 2012 Dave Anderson - 6.0.8-1 +- Update to latest upstream release. +- Replace usage of "struct siginfo" with "siginfo_t". + +* Mon Apr 30 2012 Dave Anderson - 6.0.6-1 +- Update to latest upstream release + +* Mon Mar 26 2012 Dave Anderson - 6.0.5-1 +- Update to latest upstream release + +* Wed Jan 4 2012 Dave Anderson - 6.0.2-1 +- Update to latest upstream release + +* Wed Oct 26 2011 Dave Anderson - 6.0.0-1 +- Update to latest upstream release + +* Tue Sep 20 2011 Dave Anderson - 5.1.8-1 +- Update to latest upstream release +- Additional fixes for gcc-4.6 -Werror compile failures for ARM architecture. + +* Thu Sep 1 2011 Dave Anderson - 5.1.7-2 +- Fixes for gcc-4.6 -Werror compile failures for ARM architecture. + +* Wed Aug 17 2011 Dave Anderson - 5.1.7-1 +- Update to latest upstream release +- Fixes for gcc-4.6 -Werror compile failures for ppc64/ppc. + +* Tue May 31 2011 Peter Robinson - 5.1.5-1 +- Update to latest upstream release +- Add ARM to the Exclusive arch + +* Wed Feb 25 2011 Dave Anderson - 5.1.2-2 +- Fixes for gcc-4.6 -Werror compile failures in gdb module. + +* Wed Feb 23 2011 Dave Anderson - 5.1.2-1 +- Upstream version. + +* Tue Feb 08 2011 Fedora Release Engineering - 5.0.6-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Tue Jul 20 2010 Dave Anderson - 5.0.6-2 +- Bump version. + +* Tue Jul 20 2010 Dave Anderson - 5.0.6-1 +- Update to upstream version. + +* Fri Sep 11 2009 Dave Anderson - 4.0.9-2 + Bump version. + +* Fri Sep 11 2009 Dave Anderson - 4.0.9-1 +- Update to upstream release, which allows the removal of the + Revision tag workaround, the crash-4.0-8.11-dwarf3.patch and + the crash-4.0-8.11-optflags.patch + +* Sun Aug 05 2009 Lubomir Rintel - 4.0.8.11-2 +- Fix reading of dwarf 3 DW_AT_data_member_location +- Use proper compiler flags + +* Wed Aug 05 2009 Lubomir Rintel - 4.0.8.11-1 +- Update to later upstream release +- Fix abuse of Revision tag + +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild +* Fri Jul 24 2009 Fedora Release Engineering - 4.0-9.7.2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Tue Feb 24 2009 Fedora Release Engineering - 4.0-8.7.2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Thu Feb 19 2009 Dave Anderson - 4.0-7.7.2 +- Replace exclusive arch i386 with ix86. + +* Thu Feb 19 2009 Dave Anderson - 4.0-7.7.1 +- Updates to this file per crash merge review +- Update to upstream version 4.0-7.7. Full changelog viewable in: + http://people.redhat.com/anderson/crash.changelog.html + +* Tue Jul 15 2008 Tom "spot" Callaway 4.0-7 +- fix license tag + +* Tue Apr 29 2008 Dave Anderson - 4.0-6.3 +- Added crash-devel subpackage +- Updated crash.patch to match upstream version 4.0-6.3 + +* Wed Feb 20 2008 Dave Anderson - 4.0-6.0.5 +- Second attempt at addressing the GCC 4.3 build, which failed due + to additional ptrace.h includes in the lkcd vmdump header files. + +* Wed Feb 20 2008 Dave Anderson - 4.0-6.0.4 +- First attempt at addressing the GCC 4.3 build, which failed on x86_64 + because ptrace-abi.h (included by ptrace.h) uses the "u32" typedef, + which relies on , and include/asm-x86_64/types.h + does not not typedef u32 as done in include/asm-x86/types.h. + +* Mon Feb 18 2008 Fedora Release Engineering - 4.0-6.0.3 +- Autorebuild for GCC 4.3 + +* Wed Jan 23 2008 Dave Anderson - 4.0-5.0.3 +- Updated crash.patch to match upstream version 4.0-5.0. + +* 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 + +* Mon Aug 7 2006 Dave Anderson - 4.0-3.1 +- Updated crash.patch to match upstream version 4.0-3.1. +- Added kdump reference to description. +- Added s390 and s390x to ExclusiveArch list. BZ #199125 +- Removed LKCD v1 pt_regs references for s390/s390x build. +- Removed LKCD v2_v3 pt_regs references for for s390/s390x build. + +* Fri Jul 14 2006 Jesse Keating - 4.0-3 +- rebuild + +* Mon May 15 2006 Dave Anderson - 4.0-2.26.4 +- Updated crash.patch such that is not #include'd + by s390_dump.c; IBM did not make the file s390[s] only; BZ #192719 + +* Mon May 15 2006 Dave Anderson - 4.0-2.26.3 +- Updated crash.patch such that is not #include'd + by vas_crash.h; only ia64 build complained; BZ #191719 + +* Mon May 15 2006 Dave Anderson - 4.0-2.26.2 +- Updated crash.patch such that is not #include'd + by lkcd_x86_trace.c; also for BZ #191719 + +* Mon May 15 2006 Dave Anderson - 4.0-2.26.1 +- Updated crash.patch to bring it up to 4.0-2.26, which should + address BZ #191719 - "crash fails to build in mock" + +* Tue Feb 07 2006 Jesse Keating - 4.0-2.18.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Wed Jan 04 2006 Dave Anderson 4.0-2.18 +- Updated source package to crash-4.0.tar.gz, and crash.patch + to bring it up to 4.0-2.18. + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Thu Mar 03 2005 Dave Anderson 3.10-13 +- Compiler error- and warning-related fixes for gcc 4 build. +- Update to enhance x86 and x86_64 gdb disassembly output so as to + symbolically display call targets from kernel module text without + requiring module debuginfo data. +- Fix hole where an ia64 vmcore could be mistakenly accepted as a + usable dumpfile on an x86_64 machine, leading eventually to a + non-related error message. +* Wed Mar 02 2005 Dave Anderson 3.10-12 +- rebuild (gcc 4) +* Thu Feb 10 2005 Dave Anderson 3.10-9 +- Updated source package to crash-3.10.tar.gz, containing + IBM's final ppc64 processor support for RHEL4 +- Fixes potential "bt -a" hang on dumpfile where netdump IPI interrupted + an x86 process while executing the instructions just after it had entered + the kernel for a syscall, but before calling the handler. BZ #139437 +- Update to handle backtraces in dumpfiles generated on IA64 with the + INIT switch (functionality intro'd in RHEL3-U5 kernel). BZ #139429 +- Fix for handling ia64 and x86_64 machines booted with maxcpus=1 on + an SMP kernel. BZ #139435 +- Update to handle backtraces in dumpfiles generated on x86_64 from the + NMI exception stack (functionality intro'd in RHEL3-U5 kernel). +- "kmem -[sS]" beefed up to more accurately verify slab cache chains + and report errors found. +- Fix for ia64 INIT switch-generated backtrace handling when + init_handler_platform() is inlined into ia64_init_handler(); + properly handles both RHEL3 and RHEL4 kernel patches. + BZ #138350 +- Update to enhance ia64 gdb disassembly output so as to + symbolically display call targets from kernel module + text without requiring module debuginfo data. + +* Wed Jul 14 2004 Dave Anderson 3.8-5 +- bump release for fc3 + +* Tue Jul 13 2004 Dave Anderson 3.8-4 +- Fix for gcc 3.4.x/gdb issue where vmlinux was mistakenly presumed non-debug + +* Fri Jun 25 2004 Dave Anderson 3.8-3 +- remove (harmless) error message during ia64 diskdump invocation when + an SMP system gets booted with maxcpus=1 +- several 2.6 kernel specific updates + +* Thu Jun 17 2004 Dave Anderson 3.8-2 +- updated source package to crash-3.8.tar.gz +- diskdump support +- x86_64 processor support + +* Mon Sep 22 2003 Dave Anderson 3.7-5 +- make bt recovery code start fix-up only upon reaching first faulting frame + +* Fri Sep 19 2003 Dave Anderson 3.7-4 +- fix "bt -e" and bt recovery code to recognize new __KERNEL_CS and DS + +* Wed Sep 10 2003 Dave Anderson 3.7-3 +- patch to recognize per-cpu GDT changes that redefine __KERNEL_CS and DS + +* Wed Sep 10 2003 Dave Anderson 3.7-2 +- patches for netdump active_set determination and slab info gathering + +* Wed Aug 20 2003 Dave Anderson 3.7-1 +- updated source package to crash-3.7.tar.gz + +* Wed Jul 23 2003 Dave Anderson 3.6-1 +- removed Packager, Distribution, and Vendor tags +- updated source package to crash-3.6.tar.gz + +* Fri Jul 18 2003 Jay Fenlason 3.5-2 +- remove ppc from arch list, since it doesn't work with ppc64 kernels +- remove alpha from the arch list since we don't build it any more + +* Fri Jul 18 2003 Matt Wilson 3.5-1 +- use %%defattr(-,root,root) + +* Tue Jul 15 2003 Jay Fenlason +- Updated spec file as first step in turning this into a real RPM for taroon. +- Wrote man page.