diff --git a/crash.spec b/crash.spec index bc6766cf24d994532386678ba2bca501bf9b31d5..593b14ce8e3fc800f522f60000d0b4cd0dc4d3e2 100644 --- a/crash.spec +++ b/crash.spec @@ -5,7 +5,7 @@ Summary: Linux kernel crash utility. License: GPLv3 URL: https://crash-utility.github.io Source0: https://github.com/crash-utility/crash/archive/%{version}.tar.gz -Source1: http://ftp.gnu.org/gnu/gdb/gdb-7.6.tar.gz +Source1: http://ftp.gnu.org/gnu/gdb/gdb-10.2.tar.gz Patch1: lzo_snappy.patch Patch2: 0001-arm64-rename-ARM64_PAGE_OFFSET_ACTUAL-to-ARM64_FLIP_.patch @@ -23,12 +23,13 @@ Patch11: Fix-live-debugging-with-lockdown-integrity.patch Patch12: arm64-fix-backtraces-of-KASAN-kernel-dumpfile-truncated.patch Patch13: 0001-arm64-Fix-segfault-by-bt-command-with-offline-cpus.patch Patch14: arm64-Use-VA_BITS-for-page_offset-calculation.patch +Patch15: update-internal-gdb-to-10.2.patch BuildRequires: ncurses-devel zlib-devel lzo-devel snappy-devel -BuildRequires: gcc gcc-c++ bison m4 +BuildRequires: gcc gcc-c++ bison m4 texinfo libzstd-devel Requires: binutils -Provides: bundled(libiberty) bundled(gdb) = 7.6 +Provides: bundled(libiberty) bundled(gdb) = 10.2 %description The core analysis suite is a self-contained tool that can be used to @@ -88,6 +89,9 @@ install -D -m 0644 defs.h %{buildroot}%{_includedir}/%{name}/defs.h %{_mandir}/man8/crash.8* %changelog +* Fri Jul 7 2023 wangqiang - 7.3.0-12 +- Update internal gdb version to 10.2 + * Mon Jul 17 2023 chenhaixiang - 7.3.0-11 - arm64: Use VA_BITS for page_offset calculation diff --git a/gdb-7.6.tar.gz b/gdb-10.2.tar.gz similarity index 65% rename from gdb-7.6.tar.gz rename to gdb-10.2.tar.gz index 8325f090e2cac664b737b41635c31616643bf466..dfe4b7d83e0f7f0894de0e961490ff600d84e2b5 100644 Binary files a/gdb-7.6.tar.gz and b/gdb-10.2.tar.gz differ diff --git a/update-internal-gdb-to-10.2.patch b/update-internal-gdb-to-10.2.patch new file mode 100644 index 0000000000000000000000000000000000000000..ae526d21d51cf161fede855b0f6ee5fa3ea49823 --- /dev/null +++ b/update-internal-gdb-to-10.2.patch @@ -0,0 +1,93048 @@ +diff -Nur crash-7.3.0-orig/alpha.c crash-7.3.0/alpha.c +--- crash-7.3.0-orig/alpha.c 2023-07-07 14:06:14.163365900 +0800 ++++ crash-7.3.0/alpha.c 2023-07-07 14:08:21.983028121 +0800 +@@ -776,12 +776,8 @@ + * Don't go any farther than "stq ra,0(sp)" (0xb75e0000) + */ + while (ival != 0xb75e0000) { +- if (!text_value_cache((ulong)ip, 0, &ival)) { +- readmem((ulong)ip, KVADDR, &ival, +- sizeof(uint), "uncached text value", +- FAULT_ON_ERROR); +- text_value_cache((ulong)ip, ival, NULL); +- } ++ readmem((ulong)ip, KVADDR, &ival, sizeof(uint), ++ "text value", FAULT_ON_ERROR); + + if ((ival & 0xffe01fff) == 0x43c0153e) { + value = (ival & 0x1fe000) >> 13; +diff -Nur crash-7.3.0-orig/arm64.c crash-7.3.0/arm64.c +--- crash-7.3.0-orig/arm64.c 2023-07-07 14:06:14.177365972 +0800 ++++ crash-7.3.0/arm64.c 2023-07-07 14:08:21.987028142 +0800 +@@ -3877,14 +3877,48 @@ + { + struct machine_specific *ms = machdep->machspec; + ulong crash_notes; +- Elf64_Nhdr *note; ++ Elf64_Nhdr *note = NULL; + ulong offset; + char *buf, *p; + ulong *notes_ptrs; + ulong i, found; + +- if (!symbol_exists("crash_notes")) ++ if (!symbol_exists("crash_notes")) { ++ if (DISKDUMP_DUMPFILE() || KDUMP_DUMPFILE()) { ++ if (!(ms->panic_task_regs = calloc((size_t)kt->cpus, sizeof(struct arm64_pt_regs)))) ++ error(FATAL, "cannot calloc panic_task_regs space\n"); ++ ++ for (i = found = 0; i < kt->cpus; i++) { ++ if (DISKDUMP_DUMPFILE()) ++ note = diskdump_get_prstatus_percpu(i); ++ else if (KDUMP_DUMPFILE()) ++ note = netdump_get_prstatus_percpu(i); ++ ++ if (!note) { ++ error(WARNING, "cpu %d: cannot find NT_PRSTATUS note\n", i); ++ continue; ++ } ++ ++ /* ++ * Find correct location of note data. This contains elf_prstatus ++ * structure which has registers etc. for the crashed task. ++ */ ++ offset = sizeof(Elf64_Nhdr); ++ offset = roundup(offset + note->n_namesz, 4); ++ p = (char *)note + offset; /* start of elf_prstatus */ ++ ++ BCOPY(p + OFFSET(elf_prstatus_pr_reg), &ms->panic_task_regs[i], ++ sizeof(struct arm64_pt_regs)); ++ ++ found++; ++ } ++ if (!found) { ++ free(ms->panic_task_regs); ++ ms->panic_task_regs = NULL; ++ } ++ } + return; ++ } + + crash_notes = symbol_value("crash_notes"); + +diff -Nur crash-7.3.0-orig/arm64.c.orig crash-7.3.0/arm64.c.orig +--- crash-7.3.0-orig/arm64.c.orig 1970-01-01 08:00:00.000000000 +0800 ++++ crash-7.3.0/arm64.c.orig 2023-07-07 14:05:59.063287668 +0800 +@@ -0,0 +1,4399 @@ ++/* ++ * arm64.c - core analysis suite ++ * ++ * Copyright (C) 2012-2020 David Anderson ++ * Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifdef ARM64 ++ ++#include "defs.h" ++#include ++#include ++#include ++ ++#define NOT_IMPLEMENTED(X) error((X), "%s: function not implemented\n", __func__) ++ ++static struct machine_specific arm64_machine_specific = { 0 }; ++static int arm64_verify_symbol(const char *, ulong, char); ++static void arm64_parse_cmdline_args(void); ++static int arm64_search_for_kimage_voffset(ulong); ++static int verify_kimage_voffset(void); ++static void arm64_calc_kimage_voffset(void); ++static void arm64_calc_phys_offset(void); ++static void arm64_calc_physvirt_offset(void); ++static void arm64_calc_virtual_memory_ranges(void); ++static void arm64_get_section_size_bits(void); ++static int arm64_kdump_phys_base(ulong *); ++static ulong arm64_processor_speed(void); ++static void arm64_init_kernel_pgd(void); ++static int arm64_kvtop(struct task_context *, ulong, physaddr_t *, int); ++static int arm64_uvtop(struct task_context *, ulong, physaddr_t *, int); ++static int arm64_vtop_2level_64k(ulong, ulong, physaddr_t *, int); ++static int arm64_vtop_3level_64k(ulong, ulong, physaddr_t *, int); ++static int arm64_vtop_3level_4k(ulong, ulong, physaddr_t *, int); ++static int arm64_vtop_4level_4k(ulong, ulong, physaddr_t *, int); ++static ulong arm64_get_task_pgd(ulong); ++static void arm64_irq_stack_init(void); ++static void arm64_stackframe_init(void); ++static int arm64_eframe_search(struct bt_info *); ++static int arm64_is_kernel_exception_frame(struct bt_info *, ulong); ++static int arm64_in_exception_text(ulong); ++static int arm64_in_exp_entry(ulong); ++static void arm64_back_trace_cmd(struct bt_info *); ++static void arm64_back_trace_cmd_v2(struct bt_info *); ++static void arm64_print_text_symbols(struct bt_info *, struct arm64_stackframe *, FILE *); ++static int arm64_print_stackframe_entry(struct bt_info *, int, struct arm64_stackframe *, FILE *); ++static int arm64_print_stackframe_entry_v2(struct bt_info *, int, struct arm64_stackframe *, FILE *); ++static void arm64_display_full_frame(struct bt_info *, ulong); ++static void arm64_display_full_frame_v2(struct bt_info *, struct arm64_stackframe *, struct arm64_stackframe *); ++static int arm64_unwind_frame(struct bt_info *, struct arm64_stackframe *); ++static int arm64_unwind_frame_v2(struct bt_info *, struct arm64_stackframe *, FILE *); ++static int arm64_get_dumpfile_stackframe(struct bt_info *, struct arm64_stackframe *); ++static int arm64_in_kdump_text(struct bt_info *, struct arm64_stackframe *); ++static int arm64_in_kdump_text_on_irq_stack(struct bt_info *); ++static int arm64_switch_stack(struct bt_info *, struct arm64_stackframe *, FILE *); ++static int arm64_get_stackframe(struct bt_info *, struct arm64_stackframe *); ++static void arm64_get_stack_frame(struct bt_info *, ulong *, ulong *); ++static void arm64_gen_hidden_frame(struct bt_info *bt, ulong, struct arm64_stackframe *); ++static void arm64_print_exception_frame(struct bt_info *, ulong, int, FILE *); ++static void arm64_do_bt_reference_check(struct bt_info *, ulong, char *); ++static int arm64_translate_pte(ulong, void *, ulonglong); ++static ulong arm64_vmalloc_start(void); ++static int arm64_is_task_addr(ulong); ++static int arm64_dis_filter(ulong, char *, unsigned int); ++static void arm64_cmd_mach(void); ++static void arm64_display_machine_stats(void); ++static int arm64_get_smp_cpus(void); ++static void arm64_clear_machdep_cache(void); ++static int arm64_on_process_stack(struct bt_info *, ulong); ++static int arm64_in_alternate_stack(int, ulong); ++static int arm64_on_irq_stack(int, ulong); ++static void arm64_set_irq_stack(struct bt_info *); ++static void arm64_set_process_stack(struct bt_info *); ++static int arm64_get_kvaddr_ranges(struct vaddr_range *); ++static void arm64_get_crash_notes(void); ++static void arm64_calc_VA_BITS(void); ++static int arm64_is_uvaddr(ulong, struct task_context *); ++static void arm64_calc_KERNELPACMASK(void); ++ ++static int arm64_in_sdei_normal_stack(int cpu, ulong stkptr); ++static void arm64_set_sdei_normal_stack(struct bt_info *bt); ++static void arm64_sdei_stack_init(void); ++static int arm64_in_kdump_text_on_sdei_stack(struct bt_info *bt); ++ ++/* ++ * Do all necessary machine-specific setup here. This is called several times ++ * during initialization. ++ */ ++void ++arm64_init(int when) ++{ ++ ulong value; ++ char *string; ++ struct machine_specific *ms; ++ ++#if defined(__x86_64__) ++ if (ACTIVE()) ++ error(FATAL, "compiled for the ARM64 architecture\n"); ++#endif ++ ++ switch (when) { ++ case SETUP_ENV: ++ machdep->process_elf_notes = process_elf64_notes; ++ break; ++ ++ case PRE_SYMTAB: ++ machdep->machspec = &arm64_machine_specific; ++ machdep->verify_symbol = arm64_verify_symbol; ++ if (pc->flags & KERNEL_DEBUG_QUERY) ++ return; ++ machdep->verify_paddr = generic_verify_paddr; ++ if (machdep->cmdline_args[0]) ++ arm64_parse_cmdline_args(); ++ machdep->flags |= MACHDEP_BT_TEXT; ++ ++ ms = machdep->machspec; ++ ++ if (!ms->kimage_voffset && STREQ(pc->live_memsrc, "/dev/crash")) ++ ioctl(pc->mfd, DEV_CRASH_ARCH_DATA, &ms->kimage_voffset); ++ ++ if (!ms->kimage_voffset && ++ (string = pc->read_vmcoreinfo("NUMBER(kimage_voffset)"))) { ++ ms->kimage_voffset = htol(string, QUIET, NULL); ++ free(string); ++ } ++ ++ if (ms->kimage_voffset || ++ (ACTIVE() && (symbol_value_from_proc_kallsyms("kimage_voffset") != BADVAL))) { ++ machdep->flags |= NEW_VMEMMAP; ++ ++ /* ++ * Even if CONFIG_RANDOMIZE_BASE is not configured, ++ * derive_kaslr_offset() should work and set ++ * kt->relocate to 0 ++ */ ++ if (!kt->relocate && !(kt->flags2 & (RELOC_AUTO|KASLR))) ++ kt->flags2 |= (RELOC_AUTO|KASLR); ++ } ++ ++ break; ++ ++ case PRE_GDB: ++ if (kernel_symbol_exists("kimage_voffset")) ++ machdep->flags |= NEW_VMEMMAP; ++ ++ if (!machdep->pagesize && ++ (string = pc->read_vmcoreinfo("PAGESIZE"))) { ++ machdep->pagesize = atoi(string); ++ free(string); ++ } ++ ++ if (!machdep->pagesize) { ++ /* ++ * Kerneldoc Documentation/arm64/booting.txt describes ++ * the kernel image header flags field. ++ */ ++ value = machdep->machspec->kernel_flags; ++ value = (value >> 1) & 3; ++ ++ switch(value) ++ { ++ case 0: ++ break; ++ case 1: ++ machdep->pagesize = 4096; ++ break; ++ case 2: ++ /* TODO: machdep->pagesize = 16384; */ ++ error(FATAL, "16K pages not supported."); ++ break; ++ case 3: ++ machdep->pagesize = 65536; ++ break; ++ } ++ ++ } ++ ++ /* ++ * This code section will only be executed if the kernel is ++ * earlier than Linux 4.4 (if there is no vmcoreinfo) ++ */ ++ if (!machdep->pagesize && ++ kernel_symbol_exists("swapper_pg_dir") && ++ kernel_symbol_exists("idmap_pg_dir")) { ++ value = symbol_value("swapper_pg_dir") - ++ symbol_value("idmap_pg_dir"); ++ ++ /* ++ * idmap_pg_dir is 2 pages prior to 4.1, ++ * and 3 pages thereafter. Only 4K and 64K ++ * page sizes are supported. ++ */ ++ switch (value) ++ { ++ case (4096 * 2): ++ case (4096 * 3): ++ machdep->pagesize = 4096; ++ break; ++ case (65536 * 2): ++ case (65536 * 3): ++ machdep->pagesize = 65536; ++ break; ++ } ++ } else if (ACTIVE()) ++ machdep->pagesize = memory_page_size(); /* host */ ++ ++ machdep->pageshift = ffs(machdep->pagesize) - 1; ++ machdep->pageoffset = machdep->pagesize - 1; ++ machdep->pagemask = ~((ulonglong)machdep->pageoffset); ++ ++ arm64_calc_VA_BITS(); ++ arm64_calc_KERNELPACMASK(); ++ ms = machdep->machspec; ++ ++ /* vabits_actual introduced after mm flip, so it should be flipped layout */ ++ if (ms->VA_BITS_ACTUAL) { ++ ms->page_offset = ARM64_FLIP_PAGE_OFFSET; ++ /* useless on arm64 */ ++ machdep->identity_map_base = ARM64_FLIP_PAGE_OFFSET; ++ machdep->kvbase = ARM64_FLIP_PAGE_OFFSET; ++ ms->userspace_top = ARM64_USERSPACE_TOP_ACTUAL; ++ } else { ++ ms->page_offset = ARM64_PAGE_OFFSET; ++ machdep->identity_map_base = ARM64_PAGE_OFFSET; ++ machdep->kvbase = ARM64_VA_START; ++ ms->userspace_top = ARM64_USERSPACE_TOP; ++ } ++ machdep->is_kvaddr = generic_is_kvaddr; ++ machdep->kvtop = arm64_kvtop; ++ if (machdep->flags & NEW_VMEMMAP) { ++ struct syment *sp; ++ ++ sp = kernel_symbol_search("_text"); ++ ms->kimage_text = (sp ? sp->value : 0); ++ sp = kernel_symbol_search("_end"); ++ ms->kimage_end = (sp ? sp->value : 0); ++ ++ if (ms->VA_BITS_ACTUAL) { ++ ms->modules_vaddr = (st->_stext_vmlinux & TEXT_OFFSET_MASK) - ARM64_MODULES_VSIZE; ++ ms->modules_end = ms->modules_vaddr + ARM64_MODULES_VSIZE -1; ++ } else { ++ ms->modules_vaddr = ARM64_VA_START; ++ if (kernel_symbol_exists("kasan_init")) ++ ms->modules_vaddr += ARM64_KASAN_SHADOW_SIZE; ++ ms->modules_end = ms->modules_vaddr + ARM64_MODULES_VSIZE -1; ++ } ++ ++ ms->vmalloc_start_addr = ms->modules_end + 1; ++ ++ arm64_calc_kimage_voffset(); ++ } else { ++ ms->modules_vaddr = ARM64_PAGE_OFFSET - MEGABYTES(64); ++ ms->modules_end = ARM64_PAGE_OFFSET - 1; ++ ms->vmalloc_start_addr = ARM64_VA_START; ++ } ++ ms->vmalloc_end = ARM64_VMALLOC_END; ++ ms->vmemmap_vaddr = ARM64_VMEMMAP_VADDR; ++ ms->vmemmap_end = ARM64_VMEMMAP_END; ++ ++ switch (machdep->pagesize) ++ { ++ case 4096: ++ machdep->ptrs_per_pgd = PTRS_PER_PGD_L3_4K; ++ if ((machdep->pgd = ++ (char *)malloc(PTRS_PER_PGD_L3_4K * 8)) == NULL) ++ error(FATAL, "cannot malloc pgd space."); ++ if (machdep->machspec->VA_BITS > PGDIR_SHIFT_L4_4K) { ++ machdep->flags |= VM_L4_4K; ++ if ((machdep->pud = ++ (char *)malloc(PTRS_PER_PUD_L4_4K * 8)) ++ == NULL) ++ error(FATAL, "cannot malloc pud space."); ++ } else { ++ machdep->flags |= VM_L3_4K; ++ machdep->pud = NULL; /* not used */ ++ } ++ if ((machdep->pmd = ++ (char *)malloc(PTRS_PER_PMD_L3_4K * 8)) == NULL) ++ error(FATAL, "cannot malloc pmd space."); ++ if ((machdep->ptbl = ++ (char *)malloc(PTRS_PER_PTE_L3_4K * 8)) == NULL) ++ error(FATAL, "cannot malloc ptbl space."); ++ 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", QUIET|RETURN_ON_ERROR)) ++ machdep->ptrs_per_pgd = value; ++ ++ if (machdep->machspec->VA_BITS > PGDIR_SHIFT_L3_64K) { ++ machdep->flags |= VM_L3_64K; ++ if (!machdep->ptrs_per_pgd) ++ machdep->ptrs_per_pgd = PTRS_PER_PGD_L3_64K; ++ if ((machdep->pgd = ++ (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) ++ error(FATAL, "cannot malloc pmd space."); ++ if ((machdep->ptbl = ++ (char *)malloc(PTRS_PER_PTE_L3_64K * 8)) == NULL) ++ error(FATAL, "cannot malloc ptbl space."); ++ } else { ++ machdep->flags |= VM_L2_64K; ++ if (!machdep->ptrs_per_pgd) ++ machdep->ptrs_per_pgd = PTRS_PER_PGD_L2_64K; ++ if ((machdep->pgd = ++ (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) ++ error(FATAL, "cannot malloc ptbl space."); ++ machdep->pmd = NULL; /* not used */ ++ } ++ machdep->pud = NULL; /* not used */ ++ break; ++ ++ default: ++ if (machdep->pagesize) ++ error(FATAL, "invalid/unsupported page size: %d\n", ++ machdep->pagesize); ++ else ++ error(FATAL, "cannot determine page size\n"); ++ } ++ ++ machdep->last_pgd_read = 0; ++ machdep->last_pud_read = 0; ++ machdep->last_pmd_read = 0; ++ machdep->last_ptbl_read = 0; ++ machdep->clear_machdep_cache = arm64_clear_machdep_cache; ++ ++ machdep->stacksize = ARM64_STACK_SIZE; ++ machdep->flags |= VMEMMAP; ++ ++ machdep->uvtop = arm64_uvtop; ++ machdep->is_uvaddr = arm64_is_uvaddr; ++ machdep->eframe_search = arm64_eframe_search; ++ machdep->back_trace = arm64_back_trace_cmd; ++ machdep->in_alternate_stack = arm64_in_alternate_stack; ++ machdep->processor_speed = arm64_processor_speed; ++ machdep->get_task_pgd = arm64_get_task_pgd; ++ machdep->get_stack_frame = arm64_get_stack_frame; ++ machdep->get_stackbase = generic_get_stackbase; ++ machdep->get_stacktop = generic_get_stacktop; ++ machdep->translate_pte = arm64_translate_pte; ++ machdep->memory_size = generic_memory_size; ++ machdep->vmalloc_start = arm64_vmalloc_start; ++ machdep->get_kvaddr_ranges = arm64_get_kvaddr_ranges; ++ machdep->is_task_addr = arm64_is_task_addr; ++ machdep->dis_filter = arm64_dis_filter; ++ machdep->cmd_mach = arm64_cmd_mach; ++ machdep->get_smp_cpus = arm64_get_smp_cpus; ++ machdep->line_number_hooks = NULL; ++ machdep->value_to_symbol = generic_machdep_value_to_symbol; ++ machdep->dump_irq = generic_dump_irq; ++ machdep->show_interrupts = generic_show_interrupts; ++ machdep->get_irq_affinity = generic_get_irq_affinity; ++ machdep->dumpfile_init = NULL; ++ machdep->verify_line_number = NULL; ++ machdep->init_kernel_pgd = arm64_init_kernel_pgd; ++ ++ /* use machdep parameters */ ++ arm64_calc_phys_offset(); ++ arm64_calc_physvirt_offset(); ++ ++ if (CRASHDEBUG(1)) { ++ if (machdep->flags & NEW_VMEMMAP) ++ fprintf(fp, "kimage_voffset: %lx\n", ++ machdep->machspec->kimage_voffset); ++ fprintf(fp, "phys_offset: %lx\n", ++ machdep->machspec->phys_offset); ++ fprintf(fp, "physvirt_offset: %lx\n", machdep->machspec->physvirt_offset); ++ } ++ ++ break; ++ ++ case POST_GDB: ++ arm64_calc_virtual_memory_ranges(); ++ arm64_get_section_size_bits(); ++ ++ if (!machdep->max_physmem_bits) { ++ 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; ++ else ++ machdep->max_physmem_bits = _MAX_PHYSMEM_BITS; ++ } ++ ++ ms = machdep->machspec; ++ ++ if (CRASHDEBUG(1)) { ++ if (ms->VA_BITS_ACTUAL) { ++ fprintf(fp, "CONFIG_ARM64_VA_BITS: %ld\n", ms->CONFIG_ARM64_VA_BITS); ++ fprintf(fp, " VA_BITS_ACTUAL: %ld\n", ms->VA_BITS_ACTUAL); ++ fprintf(fp, "(calculated) VA_BITS: %ld\n", ms->VA_BITS); ++ fprintf(fp, " PAGE_OFFSET: %lx\n", ARM64_FLIP_PAGE_OFFSET_ACTUAL); ++ fprintf(fp, " VA_START: %lx\n", ms->VA_START); ++ fprintf(fp, " modules: %lx - %lx\n", ms->modules_vaddr, ms->modules_end); ++ fprintf(fp, " vmalloc: %lx - %lx\n", ms->vmalloc_start_addr, ms->vmalloc_end); ++ fprintf(fp, "kernel image: %lx - %lx\n", ms->kimage_text, ms->kimage_end); ++ fprintf(fp, " vmemmap: %lx - %lx\n\n", ms->vmemmap_vaddr, ms->vmemmap_end); ++ } ++ } ++ ++ ++ if (THIS_KERNEL_VERSION >= LINUX(4,0,0)) { ++ ms->__SWP_TYPE_BITS = 6; ++ ms->__SWP_TYPE_SHIFT = 2; ++ ms->__SWP_TYPE_MASK = ((1UL << ms->__SWP_TYPE_BITS) - 1); ++ ms->__SWP_OFFSET_SHIFT = (ms->__SWP_TYPE_BITS + ms->__SWP_TYPE_SHIFT); ++ ms->__SWP_OFFSET_BITS = 50; ++ ms->__SWP_OFFSET_MASK = ((1UL << ms->__SWP_OFFSET_BITS) - 1); ++ ms->PTE_PROT_NONE = (1UL << 58); ++ ms->PTE_FILE = 0; /* unused */ ++ } else if (THIS_KERNEL_VERSION >= LINUX(3,13,0)) { ++ ms->__SWP_TYPE_BITS = 6; ++ ms->__SWP_TYPE_SHIFT = 3; ++ ms->__SWP_TYPE_MASK = ((1UL << ms->__SWP_TYPE_BITS) - 1); ++ ms->__SWP_OFFSET_SHIFT = (ms->__SWP_TYPE_BITS + ms->__SWP_TYPE_SHIFT); ++ ms->__SWP_OFFSET_BITS = 49; ++ ms->__SWP_OFFSET_MASK = ((1UL << ms->__SWP_OFFSET_BITS) - 1); ++ ms->PTE_PROT_NONE = (1UL << 58); ++ ms->PTE_FILE = (1UL << 2); ++ } else if (THIS_KERNEL_VERSION >= LINUX(3,11,0)) { ++ ms->__SWP_TYPE_BITS = 6; ++ ms->__SWP_TYPE_SHIFT = 4; ++ ms->__SWP_TYPE_MASK = ((1UL << ms->__SWP_TYPE_BITS) - 1); ++ ms->__SWP_OFFSET_SHIFT = (ms->__SWP_TYPE_BITS + ms->__SWP_TYPE_SHIFT); ++ ms->__SWP_OFFSET_BITS = 0; /* unused */ ++ ms->__SWP_OFFSET_MASK = 0; /* unused */ ++ ms->PTE_PROT_NONE = (1UL << 2); ++ ms->PTE_FILE = (1UL << 3); ++ } else { ++ ms->__SWP_TYPE_BITS = 6; ++ ms->__SWP_TYPE_SHIFT = 3; ++ ms->__SWP_TYPE_MASK = ((1UL << ms->__SWP_TYPE_BITS) - 1); ++ ms->__SWP_OFFSET_SHIFT = (ms->__SWP_TYPE_BITS + ms->__SWP_TYPE_SHIFT); ++ ms->__SWP_OFFSET_BITS = 0; /* unused */ ++ ms->__SWP_OFFSET_MASK = 0; /* unused */ ++ ms->PTE_PROT_NONE = (1UL << 1); ++ ms->PTE_FILE = (1UL << 2); ++ } ++ ++ if (symbol_exists("irq_desc")) ++ ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc, ++ "irq_desc", NULL, 0); ++ else if (kernel_symbol_exists("nr_irqs")) ++ get_symbol_data("nr_irqs", sizeof(unsigned int), ++ &machdep->nr_irqs); ++ ++ if (!machdep->hz) ++ machdep->hz = 100; ++ ++ arm64_irq_stack_init(); ++ arm64_stackframe_init(); ++ arm64_sdei_stack_init(); ++ break; ++ ++ case POST_INIT: ++ /* ++ * crash_notes contains machine specific information about the ++ * crash. In particular, it contains CPU registers at the time ++ * of the crash. We need this information to extract correct ++ * backtraces from the panic task. ++ */ ++ if (!LIVE()) ++ arm64_get_crash_notes(); ++ break; ++ ++ case LOG_ONLY: ++ machdep->machspec = &arm64_machine_specific; ++ arm64_calc_VA_BITS(); ++ arm64_calc_KERNELPACMASK(); ++ arm64_calc_phys_offset(); ++ machdep->machspec->page_offset = ARM64_PAGE_OFFSET; ++ arm64_calc_physvirt_offset(); ++ break; ++ } ++} ++ ++/* ++ * Accept or reject a symbol from the kernel namelist. ++ */ ++static int ++arm64_verify_symbol(const char *name, ulong value, char type) ++{ ++ if (!name || !strlen(name)) ++ return FALSE; ++ ++ if ((type == 'A') && STREQ(name, "_kernel_flags_le")) ++ machdep->machspec->kernel_flags = le64toh(value); ++ ++ if ((type == 'A') && STREQ(name, "_kernel_flags_le_hi32")) ++ machdep->machspec->kernel_flags |= ((ulong)le32toh(value) << 32); ++ ++ if ((type == 'A') && STREQ(name, "_kernel_flags_le_lo32")) ++ machdep->machspec->kernel_flags |= le32toh(value); ++ ++ if (((type == 'A') || (type == 'a')) && (highest_bit_long(value) != 63)) ++ return FALSE; ++ ++ if ((value == 0) && ++ ((type == 'a') || (type == 'n') || (type == 'N') || (type == 'U'))) ++ return FALSE; ++ ++ if (STREQ(name, "$d") || STRNEQ(name, "$d.") || ++ STREQ(name, "$x") || STRNEQ(name, "$x.") || ++ STREQ(name, "$c") || STRNEQ(name, "$c.")) ++ return FALSE; ++ ++ if ((type == 'A') && STRNEQ(name, "__crc_")) ++ return FALSE; ++ ++ if ((type == 'N') && strstr(name, "$d")) ++ return FALSE; ++ ++ if (!(machdep->flags & KSYMS_START) && STREQ(name, "idmap_pg_dir")) ++ machdep->flags |= KSYMS_START; ++ ++ return TRUE; ++} ++ ++ ++void ++arm64_dump_machdep_table(ulong arg) ++{ ++ const struct machine_specific *ms; ++ int others, i; ++ ++ others = 0; ++ fprintf(fp, " flags: %lx (", machdep->flags); ++ if (machdep->flags & KSYMS_START) ++ fprintf(fp, "%sKSYMS_START", others++ ? "|" : ""); ++ if (machdep->flags & PHYS_OFFSET) ++ fprintf(fp, "%sPHYS_OFFSET", others++ ? "|" : ""); ++ if (machdep->flags & VM_L2_64K) ++ fprintf(fp, "%sVM_L2_64K", others++ ? "|" : ""); ++ if (machdep->flags & VM_L3_64K) ++ fprintf(fp, "%sVM_L3_64K", others++ ? "|" : ""); ++ if (machdep->flags & VM_L3_4K) ++ fprintf(fp, "%sVM_L3_4K", others++ ? "|" : ""); ++ if (machdep->flags & VM_L4_4K) ++ fprintf(fp, "%sVM_L4_4K", others++ ? "|" : ""); ++ if (machdep->flags & VMEMMAP) ++ fprintf(fp, "%sVMEMMAP", others++ ? "|" : ""); ++ if (machdep->flags & KDUMP_ENABLED) ++ fprintf(fp, "%sKDUMP_ENABLED", others++ ? "|" : ""); ++ if (machdep->flags & IRQ_STACKS) ++ fprintf(fp, "%sIRQ_STACKS", others++ ? "|" : ""); ++ if (machdep->flags & UNW_4_14) ++ fprintf(fp, "%sUNW_4_14", others++ ? "|" : ""); ++ if (machdep->flags & MACHDEP_BT_TEXT) ++ fprintf(fp, "%sMACHDEP_BT_TEXT", others++ ? "|" : ""); ++ if (machdep->flags & NEW_VMEMMAP) ++ fprintf(fp, "%sNEW_VMEMMAP", others++ ? "|" : ""); ++ if (machdep->flags & FLIPPED_VM) ++ fprintf(fp, "%sFLIPPED_VM", others++ ? "|" : ""); ++ if (machdep->flags & HAS_PHYSVIRT_OFFSET) ++ fprintf(fp, "%sHAS_PHYSVIRT_OFFSET", others++ ? "|" : ""); ++ fprintf(fp, ")\n"); ++ ++ fprintf(fp, " kvbase: %lx\n", machdep->kvbase); ++ fprintf(fp, " identity_map_base: %lx\n", machdep->identity_map_base); ++ fprintf(fp, " pagesize: %d\n", machdep->pagesize); ++ fprintf(fp, " pageshift: %d\n", machdep->pageshift); ++ fprintf(fp, " pagemask: %lx\n", (ulong)machdep->pagemask); ++ fprintf(fp, " pageoffset: %lx\n", machdep->pageoffset); ++ fprintf(fp, " stacksize: %ld\n", machdep->stacksize); ++ fprintf(fp, " hz: %d\n", machdep->hz); ++ fprintf(fp, " mhz: %ld\n", machdep->mhz); ++ fprintf(fp, " memsize: %lld (0x%llx)\n", ++ (ulonglong)machdep->memsize, (ulonglong)machdep->memsize); ++ fprintf(fp, " bits: %d\n", machdep->bits); ++ fprintf(fp, " nr_irqs: %d\n", machdep->nr_irqs); ++ fprintf(fp, " eframe_search: arm64_eframe_search()\n"); ++ fprintf(fp, " back_trace: arm64_back_trace_cmd() (default: %s method)\n", ++ kt->flags & USE_OPT_BT ? "optional" : "original"); ++ fprintf(fp, " in_alternate_stack: arm64_in_alternate_stack()\n"); ++ fprintf(fp, " processor_speed: arm64_processor_speed()\n"); ++ fprintf(fp, " uvtop: arm64_uvtop()->%s()\n", ++ machdep->flags & VM_L3_4K ? ++ "arm64_vtop_3level_4k" : ++ machdep->flags & VM_L4_4K ? ++ "arm64_vtop_4level_4k" : ++ machdep->flags & VM_L3_64K ? ++ "arm64_vtop_3level_64k" : "arm64_vtop_2level_64k"); ++ fprintf(fp, " kvtop: arm64_kvtop()->%s()\n", ++ machdep->flags & VM_L3_4K ? ++ "arm64_vtop_3level_4k" : ++ machdep->flags & VM_L4_4K ? ++ "arm64_vtop_4level_4k" : ++ machdep->flags & VM_L3_64K ? ++ "arm64_vtop_3level_64k" : "arm64_vtop_2level_64k"); ++ fprintf(fp, " get_task_pgd: arm64_get_task_pgd()\n"); ++ fprintf(fp, " dump_irq: generic_dump_irq()\n"); ++ fprintf(fp, " get_stack_frame: arm64_get_stack_frame()\n"); ++ fprintf(fp, " get_stackbase: generic_get_stackbase()\n"); ++ fprintf(fp, " get_stacktop: generic_get_stacktop()\n"); ++ fprintf(fp, " translate_pte: arm64_translate_pte()\n"); ++ fprintf(fp, " memory_size: generic_memory_size()\n"); ++ fprintf(fp, " vmalloc_start: arm64_vmalloc_start()\n"); ++ fprintf(fp, " get_kvaddr_ranges: arm64_get_kvaddr_ranges()\n"); ++ fprintf(fp, " is_task_addr: arm64_is_task_addr()\n"); ++ fprintf(fp, " verify_symbol: arm64_verify_symbol()\n"); ++ fprintf(fp, " dis_filter: arm64_dis_filter()\n"); ++ fprintf(fp, " cmd_mach: arm64_cmd_mach()\n"); ++ fprintf(fp, " get_smp_cpus: arm64_get_smp_cpus()\n"); ++ fprintf(fp, " is_kvaddr: generic_is_kvaddr()\n"); ++ fprintf(fp, " is_uvaddr: arm64_is_uvaddr()\n"); ++ fprintf(fp, " value_to_symbol: generic_machdep_value_to_symbol()\n"); ++ fprintf(fp, " init_kernel_pgd: arm64_init_kernel_pgd\n"); ++ fprintf(fp, " verify_paddr: generic_verify_paddr()\n"); ++ fprintf(fp, " show_interrupts: generic_show_interrupts()\n"); ++ fprintf(fp, " get_irq_affinity: generic_get_irq_affinity()\n"); ++ fprintf(fp, " dumpfile_init: (not used)\n"); ++ fprintf(fp, " process_elf_notes: process_elf64_notes()\n"); ++ fprintf(fp, " verify_line_number: (not used)\n"); ++ ++ fprintf(fp, " xendump_p2m_create: (n/a)\n"); ++ fprintf(fp, "xen_kdump_p2m_create: (n/a)\n"); ++ fprintf(fp, " xendump_panic_task: (n/a)\n"); ++ fprintf(fp, " get_xendump_regs: (n/a)\n"); ++ fprintf(fp, " line_number_hooks: (not used)\n"); ++ fprintf(fp, " last_pgd_read: %lx\n", machdep->last_pgd_read); ++ fprintf(fp, " last_pud_read: "); ++ if ((PAGESIZE() == 65536) || ++ ((PAGESIZE() == 4096) && !(machdep->flags & VM_L4_4K))) ++ fprintf(fp, "(not used)\n"); ++ else ++ fprintf(fp, "%lx\n", machdep->last_pud_read); ++ fprintf(fp, " last_pmd_read: "); ++ if (PAGESIZE() == 65536) ++ fprintf(fp, "(not used)\n"); ++ else ++ fprintf(fp, "%lx\n", machdep->last_pmd_read); ++ fprintf(fp, " last_ptbl_read: %lx\n", machdep->last_ptbl_read); ++ fprintf(fp, " clear_machdep_cache: arm64_clear_machdep_cache()\n"); ++ fprintf(fp, " pgd: %lx\n", (ulong)machdep->pgd); ++ fprintf(fp, " pud: %lx\n", (ulong)machdep->pud); ++ fprintf(fp, " pmd: %lx\n", (ulong)machdep->pmd); ++ fprintf(fp, " ptbl: %lx\n", (ulong)machdep->ptbl); ++ fprintf(fp, " ptrs_per_pgd: %d\n", machdep->ptrs_per_pgd); ++ fprintf(fp, " section_size_bits: %ld\n", machdep->section_size_bits); ++ fprintf(fp, " max_physmem_bits: %ld\n", machdep->max_physmem_bits); ++ fprintf(fp, " sections_per_root: %ld\n", machdep->sections_per_root); ++ ++ for (i = 0; i < MAX_MACHDEP_ARGS; i++) { ++ fprintf(fp, " cmdline_args[%d]: %s\n", ++ i, machdep->cmdline_args[i] ? ++ machdep->cmdline_args[i] : "(unused)"); ++ } ++ ++ ms = machdep->machspec; ++ ++ fprintf(fp, " machspec: %lx\n", (ulong)ms); ++ fprintf(fp, " VA_BITS: %ld\n", ms->VA_BITS); ++ fprintf(fp, " CONFIG_ARM64_VA_BITS: %ld\n", ms->CONFIG_ARM64_VA_BITS); ++ fprintf(fp, " VA_START: "); ++ if (ms->VA_START) ++ fprintf(fp, "%lx\n", ms->VA_START); ++ else ++ fprintf(fp, "(unused)\n"); ++ fprintf(fp, " VA_BITS_ACTUAL: "); ++ if (ms->VA_BITS_ACTUAL) ++ fprintf(fp, "%ld\n", ms->VA_BITS_ACTUAL); ++ else ++ fprintf(fp, "(unused)\n"); ++ fprintf(fp, "CONFIG_ARM64_KERNELPACMASK: "); ++ if (ms->CONFIG_ARM64_KERNELPACMASK) ++ fprintf(fp, "%lx\n", ms->CONFIG_ARM64_KERNELPACMASK); ++ 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); ++ fprintf(fp, " vmalloc_end: %016lx\n", ms->vmalloc_end); ++ fprintf(fp, " modules_vaddr: %016lx\n", ms->modules_vaddr); ++ fprintf(fp, " modules_end: %016lx\n", ms->modules_end); ++ fprintf(fp, " vmemmap_vaddr: %016lx\n", ms->vmemmap_vaddr); ++ fprintf(fp, " vmemmap_end: %016lx\n", ms->vmemmap_end); ++ if (machdep->flags & NEW_VMEMMAP) { ++ fprintf(fp, " kimage_text: %016lx\n", ms->kimage_text); ++ fprintf(fp, " kimage_end: %016lx\n", ms->kimage_end); ++ fprintf(fp, " kimage_voffset: %016lx\n", ms->kimage_voffset); ++ } ++ fprintf(fp, " phys_offset: %lx\n", ms->phys_offset); ++ fprintf(fp, "__exception_text_start: %lx\n", ms->__exception_text_start); ++ fprintf(fp, " __exception_text_end: %lx\n", ms->__exception_text_end); ++ fprintf(fp, " __irqentry_text_start: %lx\n", ms->__irqentry_text_start); ++ fprintf(fp, " __irqentry_text_end: %lx\n", ms->__irqentry_text_end); ++ fprintf(fp, " exp_entry1_start: %lx\n", ms->exp_entry1_start); ++ fprintf(fp, " exp_entry1_end: %lx\n", ms->exp_entry1_end); ++ fprintf(fp, " exp_entry2_start: %lx\n", ms->exp_entry2_start); ++ fprintf(fp, " exp_entry2_end: %lx\n", ms->exp_entry2_end); ++ fprintf(fp, " panic_task_regs: %lx\n", (ulong)ms->panic_task_regs); ++ fprintf(fp, " user_eframe_offset: %ld\n", ms->user_eframe_offset); ++ fprintf(fp, " kern_eframe_offset: %ld\n", ms->kern_eframe_offset); ++ fprintf(fp, " PTE_PROT_NONE: %lx\n", ms->PTE_PROT_NONE); ++ fprintf(fp, " PTE_FILE: "); ++ if (ms->PTE_FILE) ++ fprintf(fp, "%lx\n", ms->PTE_FILE); ++ else ++ fprintf(fp, "(unused)\n"); ++ fprintf(fp, " __SWP_TYPE_BITS: %ld\n", ms->__SWP_TYPE_BITS); ++ fprintf(fp, " __SWP_TYPE_SHIFT: %ld\n", ms->__SWP_TYPE_SHIFT); ++ fprintf(fp, " __SWP_TYPE_MASK: %lx\n", ms->__SWP_TYPE_MASK); ++ fprintf(fp, " __SWP_OFFSET_BITS: "); ++ if (ms->__SWP_OFFSET_BITS) ++ fprintf(fp, "%ld\n", ms->__SWP_OFFSET_BITS); ++ else ++ fprintf(fp, "(unused)\n"); ++ fprintf(fp, " __SWP_OFFSET_SHIFT: %ld\n", ms->__SWP_OFFSET_SHIFT); ++ fprintf(fp, " __SWP_OFFSET_MASK: "); ++ if (ms->__SWP_OFFSET_MASK) ++ fprintf(fp, "%lx\n", ms->__SWP_OFFSET_MASK); ++ else ++ fprintf(fp, "(unused)\n"); ++ fprintf(fp, " machine_kexec_start: %lx\n", ms->machine_kexec_start); ++ fprintf(fp, " machine_kexec_end: %lx\n", ms->machine_kexec_end); ++ fprintf(fp, " crash_kexec_start: %lx\n", ms->crash_kexec_start); ++ fprintf(fp, " crash_kexec_end: %lx\n", ms->crash_kexec_end); ++ fprintf(fp, " crash_save_cpu_start: %lx\n", ms->crash_save_cpu_start); ++ fprintf(fp, " crash_save_cpu_end: %lx\n", ms->crash_save_cpu_end); ++ fprintf(fp, " kernel_flags: %lx\n", ms->kernel_flags); ++ fprintf(fp, " irq_stackbuf: %lx\n", (ulong)ms->irq_stackbuf); ++ if (machdep->flags & IRQ_STACKS) { ++ fprintf(fp, " irq_stack_size: %ld\n", ms->irq_stack_size); ++ for (i = 0; i < kt->cpus; i++) ++ fprintf(fp, " irq_stacks[%d]: %lx\n", ++ i, ms->irq_stacks[i]); ++ } else { ++ fprintf(fp, " irq_stack_size: (unused)\n"); ++ fprintf(fp, " irq_stacks: (unused)\n"); ++ } ++} ++ ++static int ++arm64_parse_machdep_arg_l(char *argstring, char *param, ulong *value) ++{ ++ int len; ++ int megabytes = FALSE; ++ char *p; ++ ++ len = strlen(param); ++ if (!STRNEQ(argstring, param) || (argstring[len] != '=')) ++ return FALSE; ++ ++ if ((LASTCHAR(argstring) == 'm') || ++ (LASTCHAR(argstring) == 'M')) { ++ LASTCHAR(argstring) = NULLCHAR; ++ megabytes = TRUE; ++ } ++ ++ p = argstring + len + 1; ++ if (strlen(p)) { ++ int flags = RETURN_ON_ERROR | QUIET; ++ int err = 0; ++ ++ if (STRNEQ(argstring, "max_physmem_bits")) { ++ *value = dtol(p, flags, &err); ++ } else if (STRNEQ(argstring, "vabits_actual")) { ++ *value = dtol(p, flags, &err); ++ } else if (megabytes) { ++ *value = dtol(p, flags, &err); ++ if (!err) ++ *value = MEGABYTES(*value); ++ } else { ++ *value = htol(p, flags, &err); ++ } ++ ++ if (!err) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/* ++ * Parse machine dependent command line arguments. ++ * ++ * Force the phys_offset address via: ++ * ++ * --machdep phys_offset=
++ */ ++static void ++arm64_parse_cmdline_args(void) ++{ ++ int index, i, c; ++ char *arglist[MAXARGS]; ++ char buf[BUFSIZE]; ++ char *p; ++ ++ for (index = 0; index < MAX_MACHDEP_ARGS; index++) { ++ if (!machdep->cmdline_args[index]) ++ break; ++ ++ if (!strstr(machdep->cmdline_args[index], "=")) { ++ error(WARNING, "ignoring --machdep option: %x\n", ++ machdep->cmdline_args[index]); ++ continue; ++ } ++ ++ strcpy(buf, machdep->cmdline_args[index]); ++ ++ for (p = buf; *p; p++) { ++ if (*p == ',') ++ *p = ' '; ++ } ++ ++ c = parse_line(buf, arglist); ++ ++ for (i = 0; i < c; i++) { ++ if (arm64_parse_machdep_arg_l(arglist[i], "phys_offset", ++ &machdep->machspec->phys_offset)) { ++ error(NOTE, ++ "setting phys_offset to: 0x%lx\n\n", ++ machdep->machspec->phys_offset); ++ machdep->flags |= PHYS_OFFSET; ++ continue; ++ } else if (arm64_parse_machdep_arg_l(arglist[i], "kimage_voffset", ++ &machdep->machspec->kimage_voffset)) { ++ error(NOTE, ++ "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; ++ } else if (arm64_parse_machdep_arg_l(arglist[i], "vabits_actual", ++ &machdep->machspec->VA_BITS_ACTUAL)) { ++ error(NOTE, ++ "setting vabits_actual to: %ld\n\n", ++ machdep->machspec->VA_BITS_ACTUAL); ++ continue; ++ } ++ ++ error(WARNING, "ignoring --machdep option: %s\n", ++ arglist[i]); ++ } ++ } ++} ++ ++#define MIN_KIMG_ALIGN (0x00200000) /* kimage load address must be aligned 2M */ ++/* ++ * Traverse the entire dumpfile to find/verify kimage_voffset. ++ */ ++static int ++arm64_search_for_kimage_voffset(ulong phys_base) ++{ ++ ulong kimage_load_addr; ++ ulong phys_end; ++ struct machine_specific *ms = machdep->machspec; ++ ++ if (!arm_kdump_phys_end(&phys_end)) ++ return FALSE; ++ ++ for (kimage_load_addr = phys_base; ++ kimage_load_addr <= phys_end; kimage_load_addr += MIN_KIMG_ALIGN) { ++ ms->kimage_voffset = ms->vmalloc_start_addr - kimage_load_addr; ++ ++ if ((kt->flags2 & KASLR) && (kt->flags & RELOC_SET)) ++ ms->kimage_voffset += (kt->relocate * - 1); ++ ++ if (verify_kimage_voffset()) { ++ if (CRASHDEBUG(1)) ++ error(INFO, ++ "dumpfile searched for kimage_voffset: %lx\n\n", ++ ms->kimage_voffset); ++ break; ++ } ++ } ++ ++ if (kimage_load_addr > phys_end) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++static int ++verify_kimage_voffset(void) ++{ ++ ulong kimage_voffset; ++ ++ if (!readmem(symbol_value("kimage_voffset"), KVADDR, &kimage_voffset, ++ sizeof(kimage_voffset), "verify kimage_voffset", QUIET|RETURN_ON_ERROR)) ++ return FALSE; ++ ++ return (machdep->machspec->kimage_voffset == kimage_voffset); ++} ++ ++static void ++arm64_calc_kimage_voffset(void) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ ulong phys_addr = 0; ++ int errflag; ++ ++ if (ms->kimage_voffset) /* vmcoreinfo, ioctl, or --machdep override */ ++ return; ++ ++ if (ACTIVE()) { ++ char buf[BUFSIZE]; ++ char *p1; ++ 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; ++ ++ errflag = 1; ++ while (fgets(buf, BUFSIZE, iomem)) { ++ if(strstr(buf, ": Kernel code")) { ++ errflag = 0; ++ break; ++ } ++ if (strstr(buf, ": System RAM")) { ++ clean_line(buf); ++ ++ if (!(p1 = strstr(buf, "-"))) ++ continue; ++ ++ *p1 = NULLCHAR; ++ ++ phys_addr = htol(buf, RETURN_ON_ERROR | QUIET, NULL); ++ if (phys_addr == BADADDR) ++ continue; ++ } ++ } ++ fclose(iomem); ++ ++ if (errflag) ++ return; ++ ++ } else if (KDUMP_DUMPFILE()) { ++ errflag = 1; ++ if (arm_kdump_phys_base(&phys_addr)) { /* Get start address of first memory block */ ++ ms->kimage_voffset = ms->vmalloc_start_addr - phys_addr; ++ if ((kt->flags2 & KASLR) && (kt->flags & RELOC_SET)) ++ ms->kimage_voffset += (kt->relocate * -1); ++ if (verify_kimage_voffset() || arm64_search_for_kimage_voffset(phys_addr)) ++ errflag = 0; ++ } ++ ++ if (errflag) { ++ error(WARNING, ++ "kimage_voffset cannot be determined from the dumpfile.\n"); ++ error(CONT, ++ "Try using the command line option: --machdep kimage_voffset=\n"); ++ } ++ return; ++ } else { ++ error(WARNING, ++ "kimage_voffset cannot be determined from the dumpfile.\n"); ++ error(CONT, ++ "Using default value of 0. If this is not correct, then try\n"); ++ error(CONT, ++ "using the command line option: --machdep kimage_voffset=\n"); ++ return; ++ } ++ ++ ms->kimage_voffset = ms->vmalloc_start_addr - phys_addr; ++ ++ if ((kt->flags2 & KASLR) && (kt->flags & RELOC_SET)) ++ ms->kimage_voffset += (kt->relocate * -1); ++} ++ ++static void ++arm64_calc_physvirt_offset(void) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ ulong physvirt_offset; ++ struct syment *sp; ++ ++ if ((sp = kernel_symbol_search("physvirt_offset")) && ++ machdep->machspec->kimage_voffset) { ++ if (READMEM(pc->mfd, &physvirt_offset, sizeof(physvirt_offset), ++ sp->value, sp->value - ++ machdep->machspec->kimage_voffset) > 0) { ++ machdep->flags |= HAS_PHYSVIRT_OFFSET; ++ ms->physvirt_offset = physvirt_offset; ++ return; ++ } ++ } ++ ++ /* Useless if no symbol 'physvirt_offset', just keep semantics */ ++ ms->physvirt_offset = ms->phys_offset - ms->page_offset; ++ ++} ++ ++static void ++arm64_calc_phys_offset(void) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ ulong phys_offset; ++ ++ if (machdep->flags & PHYS_OFFSET) /* --machdep override */ ++ return; ++ ++ /* ++ * Next determine suitable value for phys_offset. User can override this ++ * by passing valid '--machdep phys_offset=' option. ++ */ ++ ms->phys_offset = 0; ++ ++ if (ACTIVE()) { ++ char buf[BUFSIZE]; ++ char *p1; ++ int errflag; ++ FILE *iomem; ++ physaddr_t paddr; ++ ulong vaddr; ++ struct syment *sp; ++ char *string; ++ ++ if ((machdep->flags & NEW_VMEMMAP) && ++ ms->kimage_voffset && (sp = kernel_symbol_search("memstart_addr"))) { ++ if (pc->flags & PROC_KCORE) { ++ if ((string = pc->read_vmcoreinfo("NUMBER(PHYS_OFFSET)"))) { ++ ms->phys_offset = htol(string, QUIET, NULL); ++ free(string); ++ return; ++ } ++ vaddr = symbol_value_from_proc_kallsyms("memstart_addr"); ++ if (vaddr == BADVAL) ++ vaddr = sp->value; ++ paddr = KCORE_USE_VADDR; ++ } else { ++ vaddr = sp->value; ++ paddr = sp->value - machdep->machspec->kimage_voffset; ++ } ++ if (READMEM(pc->mfd, &phys_offset, sizeof(phys_offset), ++ vaddr, paddr) > 0) { ++ ms->phys_offset = phys_offset; ++ ++ return; ++ } ++ } ++ ++ if ((iomem = fopen("/proc/iomem", "r")) == NULL) ++ return; ++ ++ /* ++ * Memory regions are sorted in ascending order. We take the ++ * first region which should be correct for most uses. ++ */ ++ errflag = 1; ++ while (fgets(buf, BUFSIZE, iomem)) { ++ if (strstr(buf, ": System RAM")) { ++ clean_line(buf); ++ errflag = 0; ++ break; ++ } ++ } ++ fclose(iomem); ++ ++ if (errflag) ++ return; ++ ++ if (!(p1 = strstr(buf, "-"))) ++ return; ++ ++ *p1 = NULLCHAR; ++ ++ phys_offset = htol(buf, RETURN_ON_ERROR | QUIET, &errflag); ++ if (errflag) ++ return; ++ ++ ms->phys_offset = phys_offset; ++ } else if (DISKDUMP_DUMPFILE() && diskdump_phys_base(&phys_offset)) { ++ ms->phys_offset = phys_offset; ++ } else if (KDUMP_DUMPFILE() && arm64_kdump_phys_base(&phys_offset)) { ++ ms->phys_offset = phys_offset; ++ } else { ++ error(WARNING, ++ "phys_offset cannot be determined from the dumpfile.\n"); ++ error(CONT, ++ "Using default value of 0. If this is not correct, then try\n"); ++ error(CONT, ++ "using the command line option: --machdep phys_offset=\n"); ++ } ++ ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "using %lx as phys_offset\n", ms->phys_offset); ++} ++ ++/* ++ * Determine SECTION_SIZE_BITS either by reading VMCOREINFO or the kernel ++ * config, otherwise use the 64-bit ARM default definiton. ++ */ ++static void ++arm64_get_section_size_bits(void) ++{ ++ int ret; ++ char *string; ++ ++ machdep->section_size_bits = _SECTION_SIZE_BITS; ++ ++ if ((string = pc->read_vmcoreinfo("NUMBER(SECTION_SIZE_BITS)"))) { ++ machdep->section_size_bits = atol(string); ++ free(string); ++ } else if (kt->ikconfig_flags & IKCONFIG_AVAIL) { ++ if ((ret = get_kernel_config("CONFIG_MEMORY_HOTPLUG", NULL)) == IKCONFIG_Y) { ++ if ((ret = get_kernel_config("CONFIG_HOTPLUG_SIZE_BITS", &string)) == IKCONFIG_STR) ++ machdep->section_size_bits = atol(string); ++ } ++ } ++ ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "SECTION_SIZE_BITS: %ld\n", machdep->section_size_bits); ++} ++ ++/* ++ * Determine PHYS_OFFSET either by reading VMCOREINFO or the kernel ++ * symbol, otherwise borrow the 32-bit ARM functionality. ++ */ ++static int ++arm64_kdump_phys_base(ulong *phys_offset) ++{ ++ char *string; ++ struct syment *sp; ++ physaddr_t paddr; ++ ++ if ((string = pc->read_vmcoreinfo("NUMBER(PHYS_OFFSET)"))) { ++ *phys_offset = htol(string, QUIET, NULL); ++ free(string); ++ return TRUE; ++ } ++ ++ if ((machdep->flags & NEW_VMEMMAP) && ++ machdep->machspec->kimage_voffset && ++ (sp = kernel_symbol_search("memstart_addr"))) { ++ paddr = sp->value - machdep->machspec->kimage_voffset; ++ if (READMEM(-1, phys_offset, sizeof(*phys_offset), ++ sp->value, paddr) > 0) ++ return TRUE; ++ } ++ ++ return arm_kdump_phys_base(phys_offset); ++} ++ ++static void ++arm64_init_kernel_pgd(void) ++{ ++ int i; ++ ulong value; ++ ++ if (!kernel_symbol_exists("init_mm") || ++ !readmem(symbol_value("init_mm") + OFFSET(mm_struct_pgd), KVADDR, ++ &value, sizeof(void *), "init_mm.pgd", RETURN_ON_ERROR)) { ++ if (kernel_symbol_exists("swapper_pg_dir")) ++ value = symbol_value("swapper_pg_dir"); ++ else { ++ error(WARNING, "cannot determine kernel pgd location\n"); ++ return; ++ } ++ } ++ ++ for (i = 0; i < NR_CPUS; i++) ++ vt->kernel_pgd[i] = value; ++} ++ ++ulong arm64_PTOV(ulong paddr) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ ++ /* ++ * Either older kernel before kernel has 'physvirt_offset' or newer ++ * kernel which removes 'physvirt_offset' has the same formula: ++ * #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET) ++ */ ++ if (!(machdep->flags & HAS_PHYSVIRT_OFFSET)) ++ return (paddr - ms->phys_offset) | PAGE_OFFSET; ++ else ++ return paddr - ms->physvirt_offset; ++} ++ ++ulong ++arm64_VTOP(ulong addr) ++{ ++ if (machdep->flags & NEW_VMEMMAP) { ++ if (machdep->machspec->VA_START && ++ (addr >= machdep->machspec->kimage_text) && ++ (addr <= machdep->machspec->kimage_end)) { ++ return addr - machdep->machspec->kimage_voffset; ++ } ++ ++ if (addr >= machdep->machspec->page_offset) { ++ if (machdep->flags & HAS_PHYSVIRT_OFFSET) { ++ return addr + machdep->machspec->physvirt_offset; ++ } else { ++ /* ++ * Either older kernel before kernel has 'physvirt_offset' or newer ++ * kernel which removes 'physvirt_offset' has the same formula: ++ * #define __lm_to_phys(addr) (((addr) & ~PAGE_OFFSET) + PHYS_OFFSET) ++ */ ++ return (addr & ~PAGE_OFFSET) + machdep->machspec->phys_offset; ++ } ++ } ++ else if (machdep->machspec->kimage_voffset) ++ return addr - machdep->machspec->kimage_voffset; ++ else /* no randomness */ ++ return machdep->machspec->phys_offset ++ + (addr - machdep->machspec->vmalloc_start_addr); ++ } else { ++ return machdep->machspec->phys_offset ++ + (addr - machdep->machspec->page_offset); ++ } ++} ++ ++static int ++arm64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose) ++{ ++ ulong kernel_pgd; ++ ++ if (!IS_KVADDR(kvaddr)) ++ return FALSE; ++ ++ if (!vt->vmalloc_start) { ++ *paddr = VTOP(kvaddr); ++ return TRUE; ++ } ++ ++ if (!IS_VMALLOC_ADDR(kvaddr)) { ++ *paddr = VTOP(kvaddr); ++ if (!verbose) ++ return TRUE; ++ } ++ ++ kernel_pgd = vt->kernel_pgd[0]; ++ *paddr = 0; ++ ++ switch (machdep->flags & (VM_L2_64K|VM_L3_64K|VM_L3_4K|VM_L4_4K)) ++ { ++ case VM_L2_64K: ++ return arm64_vtop_2level_64k(kernel_pgd, kvaddr, paddr, verbose); ++ case VM_L3_64K: ++ return arm64_vtop_3level_64k(kernel_pgd, kvaddr, paddr, verbose); ++ case VM_L3_4K: ++ return arm64_vtop_3level_4k(kernel_pgd, kvaddr, paddr, verbose); ++ case VM_L4_4K: ++ return arm64_vtop_4level_4k(kernel_pgd, kvaddr, paddr, verbose); ++ default: ++ return FALSE; ++ } ++} ++ ++static int ++arm64_uvtop(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int verbose) ++{ ++ ulong user_pgd; ++ ++ readmem(tc->mm_struct + OFFSET(mm_struct_pgd), KVADDR, ++ &user_pgd, sizeof(long), "user pgd", FAULT_ON_ERROR); ++ ++ *paddr = 0; ++ ++ switch (machdep->flags & (VM_L2_64K|VM_L3_64K|VM_L3_4K|VM_L4_4K)) ++ { ++ case VM_L2_64K: ++ return arm64_vtop_2level_64k(user_pgd, uvaddr, paddr, verbose); ++ case VM_L3_64K: ++ return arm64_vtop_3level_64k(user_pgd, uvaddr, paddr, verbose); ++ case VM_L3_4K: ++ return arm64_vtop_3level_4k(user_pgd, uvaddr, paddr, verbose); ++ case VM_L4_4K: ++ return arm64_vtop_4level_4k(user_pgd, uvaddr, paddr, verbose); ++ default: ++ return FALSE; ++ } ++} ++ ++#define PTE_ADDR_LOW ((((1UL) << (48 - machdep->pageshift)) - 1) << machdep->pageshift) ++#define PTE_ADDR_HIGH ((0xfUL) << 12) ++#define PTE_TO_PHYS(pteval) (machdep->max_physmem_bits == 52 ? \ ++ (((pteval & PTE_ADDR_LOW) | ((pteval & PTE_ADDR_HIGH) << 36))) : (pteval & PTE_ADDR_LOW)) ++ ++#define PUD_TYPE_MASK 3 ++#define PUD_TYPE_SECT 1 ++#define PMD_TYPE_MASK 3 ++#define PMD_TYPE_SECT 1 ++#define PMD_TYPE_TABLE 2 ++#define SECTION_PAGE_MASK_2MB ((long)(~((MEGABYTES(2))-1))) ++#define SECTION_PAGE_MASK_512MB ((long)(~((MEGABYTES(512))-1))) ++#define SECTION_PAGE_MASK_1GB ((long)(~((GIGABYTES(1))-1))) ++ ++static int ++arm64_vtop_2level_64k(ulong pgd, ulong vaddr, physaddr_t *paddr, int verbose) ++{ ++ ulong *pgd_base, *pgd_ptr, pgd_val; ++ ulong *pte_base, *pte_ptr, pte_val; ++ ++ if (verbose) ++ fprintf(fp, "PAGE DIRECTORY: %lx\n", pgd); ++ ++ pgd_base = (ulong *)pgd; ++ 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); ++ if (!pgd_val) ++ goto no_page; ++ ++ /* ++ * #define __PAGETABLE_PUD_FOLDED ++ * #define __PAGETABLE_PMD_FOLDED ++ */ ++ ++ if ((pgd_val & PMD_TYPE_MASK) == PMD_TYPE_SECT) { ++ ulong sectionbase = (pgd_val & SECTION_PAGE_MASK_512MB) & PHYS_MASK; ++ if (verbose) { ++ fprintf(fp, " PAGE: %lx (512MB)\n\n", sectionbase); ++ arm64_translate_pte(pgd_val, 0, 0); ++ } ++ *paddr = sectionbase + (vaddr & ~SECTION_PAGE_MASK_512MB); ++ return TRUE; ++ } ++ ++ pte_base = (ulong *)PTOV(pgd_val & PHYS_MASK & (s32)machdep->pagemask); ++ FILL_PTBL(pte_base, KVADDR, PTRS_PER_PTE_L2_64K * sizeof(ulong)); ++ pte_ptr = pte_base + (((vaddr) >> machdep->pageshift) & (PTRS_PER_PTE_L2_64K - 1)); ++ pte_val = ULONG(machdep->ptbl + PAGEOFFSET(pte_ptr)); ++ if (verbose) ++ fprintf(fp, " PTE: %lx => %lx\n", (ulong)pte_ptr, pte_val); ++ if (!pte_val) ++ goto no_page; ++ ++ if (pte_val & PTE_VALID) { ++ *paddr = (PAGEBASE(pte_val) & PHYS_MASK) + PAGEOFFSET(vaddr); ++ if (verbose) { ++ fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(*paddr)); ++ arm64_translate_pte(pte_val, 0, 0); ++ } ++ } else { ++ if (IS_UVADDR(vaddr, NULL)) ++ *paddr = pte_val; ++ if (verbose) { ++ fprintf(fp, "\n"); ++ arm64_translate_pte(pte_val, 0, 0); ++ } ++ goto no_page; ++ } ++ ++ return TRUE; ++no_page: ++ return FALSE; ++} ++ ++static int ++arm64_vtop_3level_64k(ulong pgd, ulong vaddr, physaddr_t *paddr, int verbose) ++{ ++ ulong *pgd_base, *pgd_ptr, pgd_val; ++ ulong *pmd_base, *pmd_ptr, pmd_val; ++ ulong *pte_base, *pte_ptr, pte_val; ++ ++ if (verbose) ++ fprintf(fp, "PAGE DIRECTORY: %lx\n", pgd); ++ ++ pgd_base = (ulong *)pgd; ++ 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); ++ if (!pgd_val) ++ goto no_page; ++ ++ /* ++ * #define __PAGETABLE_PUD_FOLDED ++ */ ++ ++ pmd_base = (ulong *)PTOV(PTE_TO_PHYS(pgd_val)); ++ FILL_PMD(pmd_base, KVADDR, PTRS_PER_PMD_L3_64K * sizeof(ulong)); ++ pmd_ptr = pmd_base + (((vaddr) >> PMD_SHIFT_L3_64K) & (PTRS_PER_PMD_L3_64K - 1)); ++ pmd_val = ULONG(machdep->pmd + PAGEOFFSET(pmd_ptr)); ++ if (verbose) ++ fprintf(fp, " PMD: %lx => %lx\n", (ulong)pmd_ptr, pmd_val); ++ if (!pmd_val) ++ goto no_page; ++ ++ if ((pmd_val & PMD_TYPE_MASK) == PMD_TYPE_SECT) { ++ ulong sectionbase = PTE_TO_PHYS(pmd_val) & SECTION_PAGE_MASK_512MB; ++ if (verbose) { ++ fprintf(fp, " PAGE: %lx (512MB)\n\n", sectionbase); ++ arm64_translate_pte(pmd_val, 0, 0); ++ } ++ *paddr = sectionbase + (vaddr & ~SECTION_PAGE_MASK_512MB); ++ return TRUE; ++ } ++ ++ pte_base = (ulong *)PTOV(PTE_TO_PHYS(pmd_val)); ++ FILL_PTBL(pte_base, KVADDR, PTRS_PER_PTE_L3_64K * sizeof(ulong)); ++ pte_ptr = pte_base + (((vaddr) >> machdep->pageshift) & (PTRS_PER_PTE_L3_64K - 1)); ++ pte_val = ULONG(machdep->ptbl + PAGEOFFSET(pte_ptr)); ++ if (verbose) ++ fprintf(fp, " PTE: %lx => %lx\n", (ulong)pte_ptr, pte_val); ++ if (!pte_val) ++ goto no_page; ++ ++ if (pte_val & PTE_VALID) { ++ *paddr = PTE_TO_PHYS(pte_val) + PAGEOFFSET(vaddr); ++ if (verbose) { ++ fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(*paddr)); ++ arm64_translate_pte(pte_val, 0, 0); ++ } ++ } else { ++ if (IS_UVADDR(vaddr, NULL)) ++ *paddr = pte_val; ++ if (verbose) { ++ fprintf(fp, "\n"); ++ arm64_translate_pte(pte_val, 0, 0); ++ } ++ goto no_page; ++ } ++ ++ return TRUE; ++no_page: ++ return FALSE; ++} ++ ++static int ++arm64_vtop_3level_4k(ulong pgd, ulong vaddr, physaddr_t *paddr, int verbose) ++{ ++ ulong *pgd_base, *pgd_ptr, pgd_val; ++ ulong *pmd_base, *pmd_ptr, pmd_val; ++ ulong *pte_base, *pte_ptr, pte_val; ++ ++ if (verbose) ++ fprintf(fp, "PAGE DIRECTORY: %lx\n", pgd); ++ ++ pgd_base = (ulong *)pgd; ++ FILL_PGD(pgd_base, KVADDR, PTRS_PER_PGD_L3_4K * sizeof(ulong)); ++ pgd_ptr = pgd_base + (((vaddr) >> PGDIR_SHIFT_L3_4K) & (PTRS_PER_PGD_L3_4K - 1)); ++ pgd_val = ULONG(machdep->pgd + PAGEOFFSET(pgd_ptr)); ++ if (verbose) ++ fprintf(fp, " PGD: %lx => %lx\n", (ulong)pgd_ptr, pgd_val); ++ if (!pgd_val) ++ goto no_page; ++ ++ if ((pgd_val & PUD_TYPE_MASK) == PUD_TYPE_SECT) { ++ ulong sectionbase = (pgd_val & SECTION_PAGE_MASK_1GB) & PHYS_MASK; ++ if (verbose) { ++ fprintf(fp, " PAGE: %lx (1GB)\n\n", sectionbase); ++ arm64_translate_pte(pgd_val, 0, 0); ++ } ++ *paddr = sectionbase + (vaddr & ~SECTION_PAGE_MASK_1GB); ++ return TRUE; ++ } ++ /* ++ * #define __PAGETABLE_PUD_FOLDED ++ */ ++ ++ pmd_base = (ulong *)PTOV(pgd_val & PHYS_MASK & (s32)machdep->pagemask); ++ FILL_PMD(pmd_base, KVADDR, PTRS_PER_PMD_L3_4K * sizeof(ulong)); ++ pmd_ptr = pmd_base + (((vaddr) >> PMD_SHIFT_L3_4K) & (PTRS_PER_PMD_L3_4K - 1)); ++ pmd_val = ULONG(machdep->pmd + PAGEOFFSET(pmd_ptr)); ++ if (verbose) ++ fprintf(fp, " PMD: %lx => %lx\n", (ulong)pmd_ptr, pmd_val); ++ if (!pmd_val) ++ goto no_page; ++ ++ if ((pmd_val & PMD_TYPE_MASK) == PMD_TYPE_SECT) { ++ ulong sectionbase = (pmd_val & SECTION_PAGE_MASK_2MB) & PHYS_MASK; ++ if (verbose) { ++ fprintf(fp, " PAGE: %lx (2MB)\n\n", sectionbase); ++ arm64_translate_pte(pmd_val, 0, 0); ++ } ++ *paddr = sectionbase + (vaddr & ~SECTION_PAGE_MASK_2MB); ++ return TRUE; ++ } ++ ++ pte_base = (ulong *)PTOV(pmd_val & PHYS_MASK & (s32)machdep->pagemask); ++ FILL_PTBL(pte_base, KVADDR, PTRS_PER_PTE_L3_4K * sizeof(ulong)); ++ pte_ptr = pte_base + (((vaddr) >> machdep->pageshift) & (PTRS_PER_PTE_L3_4K - 1)); ++ pte_val = ULONG(machdep->ptbl + PAGEOFFSET(pte_ptr)); ++ if (verbose) ++ fprintf(fp, " PTE: %lx => %lx\n", (ulong)pte_ptr, pte_val); ++ if (!pte_val) ++ goto no_page; ++ ++ if (pte_val & PTE_VALID) { ++ *paddr = (PAGEBASE(pte_val) & PHYS_MASK) + PAGEOFFSET(vaddr); ++ if (verbose) { ++ fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(*paddr)); ++ arm64_translate_pte(pte_val, 0, 0); ++ } ++ } else { ++ if (IS_UVADDR(vaddr, NULL)) ++ *paddr = pte_val; ++ if (verbose) { ++ fprintf(fp, "\n"); ++ arm64_translate_pte(pte_val, 0, 0); ++ } ++ goto no_page; ++ } ++ ++ return TRUE; ++no_page: ++ return FALSE; ++} ++ ++static int ++arm64_vtop_4level_4k(ulong pgd, ulong vaddr, physaddr_t *paddr, int verbose) ++{ ++ ulong *pgd_base, *pgd_ptr, pgd_val; ++ ulong *pud_base, *pud_ptr, pud_val; ++ ulong *pmd_base, *pmd_ptr, pmd_val; ++ ulong *pte_base, *pte_ptr, pte_val; ++ ++ if (verbose) ++ fprintf(fp, "PAGE DIRECTORY: %lx\n", pgd); ++ ++ pgd_base = (ulong *)pgd; ++ FILL_PGD(pgd_base, KVADDR, PTRS_PER_PGD_L4_4K * sizeof(ulong)); ++ pgd_ptr = pgd_base + (((vaddr) >> PGDIR_SHIFT_L4_4K) & (PTRS_PER_PGD_L4_4K - 1)); ++ pgd_val = ULONG(machdep->pgd + PGDIR_OFFSET_48VA(pgd_ptr)); ++ if (verbose) ++ fprintf(fp, " PGD: %lx => %lx\n", (ulong)pgd_ptr, pgd_val); ++ if (!pgd_val) ++ goto no_page; ++ ++ pud_base = (ulong *)PTOV(pgd_val & PHYS_MASK & PGDIR_MASK_48VA); ++ ++ FILL_PUD(pud_base, KVADDR, PTRS_PER_PUD_L4_4K * sizeof(ulong)); ++ pud_ptr = pud_base + (((vaddr) >> PUD_SHIFT_L4_4K) & (PTRS_PER_PUD_L4_4K - 1)); ++ pud_val = ULONG(machdep->pud + PAGEOFFSET(pud_ptr)); ++ if (verbose) ++ fprintf(fp, " PUD: %lx => %lx\n", (ulong)pud_ptr, pud_val); ++ if (!pud_val) ++ goto no_page; ++ ++ pmd_base = (ulong *)PTOV(pud_val & PHYS_MASK & (s32)machdep->pagemask); ++ FILL_PMD(pmd_base, KVADDR, PTRS_PER_PMD_L4_4K * sizeof(ulong)); ++ pmd_ptr = pmd_base + (((vaddr) >> PMD_SHIFT_L4_4K) & (PTRS_PER_PMD_L4_4K - 1)); ++ pmd_val = ULONG(machdep->pmd + PAGEOFFSET(pmd_ptr)); ++ if (verbose) ++ fprintf(fp, " PMD: %lx => %lx\n", (ulong)pmd_ptr, pmd_val); ++ if (!pmd_val) ++ goto no_page; ++ ++ if ((pmd_val & PMD_TYPE_MASK) == PMD_TYPE_SECT) { ++ ulong sectionbase = (pmd_val & SECTION_PAGE_MASK_2MB) & PHYS_MASK; ++ if (verbose) { ++ fprintf(fp, " PAGE: %lx (2MB)\n\n", sectionbase); ++ arm64_translate_pte(pmd_val, 0, 0); ++ } ++ *paddr = sectionbase + (vaddr & ~SECTION_PAGE_MASK_2MB); ++ return TRUE; ++ } ++ ++ pte_base = (ulong *)PTOV(pmd_val & PHYS_MASK & (s32)machdep->pagemask); ++ FILL_PTBL(pte_base, KVADDR, PTRS_PER_PTE_L4_4K * sizeof(ulong)); ++ pte_ptr = pte_base + (((vaddr) >> machdep->pageshift) & (PTRS_PER_PTE_L4_4K - 1)); ++ pte_val = ULONG(machdep->ptbl + PAGEOFFSET(pte_ptr)); ++ if (verbose) ++ fprintf(fp, " PTE: %lx => %lx\n", (ulong)pte_ptr, pte_val); ++ if (!pte_val) ++ goto no_page; ++ ++ if (pte_val & PTE_VALID) { ++ *paddr = (PAGEBASE(pte_val) & PHYS_MASK) + PAGEOFFSET(vaddr); ++ if (verbose) { ++ fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(*paddr)); ++ arm64_translate_pte(pte_val, 0, 0); ++ } ++ } else { ++ if (IS_UVADDR(vaddr, NULL)) ++ *paddr = pte_val; ++ if (verbose) { ++ fprintf(fp, "\n"); ++ arm64_translate_pte(pte_val, 0, 0); ++ } ++ goto no_page; ++ } ++ ++ return TRUE; ++no_page: ++ return FALSE; ++} ++ ++static ulong ++arm64_get_task_pgd(ulong task) ++{ ++ struct task_context *tc; ++ ulong pgd; ++ ++ if ((tc = task_to_context(task)) && ++ readmem(tc->mm_struct + OFFSET(mm_struct_pgd), KVADDR, ++ &pgd, sizeof(long), "user pgd", RETURN_ON_ERROR)) ++ return pgd; ++ else ++ return NO_TASK; ++} ++ ++static ulong ++arm64_processor_speed(void) ++{ ++ return 0; ++}; ++ ++/* ++ * Gather IRQ stack values. ++ */ ++static void ++arm64_irq_stack_init(void) ++{ ++ int i; ++ struct syment *sp; ++ struct gnu_request request, *req; ++ struct machine_specific *ms = machdep->machspec; ++ ulong p, sz; ++ req = &request; ++ ++ if (symbol_exists("irq_stack") && ++ (sp = per_cpu_symbol_search("irq_stack")) && ++ get_symbol_type("irq_stack", NULL, req)) { ++ /* before v4.14 or CONFIG_VMAP_STACK disabled */ ++ if (CRASHDEBUG(1)) { ++ fprintf(fp, "irq_stack: \n"); ++ fprintf(fp, " type: %s\n", ++ (req->typecode == TYPE_CODE_ARRAY) ? ++ "TYPE_CODE_ARRAY" : "other"); ++ fprintf(fp, " target_typecode: %s\n", ++ req->target_typecode == TYPE_CODE_INT ? ++ "TYPE_CODE_INT" : "other"); ++ fprintf(fp, " target_length: %ld\n", ++ req->target_length); ++ fprintf(fp, " length: %ld\n", req->length); ++ } ++ ++ if (!(ms->irq_stacks = (ulong *)malloc((size_t)(kt->cpus * sizeof(ulong))))) ++ error(FATAL, "cannot malloc irq_stack addresses\n"); ++ ms->irq_stack_size = req->length; ++ machdep->flags |= IRQ_STACKS; ++ ++ for (i = 0; i < kt->cpus; i++) ++ ms->irq_stacks[i] = kt->__per_cpu_offset[i] + sp->value; ++ } else if (symbol_exists("irq_stack_ptr") && ++ (sp = per_cpu_symbol_search("irq_stack_ptr")) && ++ get_symbol_type("irq_stack_ptr", NULL, req)) { ++ /* v4.14 and later with CONFIG_VMAP_STACK enabled */ ++ if (CRASHDEBUG(1)) { ++ fprintf(fp, "irq_stack_ptr: \n"); ++ fprintf(fp, " type: %x, %s\n", ++ (int)req->typecode, ++ (req->typecode == TYPE_CODE_PTR) ? ++ "TYPE_CODE_PTR" : "other"); ++ fprintf(fp, " target_typecode: %x, %s\n", ++ (int)req->target_typecode, ++ req->target_typecode == TYPE_CODE_INT ? ++ "TYPE_CODE_INT" : "other"); ++ fprintf(fp, " target_length: %ld\n", ++ req->target_length); ++ fprintf(fp, " length: %ld\n", req->length); ++ } ++ ++ if (!(ms->irq_stacks = (ulong *)malloc((size_t)(kt->cpus * sizeof(ulong))))) ++ error(FATAL, "cannot malloc irq_stack addresses\n"); ++ ++ /* ++ * Determining the IRQ_STACK_SIZE is tricky, but for now ++ * 4.14 kernel has: ++ * ++ * #define IRQ_STACK_SIZE THREAD_SIZE ++ * ++ * and finding a solid usage of THREAD_SIZE is hard, but: ++ * ++ * union thread_union { ++ * ... ++ * unsigned long stack[THREAD_SIZE/sizeof(long)]; ++ * }; ++ */ ++ if (MEMBER_EXISTS("thread_union", "stack")) { ++ if ((sz = MEMBER_SIZE("thread_union", "stack")) > 0) ++ ms->irq_stack_size = sz; ++ } else ++ ms->irq_stack_size = ARM64_IRQ_STACK_SIZE; ++ ++ machdep->flags |= IRQ_STACKS; ++ ++ for (i = 0; i < kt->cpus; i++) { ++ p = kt->__per_cpu_offset[i] + sp->value; ++ readmem(p, KVADDR, &(ms->irq_stacks[i]), sizeof(ulong), ++ "IRQ stack pointer", RETURN_ON_ERROR); ++ } ++ } ++} ++ ++/* ++ * Gather IRQ stack values. ++ */ ++static void ++arm64_sdei_stack_init(void) ++{ ++ int i; ++ struct syment *sp; ++ struct gnu_request request, *req; ++ struct machine_specific *ms = machdep->machspec; ++ ulong p, sz; ++ req = &request; ++ ++ if (symbol_exists("sdei_stack_normal_ptr") && ++ (sp = per_cpu_symbol_search("sdei_stack_normal_ptr")) && ++ get_symbol_type("sdei_stack_normal_ptr", NULL, req)) { ++ /* v4.14 and later with CONFIG_VMAP_STACK enabled */ ++ if (CRASHDEBUG(1)) { ++ fprintf(fp, "sdei_stack_normal_ptr: \n"); ++ fprintf(fp, " type: %x, %s\n", ++ (int)req->typecode, ++ (req->typecode == TYPE_CODE_PTR) ? ++ "TYPE_CODE_PTR" : "other"); ++ fprintf(fp, " target_typecode: %x, %s\n", ++ (int)req->target_typecode, ++ req->target_typecode == TYPE_CODE_INT ? ++ "TYPE_CODE_INT" : "other"); ++ fprintf(fp, " target_length: %ld\n", ++ req->target_length); ++ fprintf(fp, " length: %ld\n", req->length); ++ } ++ ++ if (!(ms->sdei_stacks = (ulong *)malloc((size_t)(kt->cpus * sizeof(ulong))))) ++ error(FATAL, "cannot malloc irq_stack addresses\n"); ++ ++ /* ++ * Determining the IRQ_STACK_SIZE is tricky, but for now ++ * 4.14 kernel has: ++ * ++ * #define IRQ_STACK_SIZE THREAD_SIZE ++ * ++ * and finding a solid usage of THREAD_SIZE is hard, but: ++ * ++ * union thread_union { ++ * ... ++ * unsigned long stack[THREAD_SIZE/sizeof(long)]; ++ * }; ++ */ ++ if (MEMBER_EXISTS("thread_union", "stack")) { ++ if ((sz = MEMBER_SIZE("thread_union", "stack")) > 0) ++ ms->sdei_stack_size = sz; ++ } else ++ ms->sdei_stack_size = ARM64_IRQ_STACK_SIZE; ++ ++ machdep->flags |= IRQ_STACKS; ++ ++ for (i = 0; i < kt->cpus; i++) { ++ p = kt->__per_cpu_offset[i] + sp->value; ++ readmem(p, KVADDR, &(ms->sdei_stacks[i]), sizeof(ulong), ++ "SDEI stack pointer", RETURN_ON_ERROR); ++ } ++ } ++} ++ ++/* ++ * Gather and verify all of the backtrace requirements. ++ */ ++static void ++arm64_stackframe_init(void) ++{ ++ long task_struct_thread; ++ long thread_struct_cpu_context; ++ long context_sp, context_pc, context_fp; ++ struct syment *sp1, *sp1n, *sp2, *sp2n, *sp3, *sp3n; ++ ++ STRUCT_SIZE_INIT(note_buf, "note_buf_t"); ++ STRUCT_SIZE_INIT(elf_prstatus, "elf_prstatus"); ++ MEMBER_OFFSET_INIT(elf_prstatus_pr_pid, "elf_prstatus", "pr_pid"); ++ MEMBER_OFFSET_INIT(elf_prstatus_pr_reg, "elf_prstatus", "pr_reg"); ++ ++ if (MEMBER_EXISTS("pt_regs", "stackframe")) { ++ machdep->machspec->user_eframe_offset = SIZE(pt_regs); ++ machdep->machspec->kern_eframe_offset = SIZE(pt_regs) - 16; ++ } else { ++ machdep->machspec->user_eframe_offset = SIZE(pt_regs) + 16; ++ machdep->machspec->kern_eframe_offset = SIZE(pt_regs); ++ } ++ ++ if ((sp1 = kernel_symbol_search("__exception_text_start")) && ++ (sp2 = kernel_symbol_search("__exception_text_end"))) { ++ machdep->machspec->__exception_text_start = sp1->value; ++ machdep->machspec->__exception_text_end = sp2->value; ++ } ++ if ((sp1 = kernel_symbol_search("__irqentry_text_start")) && ++ (sp2 = kernel_symbol_search("__irqentry_text_end"))) { ++ machdep->machspec->__irqentry_text_start = sp1->value; ++ machdep->machspec->__irqentry_text_end = sp2->value; ++ } ++ if ((sp1 = kernel_symbol_search("vectors")) && ++ (sp1n = kernel_symbol_search("cpu_switch_to")) && ++ (sp2 = kernel_symbol_search("ret_fast_syscall")) && ++ (sp2n = kernel_symbol_search("sys_rt_sigreturn_wrapper"))) { ++ machdep->machspec->exp_entry1_start = sp1->value; ++ machdep->machspec->exp_entry1_end = sp1n->value; ++ machdep->machspec->exp_entry2_start = sp2->value; ++ machdep->machspec->exp_entry2_end = sp2n->value; ++ } ++ ++ if ((sp1 = kernel_symbol_search("crash_kexec")) && ++ (sp1n = next_symbol(NULL, sp1)) && ++ (sp2 = kernel_symbol_search("crash_save_cpu")) && ++ (sp2n = next_symbol(NULL, sp2)) && ++ (sp3 = kernel_symbol_search("machine_kexec")) && ++ (sp3n = next_symbol(NULL, sp3))) { ++ machdep->machspec->crash_kexec_start = sp1->value; ++ machdep->machspec->crash_kexec_end = sp1n->value; ++ machdep->machspec->crash_save_cpu_start = sp2->value; ++ machdep->machspec->crash_save_cpu_end = sp2n->value; ++ machdep->machspec->machine_kexec_start = sp3->value; ++ machdep->machspec->machine_kexec_end = sp3n->value; ++ machdep->flags |= KDUMP_ENABLED; ++ } ++ ++ task_struct_thread = MEMBER_OFFSET("task_struct", "thread"); ++ thread_struct_cpu_context = MEMBER_OFFSET("thread_struct", "cpu_context"); ++ ++ if ((task_struct_thread == INVALID_OFFSET) || ++ (thread_struct_cpu_context == INVALID_OFFSET)) { ++ error(INFO, ++ "cannot determine task_struct.thread.context offset\n"); ++ return; ++ } ++ ++ /* ++ * Pay for the convenience of using a hardcopy of a kernel structure. ++ */ ++ if (offsetof(struct arm64_stackframe, sp) != ++ MEMBER_OFFSET("stackframe", "sp")) { ++ if (CRASHDEBUG(1)) ++ error(INFO, "builtin stackframe.sp offset differs from kernel version\n"); ++ } ++ if (offsetof(struct arm64_stackframe, fp) != ++ MEMBER_OFFSET("stackframe", "fp")) { ++ if (CRASHDEBUG(1)) ++ error(INFO, "builtin stackframe.fp offset differs from kernel version\n"); ++ } ++ if (offsetof(struct arm64_stackframe, pc) != ++ MEMBER_OFFSET("stackframe", "pc")) { ++ if (CRASHDEBUG(1)) ++ error(INFO, "builtin stackframe.pc offset differs from kernel version\n"); ++ } ++ if (!MEMBER_EXISTS("stackframe", "sp")) ++ machdep->flags |= UNW_4_14; ++ ++ context_sp = MEMBER_OFFSET("cpu_context", "sp"); ++ context_fp = MEMBER_OFFSET("cpu_context", "fp"); ++ context_pc = MEMBER_OFFSET("cpu_context", "pc"); ++ if (context_sp == INVALID_OFFSET) { ++ error(INFO, "cannot determine cpu_context.sp offset\n"); ++ return; ++ } ++ if (context_fp == INVALID_OFFSET) { ++ error(INFO, "cannot determine cpu_context.fp offset\n"); ++ return; ++ } ++ if (context_pc == INVALID_OFFSET) { ++ error(INFO, "cannot determine cpu_context.pc offset\n"); ++ return; ++ } ++ ASSIGN_OFFSET(task_struct_thread_context_sp) = ++ task_struct_thread + thread_struct_cpu_context + context_sp; ++ ASSIGN_OFFSET(task_struct_thread_context_fp) = ++ task_struct_thread + thread_struct_cpu_context + context_fp; ++ ASSIGN_OFFSET(task_struct_thread_context_pc) = ++ task_struct_thread + thread_struct_cpu_context + context_pc; ++} ++ ++#define KERNEL_MODE (1) ++#define USER_MODE (2) ++ ++#define USER_EFRAME_OFFSET (machdep->machspec->user_eframe_offset) ++#define KERN_EFRAME_OFFSET (machdep->machspec->kern_eframe_offset) ++ ++/* ++ * PSR bits ++ */ ++#define PSR_MODE_EL0t 0x00000000 ++#define PSR_MODE_EL1t 0x00000004 ++#define PSR_MODE_EL1h 0x00000005 ++#define PSR_MODE_EL2t 0x00000008 ++#define PSR_MODE_EL2h 0x00000009 ++#define PSR_MODE_EL3t 0x0000000c ++#define PSR_MODE_EL3h 0x0000000d ++#define PSR_MODE_MASK 0x0000000f ++ ++/* Architecturally defined mapping between AArch32 and AArch64 registers */ ++#define compat_usr(x) regs[(x)] ++#define compat_fp regs[11] ++#define compat_sp regs[13] ++#define compat_lr regs[14] ++ ++#define user_mode(ptregs) \ ++ (((ptregs)->pstate & PSR_MODE_MASK) == PSR_MODE_EL0t) ++ ++#define compat_user_mode(ptregs) \ ++ (((ptregs)->pstate & (PSR_MODE32_BIT | PSR_MODE_MASK)) == \ ++ (PSR_MODE32_BIT | PSR_MODE_EL0t)) ++ ++#define user_stack_pointer(ptregs) \ ++ (!compat_user_mode(ptregs) ? (ptregs)->sp : (ptregs)->compat_sp) ++ ++#define user_frame_pointer(ptregs) \ ++ (!compat_user_mode(ptregs) ? (ptregs)->regs[29] : (ptregs)->compat_fp) ++ ++static int ++arm64_is_kernel_exception_frame(struct bt_info *bt, ulong stkptr) ++{ ++ struct arm64_pt_regs *regs; ++ struct machine_specific *ms = machdep->machspec; ++ ++ regs = (struct arm64_pt_regs *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(stkptr))]; ++ ++ if (INSTACK(regs->sp, bt) && INSTACK(regs->regs[29], bt) && ++ !(regs->pstate & (0xffffffff00000000ULL | PSR_MODE32_BIT)) && ++ is_kernel_text(regs->pc) && ++ is_kernel_text(regs->regs[30] | ms->CONFIG_ARM64_KERNELPACMASK)) { ++ switch (regs->pstate & PSR_MODE_MASK) ++ { ++ case PSR_MODE_EL1t: ++ case PSR_MODE_EL1h: ++ case PSR_MODE_EL2t: ++ case PSR_MODE_EL2h: ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ ++static int ++arm64_eframe_search(struct bt_info *bt) ++{ ++ int c; ++ ulong ptr, count; ++ struct machine_specific *ms; ++ ++ if (bt->flags & BT_EFRAME_SEARCH2) { ++ if (!(machdep->flags & IRQ_STACKS)) ++ error(FATAL, "IRQ stacks do not exist in this kernel\n"); ++ ++ ms = machdep->machspec; ++ ++ for (c = 0; c < kt->cpus; c++) { ++ if ((bt->flags & BT_CPUMASK) && ++ !(NUM_IN_BITMAP(bt->cpumask, c))) ++ continue; ++ ++ fprintf(fp, "CPU %d IRQ STACK:", c); ++ bt->stackbase = ms->irq_stacks[c]; ++ bt->stacktop = bt->stackbase + ms->irq_stack_size; ++ alter_stackbuf(bt); ++ count = 0; ++ ++ for (ptr = bt->stackbase; ptr < bt->stacktop - SIZE(pt_regs); ptr++) { ++ if (arm64_is_kernel_exception_frame(bt, ptr)) { ++ fprintf(fp, "%s\nKERNEL-MODE EXCEPTION FRAME AT: %lx\n", ++ count ? "" : "\n", ptr); ++ arm64_print_exception_frame(bt, ptr, KERNEL_MODE, fp); ++ count++; ++ } ++ } ++ ++ if (count) ++ fprintf(fp, "\n"); ++ else ++ fprintf(fp, "(none found)\n\n"); ++ } ++ ++ return 0; ++ } ++ ++ ++ count = 0; ++ for (ptr = bt->stackbase; ptr < bt->stacktop - SIZE(pt_regs); ptr++) { ++ if (arm64_is_kernel_exception_frame(bt, ptr)) { ++ fprintf(fp, "\nKERNEL-MODE EXCEPTION FRAME AT: %lx\n", ptr); ++ arm64_print_exception_frame(bt, ptr, KERNEL_MODE, fp); ++ count++; ++ } ++ } ++ ++ if (is_kernel_thread(bt->tc->task)) ++ return count; ++ ++ ptr = bt->stacktop - USER_EFRAME_OFFSET; ++ fprintf(fp, "%sUSER-MODE EXCEPTION FRAME AT: %lx\n", ++ count++ ? "\n" : "", ptr); ++ arm64_print_exception_frame(bt, ptr, USER_MODE, fp); ++ ++ return count; ++} ++ ++static char *arm64_exception_functions[] = { ++ "do_undefinstr", ++ "do_sysinstr", ++ "do_debug_exception", ++ "do_mem_abort", ++ "do_el0_irq_bp_hardening", ++ "do_sp_pc_abort", ++ NULL ++}; ++ ++static int ++arm64_in_exception_text(ulong ptr) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ char *name, **func; ++ ++ if (ms->__irqentry_text_start && ms->__irqentry_text_end && ++ ((ptr >= ms->__irqentry_text_start) && ++ (ptr < ms->__irqentry_text_end))) ++ return TRUE; ++ ++ if (ms->__exception_text_start && ms->__exception_text_end) { ++ if ((ptr >= ms->__exception_text_start) && ++ (ptr < ms->__exception_text_end)) ++ return TRUE; ++ } else if ((name = closest_symbol(ptr))) { /* Linux 5.5 and later */ ++ for (func = &arm64_exception_functions[0]; *func; func++) { ++ if (STREQ(name, *func)) ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ ++static int ++arm64_in_exp_entry(ulong addr) ++{ ++ struct machine_specific *ms; ++ ++ ms = machdep->machspec; ++ if ((ms->exp_entry1_start <= addr) && (addr < ms->exp_entry1_end)) ++ return TRUE; ++ if ((ms->exp_entry2_start <= addr) && (addr < ms->exp_entry2_end)) ++ return TRUE; ++ return FALSE; ++} ++ ++#define BACKTRACE_CONTINUE (1) ++#define BACKTRACE_COMPLETE_KERNEL (2) ++#define BACKTRACE_COMPLETE_USER (3) ++ ++static int ++arm64_print_stackframe_entry(struct bt_info *bt, int level, struct arm64_stackframe *frame, FILE *ofp) ++{ ++ char *name, *name_plus_offset; ++ ulong branch_pc, symbol_offset; ++ struct syment *sp; ++ struct load_module *lm; ++ char buf[BUFSIZE]; ++ ++ /* ++ * if pc comes from a saved lr, it actually points to an instruction ++ * after branch. To avoid any confusion, decrement pc by 4. ++ * See, for example, "bl schedule" before ret_to_user(). ++ */ ++ branch_pc = frame->pc - 4; ++ ++ name = closest_symbol(branch_pc); ++ name_plus_offset = NULL; ++ ++ if (bt->flags & BT_SYMBOL_OFFSET) { ++ sp = value_search(branch_pc, &symbol_offset); ++ if (sp && symbol_offset) ++ name_plus_offset = ++ value_to_symstr(branch_pc, buf, bt->radix); ++ } ++ ++ if (!INSTACK(frame->fp, bt) && IN_TASK_VMA(bt->task, frame->fp)) ++ frame->fp = 0; ++ ++ if (bt->flags & BT_FULL) { ++ if (level) ++ arm64_display_full_frame(bt, frame->fp); ++ bt->frameptr = frame->fp; ++ } ++ ++ fprintf(ofp, "%s#%d [%8lx] %s at %lx", level < 10 ? " " : "", level, ++ frame->fp ? frame->fp : bt->stacktop - USER_EFRAME_OFFSET, ++ name_plus_offset ? name_plus_offset : name, branch_pc); ++ ++ if (BT_REFERENCE_CHECK(bt)) { ++ arm64_do_bt_reference_check(bt, frame->pc, closest_symbol(frame->pc)); ++ arm64_do_bt_reference_check(bt, branch_pc, name); ++ } ++ ++ if (module_symbol(branch_pc, NULL, &lm, NULL, 0)) ++ fprintf(ofp, " [%s]", lm->mod_name); ++ ++ fprintf(ofp, "\n"); ++ ++ if (bt->flags & BT_LINE_NUMBERS) { ++ get_line_number(branch_pc, buf, FALSE); ++ if (strlen(buf)) ++ fprintf(ofp, " %s\n", buf); ++ } ++ ++ if (STREQ(name, "start_kernel") || STREQ(name, "secondary_start_kernel") || ++ STREQ(name, "kthread") || STREQ(name, "kthreadd")) ++ return BACKTRACE_COMPLETE_KERNEL; ++ ++ return BACKTRACE_CONTINUE; ++} ++ ++static int ++arm64_print_stackframe_entry_v2(struct bt_info *bt, int level, struct arm64_stackframe *frame, FILE *ofp) ++{ ++ char *name, *name_plus_offset; ++ ulong pc, symbol_offset; ++ struct syment *sp; ++ struct load_module *lm; ++ char buf[BUFSIZE]; ++ ++ /* ++ * if pc comes from a saved lr, it actually points to an instruction ++ * after branch. To avoid any confusion, decrement pc by 4. ++ * See, for example, "bl schedule" before ret_to_user(). ++ */ ++ pc = frame->pc - 0x4; ++ name = closest_symbol(pc); ++ name_plus_offset = NULL; ++ ++ if (bt->flags & BT_SYMBOL_OFFSET) { ++ sp = value_search(pc, &symbol_offset); ++ if (sp && symbol_offset) ++ name_plus_offset = value_to_symstr(pc, buf, bt->radix); ++ } ++ ++ if (bt->flags & BT_USER_EFRAME) ++ frame->fp = 0; ++ ++ fprintf(ofp, "%s#%d [%8lx] %s at %lx", level < 10 ? " " : "", level, ++ frame->fp ? frame->fp : bt->stacktop - USER_EFRAME_OFFSET, ++ name_plus_offset ? name_plus_offset : name, pc); ++ ++ if (BT_REFERENCE_CHECK(bt)) ++ arm64_do_bt_reference_check(bt, pc, name); ++ ++ if (module_symbol(pc, NULL, &lm, NULL, 0)) ++ fprintf(ofp, " [%s]", lm->mod_name); ++ ++ fprintf(ofp, "\n"); ++ ++ if (bt->flags & BT_LINE_NUMBERS) { ++ get_line_number(pc, buf, FALSE); ++ if (strlen(buf)) ++ fprintf(ofp, " %s\n", buf); ++ } ++ ++ if (STREQ(name, "start_kernel") || ++ STREQ(name, "secondary_start_kernel") || ++ STREQ(name, "kthread") || STREQ(name, "kthreadd")) ++ return BACKTRACE_COMPLETE_KERNEL; ++ ++ return BACKTRACE_CONTINUE; ++} ++ ++static void ++arm64_display_full_frame(struct bt_info *bt, ulong sp) ++{ ++ int i, u_idx; ++ ulong *up; ++ ulong words, addr; ++ char buf[BUFSIZE]; ++ ++ if (bt->frameptr == sp) ++ return; ++ ++ if (INSTACK(bt->frameptr, bt)) { ++ if (INSTACK(sp, bt)) { ++ ; /* normal case */ ++ } else { ++ if (sp == 0) ++ /* interrupt in user mode */ ++ sp = bt->stacktop - USER_EFRAME_OFFSET; ++ else ++ /* interrupt in kernel mode */ ++ sp = bt->stacktop; ++ } ++ } else { ++ /* This is a transition case from irq to process stack. */ ++ return; ++ } ++ ++ words = (sp - bt->frameptr) / sizeof(ulong); ++ ++ addr = bt->frameptr; ++ u_idx = (bt->frameptr - bt->stackbase)/sizeof(ulong); ++ for (i = 0; i < words; i++, u_idx++) { ++ if (!(i & 1)) ++ fprintf(fp, "%s %lx: ", i ? "\n" : "", addr); ++ ++ up = (ulong *)(&bt->stackbuf[u_idx*sizeof(ulong)]); ++ fprintf(fp, "%s ", format_stack_entry(bt, buf, *up, 0)); ++ ++ addr += sizeof(ulong); ++ } ++ fprintf(fp, "\n"); ++} ++ ++static void ++arm64_display_full_frame_v2(struct bt_info *bt, struct arm64_stackframe *cur, ++ struct arm64_stackframe *next) ++{ ++ struct machine_specific *ms; ++ ulong next_fp, stackbase; ++ char *stackbuf; ++ int i, u_idx; ++ ulong *up; ++ ulong words, addr; ++ char buf[BUFSIZE]; ++ ++ stackbase = bt->stackbase; ++ stackbuf = bt->stackbuf; ++ ms = machdep->machspec; ++ ++ /* Calc next fp for dump */ ++ if (next->fp == 0) ++ /* last stackframe on kernel tack */ ++ next_fp = bt->stacktop - 0x10; ++ else if (!INSTACK(cur->sp, bt)) { ++ /* We have just switched over stacks */ ++ next_fp = ms->irq_stacks[bt->tc->processor] ++ + ms->irq_stack_size - 0x10; ++ ++ /* ++ * We are already buffering a process stack. ++ * So use an old buffer for IRQ stack. ++ */ ++ stackbase = ms->irq_stacks[bt->tc->processor]; ++ stackbuf = ms->irq_stackbuf; ++ } else ++ next_fp = next->fp; ++ ++ if (CRASHDEBUG(1)) ++ fprintf(fp, " frame <%016lx:%016lx>\n", cur->fp, next_fp); ++ ++ /* Check here because we want to see a debug message above. */ ++ if (!(bt->flags & BT_FULL)) ++ return; ++ if (next_fp <= cur->fp) ++ return; ++ ++ /* Dump */ ++ words = (next_fp - cur->fp) / sizeof(ulong); ++ addr = cur->fp; ++ u_idx = (cur->fp - stackbase)/sizeof(ulong); ++ for (i = 0; i < words; i++, u_idx++) { ++ if (!(i & 1)) ++ fprintf(fp, "%s %lx: ", i ? "\n" : "", addr); ++ ++ up = (ulong *)(&stackbuf[u_idx*sizeof(ulong)]); ++ fprintf(fp, "%s ", format_stack_entry(bt, buf, *up, 0)); ++ ++ addr += sizeof(ulong); ++ } ++ fprintf(fp, "\n"); ++ ++ if (stackbuf == ms->irq_stackbuf) ++ FREEBUF(stackbuf); ++} ++ ++static int ++arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame) ++{ ++ unsigned long high, low, fp; ++ unsigned long stack_mask; ++ unsigned long irq_stack_ptr, orig_sp, sdei_stack_ptr; ++ struct arm64_pt_regs *ptregs; ++ struct machine_specific *ms = machdep->machspec; ++ ++ stack_mask = (unsigned long)(ARM64_STACK_SIZE) - 1; ++ fp = frame->fp; ++ ++ low = frame->sp; ++ high = (low + stack_mask) & ~(stack_mask); ++ ++ if (fp < low || fp > high || fp & 0xf) ++ return FALSE; ++ ++ frame->sp = fp + 0x10; ++ frame->fp = GET_STACK_ULONG(fp); ++ frame->pc = GET_STACK_ULONG(fp + 8); ++ if (is_kernel_text(frame->pc | ms->CONFIG_ARM64_KERNELPACMASK)) ++ frame->pc |= ms->CONFIG_ARM64_KERNELPACMASK; ++ ++ if ((frame->fp == 0) && (frame->pc == 0)) ++ return FALSE; ++ ++ if (!(machdep->flags & IRQ_STACKS)) ++ return TRUE; ++ ++ if (!(machdep->flags & IRQ_STACKS)) ++ return TRUE; ++ ++ if (machdep->flags & UNW_4_14) { ++ if ((bt->flags & BT_IRQSTACK) && ++ !arm64_on_irq_stack(bt->tc->processor, frame->fp) && ++ !arm64_in_sdei_normal_stack(bt->tc->processor, frame->fp)) { ++ if (arm64_on_process_stack(bt, frame->fp)) { ++ arm64_set_process_stack(bt); ++ ++ frame->sp = frame->fp - KERN_EFRAME_OFFSET; ++ /* ++ * for switch_stack ++ * fp still points to irq stack ++ */ ++ bt->bptr = fp; ++ /* ++ * for display_full_frame ++ * sp points to process stack ++ * ++ * If we want to see pt_regs, ++ * comment out the below. ++ * bt->frameptr = frame->sp; ++ */ ++ } else { ++ /* irq -> user */ ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++ } ++ ++ /* ++ * The kernel's manner of determining the end of the IRQ stack: ++ * ++ * #define THREAD_SIZE 16384 ++ * #define THREAD_START_SP (THREAD_SIZE - 16) ++ * #define IRQ_STACK_START_SP THREAD_START_SP ++ * #define IRQ_STACK_PTR(cpu) ((unsigned long)per_cpu(irq_stack, cpu) + IRQ_STACK_START_SP) ++ * #define IRQ_STACK_TO_TASK_STACK(ptr) (*((unsigned long *)((ptr) - 0x08))) ++ * ++ * irq_stack_ptr = IRQ_STACK_PTR(raw_smp_processor_id()); ++ * orig_sp = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr); (pt_regs pointer on process stack) ++ */ ++ irq_stack_ptr = ms->irq_stacks[bt->tc->processor] + ms->irq_stack_size - 16; ++ sdei_stack_ptr = ms->sdei_stacks[bt->tc->processor] + ms->sdei_stack_size - 16; ++ ++ if (frame->sp == irq_stack_ptr) { ++ orig_sp = GET_STACK_ULONG(irq_stack_ptr - 8); ++ arm64_set_process_stack(bt); ++ if (INSTACK(orig_sp, bt) && (INSTACK(frame->fp, bt) || (frame->fp == 0))) { ++ ptregs = (struct arm64_pt_regs *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(orig_sp))]; ++ frame->sp = orig_sp; ++ frame->pc = ptregs->pc; ++ bt->bptr = fp; ++ if (CRASHDEBUG(1)) ++ error(INFO, ++ "arm64_unwind_frame: switch stacks: fp: %lx sp: %lx pc: %lx\n", ++ frame->fp, frame->sp, frame->pc); ++ } else { ++ error(WARNING, ++ "arm64_unwind_frame: on IRQ stack: oriq_sp: %lx%s fp: %lx%s\n", ++ orig_sp, INSTACK(orig_sp, bt) ? "" : " (?)", ++ frame->fp, INSTACK(frame->fp, bt) ? "" : " (?)"); ++ return FALSE; ++ } ++ } else if (frame->sp == sdei_stack_ptr) { ++ orig_sp = GET_STACK_ULONG(sdei_stack_ptr - 8); ++ arm64_set_process_stack(bt); ++ if (INSTACK(orig_sp, bt) && (INSTACK(frame->fp, bt) || (frame->fp == 0))) { ++ ptregs = (struct arm64_pt_regs *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(orig_sp))]; ++ frame->sp = orig_sp; ++ frame->pc = ptregs->pc; ++ bt->bptr = fp; ++ if (CRASHDEBUG(1)) ++ error(INFO, ++ "arm64_unwind_frame: switch stacks: fp: %lx sp: %lx pc: %lx\n", ++ frame->fp, frame->sp, frame->pc); ++ } else { ++ error(WARNING, ++ "arm64_unwind_frame: on IRQ stack: oriq_sp: %lx%s fp: %lx%s\n", ++ orig_sp, INSTACK(orig_sp, bt) ? "" : " (?)", ++ frame->fp, INSTACK(frame->fp, bt) ? "" : " (?)"); ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++} ++ ++/* ++ * The following figure shows how unwinding can be done. ++ * Here we assume that the callstack order is: ++ * #(X-1) ppc (previous PC) ++ * #X cpc (current PC) ++ * < #(X+ 1) epc (Exception entry) > ++ * #(X+1/2) npc (Next PC) ++ * #(X+2/3) Npc (One before Next) ++ * #(X+3/4) NNpc (One before 'Npc') ++ * and unwind frames from #X to #(X+1). ++ * When we add a faked frame for exception entry (exception frame) ++ * as #(X+1), the next frame for npc will be recognized as #(x+2). ++ * ++ * (1)Normal stackframe: ++ * +------+ ++ * | pfp | ++ * | cpc | ++ * psp + + ++ * | | ++ * | | ++ * pfp +------+ <--- :prev stackframe = ++ * | cfp | ++ * | npc | ++ * csp + + ++ * | | ++ * | | ++ * cfp +------+ <--- :curr stackframe = ++ * | nfp | cfp = *pfp ++ * | Npc | csp = pfp + 0x10 ++ * nsp + + ++ * | | ++ * | | ++ * nfp +------+ <--- :next stackframe = ++ * | | ++ * ++ * (2)Exception on the same (IRQ or process) stack: ++ * +------+ ++ * | pfp | ++ * | cpc | ++ * psp + + ++ * | | ++ * | | ++ * pfp +------+ <--- :prev stackframe = ++ * | cfp | ++ * | npc | ++ * csp + + ++ * | | ++ * | | ++ * cfp +------+ <--- :curr stackframe = ++ * | nfp | ++ * | epc | ++ * + + ++ * | | ++ * | | faked(*) ++ * esp +------+ <--- :excp stackframe = <---, esp, epc ++ * | | esp = nsp - sizeof(pt_regs) ++ * | | ++ * | Npc | (*) If we didn't add this frame, the next frame ++ * | nfp | would be ++ * | nsp | ++ * | npc | and the frame below for npc would be lost. ++ * nsp + + ++ * | | ++ * nfp +------+ <--- :task stackframe = ++ * | Nfp | ++ * | NNpc | ++ * Nsp + + ++ * | | ++ * Nfp +------+ <--- :task stackframe = ++ * | NNfp | ++ * ++ * (3)Interrupt: ++ * +------+ ++ * | cfp | ++ * | ipc | ++ * csp + + ++ * | | ++ * | | ++ * cfp +------+ <--- :curr stackframe = ++ * | ifp | ++ * | epc | ++ * isp + + ++ * | | ++ * | | (*) ++ * ifp +------+ <--- :irq stackframe = ++ * | nfp | ifp == IRQ_STACK_PTR ++ * | esp | (*) Before the kernel enters an irq handler, frame ++ * top +------+ pointer moves to the top of IRQ stack. ++ * IRQ stack So we have to skip this frame in unwinding. ++ * ++ * faked ++ * esp +------+ <--- :excp stackframe = <---, esp, epc> ++ * | | esp = nsp - sizeof(pt_regs) ++ * | | ++ * | Npc | ++ * | nfp | ++ * | nsp | ++ * | npc | ++ * nsp + + ++ * | | ++ * nfp +------+ <--- :task stackframe = ++ * | Nfp | ++ * | NNpc | ++ * Nsp + + ++ * | | ++ * Nfp +------+ <--- :task stackframe = ++ * | NNfp | ++ */ ++ ++static struct arm64_stackframe ext_frame; ++ ++static int ++arm64_unwind_frame_v2(struct bt_info *bt, struct arm64_stackframe *frame, ++ FILE *ofp) ++{ ++ unsigned long high, low, fp; ++ unsigned long stack_mask; ++ unsigned long irq_stack_ptr; ++ struct machine_specific *ms; ++ ++ stack_mask = (unsigned long)(ARM64_STACK_SIZE) - 1; ++ fp = frame->fp; ++ ++ low = frame->sp; ++ high = (low + stack_mask) & ~(stack_mask); ++ ++ if (fp < low || fp > high || fp & 0xf) ++ return FALSE; ++ ++ if (CRASHDEBUG(1)) ++ fprintf(ofp, " cur fp:%016lx sp:%016lx pc:%016lx\n", ++ frame->fp, frame->sp, frame->pc); ++ ++ if (ext_frame.pc) { ++ /* ++ * The previous frame was a dummy for exception entry. ++ * So complement a missing (task) stackframe now. ++ */ ++ frame->fp = ext_frame.fp; ++ frame->sp = ext_frame.sp; ++ frame->pc = ext_frame.pc; ++ ++ ext_frame.pc = 0; /* back to normal unwinding */ ++ ++ goto unwind_done; ++ } ++ ++ frame->pc = GET_STACK_ULONG(fp + 8); ++ if (!arm64_in_exp_entry(frame->pc)) { ++ /* (1) Normal stack frame */ ++ ++ frame->sp = fp + 0x10; ++ frame->fp = GET_STACK_ULONG(fp); ++ } else { ++ /* ++ * We are in exception entry code, and so ++ * - add a faked frame for exception entry, and ++ * - prepare for a stackframe hidden by exception ++ */ ++ ++ ext_frame.fp = GET_STACK_ULONG(fp); ++ /* ++ * Note: ++ * In the following code, we determine a stack pointer for ++ * exception entry based on ext_frame.fp because we have ++ * no way to know a ext_frame.sp. ++ * Fortunately, this will work fine for most functions ++ * in the kernel. ++ */ ++ if (ext_frame.fp == 0) { ++ /* ++ * (2) ++ * Either on process stack or on IRQ stack, ++ * the next frame is the last one on process stack. ++ */ ++ ++ frame->sp = bt->stacktop ++ - sizeof(struct arm64_pt_regs) - 0x10; ++ frame->fp = frame->sp; ++ } else if (!arm64_on_irq_stack(bt->tc->processor, frame->sp)) { ++ /* ++ * (2) ++ * We are on process stack. Just add a faked frame ++ */ ++ ++ if (!arm64_on_irq_stack(bt->tc->processor, ext_frame.fp)) ++ frame->sp = ext_frame.fp ++ - sizeof(struct arm64_pt_regs); ++ else { ++ /* ++ * FIXME: very exceptional case ++ * We are already back on process stack, but ++ * a saved frame pointer indicates that we are ++ * on IRQ stack. Unfortunately this can happen ++ * when some functions are called after ++ * an irq handler is done because irq_exit() ++ * doesn't restore a frame pointer (x29). ++ * Those functions include ++ * - do_notify_resume() ++ * - trace_hardirqs_off() ++ * - schedule() ++ * ++ * We have no perfect way to determine a true ++ * stack pointer value here. ++ * 0x20 is a stackframe size of schedule(). ++ * Really ugly ++ */ ++ frame->sp = frame->fp + 0x20; ++ fprintf(ofp, " (Next exception frame might be wrong)\n"); ++ } ++ ++ frame->fp = frame->sp; ++ } else { ++ /* We are on IRQ stack */ ++ ++ ms = machdep->machspec; ++ irq_stack_ptr = ms->irq_stacks[bt->tc->processor] ++ + ms->irq_stack_size - 0x20; ++ if (ext_frame.fp != irq_stack_ptr) { ++ /* (2) Just add a faked frame */ ++ ++ frame->sp = ext_frame.fp ++ - sizeof(struct arm64_pt_regs); ++ frame->fp = frame->sp; ++ } else { ++ /* ++ * (3) ++ * Switch from IRQ stack to process stack ++ */ ++ ++ frame->sp = GET_STACK_ULONG(irq_stack_ptr + 8); ++ frame->fp = frame->sp; ++ ++ /* ++ * Keep a buffer for a while until ++ * displaying the last frame on IRQ stack ++ * at next arm64_print_stackframe_entry_v2() ++ */ ++ if (bt->flags & BT_FULL) ++ ms->irq_stackbuf = bt->stackbuf; ++ ++ arm64_set_process_stack(bt); ++ } ++ } ++ ++ /* prepare for a stackframe hidden by exception */ ++ arm64_gen_hidden_frame(bt, frame->sp, &ext_frame); ++ } ++ ++unwind_done: ++ if (CRASHDEBUG(1)) ++ fprintf(ofp, " nxt fp:%016lx sp:%016lx pc:%016lx\n", ++ frame->fp, frame->sp, frame->pc); ++ ++ return TRUE; ++} ++ ++/* ++ * A layout of a stack frame in a function looks like: ++ * ++ * stack grows to lower addresses. ++ * /|\ ++ * | ++ * | | ++ * new sp +------+ <--- ++ * |dyn | | ++ * | vars | | ++ * new fp +- - - + | ++ * |old fp| | a function's stack frame ++ * |old lr| | ++ * |static| | ++ * | vars| | ++ * old sp +------+ <--- ++ * |dyn | ++ * | vars | ++ * old fp +------+ ++ * | | ++ * ++ * - On function entry, sp is decremented down to new fp. ++ * ++ * - and old fp and sp are saved into this stack frame. ++ * "Static" local variables are allocated at the same time. ++ * ++ * - Later on, "dynamic" local variables may be allocated on a stack. ++ * But those dynamic variables are rarely used in the kernel image, ++ * and, as a matter of fact, sp is equal to fp in almost all functions. ++ * (not 100% though.) ++ * ++ * - Currently, sp is determined in arm64_unwind_frame() by ++ * sp = a callee's fp + 0x10 ++ * where 0x10 stands for a saved area for fp and sp ++ * ++ * - As you can see, however, this calculated sp still points to the top of ++ * callee's static local variables and doesn't match with a *real* sp. ++ * ++ * - So, generally, dumping a stack from this calculated sp to the next frame's ++ * sp shows "callee's static local variables", old fp and sp. ++ * ++ * Diagram and explanation courtesy of Takahiro Akashi ++ */ ++ ++static void ++arm64_back_trace_cmd(struct bt_info *bt) ++{ ++ struct arm64_stackframe stackframe; ++ int level; ++ ulong exception_frame; ++ FILE *ofp; ++ ++ if (bt->flags & BT_OPT_BACK_TRACE) { ++ if (machdep->flags & UNW_4_14) { ++ option_not_supported('o'); ++ return; ++ } ++ ++ arm64_back_trace_cmd_v2(bt); ++ return; ++ } ++ ++ ofp = BT_REFERENCE_CHECK(bt) ? pc->nullfp : fp; ++ ++ /* ++ * stackframes are created from 3 contiguous stack addresses: ++ * ++ * x: contains stackframe.fp -- points to next triplet ++ * x+8: contains stackframe.pc -- text return address ++ * x+16: is the stackframe.sp address ++ */ ++ ++ if (bt->flags & BT_KDUMP_ADJUST) { ++ if (arm64_on_irq_stack(bt->tc->processor, bt->bptr)) { ++ arm64_set_irq_stack(bt); ++ bt->flags |= BT_IRQSTACK; ++ } ++ if (arm64_in_sdei_normal_stack(bt->tc->processor, bt->bptr)) { ++ arm64_set_sdei_normal_stack(bt); ++ bt->flags |= BT_IRQSTACK; ++ } ++ stackframe.fp = GET_STACK_ULONG(bt->bptr - 8); ++ stackframe.pc = GET_STACK_ULONG(bt->bptr); ++ stackframe.sp = bt->bptr + 8; ++ bt->frameptr = stackframe.sp; ++ } else if (bt->hp && bt->hp->esp) { ++ if (arm64_on_irq_stack(bt->tc->processor, bt->hp->esp)) { ++ arm64_set_irq_stack(bt); ++ bt->flags |= BT_IRQSTACK; ++ } ++ if (arm64_in_sdei_normal_stack(bt->tc->processor, bt->hp->esp)) { ++ arm64_set_sdei_normal_stack(bt); ++ bt->flags |= BT_IRQSTACK; ++ } ++ stackframe.fp = GET_STACK_ULONG(bt->hp->esp - 8); ++ stackframe.pc = bt->hp->eip ? ++ bt->hp->eip : GET_STACK_ULONG(bt->hp->esp); ++ stackframe.sp = bt->hp->esp + 8; ++ bt->flags &= ~BT_REGS_NOT_FOUND; ++ } else { ++ if (arm64_on_irq_stack(bt->tc->processor, bt->frameptr)) { ++ arm64_set_irq_stack(bt); ++ bt->flags |= BT_IRQSTACK; ++ } ++ if (arm64_in_sdei_normal_stack(bt->tc->processor, bt->frameptr)) { ++ arm64_set_sdei_normal_stack(bt); ++ bt->flags |= BT_IRQSTACK; ++ } ++ stackframe.sp = bt->stkptr; ++ stackframe.pc = bt->instptr; ++ stackframe.fp = bt->frameptr; ++ } ++ ++ if (bt->flags & BT_TEXT_SYMBOLS) { ++ arm64_print_text_symbols(bt, &stackframe, ofp); ++ if (BT_REFERENCE_FOUND(bt)) { ++ print_task_header(fp, task_to_context(bt->task), 0); ++ arm64_print_text_symbols(bt, &stackframe, fp); ++ fprintf(fp, "\n"); ++ } ++ return; ++ } ++ ++ if (bt->flags & BT_REGS_NOT_FOUND) ++ return; ++ ++ if (!(bt->flags & BT_KDUMP_ADJUST)) { ++ if (bt->flags & BT_USER_SPACE) ++ goto complete_user; ++ ++ if (DUMPFILE() && is_task_active(bt->task)) { ++ exception_frame = stackframe.fp - KERN_EFRAME_OFFSET; ++ if (arm64_is_kernel_exception_frame(bt, exception_frame)) ++ arm64_print_exception_frame(bt, exception_frame, ++ KERNEL_MODE, ofp); ++ } ++ } ++ ++ level = exception_frame = 0; ++ while (1) { ++ bt->instptr = stackframe.pc; ++ ++ switch (arm64_print_stackframe_entry(bt, level, &stackframe, ofp)) ++ { ++ case BACKTRACE_COMPLETE_KERNEL: ++ return; ++ case BACKTRACE_COMPLETE_USER: ++ goto complete_user; ++ case BACKTRACE_CONTINUE: ++ break; ++ } ++ ++ if (exception_frame) { ++ arm64_print_exception_frame(bt, exception_frame, KERNEL_MODE, ofp); ++ exception_frame = 0; ++ } ++ ++ if (!arm64_unwind_frame(bt, &stackframe)) ++ break; ++ ++ if (arm64_in_exception_text(bt->instptr) && INSTACK(stackframe.fp, bt)) { ++ if (!(bt->flags & BT_IRQSTACK) || ++ ((stackframe.sp + SIZE(pt_regs)) < bt->stacktop)) { ++ if (arm64_is_kernel_exception_frame(bt, stackframe.fp - KERN_EFRAME_OFFSET)) ++ exception_frame = stackframe.fp - KERN_EFRAME_OFFSET; ++ } ++ } ++ ++ if ((bt->flags & BT_IRQSTACK) && ++ !arm64_on_irq_stack(bt->tc->processor, stackframe.fp) && ++ !arm64_in_sdei_normal_stack(bt->tc->processor, stackframe.fp)) { ++ bt->flags &= ~BT_IRQSTACK; ++ if (arm64_switch_stack(bt, &stackframe, ofp) == USER_MODE) ++ break; ++ } ++ ++ ++ level++; ++ } ++ ++ if (is_kernel_thread(bt->tc->task)) ++ return; ++ ++complete_user: ++ exception_frame = bt->stacktop - USER_EFRAME_OFFSET; ++ arm64_print_exception_frame(bt, exception_frame, USER_MODE, ofp); ++ if ((bt->flags & (BT_USER_SPACE|BT_KDUMP_ADJUST)) == BT_USER_SPACE) ++ fprintf(ofp, " #0 [user space]\n"); ++} ++ ++static void ++arm64_back_trace_cmd_v2(struct bt_info *bt) ++{ ++ struct arm64_stackframe stackframe, cur_frame; ++ int level, mode; ++ ulong exception_frame; ++ FILE *ofp; ++ ++ ofp = BT_REFERENCE_CHECK(bt) ? pc->nullfp : fp; ++ ++ /* ++ * stackframes are created from 3 contiguous stack addresses: ++ * ++ * x: contains stackframe.fp -- points to next triplet ++ * x+8: contains stackframe.pc -- text return address ++ * x+16: is the stackframe.sp address ++ */ ++ ++ if (bt->flags & BT_KDUMP_ADJUST) { ++ if (arm64_on_irq_stack(bt->tc->processor, bt->bptr)) { ++ arm64_set_irq_stack(bt); ++ bt->flags |= BT_IRQSTACK; ++ } ++ stackframe.fp = GET_STACK_ULONG(bt->bptr); ++ stackframe.pc = GET_STACK_ULONG(bt->bptr + 8); ++ stackframe.sp = bt->bptr + 16; ++ bt->frameptr = stackframe.fp; ++ } else { ++ if (arm64_on_irq_stack(bt->tc->processor, bt->frameptr)) { ++ arm64_set_irq_stack(bt); ++ bt->flags |= BT_IRQSTACK; ++ } ++ stackframe.sp = bt->stkptr; ++ stackframe.pc = bt->instptr; ++ stackframe.fp = bt->frameptr; ++ } ++ ++ if (bt->flags & BT_TEXT_SYMBOLS) { ++ arm64_print_text_symbols(bt, &stackframe, ofp); ++ if (BT_REFERENCE_FOUND(bt)) { ++ print_task_header(fp, task_to_context(bt->task), 0); ++ arm64_print_text_symbols(bt, &stackframe, fp); ++ fprintf(fp, "\n"); ++ } ++ return; ++ } ++ ++ if (bt->flags & BT_REGS_NOT_FOUND) ++ return; ++ ++ if (!(bt->flags & BT_KDUMP_ADJUST)) { ++ if (bt->flags & BT_USER_SPACE) { ++user_space: ++ exception_frame = bt->stacktop - USER_EFRAME_OFFSET; ++ arm64_print_exception_frame(bt, exception_frame, ++ USER_MODE, ofp); ++// fprintf(ofp, " #0 [user space]\n"); ++ ++ return; ++ } ++ ++ if (DUMPFILE() && is_task_active(bt->task)) { ++ exception_frame = stackframe.fp - SIZE(pt_regs); ++ if (arm64_is_kernel_exception_frame(bt, exception_frame)) ++ arm64_print_exception_frame(bt, exception_frame, ++ KERNEL_MODE, ofp); ++ } ++ } ++ ++ for (level = 0;; level++) { ++ bt->instptr = stackframe.pc; ++ ++ /* ++ * Show one-line stackframe info ++ */ ++ if (arm64_print_stackframe_entry_v2(bt, level, &stackframe, ofp) ++ == BACKTRACE_COMPLETE_KERNEL) ++ break; ++ ++ cur_frame = stackframe; ++ if (!arm64_unwind_frame_v2(bt, &stackframe, ofp)) ++ break; ++ ++ /* ++ * Dump the contents of the current stackframe. ++ * We need to know the next stackframe to determine ++ * the dump range: ++ * ++ */ ++ arm64_display_full_frame_v2(bt, &cur_frame, &stackframe); ++ ++ /* ++ * If we are in a normal stackframe, just continue, ++ * otherwise show an exception frame. ++ * Since exception entry code doesn't have a real ++ * stackframe, we fake a dummy frame here. ++ */ ++ if (!arm64_in_exp_entry(stackframe.pc)) ++ continue; ++ ++ if (!INSTACK(cur_frame.sp, bt)) ++ fprintf(ofp, "--- ---\n"); ++ ++ arm64_print_stackframe_entry_v2(bt, ++level, &stackframe, ofp); ++ if (bt->flags & BT_USER_EFRAME) ++ goto user_space; ++ cur_frame = stackframe; ++ arm64_unwind_frame_v2(bt, &stackframe, ofp); ++ ++ /* ++ * and don't show the contenxts. Instead, ++ * show an exception frame below ++ */ ++ ++ if (!INSTACK(cur_frame.sp, bt)) { ++ /* This check is a safeguard. See unwind_frame(). */ ++ error(WARNING, ++ "stack pointer for exception frame is wrong\n"); ++ return; ++ } ++ mode = (stackframe.pc < machdep->machspec->userspace_top) ? ++ USER_MODE : KERNEL_MODE; ++// fprintf(ofp, "--- ---\n", ++// mode == KERNEL_MODE ? "kernel" : "user"); ++ arm64_print_exception_frame(bt, cur_frame.sp, mode, ofp); ++ ++ if (mode == USER_MODE) ++ break; ++ } ++} ++ ++static void ++arm64_print_text_symbols(struct bt_info *bt, struct arm64_stackframe *frame, FILE *ofp) ++{ ++ int i; ++ ulong *up; ++ struct load_module *lm; ++ char buf1[BUFSIZE]; ++ char buf2[BUFSIZE]; ++ char *name; ++ ulong start; ++ ulong val; ++ struct machine_specific *ms = machdep->machspec; ++ ++ if (bt->flags & BT_TEXT_SYMBOLS_ALL) ++ start = bt->stackbase; ++ else { ++ start = frame->sp - 8; ++ fprintf(ofp, "%sSTART: %s at %lx\n", ++ space(VADDR_PRLEN > 8 ? 14 : 6), ++ bt->flags & BT_SYMBOL_OFFSET ? ++ value_to_symstr(frame->pc, buf2, bt->radix) : ++ closest_symbol(frame->pc), frame->pc); ++ } ++ ++ for (i = (start - bt->stackbase)/sizeof(ulong); i < LONGS_PER_STACK; i++) { ++ up = (ulong *)(&bt->stackbuf[i*sizeof(ulong)]); ++ val = *up; ++ if (is_kernel_text(val | ms->CONFIG_ARM64_KERNELPACMASK)) { ++ val |= ms->CONFIG_ARM64_KERNELPACMASK; ++ name = closest_symbol(val); ++ fprintf(ofp, " %s[%s] %s at %lx", ++ bt->flags & BT_ERROR_MASK ? ++ " " : "", ++ mkstring(buf1, VADDR_PRLEN, ++ RJUST|LONG_HEX, ++ MKSTR(bt->stackbase + ++ (i * sizeof(long)))), ++ bt->flags & BT_SYMBOL_OFFSET ? ++ value_to_symstr(val, buf2, bt->radix) : ++ name, val); ++ if (module_symbol(val, NULL, &lm, NULL, 0)) ++ fprintf(ofp, " [%s]", lm->mod_name); ++ fprintf(ofp, "\n"); ++ if (BT_REFERENCE_CHECK(bt)) ++ arm64_do_bt_reference_check(bt, val, name); ++ } ++ } ++} ++ ++static int ++arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame) ++{ ++ ulong *ptr, *start, *base; ++ struct machine_specific *ms; ++ ulong crash_kexec_frame; ++ ++ if (!(machdep->flags & KDUMP_ENABLED)) ++ return FALSE; ++ ++ base = (ulong *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(bt->stackbase))]; ++ if (bt->flags & BT_USER_SPACE) ++ start = (ulong *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(bt->stacktop))]; ++ else { ++ if (INSTACK(frame->fp, bt)) ++ start = (ulong *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(frame->fp))]; ++ else ++ start = (ulong *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(bt->stacktop))]; ++ } ++ ++ crash_kexec_frame = 0; ++ ms = machdep->machspec; ++ for (ptr = start - 8; ptr >= base; ptr--) { ++ if (bt->flags & BT_OPT_BACK_TRACE) { ++ if ((*ptr > ms->crash_kexec_start) && ++ (*ptr < ms->crash_kexec_end) && ++ INSTACK(*(ptr - 1), bt)) { ++ bt->bptr = ((ulong)(ptr - 1) - (ulong)base) ++ + task_to_stackbase(bt->tc->task); ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "%lx: %lx (crash_kexec)\n", bt->bptr, *ptr); ++ return TRUE; ++ } ++ if ((*ptr > ms->crash_save_cpu_start) && ++ (*ptr < ms->crash_save_cpu_end) && ++ INSTACK(*(ptr - 1), bt)) { ++ bt->bptr = ((ulong)(ptr - 1) - (ulong)base) ++ + task_to_stackbase(bt->tc->task); ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "%lx: %lx (crash_save_cpu)\n", bt->bptr, *ptr); ++ return TRUE; ++ } ++ } else { ++ if ((*ptr > ms->machine_kexec_start) && (*ptr < ms->machine_kexec_end)) { ++ bt->bptr = ((ulong)ptr - (ulong)base) ++ + task_to_stackbase(bt->tc->task); ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "%lx: %lx (machine_kexec)\n", bt->bptr, *ptr); ++ return TRUE; ++ } ++ if ((*ptr > ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) { ++ /* ++ * Stash the first crash_kexec frame in case the machine_kexec ++ * frame is not found. ++ */ ++ if (!crash_kexec_frame) { ++ crash_kexec_frame = ((ulong)ptr - (ulong)base) ++ + task_to_stackbase(bt->tc->task); ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "%lx: %lx (crash_kexec)\n", ++ bt->bptr, *ptr); ++ } ++ continue; ++ } ++ if ((*ptr > ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) { ++ bt->bptr = ((ulong)ptr - (ulong)base) ++ + task_to_stackbase(bt->tc->task); ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "%lx: %lx (crash_save_cpu)\n", bt->bptr, *ptr); ++ return TRUE; ++ } ++ } ++ } ++ ++ if (crash_kexec_frame) { ++ bt->bptr = crash_kexec_frame; ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++static int ++arm64_in_kdump_text_on_sdei_stack(struct bt_info *bt) ++{ ++ int cpu; ++ ulong stackbase; ++ char *stackbuf; ++ ulong *ptr, *start, *base; ++ struct machine_specific *ms; ++ ++ if ((machdep->flags & (IRQ_STACKS|KDUMP_ENABLED)) != (IRQ_STACKS|KDUMP_ENABLED)) ++ return FALSE; ++ ++ ms = machdep->machspec; ++ if (!ms->sdei_stacks) ++ return FALSE; ++ cpu = bt->tc->processor; ++ stackbase = ms->sdei_stacks[cpu]; ++ stackbuf = GETBUF(ms->sdei_stack_size); ++ ++ if (!readmem(stackbase, KVADDR, stackbuf, ++ ms->sdei_stack_size, "IRQ stack contents", RETURN_ON_ERROR)) { ++ error(INFO, "read of IRQ stack at %lx failed\n", stackbase); ++ FREEBUF(stackbuf); ++ return FALSE; ++ } ++ ++ base = (ulong *)stackbuf; ++ start = (ulong *)(stackbuf + ms->sdei_stack_size); ++ ++ for (ptr = start - 8; ptr >= base; ptr--) { ++ if (bt->flags & BT_OPT_BACK_TRACE) { ++ if ((*ptr > ms->crash_kexec_start) && ++ (*ptr < ms->crash_kexec_end) && ++ INSTACK(*(ptr - 1), bt)) { ++ bt->bptr = ((ulong)(ptr - 1) - (ulong)base) + stackbase; ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "%lx: %lx (crash_kexec on IRQ stack)\n", ++ bt->bptr, *ptr); ++ FREEBUF(stackbuf); ++ return TRUE; ++ } ++ if ((*ptr > ms->crash_save_cpu_start) && ++ (*ptr < ms->crash_save_cpu_end) && ++ INSTACK(*(ptr - 1), bt)) { ++ bt->bptr = ((ulong)(ptr - 1) - (ulong)base) + stackbase; ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "%lx: %lx (crash_save_cpu on IRQ stack)\n", ++ bt->bptr, *ptr); ++ FREEBUF(stackbuf); ++ return TRUE; ++ } ++ } else { ++ if ((*ptr > ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) { ++ bt->bptr = ((ulong)ptr - (ulong)base) + stackbase; ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "%lx: %lx (crash_kexec on IRQ stack)\n", ++ bt->bptr, *ptr); ++ FREEBUF(stackbuf); ++ return TRUE; ++ } ++ if ((*ptr > ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) { ++ bt->bptr = ((ulong)ptr - (ulong)base) + stackbase; ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "%lx: %lx (crash_save_cpu on IRQ stack)\n", ++ bt->bptr, *ptr); ++ FREEBUF(stackbuf); ++ return TRUE; ++ } ++ } ++ } ++ ++ FREEBUF(stackbuf); ++ return FALSE; ++} ++ ++static int ++arm64_in_kdump_text_on_irq_stack(struct bt_info *bt) ++{ ++ int cpu; ++ ulong stackbase; ++ char *stackbuf; ++ ulong *ptr, *start, *base; ++ struct machine_specific *ms; ++ ++ if ((machdep->flags & (IRQ_STACKS|KDUMP_ENABLED)) != (IRQ_STACKS|KDUMP_ENABLED)) ++ return FALSE; ++ ++ ms = machdep->machspec; ++ cpu = bt->tc->processor; ++ stackbase = ms->irq_stacks[cpu]; ++ stackbuf = GETBUF(ms->irq_stack_size); ++ ++ if (!readmem(stackbase, KVADDR, stackbuf, ++ ms->irq_stack_size, "IRQ stack contents", RETURN_ON_ERROR)) { ++ error(INFO, "read of IRQ stack at %lx failed\n", stackbase); ++ FREEBUF(stackbuf); ++ return FALSE; ++ } ++ ++ base = (ulong *)stackbuf; ++ start = (ulong *)(stackbuf + ms->irq_stack_size); ++ ++ for (ptr = start - 8; ptr >= base; ptr--) { ++ if (bt->flags & BT_OPT_BACK_TRACE) { ++ if ((*ptr > ms->crash_kexec_start) && ++ (*ptr < ms->crash_kexec_end) && ++ INSTACK(*(ptr - 1), bt)) { ++ bt->bptr = ((ulong)(ptr - 1) - (ulong)base) + stackbase; ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "%lx: %lx (crash_kexec on IRQ stack)\n", ++ bt->bptr, *ptr); ++ FREEBUF(stackbuf); ++ return TRUE; ++ } ++ if ((*ptr > ms->crash_save_cpu_start) && ++ (*ptr < ms->crash_save_cpu_end) && ++ INSTACK(*(ptr - 1), bt)) { ++ bt->bptr = ((ulong)(ptr - 1) - (ulong)base) + stackbase; ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "%lx: %lx (crash_save_cpu on IRQ stack)\n", ++ bt->bptr, *ptr); ++ FREEBUF(stackbuf); ++ return TRUE; ++ } ++ } else { ++ if ((*ptr > ms->crash_kexec_start) && (*ptr < ms->crash_kexec_end)) { ++ bt->bptr = ((ulong)ptr - (ulong)base) + stackbase; ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "%lx: %lx (crash_kexec on IRQ stack)\n", ++ bt->bptr, *ptr); ++ FREEBUF(stackbuf); ++ return TRUE; ++ } ++ if ((*ptr > ms->crash_save_cpu_start) && (*ptr < ms->crash_save_cpu_end)) { ++ bt->bptr = ((ulong)ptr - (ulong)base) + stackbase; ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "%lx: %lx (crash_save_cpu on IRQ stack)\n", ++ bt->bptr, *ptr); ++ FREEBUF(stackbuf); ++ return TRUE; ++ } ++ } ++ } ++ ++ FREEBUF(stackbuf); ++ return FALSE; ++} ++ ++static int ++arm64_switch_stack(struct bt_info *bt, struct arm64_stackframe *frame, FILE *ofp) ++{ ++ int i; ++ ulong stacktop, words, addr; ++ ulong *stackbuf; ++ char buf[BUFSIZE]; ++ struct machine_specific *ms = machdep->machspec; ++ ++ if (bt->flags & BT_FULL) { ++ stacktop = ms->irq_stacks[bt->tc->processor] + ms->irq_stack_size; ++ words = (stacktop - bt->bptr) / sizeof(ulong); ++ stackbuf = (ulong *)GETBUF(words * sizeof(ulong)); ++ readmem(bt->bptr, KVADDR, stackbuf, words * sizeof(long), ++ "top of IRQ stack", FAULT_ON_ERROR); ++ ++ addr = bt->bptr; ++ for (i = 0; i < words; i++) { ++ if (!(i & 1)) ++ fprintf(ofp, "%s %lx: ", i ? "\n" : "", addr); ++ fprintf(ofp, "%s ", format_stack_entry(bt, buf, stackbuf[i], 0)); ++ addr += sizeof(ulong); ++ } ++ fprintf(ofp, "\n"); ++ FREEBUF(stackbuf); ++ } ++ fprintf(ofp, "--- ---\n"); ++ ++ if (frame->fp == 0) ++ return USER_MODE; ++ ++ if (!(machdep->flags & UNW_4_14)) ++ arm64_print_exception_frame(bt, frame->sp, KERNEL_MODE, ofp); ++ ++ return KERNEL_MODE; ++} ++ ++static int ++arm64_get_dumpfile_stackframe(struct bt_info *bt, struct arm64_stackframe *frame) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ struct arm64_pt_regs *ptregs; ++ ++ if (!ms->panic_task_regs || ++ (!ms->panic_task_regs[bt->tc->processor].sp && ++ !ms->panic_task_regs[bt->tc->processor].pc)) { ++ bt->flags |= BT_REGS_NOT_FOUND; ++ return FALSE; ++ } ++ ++ ptregs = &ms->panic_task_regs[bt->tc->processor]; ++ frame->pc = ptregs->pc; ++ if (user_mode(ptregs)) { ++ frame->sp = user_stack_pointer(ptregs); ++ frame->fp = user_frame_pointer(ptregs); ++ if (is_kernel_text(frame->pc) || ++ !in_user_stack(bt->tc->task, frame->sp)) { ++ error(WARNING, ++ "corrupt NT_PRSTATUS? pstate: 0x%lx, but no user frame found\n", ++ ptregs->pstate); ++ if (is_kernel_text(frame->pc) && ++ INSTACK(frame->sp, bt) && INSTACK(frame->fp, bt)) ++ goto try_kernel; ++ bt->flags |= BT_REGS_NOT_FOUND; ++ return FALSE; ++ } ++ bt->flags |= BT_USER_SPACE; ++ } else { ++try_kernel: ++ frame->sp = ptregs->sp; ++ frame->fp = ptregs->regs[29]; ++ } ++ ++ if (arm64_in_kdump_text(bt, frame) || ++ arm64_in_kdump_text_on_irq_stack(bt) || ++ arm64_in_kdump_text_on_sdei_stack(bt)) ++ bt->flags |= BT_KDUMP_ADJUST; ++ ++ return TRUE; ++} ++ ++static int ++arm64_get_stackframe(struct bt_info *bt, struct arm64_stackframe *frame) ++{ ++ if (!fill_task_struct(bt->task)) ++ return FALSE; ++ ++ frame->sp = ULONG(tt->task_struct + OFFSET(task_struct_thread_context_sp)); ++ frame->pc = ULONG(tt->task_struct + OFFSET(task_struct_thread_context_pc)); ++ frame->fp = ULONG(tt->task_struct + OFFSET(task_struct_thread_context_fp)); ++ ++ return TRUE; ++} ++ ++static void ++arm64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp) ++{ ++ int ret; ++ struct arm64_stackframe stackframe = { 0 }; ++ ++ if (DUMPFILE() && is_task_active(bt->task)) ++ ret = arm64_get_dumpfile_stackframe(bt, &stackframe); ++ else ++ ret = arm64_get_stackframe(bt, &stackframe); ++ ++ if (!ret) ++ error(WARNING, ++ "cannot determine starting stack frame for task %lx\n", ++ bt->task); ++ ++ bt->frameptr = stackframe.fp; ++ if (pcp) ++ *pcp = stackframe.pc; ++ if (spp) ++ *spp = stackframe.sp; ++} ++ ++static void ++arm64_gen_hidden_frame(struct bt_info *bt, ulong sp, ++ struct arm64_stackframe *frame) ++{ ++ struct arm64_pt_regs *ptregs; ++ ++ if (IN_TASK_VMA(bt->task, sp)) { ++ bt->flags |= BT_USER_EFRAME; ++ return; ++ } ++ ++ ptregs = (struct arm64_pt_regs *) ++ &bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(sp))]; ++ ++ frame->pc = ptregs->pc; ++ frame->fp = ptregs->regs[29]; ++ frame->sp = ptregs->sp; ++} ++ ++static void ++arm64_print_exception_frame(struct bt_info *bt, ulong pt_regs, int mode, FILE *ofp) ++{ ++ int i, r, rows, top_reg, is_64_bit; ++ struct arm64_pt_regs *regs; ++ struct syment *sp; ++ ulong LR, SP, offset; ++ char buf[BUFSIZE]; ++ struct machine_specific *ms = machdep->machspec; ++ ++ if (CRASHDEBUG(1)) ++ fprintf(ofp, "pt_regs: %lx\n", pt_regs); ++ ++ regs = (struct arm64_pt_regs *) ++ &bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(pt_regs))]; ++ ++ if ((mode == USER_MODE) && (regs->pstate & PSR_MODE32_BIT)) { ++ LR = regs->regs[14]; ++ SP = regs->regs[13]; ++ top_reg = 12; ++ is_64_bit = FALSE; ++ rows = 4; ++ } else { ++ LR = regs->regs[30]; ++ if (is_kernel_text (LR | ms->CONFIG_ARM64_KERNELPACMASK)) ++ LR |= ms->CONFIG_ARM64_KERNELPACMASK; ++ SP = regs->sp; ++ top_reg = 29; ++ is_64_bit = TRUE; ++ rows = 3; ++ } ++ ++ switch (mode) { ++ case USER_MODE: ++ if (is_64_bit) ++ fprintf(ofp, ++ " PC: %016lx LR: %016lx SP: %016lx\n ", ++ (ulong)regs->pc, LR, SP); ++ else ++ fprintf(ofp, ++ " PC: %08lx LR: %08lx SP: %08lx PSTATE: %08lx\n ", ++ (ulong)regs->pc, LR, SP, (ulong)regs->pstate); ++ break; ++ ++ case KERNEL_MODE: ++ fprintf(ofp, " PC: %016lx ", (ulong)regs->pc); ++ if (is_kernel_text(regs->pc) && ++ (sp = value_search(regs->pc, &offset))) { ++ fprintf(ofp, "[%s", sp->name); ++ if (offset) ++ fprintf(ofp, (*gdb_output_radix == 16) ? ++ "+0x%lx" : "+%ld", ++ offset); ++ fprintf(ofp, "]\n"); ++ } else ++ fprintf(ofp, "[unknown or invalid address]\n"); ++ ++ fprintf(ofp, " LR: %016lx ", LR); ++ if (is_kernel_text(LR) && ++ (sp = value_search(LR, &offset))) { ++ fprintf(ofp, "[%s", sp->name); ++ if (offset) ++ fprintf(ofp, (*gdb_output_radix == 16) ? ++ "+0x%lx" : "+%ld", ++ offset); ++ fprintf(ofp, "]\n"); ++ } else ++ fprintf(ofp, "[unknown or invalid address]\n"); ++ ++ fprintf(ofp, " SP: %016lx PSTATE: %08lx\n ", ++ SP, (ulong)regs->pstate); ++ break; ++ } ++ ++ for (i = top_reg, r = 1; i >= 0; r++, i--) { ++ fprintf(ofp, "%sX%d: ", ++ i < 10 ? " " : "", i); ++ fprintf(ofp, is_64_bit ? "%016lx" : "%08lx", ++ (ulong)regs->regs[i]); ++ if ((i == 0) && !is_64_bit) ++ fprintf(ofp, "\n"); ++ else if ((i == 0) || ((r % rows) == 0)) ++ fprintf(ofp, "\n%s", ++ (i == 0) && (mode == KERNEL_MODE) ? "" : " "); ++ else ++ fprintf(ofp, "%s", is_64_bit ? " " : " "); ++ } ++ ++ if (is_64_bit) { ++ if (mode == USER_MODE) { ++ fprintf(ofp, "ORIG_X0: %016lx SYSCALLNO: %lx", ++ (ulong)regs->orig_x0, (ulong)regs->syscallno); ++ fprintf(ofp, " PSTATE: %08lx\n", (ulong)regs->pstate); ++ } ++ } ++ ++ if (is_kernel_text(regs->pc) && (bt->flags & BT_LINE_NUMBERS)) { ++ get_line_number(regs->pc, buf, FALSE); ++ if (strlen(buf)) ++ fprintf(ofp, " %s\n", buf); ++ } ++ ++ if (BT_REFERENCE_CHECK(bt)) { ++ arm64_do_bt_reference_check(bt, regs->pc, NULL); ++ if ((sp = value_search(regs->pc, &offset))) ++ arm64_do_bt_reference_check(bt, 0, sp->name); ++ arm64_do_bt_reference_check(bt, LR, NULL); ++ arm64_do_bt_reference_check(bt, SP, NULL); ++ arm64_do_bt_reference_check(bt, regs->pstate, NULL); ++ for (i = 0; i <= top_reg; i++) ++ arm64_do_bt_reference_check(bt, regs->regs[i], NULL); ++ if (is_64_bit) { ++ arm64_do_bt_reference_check(bt, regs->orig_x0, NULL); ++ arm64_do_bt_reference_check(bt, regs->syscallno, NULL); ++ } ++ } ++} ++ ++/* ++ * Check a frame for a requested reference. ++ */ ++static void ++arm64_do_bt_reference_check(struct bt_info *bt, ulong text, char *name) ++{ ++ ulong offset; ++ struct syment *sp = NULL; ++ ++ if (!name) ++ sp = value_search(text, &offset); ++ else if (!text) ++ sp = symbol_search(name); ++ ++ switch (bt->ref->cmdflags & (BT_REF_SYMBOL|BT_REF_HEXVAL)) ++ { ++ case BT_REF_SYMBOL: ++ if (name) { ++ if (STREQ(name, bt->ref->str)) ++ bt->ref->cmdflags |= BT_REF_FOUND; ++ } else { ++ if (sp && !offset && STREQ(sp->name, bt->ref->str)) ++ bt->ref->cmdflags |= BT_REF_FOUND; ++ } ++ break; ++ ++ case BT_REF_HEXVAL: ++ if (text) { ++ if (bt->ref->hexval == text) ++ bt->ref->cmdflags |= BT_REF_FOUND; ++ } else if (sp && (bt->ref->hexval == sp->value)) ++ bt->ref->cmdflags |= BT_REF_FOUND; ++ else if (!name && !text && (bt->ref->hexval == 0)) ++ bt->ref->cmdflags |= BT_REF_FOUND; ++ break; ++ } ++} ++ ++/* ++ * Translate a PTE, returning TRUE if the page is present. ++ * If a physaddr pointer is passed in, don't print anything. ++ */ ++static int ++arm64_translate_pte(ulong pte, void *physaddr, ulonglong unused) ++{ ++ int c, others, len1, len2, len3; ++ ulong paddr; ++ char buf1[BUFSIZE]; ++ char buf2[BUFSIZE]; ++ char buf3[BUFSIZE]; ++ char ptebuf[BUFSIZE]; ++ char physbuf[BUFSIZE]; ++ char *arglist[MAXARGS]; ++ int page_present; ++ ++ paddr = PTE_TO_PHYS(pte); ++ page_present = pte & (PTE_VALID | machdep->machspec->PTE_PROT_NONE); ++ ++ if (physaddr) { ++ *((ulong *)physaddr) = paddr; ++ return page_present; ++ } ++ ++ sprintf(ptebuf, "%lx", pte); ++ len1 = MAX(strlen(ptebuf), strlen("PTE")); ++ fprintf(fp, "%s ", mkstring(buf1, len1, CENTER|LJUST, "PTE")); ++ ++ if (!page_present) { ++ swap_location(pte, buf1); ++ if ((c = parse_line(buf1, arglist)) != 3) ++ error(FATAL, "cannot determine swap location\n"); ++ ++ len2 = MAX(strlen(arglist[0]), strlen("SWAP")); ++ len3 = MAX(strlen(arglist[2]), strlen("OFFSET")); ++ ++ fprintf(fp, "%s %s\n", ++ mkstring(buf2, len2, CENTER|LJUST, "SWAP"), ++ mkstring(buf3, len3, CENTER|LJUST, "OFFSET")); ++ ++ strcpy(buf2, arglist[0]); ++ strcpy(buf3, arglist[2]); ++ fprintf(fp, "%s %s %s\n", ++ mkstring(ptebuf, len1, CENTER|RJUST, NULL), ++ mkstring(buf2, len2, CENTER|RJUST, NULL), ++ mkstring(buf3, len3, CENTER|RJUST, NULL)); ++ return page_present; ++ } ++ ++ sprintf(physbuf, "%lx", paddr); ++ len2 = MAX(strlen(physbuf), strlen("PHYSICAL")); ++ fprintf(fp, "%s ", mkstring(buf1, len2, CENTER|LJUST, "PHYSICAL")); ++ ++ fprintf(fp, "FLAGS\n"); ++ ++ fprintf(fp, "%s %s ", ++ mkstring(ptebuf, len1, CENTER|RJUST, NULL), ++ mkstring(physbuf, len2, CENTER|RJUST, NULL)); ++ fprintf(fp, "("); ++ others = 0; ++ ++ if (pte) { ++ if (pte & PTE_VALID) ++ fprintf(fp, "%sVALID", others++ ? "|" : ""); ++ if (pte & machdep->machspec->PTE_FILE) ++ fprintf(fp, "%sFILE", others++ ? "|" : ""); ++ if (pte & machdep->machspec->PTE_PROT_NONE) ++ fprintf(fp, "%sPROT_NONE", others++ ? "|" : ""); ++ if (pte & PTE_USER) ++ fprintf(fp, "%sUSER", others++ ? "|" : ""); ++ if (pte & PTE_RDONLY) ++ fprintf(fp, "%sRDONLY", others++ ? "|" : ""); ++ if (pte & PTE_SHARED) ++ fprintf(fp, "%sSHARED", others++ ? "|" : ""); ++ if (pte & PTE_AF) ++ fprintf(fp, "%sAF", others++ ? "|" : ""); ++ if (pte & PTE_NG) ++ fprintf(fp, "%sNG", others++ ? "|" : ""); ++ if (pte & PTE_PXN) ++ fprintf(fp, "%sPXN", others++ ? "|" : ""); ++ if (pte & PTE_UXN) ++ fprintf(fp, "%sUXN", others++ ? "|" : ""); ++ if (pte & PTE_DIRTY) ++ fprintf(fp, "%sDIRTY", others++ ? "|" : ""); ++ if (pte & PTE_SPECIAL) ++ fprintf(fp, "%sSPECIAL", others++ ? "|" : ""); ++ } else { ++ fprintf(fp, "no mapping"); ++ } ++ ++ fprintf(fp, ")\n"); ++ ++ return (page_present); ++} ++ ++static ulong ++arm64_vmalloc_start(void) ++{ ++ return machdep->machspec->vmalloc_start_addr; ++} ++ ++/* ++ * Not so accurate since thread_info introduction. ++ */ ++static int ++arm64_is_task_addr(ulong task) ++{ ++ if (tt->flags & THREAD_INFO) ++ return IS_KVADDR(task); ++ else ++ return (IS_KVADDR(task) && (ALIGNED_STACK_OFFSET(task) == 0)); ++} ++ ++static ulong ++PLT_veneer_to_kvaddr(ulong value) ++{ ++ uint32_t insn; ++ ulong addr = 0; ++ int i; ++ ++ /* ++ * PLT veneer always looks: ++ * movn x16, #0x.... ++ * movk x16, #0x...., lsl #16 ++ * movk x16, #0x...., lsl #32 ++ * br x16 ++ */ ++ for (i = 0; i < 4; i++) { ++ if (!readmem(value + i * sizeof(insn), KVADDR, &insn, ++ sizeof(insn), "PLT veneer", RETURN_ON_ERROR)) { ++ error(WARNING, "cannot read PLT veneer instruction at %lx\n", ++ value + i * sizeof(insn)); ++ return value; ++ } ++ switch (i) { ++ case 0: ++ if ((insn & 0xffe0001f) != 0x92800010) ++ goto not_plt; ++ addr = ~((ulong)(insn & 0x1fffe0) >> 5); ++ break; ++ case 1: ++ if ((insn & 0xffe0001f) != 0xf2a00010) ++ goto not_plt; ++ addr &= 0xffffffff0000ffff; ++ addr |= (ulong)(insn & 0x1fffe0) << (16 - 5); ++ break; ++ case 2: ++ if ((insn & 0xffe0001f) != 0xf2c00010) ++ goto not_plt; ++ addr &= 0xffff0000ffffffff; ++ addr |= (ulong)(insn & 0x1fffe0) << (32 - 5); ++ break; ++ case 3: ++ if (insn != 0xd61f0200) ++ goto not_plt; ++ break; ++ default: ++ return value; /* to avoid any warnings */ ++ } ++ } ++ ++ return addr; ++ ++not_plt: ++ return value; ++} ++ ++/* ++ * Filter dissassembly output if the output radix is not gdb's default 10 ++ */ ++static int ++arm64_dis_filter(ulong vaddr, char *inbuf, unsigned int output_radix) ++{ ++ char buf1[BUFSIZE]; ++ char buf2[BUFSIZE]; ++ char *colon, *p1; ++ int argc; ++ char *argv[MAXARGS]; ++ ulong value; ++ ++ if (!inbuf) ++ return TRUE; ++ ++ console("IN: %s", inbuf); ++ ++ colon = strstr(inbuf, ":"); ++ ++ if (colon) { ++ sprintf(buf1, "0x%lx <%s>", vaddr, ++ value_to_symstr(vaddr, buf2, output_radix)); ++ sprintf(buf2, "%s%s", buf1, colon); ++ strcpy(inbuf, buf2); ++ } ++ ++ strcpy(buf1, inbuf); ++ argc = parse_line(buf1, argv); ++ ++ if ((FIRSTCHAR(argv[argc-1]) == '<') && ++ (LASTCHAR(argv[argc-1]) == '>')) { ++ p1 = rindex(inbuf, '<'); ++ while ((p1 > inbuf) && !(STRNEQ(p1, " 0x") || STRNEQ(p1, "\t0x"))) ++ p1--; ++ ++ if (!(STRNEQ(p1, " 0x") || STRNEQ(p1, "\t0x"))) ++ return FALSE; ++ p1++; ++ ++ if (!extract_hex(p1, &value, NULLCHAR, TRUE)) ++ return FALSE; ++ ++ sprintf(buf1, "0x%lx <%s>\n", value, ++ value_to_symstr(value, buf2, output_radix)); ++ ++ sprintf(p1, "%s", buf1); ++ } ++ ++ if (IS_MODULE_VADDR(vaddr)) { ++ ulong orig_value; ++ ++ p1 = &inbuf[strlen(inbuf)-1]; ++ strcpy(buf1, inbuf); ++ argc = parse_line(buf1, argv); ++ ++ if ((STREQ(argv[argc-2], "b") || STREQ(argv[argc-2], "bl")) && ++ extract_hex(argv[argc-1], &orig_value, NULLCHAR, TRUE)) { ++ value = PLT_veneer_to_kvaddr(orig_value); ++ sprintf(p1, " <%s%s>\n", ++ value == orig_value ? "" : "plt:", ++ value_to_symstr(value, buf2, output_radix)); ++ } ++ } ++ ++ console(" %s", inbuf); ++ ++ return TRUE; ++} ++ ++/* ++ * Machine dependent command. ++ */ ++static void ++arm64_cmd_mach(void) ++{ ++ int c; ++ ++ while ((c = getopt(argcnt, args, "cm")) != -1) { ++ switch (c) { ++ case 'c': ++ case 'm': ++ option_not_supported(c); ++ break; ++ ++ default: ++ argerrs++; ++ break; ++ } ++ } ++ ++ if (argerrs) ++ cmd_usage(pc->curcmd, SYNOPSIS); ++ ++ arm64_display_machine_stats(); ++} ++ ++static void ++arm64_display_machine_stats(void) ++{ ++ int i, pad; ++ struct new_utsname *uts; ++ char buf[BUFSIZE]; ++ ulong mhz; ++ ++ uts = &kt->utsname; ++ ++ fprintf(fp, " MACHINE TYPE: %s\n", uts->machine); ++ fprintf(fp, " MEMORY SIZE: %s\n", get_memory_size(buf)); ++ fprintf(fp, " CPUS: %d\n", get_cpus_to_display()); ++ if ((mhz = machdep->processor_speed())) ++ fprintf(fp, " PROCESSOR SPEED: %ld Mhz\n", mhz); ++ fprintf(fp, " HZ: %d\n", machdep->hz); ++ fprintf(fp, " PAGE SIZE: %d\n", PAGESIZE()); ++ fprintf(fp, "KERNEL VIRTUAL BASE: %lx\n", machdep->machspec->page_offset); ++ fprintf(fp, "KERNEL MODULES BASE: %lx\n", machdep->machspec->modules_vaddr); ++ fprintf(fp, "KERNEL VMALLOC BASE: %lx\n", machdep->machspec->vmalloc_start_addr); ++ fprintf(fp, "KERNEL VMEMMAP BASE: %lx\n", machdep->machspec->vmemmap_vaddr); ++ fprintf(fp, " KERNEL STACK SIZE: %ld\n", STACKSIZE()); ++ if (machdep->machspec->irq_stack_size) { ++ fprintf(fp, " IRQ STACK SIZE: %ld\n", ++ machdep->machspec->irq_stack_size); ++ fprintf(fp, " IRQ STACKS:\n"); ++ for (i = 0; i < kt->cpus; i++) { ++ pad = (i < 10) ? 3 : (i < 100) ? 2 : (i < 1000) ? 1 : 0; ++ fprintf(fp, "%s CPU %d: %lx\n", space(pad), i, ++ machdep->machspec->irq_stacks[i]); ++ } ++ } ++} ++ ++static int ++arm64_get_smp_cpus(void) ++{ ++ int cpus; ++ ++ if ((cpus = get_cpus_present())) ++ return cpus; ++ else ++ return MAX(get_cpus_online(), get_highest_cpu_online()+1); ++} ++ ++ ++/* ++ * Retrieve task registers for the time of the crash. ++ */ ++static void ++arm64_get_crash_notes(void) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ ulong crash_notes; ++ Elf64_Nhdr *note; ++ ulong offset; ++ char *buf, *p; ++ ulong *notes_ptrs; ++ ulong i, found; ++ ++ if (!symbol_exists("crash_notes")) ++ return; ++ ++ crash_notes = symbol_value("crash_notes"); ++ ++ notes_ptrs = (ulong *)GETBUF(kt->cpus*sizeof(notes_ptrs[0])); ++ ++ /* ++ * Read crash_notes for the first CPU. crash_notes are in standard ELF ++ * note format. ++ */ ++ if (!readmem(crash_notes, KVADDR, ¬es_ptrs[kt->cpus-1], ++ sizeof(notes_ptrs[kt->cpus-1]), "crash_notes", RETURN_ON_ERROR)) { ++ error(WARNING, "cannot read \"crash_notes\"\n"); ++ FREEBUF(notes_ptrs); ++ return; ++ } ++ ++ if (symbol_exists("__per_cpu_offset")) { ++ /* ++ * Add __per_cpu_offset for each cpu to form the notes pointer. ++ */ ++ for (i = 0; icpus; i++) ++ notes_ptrs[i] = notes_ptrs[kt->cpus-1] + kt->__per_cpu_offset[i]; ++ } ++ ++ buf = GETBUF(SIZE(note_buf)); ++ ++ if (!(ms->panic_task_regs = calloc((size_t)kt->cpus, sizeof(struct arm64_pt_regs)))) ++ error(FATAL, "cannot calloc panic_task_regs space\n"); ++ ++ for (i = found = 0; i < kt->cpus; i++) { ++ if (!readmem(notes_ptrs[i], KVADDR, buf, SIZE(note_buf), ++ "note_buf_t", RETURN_ON_ERROR)) { ++ error(WARNING, "cpu %d: cannot read NT_PRSTATUS note\n", i); ++ continue; ++ } ++ ++ /* ++ * Do some sanity checks for this note before reading registers from it. ++ */ ++ note = (Elf64_Nhdr *)buf; ++ p = buf + sizeof(Elf64_Nhdr); ++ ++ /* ++ * dumpfiles created with qemu won't have crash_notes, but there will ++ * be elf notes; dumpfiles created by kdump do not create notes for ++ * offline cpus. ++ */ ++ if (note->n_namesz == 0 && (DISKDUMP_DUMPFILE() || KDUMP_DUMPFILE())) { ++ if (DISKDUMP_DUMPFILE()) ++ note = diskdump_get_prstatus_percpu(i); ++ else if (KDUMP_DUMPFILE()) ++ note = netdump_get_prstatus_percpu(i); ++ if (note) { ++ /* ++ * SIZE(note_buf) accounts for a "final note", which is a ++ * trailing empty elf note header. ++ */ ++ long notesz = SIZE(note_buf) - sizeof(Elf64_Nhdr); ++ ++ if (sizeof(Elf64_Nhdr) + roundup(note->n_namesz, 4) + ++ note->n_descsz == notesz) ++ BCOPY((char *)note, buf, notesz); ++ } else { ++ error(WARNING, "cpu %d: cannot find NT_PRSTATUS note\n", i); ++ continue; ++ } ++ } ++ ++ /* ++ * Check the sanity of NT_PRSTATUS note only for each online cpu. ++ * If this cpu has invalid note, continue to find the crash notes ++ * for other online cpus. ++ */ ++ if (note->n_type != NT_PRSTATUS) { ++ error(WARNING, "cpu %d: invalid NT_PRSTATUS note (n_type != NT_PRSTATUS)\n", i); ++ continue; ++ } ++ ++ if (!STRNEQ(p, "CORE")) { ++ error(WARNING, "cpu %d: invalid NT_PRSTATUS note (name != \"CORE\")\n", i); ++ continue; ++ } ++ ++ /* ++ * Find correct location of note data. This contains elf_prstatus ++ * structure which has registers etc. for the crashed task. ++ */ ++ offset = sizeof(Elf64_Nhdr); ++ offset = roundup(offset + note->n_namesz, 4); ++ p = buf + offset; /* start of elf_prstatus */ ++ ++ BCOPY(p + OFFSET(elf_prstatus_pr_reg), &ms->panic_task_regs[i], ++ sizeof(struct arm64_pt_regs)); ++ ++ found++; ++ } ++ ++ FREEBUF(buf); ++ FREEBUF(notes_ptrs); ++ ++ if (!found) { ++ free(ms->panic_task_regs); ++ ms->panic_task_regs = NULL; ++ } ++} ++ ++static void ++arm64_clear_machdep_cache(void) { ++ /* ++ * TBD: probably not necessary... ++ */ ++ return; ++} ++ ++static int ++arm64_on_process_stack(struct bt_info *bt, ulong stkptr) ++{ ++ ulong stackbase, stacktop; ++ ++ stackbase = GET_STACKBASE(bt->task); ++ stacktop = GET_STACKTOP(bt->task); ++ ++ if ((stkptr >= stackbase) && (stkptr < stacktop)) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++static int ++arm64_on_irq_stack(int cpu, ulong stkptr) ++{ ++ return arm64_in_alternate_stack(cpu, stkptr); ++} ++ ++static int ++arm64_in_alternate_stack(int cpu, ulong stkptr) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ ++ if (!ms->irq_stack_size || (cpu >= kt->cpus)) ++ return FALSE; ++ ++ if ((stkptr >= ms->irq_stacks[cpu]) && ++ (stkptr < (ms->irq_stacks[cpu] + ms->irq_stack_size))) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++static int ++arm64_in_sdei_normal_stack(int cpu, ulong stkptr) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ ++ if (!ms->sdei_stack_size || (cpu >= kt->cpus)) ++ return FALSE; ++ ++ if ((stkptr >= ms->sdei_stacks[cpu]) && ++ (stkptr < (ms->sdei_stacks[cpu] + ms->sdei_stack_size))) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++static void ++arm64_set_sdei_normal_stack(struct bt_info *bt) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ ++ bt->stackbase = ms->sdei_stacks[bt->tc->processor]; ++ bt->stacktop = bt->stackbase + ms->sdei_stack_size; ++ alter_stackbuf(bt); ++} ++ ++static void ++arm64_set_irq_stack(struct bt_info *bt) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ ++ bt->stackbase = ms->irq_stacks[bt->tc->processor]; ++ bt->stacktop = bt->stackbase + ms->irq_stack_size; ++ alter_stackbuf(bt); ++} ++ ++static void ++arm64_set_process_stack(struct bt_info *bt) ++{ ++ bt->stackbase = GET_STACKBASE(bt->task); ++ bt->stacktop = GET_STACKTOP(bt->task); ++ alter_stackbuf(bt); ++} ++ ++ ++static int ++compare_kvaddr(const void *v1, const void *v2) ++{ ++ struct vaddr_range *r1, *r2; ++ ++ r1 = (struct vaddr_range *)v1; ++ r2 = (struct vaddr_range *)v2; ++ ++ return (r1->start < r2->start ? -1 : ++ r1->start == r2->start ? 0 : 1); ++} ++ ++static int ++arm64_get_kvaddr_ranges(struct vaddr_range *vrp) ++{ ++ int cnt; ++ ++ cnt = 0; ++ ++ vrp[cnt].type = KVADDR_UNITY_MAP; ++ vrp[cnt].start = machdep->machspec->page_offset; ++ vrp[cnt++].end = vt->high_memory; ++ ++ vrp[cnt].type = KVADDR_VMALLOC; ++ vrp[cnt].start = machdep->machspec->vmalloc_start_addr; ++ vrp[cnt++].end = last_vmalloc_address(); ++ ++ if (st->mods_installed) { ++ vrp[cnt].type = KVADDR_MODULES; ++ vrp[cnt].start = lowest_module_address(); ++ vrp[cnt++].end = roundup(highest_module_address(), ++ PAGESIZE()); ++ } ++ ++ if (machdep->flags & VMEMMAP) { ++ vrp[cnt].type = KVADDR_VMEMMAP; ++ vrp[cnt].start = machdep->machspec->vmemmap_vaddr; ++ vrp[cnt++].end = vt->node_table[vt->numnodes-1].mem_map + ++ (vt->node_table[vt->numnodes-1].size * SIZE(page)); ++ } ++ ++ qsort(vrp, cnt, sizeof(struct vaddr_range), compare_kvaddr); ++ ++ return cnt; ++} ++ ++/* ++ * Include both vmalloc'd, module and vmemmap address space as VMALLOC space. ++ */ ++int ++arm64_IS_VMALLOC_ADDR(ulong vaddr) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ ++ if ((machdep->flags & NEW_VMEMMAP) && ++ (vaddr >= machdep->machspec->kimage_text) && ++ (vaddr <= machdep->machspec->kimage_end)) ++ return FALSE; ++ ++ if (ms->VA_START && (vaddr >= ms->VA_START)) ++ return TRUE; ++ ++ return ((vaddr >= ms->vmalloc_start_addr && vaddr <= ms->vmalloc_end) || ++ ((machdep->flags & VMEMMAP) && ++ ((vaddr >= ms->vmemmap_vaddr && vaddr <= ms->vmemmap_end) || ++ (vaddr >= ms->vmalloc_end && vaddr <= ms->vmemmap_vaddr))) || ++ (vaddr >= ms->modules_vaddr && vaddr <= ms->modules_end)); ++} ++ ++static void ++arm64_calc_VA_BITS(void) ++{ ++ int bitval; ++ struct syment *sp; ++ ulong vabits_actual, value; ++ char *string; ++ ++ if ((string = pc->read_vmcoreinfo("NUMBER(VA_BITS)"))) { ++ value = atol(string); ++ free(string); ++ machdep->machspec->CONFIG_ARM64_VA_BITS = value; ++ } ++ ++ if (kernel_symbol_exists("vabits_actual")) { ++ if (pc->flags & PROC_KCORE) { ++ vabits_actual = symbol_value_from_proc_kallsyms("vabits_actual"); ++ if ((vabits_actual != BADVAL) && (READMEM(pc->mfd, &value, sizeof(ulong), ++ vabits_actual, KCORE_USE_VADDR) > 0)) { ++ if (CRASHDEBUG(1)) ++ fprintf(fp, ++ "/proc/kcore: vabits_actual: %ld\n", value); ++ machdep->machspec->VA_BITS_ACTUAL = value; ++ machdep->machspec->VA_BITS = value; ++ machdep->machspec->VA_START = _VA_START(machdep->machspec->VA_BITS_ACTUAL); ++ } else ++ error(FATAL, "/proc/kcore: cannot read vabits_actual\n"); ++ } else if (ACTIVE()) ++ error(FATAL, "cannot determine VA_BITS_ACTUAL: please use /proc/kcore\n"); ++ else { ++ if ((string = pc->read_vmcoreinfo("NUMBER(TCR_EL1_T1SZ)"))) { ++ /* See ARMv8 ARM for the description of ++ * TCR_EL1.T1SZ and how it can be used ++ * to calculate the vabits_actual ++ * supported by underlying kernel. ++ * ++ * Basically: ++ * vabits_actual = 64 - T1SZ; ++ */ ++ value = 64 - strtoll(string, NULL, 0); ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "vmcoreinfo : vabits_actual: %ld\n", value); ++ free(string); ++ machdep->machspec->VA_BITS_ACTUAL = value; ++ machdep->machspec->VA_BITS = value; ++ machdep->machspec->VA_START = _VA_START(machdep->machspec->VA_BITS_ACTUAL); ++ } else if (machdep->machspec->VA_BITS_ACTUAL) { ++ machdep->machspec->VA_BITS = machdep->machspec->VA_BITS_ACTUAL; ++ machdep->machspec->VA_START = _VA_START(machdep->machspec->VA_BITS_ACTUAL); ++ } else ++ error(FATAL, "cannot determine VA_BITS_ACTUAL\n"); ++ } ++ ++ /* ++ * The mm flip commit is introduced before 52-bits VA, which is before the ++ * commit to export NUMBER(TCR_EL1_T1SZ) ++ */ ++ machdep->flags |= FLIPPED_VM; ++ return; ++ } ++ ++ if (!(sp = symbol_search("swapper_pg_dir")) && ++ !(sp = symbol_search("idmap_pg_dir")) && ++ !(sp = symbol_search("_text")) && ++ !(sp = symbol_search("stext"))) { ++ for (sp = st->symtable; sp < st->symend; sp++) { ++ if (highest_bit_long(sp->value) == 63) ++ break; ++ } ++ } ++ ++ if (sp) ++ value = sp->value; ++ else ++ value = kt->vmcoreinfo.log_buf_SYMBOL; /* crash --log */ ++ ++ for (bitval = highest_bit_long(value); bitval; bitval--) { ++ if ((value & (1UL << bitval)) == 0) { ++ if (machdep->flags & NEW_VMEMMAP) ++ machdep->machspec->VA_BITS = bitval + 1; ++ else ++ machdep->machspec->VA_BITS = bitval + 2; ++ break; ++ } ++ } ++ ++ /* ++ * Verify against dumpfiles that export VA_BITS in vmcoreinfo ++ */ ++ if (machdep->machspec->CONFIG_ARM64_VA_BITS && ++ (machdep->machspec->VA_BITS != machdep->machspec->CONFIG_ARM64_VA_BITS)) { ++ error(WARNING, "VA_BITS: calculated: %ld vmcoreinfo: %ld\n", ++ machdep->machspec->VA_BITS, machdep->machspec->CONFIG_ARM64_VA_BITS); ++ machdep->machspec->VA_BITS = machdep->machspec->CONFIG_ARM64_VA_BITS; ++ } ++ ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "VA_BITS: %ld\n", machdep->machspec->VA_BITS); ++ ++} ++ ++/* ++ * The size and end of the vmalloc range is dependent upon the kernel's ++ * VMEMMAP_SIZE value, and the vmemmap range is dependent upon the end ++ * of the vmalloc range as well as the VMEMMAP_SIZE: ++ * ++ * #define VMEMMAP_SIZE ALIGN((1UL << (VA_BITS - PAGE_SHIFT)) * sizeof(struct page), PUD_SIZE) ++ * #define VMALLOC_START (UL(0xffffffffffffffff) << VA_BITS) ++ * #define VMALLOC_END (PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - SZ_64K) ++ * ++ * Since VMEMMAP_SIZE is dependent upon the size of a struct page, ++ * the two ranges cannot be determined until POST_GDB. ++ * ++ * Since 52-bit VA was introduced: ++ * ++ * #define STRUCT_PAGE_MAX_SHIFT 6 ++ * #define VMEMMAP_SIZE (UL(1) << (VA_BITS - PAGE_SHIFT - 1 + STRUCT_PAGE_MAX_SHIFT)) ++ * #define VMEMMAP_START (-VMEMMAP_SIZE) ++ * #define VMALLOC_START (MODULES_END) ++ * #define VMALLOC_END (- PUD_SIZE - VMEMMAP_SIZE - SZ_64K) ++ * #define vmemmap ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT)) ++ */ ++ ++#define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) ++#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) ++#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) ++#define SZ_64K 0x00010000 ++ ++static void ++arm64_calc_virtual_memory_ranges(void) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ ulong value, vmemmap_start, vmemmap_end, vmemmap_size, vmalloc_end; ++ char *string; ++ int ret; ++ ulong PUD_SIZE = UNINITIALIZED; ++ ++ if (!machdep->machspec->CONFIG_ARM64_VA_BITS) { ++ if ((string = pc->read_vmcoreinfo("NUMBER(VA_BITS)"))) { ++ value = atol(string); ++ free(string); ++ machdep->machspec->CONFIG_ARM64_VA_BITS = value; ++ } else if (kt->ikconfig_flags & IKCONFIG_AVAIL) { ++ if ((ret = get_kernel_config("CONFIG_ARM64_VA_BITS", ++ &string)) == IKCONFIG_STR) ++ machdep->machspec->CONFIG_ARM64_VA_BITS = atol(string); ++ } ++ } ++ ++ if (THIS_KERNEL_VERSION < LINUX(3,17,0)) /* use original hardwired values */ ++ return; ++ ++ STRUCT_SIZE_INIT(page, "page"); ++ ++ switch (machdep->flags & (VM_L2_64K|VM_L3_64K|VM_L3_4K|VM_L4_4K)) ++ { ++ case VM_L2_64K: ++ case VM_L3_64K: ++ PUD_SIZE = PGDIR_SIZE_L2_64K; ++ break; ++ case VM_L3_4K: ++ PUD_SIZE = PGDIR_SIZE_L3_4K; ++ case VM_L4_4K: ++ PUD_SIZE = PUD_SIZE_L4_4K; ++ break; ++ } ++ ++#define STRUCT_PAGE_MAX_SHIFT 6 ++ ++ if (ms->VA_BITS_ACTUAL) { ++ ulong va_bits_min = 48; ++ ++ if (machdep->machspec->CONFIG_ARM64_VA_BITS < 48) ++ va_bits_min = ms->CONFIG_ARM64_VA_BITS; ++ ++ vmemmap_size = (1UL) << (va_bits_min - machdep->pageshift - 1 + STRUCT_PAGE_MAX_SHIFT); ++ vmalloc_end = (- PUD_SIZE - vmemmap_size - KILOBYTES(64)); ++ vmemmap_start = (-vmemmap_size - MEGABYTES(2)); ++ ms->vmalloc_end = vmalloc_end - 1; ++ ms->vmemmap_vaddr = vmemmap_start; ++ ms->vmemmap_end = -1; ++ return; ++ } ++ ++ if (machdep->flags & NEW_VMEMMAP) ++ vmemmap_size = 1UL << (ms->VA_BITS - machdep->pageshift - 1 ++ + STRUCT_PAGE_MAX_SHIFT); ++ else ++ vmemmap_size = ALIGN((1UL << (ms->VA_BITS - machdep->pageshift)) * SIZE(page), PUD_SIZE); ++ ++ vmalloc_end = (ms->page_offset - PUD_SIZE - vmemmap_size - SZ_64K); ++ ++ if (machdep->flags & NEW_VMEMMAP) { ++ vmemmap_start = ms->page_offset - vmemmap_size; ++ vmemmap_end = ms->page_offset; ++ } else { ++ vmemmap_start = vmalloc_end + SZ_64K; ++ vmemmap_end = vmemmap_start + vmemmap_size; ++ } ++ ++ ms->vmalloc_end = vmalloc_end - 1; ++ ms->vmemmap_vaddr = vmemmap_start; ++ ms->vmemmap_end = vmemmap_end - 1; ++} ++ ++static int ++arm64_is_uvaddr(ulong addr, struct task_context *tc) ++{ ++ return (addr < machdep->machspec->userspace_top); ++} ++ ++ ++ulong ++arm64_swp_type(ulong pte) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ ++ pte >>= ms->__SWP_TYPE_SHIFT; ++ pte &= ms->__SWP_TYPE_MASK; ++ return pte; ++} ++ ++ulong ++arm64_swp_offset(ulong pte) ++{ ++ struct machine_specific *ms = machdep->machspec; ++ ++ pte >>= ms->__SWP_OFFSET_SHIFT; ++ if (ms->__SWP_OFFSET_MASK) ++ pte &= ms->__SWP_OFFSET_MASK; ++ return pte; ++} ++ ++static void arm64_calc_KERNELPACMASK(void) ++{ ++ ulong value; ++ char *string; ++ ++ if ((string = pc->read_vmcoreinfo("NUMBER(KERNELPACMASK)"))) { ++ value = htol(string, QUIET, NULL); ++ free(string); ++ machdep->machspec->CONFIG_ARM64_KERNELPACMASK = value; ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "CONFIG_ARM64_KERNELPACMASK: %lx\n", value); ++ } ++} ++ ++#endif /* ARM64 */ ++ ++ +diff -Nur crash-7.3.0-orig/cmdline.c crash-7.3.0/cmdline.c +--- crash-7.3.0-orig/cmdline.c 2023-07-07 14:06:14.163365900 +0800 ++++ crash-7.3.0/cmdline.c 2023-07-07 14:08:21.989028153 +0800 +@@ -1235,7 +1235,6 @@ + if (CRASHDEBUG(5)) { + dump_filesys_table(0); + dump_vma_cache(0); +- dump_text_value_cache(0); + } + + if (REMOTE()) +diff -Nur crash-7.3.0-orig/configure.c crash-7.3.0/configure.c +--- crash-7.3.0-orig/configure.c 2023-07-07 14:06:14.164365905 +0800 ++++ crash-7.3.0/configure.c 2023-07-07 14:08:21.991028163 +0800 +@@ -161,13 +161,13 @@ + + #define GDB_TARGET_DEFAULT "GDB_CONF_FLAGS=" + #define GDB_TARGET_ARM_ON_X86 "GDB_CONF_FLAGS=--target=arm-elf-linux" +-#define GDB_TARGET_ARM_ON_X86_64 "GDB_CONF_FLAGS=--target=arm-elf-linux CFLAGS=-m32" +-#define GDB_TARGET_X86_ON_X86_64 "GDB_CONF_FLAGS=--target=i686-pc-linux-gnu CFLAGS=-m32" +-#define GDB_TARGET_PPC_ON_PPC64 "GDB_CONF_FLAGS=--target=ppc-elf-linux CFLAGS=-m32" ++#define GDB_TARGET_ARM_ON_X86_64 "GDB_CONF_FLAGS=--target=arm-elf-linux CFLAGS=-m32 CXXFLAGS=-m32" ++#define GDB_TARGET_X86_ON_X86_64 "GDB_CONF_FLAGS=--target=i686-pc-linux-gnu CFLAGS=-m32 CXXFLAGS=-m32" ++#define GDB_TARGET_PPC_ON_PPC64 "GDB_CONF_FLAGS=--target=ppc-elf-linux CFLAGS=-m32 CXXFLAGS=-m32" + #define GDB_TARGET_ARM64_ON_X86_64 "GDB_CONF_FLAGS=--target=aarch64-elf-linux" /* TBD */ + #define GDB_TARGET_PPC64_ON_X86_64 "GDB_CONF_FLAGS=--target=powerpc64le-unknown-linux-gnu" + #define GDB_TARGET_MIPS_ON_X86 "GDB_CONF_FLAGS=--target=mipsel-elf-linux" +-#define GDB_TARGET_MIPS_ON_X86_64 "GDB_CONF_FLAGS=--target=mipsel-elf-linux CFLAGS=-m32" ++#define GDB_TARGET_MIPS_ON_X86_64 "GDB_CONF_FLAGS=--target=mipsel-elf-linux CFLAGS=-m32 CXXFLAGS=-m32" + + /* + * The original plan was to allow the use of a particular version +@@ -182,9 +182,10 @@ + #define GDB_7_0 (3) + #define GDB_7_3_1 (4) + #define GDB_7_6 (5) +-#define SUPPORTED_GDB_VERSIONS (GDB_7_6 + 1) ++#define GDB_10_2 (6) ++#define SUPPORTED_GDB_VERSIONS (GDB_10_2 + 1) + +-int default_gdb = GDB_7_6; ++int default_gdb = GDB_10_2; + + struct supported_gdb_version { + char *GDB; +@@ -249,6 +250,15 @@ + "GDB_FLAGS=-DGDB_7_6", + "GPLv3" + }, ++ { ++ "GDB=gdb-10.2", ++ "10.2", ++ "GDB_FILES=${GDB_10.2_FILES}", ++ "GDB_OFILES=${GDB_10.2_OFILES}", ++ "GDB_PATCH_FILES=gdb-10.2.patch", ++ "GDB_FLAGS=-DGDB_10_2", ++ "GPLv3" ++ }, + }; + + #define DAEMON 0x1 +@@ -1514,6 +1524,12 @@ + fprintf(stderr, ".gdb configuration: %s\n", sp->GDB_VERSION_IN); + return store_gdb_defaults(sp); + } ++ if (strcmp(buf, "10.2") == 0) { ++ fclose(fp); ++ sp = &supported_gdb_versions[GDB_10_2]; ++ fprintf(stderr, ".gdb configuration: %s\n", sp->GDB_VERSION_IN); ++ return store_gdb_defaults(sp); ++ } + + } + +@@ -1738,6 +1754,10 @@ + * - enter -DSNAPPY in the CFLAGS.extra file + * - enter -lsnappy in the LDFLAGS.extra file + * ++ * For zstd: ++ * - enter -DZSTD in the CFLAGS.extra file ++ * - enter -lzstd in the LDFLAGS.extra file ++ * + * For valgrind: + * - enter -DVALGRIND in the CFLAGS.extra file + */ +@@ -1746,6 +1766,7 @@ + { + int lzo, add_DLZO, add_llzo2; + int snappy, add_DSNAPPY, add_lsnappy; ++ int zstd, add_DZSTD, add_lzstd; + int valgrind, add_DVALGRIND; + char *cflags, *ldflags; + FILE *fp_cflags, *fp_ldflags; +@@ -1754,6 +1775,7 @@ + + lzo = add_DLZO = add_llzo2 = 0; + snappy = add_DSNAPPY = add_lsnappy = 0; ++ zstd = add_DZSTD = add_lzstd = 0; + valgrind = add_DVALGRIND = 0; + + ldflags = get_extra_flags("LDFLAGS.extra", NULL); +@@ -1775,13 +1797,21 @@ + add_lsnappy++; + } + ++ if (strcmp(option, "zstd") == 0) { ++ zstd++; ++ if (!cflags || !strstr(cflags, "-DZSTD")) ++ add_DZSTD++; ++ if (!ldflags || !strstr(ldflags, "-lzstd")) ++ add_lzstd++; ++ } ++ + if (strcmp(option, "valgrind") == 0) { + valgrind++; + if (!cflags || !strstr(cflags, "-DVALGRIND")) + add_DVALGRIND++; + } + +- if ((lzo || snappy) && ++ if ((lzo || snappy || zstd) && + file_exists("diskdump.o") && (unlink("diskdump.o") < 0)) { + perror("diskdump.o"); + return; +@@ -1806,24 +1836,28 @@ + return; + } + +- if (add_DLZO || add_DSNAPPY || add_DVALGRIND) { ++ if (add_DLZO || add_DSNAPPY || add_DZSTD || add_DVALGRIND) { + while (fgets(inbuf, 512, fp_cflags)) + ; + if (add_DLZO) + fputs("-DLZO\n", fp_cflags); + if (add_DSNAPPY) + fputs("-DSNAPPY\n", fp_cflags); ++ if (add_DZSTD) ++ fputs("-DZSTD\n", fp_cflags); + if (add_DVALGRIND) + fputs("-DVALGRIND\n", fp_cflags); + } + +- if (add_llzo2 || add_lsnappy) { ++ if (add_llzo2 || add_lsnappy || add_lzstd) { + while (fgets(inbuf, 512, fp_ldflags)) + ; + if (add_llzo2) + fputs("-llzo2\n", fp_ldflags); + if (add_lsnappy) + fputs("-lsnappy\n", fp_ldflags); ++ if (add_lzstd) ++ fputs("-lzstd\n", fp_ldflags); + } + + fclose(fp_cflags); +diff -Nur crash-7.3.0-orig/crash_target.c crash-7.3.0/crash_target.c +--- crash-7.3.0-orig/crash_target.c 1970-01-01 08:00:00.000000000 +0800 ++++ crash-7.3.0/crash_target.c 2023-07-07 14:08:21.992028168 +0800 +@@ -0,0 +1,135 @@ ++/* ++ * crash_target.c ++ * ++ * Copyright (c) 2021 VMware, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * Author: Alexey Makhalov ++ */ ++ ++#include ++#include "top.h" ++#include "target.h" ++#include "inferior.h" ++#include "regcache.h" ++#include "gdbarch.h" ++ ++void crash_target_init (void); ++ ++extern "C" int gdb_readmem_callback(unsigned long, void *, int, int); ++extern "C" int crash_get_nr_cpus(void); ++extern "C" int crash_get_cpu_reg (int cpu, int regno, const char *regname, ++ int regsize, void *val); ++ ++ ++/* The crash target. */ ++ ++static const target_info crash_target_info = { ++ "crash", ++ N_("Local core dump file"), ++ N_("Use a built-in crash instance as a target.") ++}; ++ ++class crash_target final : public process_stratum_target ++{ ++public: ++ ++ const target_info &info () const override ++ { return crash_target_info; } ++ ++ void fetch_registers (struct regcache *, int) override; ++ enum target_xfer_status xfer_partial (enum target_object object, ++ const char *annex, ++ gdb_byte *readbuf, ++ const gdb_byte *writebuf, ++ ULONGEST offset, ULONGEST len, ++ ULONGEST *xfered_len) override; ++ ++ bool has_all_memory () override { return true; } ++ bool has_memory () override { return true; } ++ bool has_stack () override { return true; } ++ bool has_registers () override { return true; } ++ bool thread_alive (ptid_t ptid) override { return true; } ++ std::string pid_to_str (ptid_t ptid) override ++ { return string_printf ("CPU %ld", ptid.tid ()); } ++ ++}; ++ ++/* We just get all the registers, so we don't use regno. */ ++void ++crash_target::fetch_registers (struct regcache *regcache, int regno) ++{ ++ gdb_byte regval[16]; ++ int cpu = inferior_ptid.tid(); ++ struct gdbarch *arch = regcache->arch (); ++ ++ for (int r = 0; r < gdbarch_num_regs (arch); r++) ++ { ++ const char *regname = gdbarch_register_name(arch, r); ++ int regsize = register_size (arch, r); ++ if (regsize > sizeof (regval)) ++ error (_("fatal error: buffer size is not enough to fit register value")); ++ ++ if (crash_get_cpu_reg (cpu, r, regname, regsize, (void *)®val)) ++ regcache->raw_supply (r, regval); ++ else ++ regcache->raw_supply (r, NULL); ++ } ++} ++ ++ ++enum target_xfer_status ++crash_target::xfer_partial (enum target_object object, const char *annex, ++ gdb_byte *readbuf, const gdb_byte *writebuf, ++ ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) ++{ ++ if (object != TARGET_OBJECT_MEMORY && object != TARGET_OBJECT_STACK_MEMORY ++ && object != TARGET_OBJECT_CODE_MEMORY) ++ return TARGET_XFER_E_IO; ++ ++ if (gdb_readmem_callback(offset, (void *)(readbuf ? readbuf : writebuf), len, !readbuf)) ++ { ++ *xfered_len = len; ++ return TARGET_XFER_OK; ++ } ++ ++ return TARGET_XFER_E_IO; ++} ++ ++#define CRASH_INFERIOR_PID 1 ++ ++void ++crash_target_init (void) ++{ ++ int nr_cpus = crash_get_nr_cpus(); ++ crash_target *target = new crash_target (); ++ ++ /* Own the target until it is successfully pushed. */ ++ target_ops_up target_holder (target); ++ ++ push_target (std::move (target_holder)); ++ ++ inferior_appeared (current_inferior (), CRASH_INFERIOR_PID); ++ for (int i = 0; i < nr_cpus; i++) ++ { ++ thread_info *thread = add_thread_silent (target, ++ ptid_t(CRASH_INFERIOR_PID, 0, i)); ++ if (!i) ++ switch_to_thread (thread); ++ } ++ ++ /* Fetch all registers from core file. */ ++ target_fetch_registers (get_current_regcache (), -1); ++ ++ /* Now, set up the frame cache. */ ++ reinit_frame_cache (); ++} +diff -Nur crash-7.3.0-orig/defs.h crash-7.3.0/defs.h +--- crash-7.3.0-orig/defs.h 2023-07-07 14:06:14.176365967 +0800 ++++ crash-7.3.0/defs.h 2023-07-07 14:08:21.996028189 +0800 +@@ -54,6 +54,9 @@ + #ifdef SNAPPY + #include + #endif ++#ifdef ZSTD ++#include ++#endif + + #ifndef ATTRIBUTE_UNUSED + #define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +@@ -327,6 +330,7 @@ + #define NO_ELF_NOTES (0x20) + #define LZO_SUPPORTED (0x40) + #define SNAPPY_SUPPORTED (0x80) ++#define ZSTD_SUPPORTED (0x100) + #define DISKDUMP_VALID() (dd->flags & DISKDUMP_LOCAL) + #define KDUMP_CMPRS_VALID() (dd->flags & KDUMP_CMPRS_LOCAL) + #define KDUMP_SPLIT() (dd->flags & DUMPFILE_SPLIT) +@@ -361,6 +365,7 @@ + #define READ_ERROR (-2) + #define WRITE_ERROR (-3) + #define PAGE_EXCLUDED (-4) ++#define PAGE_INCOMPLETE (-5) + + #define RESTART() (longjmp(pc->main_loop_env, 1)) + #define RESUME_FOREACH() (longjmp(pc->foreach_loop_env, 1)) +@@ -510,7 +515,6 @@ + struct sigaction gdb_sigaction; /* gdb's SIGINT sigaction. */ + jmp_buf main_loop_env; /* longjmp target default */ + jmp_buf foreach_loop_env; /* longjmp target within foreach */ +- jmp_buf gdb_interface_env; /* longjmp target for gdb error catch */ + struct termios termios_orig; /* non-raw settings */ + struct termios termios_raw; /* while gathering command input */ + int ncmds; /* number of commands in menu */ +@@ -1009,6 +1013,7 @@ + ulong (*processor_speed)(void); + int (*uvtop)(struct task_context *, ulong, physaddr_t *, int); + int (*kvtop)(struct task_context *, ulong, physaddr_t *, int); ++ int (*get_cpu_reg)(int, int, const char *, int, void *); + ulong (*get_task_pgd)(ulong); + void (*dump_irq)(int); + void (*get_stack_frame)(struct bt_info *, ulong *, ulong *); +@@ -2576,7 +2581,7 @@ + long member_size; + int member_typecode; + ulong flags; +- char *tagname; /* tagname and value for enums */ ++ const char *tagname; /* tagname and value for enums */ + long value; + ulong vaddr; + }; +@@ -4719,7 +4724,7 @@ + long member_length; + int member_typecode; + long value; +- char *tagname; ++ const char *tagname; + ulong pc; + ulong sp; + ulong ra; +@@ -4731,13 +4736,10 @@ + ulong task; + ulong debug; + struct stack_hook *hookp; +- struct global_iterator { +- int finished; +- int block_index; +- struct symtab *symtab; +- struct symbol *sym; +- struct objfile *obj; +- } global_iterator; ++ ulong lowest; ++ ulong highest; ++ void (*callback) (struct gnu_request *req, void *data); ++ void *callback_data; + struct load_module *lm; + char *member_main_type_name; + char *member_main_type_tag_name; +@@ -4767,7 +4769,7 @@ + #define GNU_USER_PRINT_OPTION (16) + #define GNU_SET_CRASH_BLOCK (17) + #define GNU_GET_FUNCTION_RANGE (18) +-#define GNU_GET_NEXT_DATATYPE (19) ++#define GNU_ITERATE_DATATYPES (19) + #define GNU_LOOKUP_STRUCT_CONTENTS (20) + #define GNU_DEBUG_COMMAND (100) + /* +@@ -4792,14 +4794,15 @@ + /* + * function prototypes required by modified gdb source files. + */ +-int console(char *, ...); +-int gdb_CRASHDEBUG(ulong); ++extern "C" int console(const char *, ...); ++extern "C" int gdb_CRASHDEBUG(ulong); + int gdb_readmem_callback(ulong, void *, int, int); + void patch_load_module(struct objfile *objfile, struct minimal_symbol *msymbol); +-int patch_kernel_symbol(struct gnu_request *); ++extern "C" int patch_kernel_symbol(struct gnu_request *); + struct syment *symbol_search(char *); + int gdb_line_number_callback(ulong, ulong, ulong); + int gdb_print_callback(ulong); ++extern "C" int same_file(char *, char *); + #endif + + #ifndef GDB_COMMON +@@ -4813,8 +4816,8 @@ + TYPE_CODE_STRUCT, /* C struct or Pascal record */ + TYPE_CODE_UNION, /* C union or Pascal variant part */ + TYPE_CODE_ENUM, /* Enumeration type */ +-#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) || defined(GDB_7_0) || defined(GDB_7_3_1) || defined(GDB_7_6) +-#if defined(GDB_7_0) || defined(GDB_7_3_1) || defined(GDB_7_6) ++#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) || defined(GDB_7_0) || defined(GDB_7_3_1) || defined(GDB_7_6) || defined(GDB_10_2) ++#if defined(GDB_7_0) || defined(GDB_7_3_1) || defined(GDB_7_6) || defined(GDB_10_2) + TYPE_CODE_FLAGS, /* Bit flags type */ + #endif + TYPE_CODE_FUNC, /* Function type */ +@@ -5091,7 +5094,7 @@ + FILE *set_error(char *); + int __error(int, char *, ...); + #define error __error /* avoid conflict with gdb error() */ +-int console(char *, ...); ++int console(const char *, ...); + void create_console_device(char *); + int console_off(void); + int console_on(int); +@@ -5321,10 +5324,6 @@ + long datatype_info(char *, char *, struct datatype_member *); + int get_symbol_type(char *, char *, struct gnu_request *); + int get_symbol_length(char *); +-int text_value_cache(ulong, uint32_t, uint32_t *); +-int text_value_cache_byte(ulong, unsigned char *); +-void dump_text_value_cache(int); +-void clear_text_value_cache(void); + void dump_numargs_cache(void); + int patch_kernel_symbol(struct gnu_request *); + struct syment *generic_machdep_value_to_symbol(ulong, ulong *); +@@ -5481,9 +5480,7 @@ + #define DUMP_DENTRY_ONLY 0x4 + #define DUMP_EMPTY_FILE 0x8 + #define DUMP_FILE_NRPAGES 0x10 +-#endif /* !GDB_COMMON */ + int same_file(char *, char *); +-#ifndef GDB_COMMON + int cleanup_memory_driver(void); + + +@@ -6855,6 +6852,7 @@ + int vmware_vmss_get_cr3_cr4_idtr(int, ulong *, ulong *, ulong *); + int vmware_vmss_phys_base(ulong *phys_base); + int vmware_vmss_set_phys_base(ulong); ++int vmware_vmss_get_cpu_reg(int, int, const char *, int, void *); + + /* + * vmware_guestdump.c +@@ -7174,10 +7172,10 @@ + int gdb_set_crash_scope(ulong, char *); + extern int *gdb_output_format; + extern unsigned int *gdb_print_max; +-extern int *gdb_prettyprint_structs; +-extern int *gdb_prettyprint_arrays; +-extern int *gdb_repeat_count_threshold; +-extern int *gdb_stop_print_at_null; ++extern unsigned char *gdb_prettyprint_structs; ++extern unsigned char *gdb_prettyprint_arrays; ++extern unsigned int *gdb_repeat_count_threshold; ++extern unsigned char *gdb_stop_print_at_null; + extern unsigned int *gdb_output_radix; + + /* +@@ -7279,4 +7277,53 @@ + #define XEN_HYPERVISOR_ARCH + #endif + ++/* ++ * Register numbers must be in sync with gdb/features/i386/64bit-core.c ++ * to make crash_target->fetch_registers() ---> machdep->get_cpu_reg() ++ * working properly. ++ */ ++enum x86_64_regnum { ++ RAX_REGNUM, ++ RBX_REGNUM, ++ RCX_REGNUM, ++ RDX_REGNUM, ++ RSI_REGNUM, ++ RDI_REGNUM, ++ RBP_REGNUM, ++ RSP_REGNUM, ++ R8_REGNUM, ++ R9_REGNUM, ++ R10_REGNUM, ++ R11_REGNUM, ++ R12_REGNUM, ++ R13_REGNUM, ++ R14_REGNUM, ++ R15_REGNUM, ++ RIP_REGNUM, ++ EFLAGS_REGNUM, ++ CS_REGNUM, ++ SS_REGNUM, ++ DS_REGNUM, ++ ES_REGNUM, ++ FS_REGNUM, ++ GS_REGNUM, ++ ST0_REGNUM, ++ ST1_REGNUM, ++ ST2_REGNUM, ++ ST3_REGNUM, ++ ST4_REGNUM, ++ ST5_REGNUM, ++ ST6_REGNUM, ++ ST7_REGNUM, ++ FCTRL_REGNUM, ++ FSTAT_REGNUM, ++ FTAG_REGNUM, ++ FISEG_REGNUM, ++ FIOFF_REGNUM, ++ FOSEG_REGNUM, ++ FOOFF_REGNUM, ++ FOP_REGNUM, ++ LAST_REGNUM ++}; ++ + #endif /* !GDB_COMMON */ +diff -Nur crash-7.3.0-orig/defs.h.orig crash-7.3.0/defs.h.orig +--- crash-7.3.0-orig/defs.h.orig 1970-01-01 08:00:00.000000000 +0800 ++++ crash-7.3.0/defs.h.orig 2023-07-07 14:05:59.063287668 +0800 +@@ -0,0 +1,7282 @@ ++/* defs.h - core analysis suite ++ * ++ * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. ++ * Copyright (C) 2002-2020 David Anderson ++ * Copyright (C) 2002-2020 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2002 Silicon Graphics, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef GDB_COMMON ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#undef basename ++#if !defined(__USE_GNU) ++#define __USE_GNU ++#include ++#undef __USE_GNU ++#else ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* backtrace() */ ++#include ++#ifdef LZO ++#include ++#endif ++#ifdef SNAPPY ++#include ++#endif ++ ++#ifndef ATTRIBUTE_UNUSED ++#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) ++#endif ++ ++#undef TRUE ++#undef FALSE ++ ++#define TRUE (1) ++#define FALSE (0) ++#define STR(x) #x ++#ifndef offsetof ++# define offsetof(TYPE, MEMBER) ((ulong)&((TYPE *)0)->MEMBER) ++#endif ++ ++#if !defined(X86) && !defined(X86_64) && !defined(ALPHA) && !defined(PPC) && \ ++ !defined(IA64) && !defined(PPC64) && !defined(S390) && !defined(S390X) && \ ++ !defined(ARM) && !defined(ARM64) && !defined(MIPS) && !defined(MIPS64) && \ ++ !defined(SPARC64) ++#ifdef __alpha__ ++#define ALPHA ++#endif ++#ifdef __i386__ ++#define X86 ++#endif ++#ifdef __powerpc64__ ++#define PPC64 ++#else ++#ifdef __powerpc__ ++#define PPC ++#endif ++#endif ++#ifdef __ia64__ ++#define IA64 ++#endif ++#ifdef __s390__ ++#define S390 ++#endif ++#ifdef __s390x__ ++#define S390X ++#endif ++#ifdef __x86_64__ ++#define X86_64 ++#endif ++#ifdef __arm__ ++#define ARM ++#endif ++#ifdef __aarch64__ ++#define ARM64 ++#endif ++#ifdef __mipsel__ ++#ifndef __mips64 ++#define MIPS ++#else ++#define MIPS64 ++#endif ++#endif ++#ifdef __sparc_v9__ ++#define SPARC64 ++#endif ++#endif ++ ++#ifdef X86 ++#define NR_CPUS (256) ++#endif ++#ifdef X86_64 ++#define NR_CPUS (8192) ++#endif ++#ifdef ALPHA ++#define NR_CPUS (64) ++#endif ++#ifdef PPC ++#define NR_CPUS (32) ++#endif ++#ifdef IA64 ++#define NR_CPUS (4096) ++#endif ++#ifdef PPC64 ++#define NR_CPUS (2048) ++#endif ++#ifdef S390 ++#define NR_CPUS (512) ++#endif ++#ifdef S390X ++#define NR_CPUS (512) ++#endif ++#ifdef ARM ++#define NR_CPUS (32) ++#endif ++#ifdef ARM64 ++#define NR_CPUS (4096) /* TBD */ ++#endif ++#ifdef MIPS ++#define NR_CPUS (32) ++#endif ++#ifdef MIPS64 ++#define NR_CPUS (256) ++#endif ++#ifdef SPARC64 ++#define NR_CPUS (4096) ++#endif ++ ++#define NR_DEVICE_DUMPS (64) ++ ++/* Some architectures require memory accesses to be aligned. */ ++#if defined(SPARC64) ++#define NEED_ALIGNED_MEM_ACCESS ++#endif ++ ++#define BUFSIZE (1500) ++#define NULLCHAR ('\0') ++ ++#define MAXARGS (100) /* max number of arguments to one function */ ++#define MAXARGLEN (40) /* max length of argument */ ++ ++#define HIST_BLKSIZE (4096) ++ ++static inline int string_exists(char *s) { return (s ? TRUE : FALSE); } ++#define STREQ(A, B) (string_exists((char *)A) && string_exists((char *)B) && \ ++ (strcmp((char *)(A), (char *)(B)) == 0)) ++#define STRNEQ(A, B) (string_exists((char *)A) && string_exists((char *)B) && \ ++ (strncmp((char *)(A), (char *)(B), strlen((char *)(B))) == 0)) ++#define BZERO(S, N) (memset(S, NULLCHAR, N)) ++#define BCOPY(S, D, C) (memcpy(D, S, C)) ++#define BNEG(S, N) (memset(S, 0xff, N)) ++#define BEEP() fprintf(stderr, "%c", 0x7) ++#define LASTCHAR(s) (s[strlen(s)-1]) ++#define FIRSTCHAR(s) (s[0]) ++#define QUOTED_STRING(s) ((FIRSTCHAR(s) == '"') && (LASTCHAR(s) == '"')) ++#define SINGLE_QUOTED_STRING(s) ((FIRSTCHAR(s) == '\'') && (LASTCHAR(s) == '\'')) ++#define PATHEQ(A, B) ((A) && (B) && (pathcmp((char *)(A), (char *)(B)) == 0)) ++ ++#ifdef roundup ++#undef roundup ++#endif ++#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) ++ ++typedef uint64_t physaddr_t; ++ ++#define PADDR_NOT_AVAILABLE (0x1ULL) ++#define KCORE_USE_VADDR (-1ULL) ++ ++typedef unsigned long long int ulonglong; ++struct number_option { ++ ulong num; ++ ulonglong ll_num; ++ ulong retflags; ++}; ++ ++/* ++ * program_context flags ++ */ ++#define LIVE_SYSTEM (0x1ULL) ++#define TTY (0x2ULL) ++#define RUNTIME (0x4ULL) ++#define IN_FOREACH (0x8ULL) ++#define MCLXCD (0x10ULL) ++#define CMDLINE_IFILE (0x20ULL) ++#define MFD_RDWR (0x40ULL) ++#define KVMDUMP (0x80ULL) ++#define SILENT (0x100ULL) ++#define SADUMP (0x200ULL) ++#define HASH (0x400ULL) ++#define SCROLL (0x800ULL) ++#define NO_CONSOLE (0x1000ULL) ++#define RUNTIME_IFILE (0x2000ULL) ++#define DROP_CORE (0x4000ULL) ++#define LKCD (0x8000ULL) ++#define GDB_INIT (0x10000ULL) ++#define IN_GDB (0x20000ULL) ++#define RCLOCAL_IFILE (0x40000ULL) ++#define RCHOME_IFILE (0x80000ULL) ++#define VMWARE_VMSS (0x100000ULL) ++#define READLINE (0x200000ULL) ++#define _SIGINT_ (0x400000ULL) ++#define IN_RESTART (0x800000ULL) ++#define KERNEL_DEBUG_QUERY (0x1000000ULL) ++#define DEVMEM (0x2000000ULL) ++#define REM_LIVE_SYSTEM (0x4000000ULL) ++#define NAMELIST_LOCAL (0x8000000ULL) ++#define LIVE_RAMDUMP (0x10000000ULL) ++#define NAMELIST_SAVED (0x20000000ULL) ++#define DUMPFILE_SAVED (0x40000000ULL) ++#define UNLINK_NAMELIST (0x80000000ULL) ++#define NAMELIST_UNLINKED (0x100000000ULL) ++#define REM_MCLXCD (0x200000000ULL) ++#define REM_LKCD (0x400000000ULL) ++#define NAMELIST_NO_GZIP (0x800000000ULL) ++#define UNLINK_MODULES (0x1000000000ULL) ++#define S390D (0x2000000000ULL) ++#define REM_S390D (0x4000000000ULL) ++#define SYSRQ (0x8000000000ULL) ++#define KDUMP (0x10000000000ULL) ++#define NETDUMP (0x20000000000ULL) ++#define REM_NETDUMP (0x40000000000ULL) ++#define SYSMAP (0x80000000000ULL) ++#define SYSMAP_ARG (0x100000000000ULL) ++#define MEMMOD (0x200000000000ULL) ++#define MODPRELOAD (0x400000000000ULL) ++#define DISKDUMP (0x800000000000ULL) ++#define DATADEBUG (0x1000000000000ULL) ++#define FINDKERNEL (0x2000000000000ULL) ++#define VERSION_QUERY (0x4000000000000ULL) ++#define READNOW (0x8000000000000ULL) ++#define NOCRASHRC (0x10000000000000ULL) ++#define INIT_IFILE (0x20000000000000ULL) ++#define XENDUMP (0x40000000000000ULL) ++#define XEN_HYPER (0x80000000000000ULL) ++#define XEN_CORE (0x100000000000000ULL) ++#define PLEASE_WAIT (0x200000000000000ULL) ++#define IFILE_ERROR (0x400000000000000ULL) ++#define KERNTYPES (0x800000000000000ULL) ++#define MINIMAL_MODE (0x1000000000000000ULL) ++#define CRASHBUILTIN (0x2000000000000000ULL) ++#define PRELOAD_EXTENSIONS \ ++ (0x4000000000000000ULL) ++#define PROC_KCORE (0x8000000000000000ULL) ++ ++#define ACTIVE() (pc->flags & LIVE_SYSTEM) ++#define LOCAL_ACTIVE() ((pc->flags & (LIVE_SYSTEM|LIVE_RAMDUMP)) == LIVE_SYSTEM) ++#define DUMPFILE() (!(pc->flags & LIVE_SYSTEM)) ++#define LIVE() (pc->flags2 & LIVE_DUMP || pc->flags & LIVE_SYSTEM) ++#define MEMORY_SOURCES (NETDUMP|KDUMP|MCLXCD|LKCD|DEVMEM|S390D|MEMMOD|DISKDUMP|XENDUMP|CRASHBUILTIN|KVMDUMP|PROC_KCORE|SADUMP|VMWARE_VMSS|LIVE_RAMDUMP) ++#define DUMPFILE_TYPES (DISKDUMP|NETDUMP|KDUMP|MCLXCD|LKCD|S390D|XENDUMP|KVMDUMP|SADUMP|VMWARE_VMSS|LIVE_RAMDUMP) ++#define REMOTE() (pc->flags2 & REMOTE_DAEMON) ++#define REMOTE_ACTIVE() (pc->flags & REM_LIVE_SYSTEM) ++#define REMOTE_DUMPFILE() \ ++ (pc->flags & (REM_NETDUMP|REM_MCLXCD|REM_LKCD|REM_S390D)) ++#define REMOTE_MEMSRC() (REMOTE_ACTIVE() || REMOTE_PAUSED() || REMOTE_DUMPFILE()) ++#define LKCD_DUMPFILE() (pc->flags & (LKCD|REM_LKCD)) ++#define NETDUMP_DUMPFILE() (pc->flags & (NETDUMP|REM_NETDUMP)) ++#define DISKDUMP_DUMPFILE() (pc->flags & DISKDUMP) ++#define KDUMP_DUMPFILE() (pc->flags & KDUMP) ++#define XENDUMP_DUMPFILE() (pc->flags & XENDUMP) ++#define XEN_HYPER_MODE() (pc->flags & XEN_HYPER) ++#define SYSRQ_TASK(X) ((pc->flags & SYSRQ) && is_task_active(X)) ++#define XEN_CORE_DUMPFILE() (pc->flags & XEN_CORE) ++#define LKCD_KERNTYPES() (pc->flags & KERNTYPES) ++#define KVMDUMP_DUMPFILE() (pc->flags & KVMDUMP) ++#define SADUMP_DUMPFILE() (pc->flags & SADUMP) ++#define VMSS_DUMPFILE() (pc->flags & VMWARE_VMSS) ++#define QEMU_MEM_DUMP_NO_VMCOREINFO() \ ++ ((pc->flags2 & (QEMU_MEM_DUMP_ELF|QEMU_MEM_DUMP_COMPRESSED)) && !(pc->flags2 & VMCOREINFO)) ++ ++ ++#define NETDUMP_LOCAL (0x1) /* netdump_data flags */ ++#define NETDUMP_REMOTE (0x2) ++#define VMCORE_VALID() (nd->flags & (NETDUMP_LOCAL|NETDUMP_REMOTE|KDUMP_LOCAL)) ++#define NETDUMP_ELF32 (0x4) ++#define NETDUMP_ELF64 (0x8) ++#define PARTIAL_DUMP (0x10) /* netdump or diskdump */ ++#define KDUMP_ELF32 (0x20) ++#define KDUMP_ELF64 (0x40) ++#define KDUMP_LOCAL (0x80) ++#define KCORE_LOCAL (0x100) ++#define KCORE_ELF32 (0x200) ++#define KCORE_ELF64 (0x400) ++#define QEMU_MEM_DUMP_KDUMP_BACKUP \ ++ (0x800) ++#define KVMDUMP_LOCAL (0x1) ++#define KVMDUMP_VALID() (kvm->flags & (KVMDUMP_LOCAL)) ++ ++#define DUMPFILE_FORMAT(flags) ((flags) & \ ++ (NETDUMP_ELF32|NETDUMP_ELF64|KDUMP_ELF32|KDUMP_ELF64)) ++ ++#define DISKDUMP_LOCAL (0x1) ++#define KDUMP_CMPRS_LOCAL (0x2) ++#define ERROR_EXCLUDED (0x4) ++#define ZERO_EXCLUDED (0x8) ++#define DUMPFILE_SPLIT (0x10) ++#define NO_ELF_NOTES (0x20) ++#define LZO_SUPPORTED (0x40) ++#define SNAPPY_SUPPORTED (0x80) ++#define DISKDUMP_VALID() (dd->flags & DISKDUMP_LOCAL) ++#define KDUMP_CMPRS_VALID() (dd->flags & KDUMP_CMPRS_LOCAL) ++#define KDUMP_SPLIT() (dd->flags & DUMPFILE_SPLIT) ++ ++#define XENDUMP_LOCAL (0x1) ++#define XENDUMP_VALID() (xd->flags & XENDUMP_LOCAL) ++ ++#define SADUMP_LOCAL (0x1) ++#define SADUMP_DISKSET (0x2) ++#define SADUMP_MEDIA (0x4) ++#define SADUMP_ZERO_EXCLUDED (0x8) ++#define SADUMP_KDUMP_BACKUP (0x10) ++#define SADUMP_VALID() (sd->flags & SADUMP_LOCAL) ++ ++#define CRASHDEBUG(x) (pc->debug >= (x)) ++ ++#define CRASHDEBUG_SUSPEND(X) { pc->debug_save = pc->debug; pc->debug = X; } ++#define CRASHDEBUG_RESTORE() { pc->debug = pc->debug_save; } ++ ++#define VERBOSE (0x1) ++#define ADDRESS_SPECIFIED (0x2) ++ ++#define FAULT_ON_ERROR (0x1) ++#define RETURN_ON_ERROR (0x2) ++#define QUIET (0x4) ++#define HEX_BIAS (0x8) ++#define LONG_LONG (0x10) ++#define RETURN_PARTIAL (0x20) ++#define NO_DEVMEM_SWITCH (0x40) ++ ++#define SEEK_ERROR (-1) ++#define READ_ERROR (-2) ++#define WRITE_ERROR (-3) ++#define PAGE_EXCLUDED (-4) ++ ++#define RESTART() (longjmp(pc->main_loop_env, 1)) ++#define RESUME_FOREACH() (longjmp(pc->foreach_loop_env, 1)) ++ ++#define INFO (1) ++#define FATAL (2) ++#define FATAL_RESTART (3) ++#define WARNING (4) ++#define NOTE (5) ++#define CONT (6) ++#define FATAL_ERROR(x) (((x) == FATAL) || ((x) == FATAL_RESTART)) ++ ++#define CONSOLE_OFF(x) ((x) = console_off()) ++#define CONSOLE_ON(x) (console_on(x)) ++ ++#define RADIX(X) (X) ++ ++#define NUM_HEX (0x1) ++#define NUM_DEC (0x2) ++#define NUM_EXPR (0x4) ++#define NUM_ANY (NUM_HEX|NUM_DEC|NUM_EXPR) ++ ++/* ++ * program context redirect flags ++ */ ++#define FROM_COMMAND_LINE (0x1) ++#define FROM_INPUT_FILE (0x2) ++#define REDIRECT_NOT_DONE (0x4) ++#define REDIRECT_TO_PIPE (0x8) ++#define REDIRECT_TO_STDPIPE (0x10) ++#define REDIRECT_TO_FILE (0x20) ++#define REDIRECT_FAILURE (0x40) ++#define REDIRECT_SHELL_ESCAPE (0x80) ++#define REDIRECT_SHELL_COMMAND (0x100) ++#define REDIRECT_PID_KNOWN (0x200) ++#define REDIRECT_MULTI_PIPE (0x400) ++ ++#define PIPE_OPTIONS (FROM_COMMAND_LINE | FROM_INPUT_FILE | REDIRECT_TO_PIPE | \ ++ REDIRECT_TO_STDPIPE | REDIRECT_TO_FILE) ++ ++#define DEFAULT_REDHAT_DEBUG_LOCATION "/usr/lib/debug/lib/modules" ++ ++#define MEMORY_DRIVER_MODULE "crash" ++#define MEMORY_DRIVER_DEVICE "/dev/crash" ++#define MEMORY_DRIVER_DEVICE_MODE (S_IFCHR|S_IRUSR) ++ ++/* ++ * structure definitions ++ */ ++struct program_context { ++ char *program_name; /* this program's name */ ++ char *program_path; /* unadulterated argv[0] */ ++ char *program_version; /* this program's version */ ++ char *gdb_version; /* embedded gdb version */ ++ char *prompt; /* this program's prompt */ ++ unsigned long long flags; /* flags from above */ ++ char *namelist; /* linux namelist */ ++ char *dumpfile; /* dumpfile or /dev/kmem */ ++ char *live_memsrc; /* live memory driver */ ++ char *system_map; /* get symbol values from System.map */ ++ char *namelist_debug; /* namelist containing debug data */ ++ char *debuginfo_file; /* separate debuginfo file */ ++ char *memory_module; /* alternative to mem.c driver */ ++ char *memory_device; /* alternative to /dev/[k]mem device */ ++ char *machine_type; /* machine's processor type */ ++ char *editing_mode; /* readline vi or emacs */ ++ char *server; /* network daemon */ ++ char *server_memsrc; /* memory source on server */ ++ char *server_namelist; /* kernel namelist on server */ ++ int nfd; /* linux namelist fd */ ++ int mfd; /* /dev/mem fd */ ++ int kfd; /* /dev/kmem fd */ ++ int dfd; /* dumpfile fd */ ++ int confd; /* console fd */ ++ int sockfd; /* network daemon socket */ ++ ushort port; /* network daemon port */ ++ int rmfd; /* remote server memory source fd */ ++ int rkfd; /* remote server /dev/kmem fd */ ++ ulong program_pid; /* program pid */ ++ ulong server_pid; /* server pid */ ++ ulong rcvbufsize; /* client-side receive buffer size */ ++ char *home; /* user's home directory */ ++ char command_line[BUFSIZE]; /* possibly parsed input command line */ ++ char orig_line[BUFSIZE]; /* original input line */ ++ char *readline; /* pointer to last readline() return */ ++ char my_tty[10]; /* real tty name (shown by ps -ef) */ ++ ulong debug; /* level of debug */ ++ ulong debug_save; /* saved level for debug-suspend */ ++ char *console; /* current debug console device */ ++ char *redhat_debug_loc; /* location of matching debug objects */ ++ int pipefd[2]; /* output pipe file descriptors */ ++ FILE *nullfp; /* bitbucket */ ++ FILE *stdpipe; /* standard pipe for output */ ++ FILE *pipe; /* command line specified pipe */ ++ FILE *ofile; /* command line specified output file */ ++ FILE *ifile; /* command line specified input file */ ++ FILE *ifile_pipe; /* output pipe specified from file */ ++ FILE *ifile_ofile; /* output file specified from file */ ++ FILE *symfile; /* symbol table data file */ ++ FILE *symfile2; /* alternate access to above */ ++ FILE *tmpfile; /* tmpfile for selective data output */ ++ FILE *saved_fp; /* for printing while parsing tmpfile */ ++ FILE *tmp_fp; /* stored tmpfile pointer */ ++ char *input_file; /* input file specified at invocation */ ++ FILE *tmpfile2; /* tmpfile2 does not use save_fp! */ ++ int eoc_index; /* end of redirected command index */ ++ int scroll_command; /* default scroll command for output */ ++#define SCROLL_NONE 0 ++#define SCROLL_LESS 1 ++#define SCROLL_MORE 2 ++#define SCROLL_CRASHPAGER 3 ++ ulong redirect; /* per-cmd origin and output flags */ ++ pid_t stdpipe_pid; /* per-cmd standard output pipe's pid */ ++ pid_t pipe_pid; /* per-cmd output pipe's pid */ ++ pid_t pipe_shell_pid; /* per-cmd output pipe's shell pid */ ++ char pipe_command[BUFSIZE]; /* pipe command line */ ++ struct command_table_entry *cmd_table; /* linux/xen command table */ ++ char *curcmd; /* currently-executing command */ ++ char *lastcmd; /* previously-executed command */ ++ ulong cmdgencur; /* current command generation number */ ++ ulong curcmd_flags; /* general purpose per-command flag */ ++#define XEN_MACHINE_ADDR (0x1) ++#define REPEAT (0x2) ++#define IDLE_TASK_SHOWN (0x4) ++#define TASK_SPECIFIED (0x8) ++#define MEMTYPE_UVADDR (0x10) ++#define MEMTYPE_FILEADDR (0x20) ++#define HEADER_PRINTED (0x40) ++#define BAD_INSTRUCTION (0x80) ++#define UD2A_INSTRUCTION (0x100) ++#define IRQ_IN_USE (0x200) ++#define NO_MODIFY (0x400) ++#define IGNORE_ERRORS (0x800) ++#define FROM_RCFILE (0x1000) ++#define MEMTYPE_KVADDR (0x2000) ++#define MOD_SECTIONS (0x4000) ++#define MOD_READNOW (0x8000) ++#define MM_STRUCT_FORCE (0x10000) ++#define CPUMASK (0x20000) ++#define PARTIAL_READ_OK (0x40000) ++ ulonglong curcmd_private; /* general purpose per-command info */ ++ int cur_gdb_cmd; /* current gdb command */ ++ int last_gdb_cmd; /* previously-executed gdb command */ ++ int sigint_cnt; /* number of ignored SIGINTs */ ++ struct gnu_request *cur_req; /* current gdb gnu_request */ ++ struct sigaction sigaction; /* general usage sigaction. */ ++ struct sigaction gdb_sigaction; /* gdb's SIGINT sigaction. */ ++ jmp_buf main_loop_env; /* longjmp target default */ ++ jmp_buf foreach_loop_env; /* longjmp target within foreach */ ++ jmp_buf gdb_interface_env; /* longjmp target for gdb error catch */ ++ struct termios termios_orig; /* non-raw settings */ ++ struct termios termios_raw; /* while gathering command input */ ++ int ncmds; /* number of commands in menu */ ++ char **cmdlist; /* current list of available commands */ ++ int cmdlistsz; /* space available in cmdlist */ ++ unsigned output_radix; /* current gdb output_radix */ ++ void *sbrk; /* current sbrk value */ ++ struct extension_table *curext; /* extension being loaded */ ++ int (*readmem)(int, void *, int, ulong, physaddr_t); /* memory access */ ++ int (*writemem)(int, void *, int, ulong, physaddr_t);/* memory access */ ++ ulong ifile_in_progress; /* original xxx_IFILE flags */ ++ off_t ifile_offset; /* current offset into input file */ ++ char *runtime_ifile_cmd; /* runtime command using input file */ ++ char *kvmdump_mapfile; /* storage of physical to file offsets */ ++ ulonglong flags2; /* flags overrun */ ++#define FLAT (0x01ULL) ++#define ELF_NOTES (0x02ULL) ++#define GET_OSRELEASE (0x04ULL) ++#define REMOTE_DAEMON (0x08ULL) ++#define ERASEINFO_DATA (0x10ULL) ++#define GDB_CMD_MODE (0x20ULL) ++#define LIVE_DUMP (0x40ULL) ++#define FLAT_FORMAT() (pc->flags2 & FLAT) ++#define ELF_NOTES_VALID() (pc->flags2 & ELF_NOTES) ++#define RADIX_OVERRIDE (0x80ULL) ++#define QEMU_MEM_DUMP_ELF (0x100ULL) ++#define GET_LOG (0x200ULL) ++#define VMCOREINFO (0x400ULL) ++#define ALLOW_FP (0x800ULL) ++#define REM_PAUSED_F (0x1000ULL) ++#define RAMDUMP (0x2000ULL) ++#define REMOTE_PAUSED() (pc->flags2 & REM_PAUSED_F) ++#define OFFLINE_HIDE (0x4000ULL) ++#define INCOMPLETE_DUMP (0x8000ULL) ++#define is_incomplete_dump() (pc->flags2 & INCOMPLETE_DUMP) ++#define QEMU_MEM_DUMP_COMPRESSED (0x10000ULL) ++#define SNAP (0x20000ULL) ++#define EXCLUDED_VMEMMAP (0x40000ULL) ++#define is_excluded_vmemmap() (pc->flags2 & EXCLUDED_VMEMMAP) ++#define MEMSRC_LOCAL (0x80000ULL) ++#define REDZONE (0x100000ULL) ++#define VMWARE_VMSS_GUESTDUMP (0x200000ULL) ++ char *cleanup; ++ char *namelist_orig; ++ char *namelist_debug_orig; ++ FILE *args_ifile; /* per-command args input file */ ++ void (*cmd_cleanup)(void *); /* per-command cleanup function */ ++ void *cmd_cleanup_arg; /* optional cleanup function argument */ ++ ulong scope; /* optional text context address */ ++ ulong nr_hash_queues; /* hash queue head count */ ++ char *(*read_vmcoreinfo)(const char *); ++ FILE *error_fp; /* error() message direction */ ++ char *error_path; /* stderr path information */ ++}; ++ ++#define READMEM pc->readmem ++ ++typedef void (*cmd_func_t)(void); ++ ++struct command_table_entry { /* one for each command in menu */ ++ char *name; ++ cmd_func_t func; ++ char **help_data; ++ ulong flags; ++}; ++ ++struct args_input_file { ++ int index; ++ int args_used; ++ int is_gdb_cmd; ++ int in_expression; ++ int start; ++ int resume; ++ char *fileptr; ++}; ++ ++#define REFRESH_TASK_TABLE (0x1) /* command_table_entry flags */ ++#define HIDDEN_COMMAND (0x2) ++#define CLEANUP (0x4) /* for extensions only */ ++#define MINIMAL (0x8) ++ ++/* ++ * A linked list of extension table structures keeps track of the current ++ * set of shared library extensions. ++ */ ++struct extension_table { ++ void *handle; /* handle from dlopen() */ ++ char *filename; /* name of shared library */ ++ struct command_table_entry *command_table; /* list of commands */ ++ ulong flags; /* registration flags */ ++ struct extension_table *next, *prev; /* bookkeeping */ ++}; ++ ++#define REGISTERED (0x1) /* extension_table flags */ ++#define DUPLICATE_COMMAND_NAME (0x2) ++#define NO_MINIMAL_COMMANDS (0x4) ++ ++struct new_utsname { ++ char sysname[65]; ++ char nodename[65]; ++ char release[65]; ++ char version[65]; ++ char machine[65]; ++ char domainname[65]; ++}; ++ ++#define NO_MODULE_ACCESS (0x1) ++#define TVEC_BASES_V1 (0x2) ++#define GCC_3_2 (0x4) ++#define GCC_3_2_3 (0x8) ++#define GCC_2_96 (0x10) ++#define RA_SEEK (0x20) ++#define NO_RA_SEEK (0x40) ++#define KALLSYMS_V1 (0x80) ++#define NO_KALLSYMS (0x100) ++#define PER_CPU_OFF (0x200) ++#define SMP (0x400) ++#define GCC_3_3_2 (0x800) ++#define KMOD_V1 (0x1000) ++#define KMOD_V2 (0x2000) ++#define KALLSYMS_V2 (0x2000) ++#define TVEC_BASES_V2 (0x4000) ++#define GCC_3_3_3 (0x8000) ++#define USE_OLD_BT (0x10000) ++#define USE_OPT_BT (0x10000) ++#define ARCH_XEN (0x20000) ++#define NO_IKCONFIG (0x40000) ++#define DWARF_UNWIND (0x80000) ++#define NO_DWARF_UNWIND (0x100000) ++#define DWARF_UNWIND_MEMORY (0x200000) ++#define DWARF_UNWIND_EH_FRAME (0x400000) ++#define DWARF_UNWIND_CAPABLE (DWARF_UNWIND_MEMORY|DWARF_UNWIND_EH_FRAME) ++#define DWARF_UNWIND_MODULES (0x800000) ++#define BUGVERBOSE_OFF (0x1000000) ++#define RELOC_SET (0x2000000) ++#define RELOC_FORCE (0x4000000) ++#define ARCH_OPENVZ (0x8000000) ++#define ARCH_PVOPS (0x10000000) ++#define PRE_KERNEL_INIT (0x20000000) ++#define ARCH_PVOPS_XEN (0x40000000) ++ ++#define GCC_VERSION_DEPRECATED (GCC_3_2|GCC_3_2_3|GCC_2_96|GCC_3_3_2|GCC_3_3_3) ++ ++/* flags2 */ ++#define RELOC_AUTO (0x1ULL) ++#define KASLR (0x2ULL) ++#define KASLR_CHECK (0x4ULL) ++#define GET_TIMESTAMP (0x8ULL) ++#define TVEC_BASES_V3 (0x10ULL) ++#define TIMER_BASES (0x20ULL) ++#define IRQ_DESC_TREE_RADIX (0x40ULL) ++#define IRQ_DESC_TREE_XARRAY (0x80ULL) ++#define KMOD_PAX (0x100ULL) ++ ++#define XEN() (kt->flags & ARCH_XEN) ++#define OPENVZ() (kt->flags & ARCH_OPENVZ) ++#define PVOPS() (kt->flags & ARCH_PVOPS) ++#define PVOPS_XEN() (kt->flags & ARCH_PVOPS_XEN) ++ ++#define PAX_MODULE_SPLIT() (kt->flags2 & KMOD_PAX) ++ ++#define XEN_MACHINE_TO_MFN(m) ((ulonglong)(m) >> PAGESHIFT()) ++#define XEN_PFN_TO_PSEUDO(p) ((ulonglong)(p) << PAGESHIFT()) ++ ++#define XEN_MFN_NOT_FOUND (~0UL) ++#define XEN_PFNS_PER_PAGE (PAGESIZE()/sizeof(ulong)) ++#define XEN_FOREIGN_FRAME (1UL << (BITS()-1)) ++ ++#define XEN_MACHADDR_NOT_FOUND (~0ULL) ++ ++#define XEN_P2M_PER_PAGE (PAGESIZE() / sizeof(unsigned long)) ++#define XEN_P2M_MID_PER_PAGE (PAGESIZE() / sizeof(unsigned long *)) ++#define XEN_P2M_TOP_PER_PAGE (PAGESIZE() / sizeof(unsigned long **)) ++ ++struct kernel_table { /* kernel data */ ++ ulong flags; ++ ulong stext; ++ ulong etext; ++ ulong stext_init; ++ ulong etext_init; ++ ulong init_begin; ++ ulong init_end; ++ ulong end; ++ int cpus; ++ char *cpus_override; ++ void (*display_bh)(void); ++ ulong module_list; ++ ulong kernel_module; ++ int mods_installed; ++ struct timespec date; ++ char proc_version[BUFSIZE]; ++ struct new_utsname utsname; ++ uint kernel_version[3]; ++ uint gcc_version[3]; ++ int runq_siblings; ++ int kernel_NR_CPUS; ++ long __per_cpu_offset[NR_CPUS]; ++ long *__rq_idx; ++ long *__cpu_idx; ++ ulong *cpu_flags; ++#define POSSIBLE (0x1) ++#define PRESENT (0x2) ++#define ONLINE (0x4) ++#define NMI (0x8) ++#define POSSIBLE_MAP (POSSIBLE) ++#define PRESENT_MAP (PRESENT) ++#define ONLINE_MAP (ONLINE) ++#define ACTIVE_MAP (0x10) ++ int BUG_bytes; ++ ulong xen_flags; ++#define WRITABLE_PAGE_TABLES (0x1) ++#define SHADOW_PAGE_TABLES (0x2) ++#define CANONICAL_PAGE_TABLES (0x4) ++#define XEN_SUSPEND (0x8) ++ char *m2p_page; ++ ulong phys_to_machine_mapping; ++ ulong p2m_table_size; ++#define P2M_MAPPING_CACHE (512) ++ struct p2m_mapping_cache { ++ ulong mapping; ++ ulong pfn; ++ ulong start; ++ ulong end; ++ } p2m_mapping_cache[P2M_MAPPING_CACHE]; ++#define P2M_MAPPING_PAGE_PFN(c) \ ++ (PVOPS_XEN() ? kt->p2m_mapping_cache[c].pfn : \ ++ (((kt->p2m_mapping_cache[c].mapping - kt->phys_to_machine_mapping)/PAGESIZE()) \ ++ * XEN_PFNS_PER_PAGE)) ++ ulong last_mapping_read; ++ ulong p2m_cache_index; ++ ulong p2m_pages_searched; ++ ulong p2m_mfn_cache_hits; ++ ulong p2m_page_cache_hits; ++ ulong relocate; ++ char *module_tree; ++ struct pvops_xen_info { ++ int p2m_top_entries; ++ ulong p2m_top; ++ ulong p2m_mid_missing; ++ ulong p2m_missing; ++ } pvops_xen; ++ int highest_irq; ++#define IKCONFIG_AVAIL 0x1 /* kernel contains ikconfig data */ ++#define IKCONFIG_LOADED 0x2 /* ikconfig data is currently loaded */ ++ int ikconfig_flags; ++ int ikconfig_ents; ++ char *hypervisor; ++ struct vmcoreinfo_data { ++ ulong log_buf_SYMBOL; ++ ulong log_end_SYMBOL; ++ ulong log_buf_len_SYMBOL; ++ ulong logged_chars_SYMBOL; ++ ulong log_first_idx_SYMBOL; ++ ulong log_next_idx_SYMBOL; ++ long log_SIZE; ++ long log_ts_nsec_OFFSET; ++ long log_len_OFFSET; ++ long log_text_len_OFFSET; ++ long log_dict_len_OFFSET; ++ ulong phys_base_SYMBOL; ++ ulong _stext_SYMBOL; ++ } vmcoreinfo; ++ ulonglong flags2; ++ char *source_tree; ++ struct timespec boot_date; ++}; ++ ++/* ++ * Aid for the two versions of the kernel's module list linkage. ++ */ ++#define NEXT_MODULE(next_module, modbuf) \ ++{ \ ++ switch (kt->flags & (KMOD_V1|KMOD_V2)) \ ++ { \ ++ case KMOD_V1: \ ++ next_module = ULONG(modbuf + OFFSET(module_next)); \ ++ break; \ ++ case KMOD_V2: \ ++ next_module = ULONG(modbuf + OFFSET(module_list)); \ ++ if (next_module != kt->kernel_module) \ ++ next_module -= OFFSET(module_list); \ ++ break; \ ++ } \ ++} ++ ++#define THIS_KERNEL_VERSION ((kt->kernel_version[0] << 16) + \ ++ (kt->kernel_version[1] << 8) + \ ++ (kt->kernel_version[2])) ++#define LINUX(x,y,z) (((uint)(x) << 16) + ((uint)(y) << 8) + (uint)(z)) ++ ++#define THIS_GCC_VERSION ((kt->gcc_version[0] << 16) + \ ++ (kt->gcc_version[1] << 8) + \ ++ (kt->gcc_version[2])) ++#define GCC(x,y,z) (((uint)(x) << 16) + ((uint)(y) << 8) + (uint)(z)) ++ ++#define IS_KERNEL_STATIC_TEXT(x) (((ulong)(x) >= kt->stext) && \ ++ ((ulong)(x) < kt->etext)) ++ ++#define TASK_COMM_LEN 16 /* task command name length including NULL */ ++ ++struct task_context { /* context stored for each task */ ++ ulong task; ++ ulong thread_info; ++ ulong pid; ++ char comm[TASK_COMM_LEN+1]; ++ int processor; ++ ulong ptask; ++ ulong mm_struct; ++ struct task_context *tc_next; ++}; ++ ++struct tgid_context { /* tgid and task stored for each task */ ++ ulong tgid; ++ ulong task; ++}; ++ ++struct task_table { /* kernel/local task table data */ ++ struct task_context *current; ++ struct task_context *context_array; ++ void (*refresh_task_table)(void); ++ ulong flags; ++ ulong task_start; ++ ulong task_end; ++ void *task_local; ++ int max_tasks; ++ int nr_threads; ++ ulong running_tasks; ++ ulong retries; ++ ulong panicmsg; ++ int panic_processor; ++ ulong *idle_threads; ++ ulong *panic_threads; ++ ulong *active_set; ++ ulong *panic_ksp; ++ ulong *hardirq_ctx; ++ ulong *hardirq_tasks; ++ ulong *softirq_ctx; ++ ulong *softirq_tasks; ++ ulong panic_task; ++ ulong this_task; ++ int pidhash_len; ++ ulong pidhash_addr; ++ ulong last_task_read; ++ ulong last_thread_info_read; ++ ulong last_mm_read; ++ char *task_struct; ++ char *thread_info; ++ char *mm_struct; ++ ulong init_pid_ns; ++ struct tgid_context *tgid_array; ++ struct tgid_context *last_tgid; ++ ulong tgid_searches; ++ ulong tgid_cache_hits; ++ long filepages; ++ long anonpages; ++ ulong stack_end_magic; ++ ulong pf_kthread; ++ ulong pid_radix_tree; ++ int callbacks; ++ struct task_context **context_by_task; /* task_context sorted by task addr */ ++ ulong pid_xarray; ++}; ++ ++#define TASK_INIT_DONE (0x1) ++#define TASK_ARRAY_EXISTS (0x2) ++#define PANIC_TASK_NOT_FOUND (0x4) ++#define TASK_REFRESH (0x8) ++#define TASK_REFRESH_OFF (0x10) ++#define PANIC_KSP (0x20) ++#define ACTIVE_SET (0x40) ++#define POPULATE_PANIC (0x80) ++#define PIDHASH (0x100) ++#define PID_HASH (0x200) ++#define THREAD_INFO (0x400) ++#define IRQSTACKS (0x800) ++#define TIMESPEC (0x1000) ++#define NO_TIMESPEC (0x2000) ++#define ACTIVE_ONLY (0x4000) ++#define START_TIME_NSECS (0x8000) ++#define THREAD_INFO_IN_TASK (0x10000) ++#define PID_RADIX_TREE (0x20000) ++#define INDEXED_CONTEXTS (0x40000) ++#define PID_XARRAY (0x80000) ++ ++#define TASK_SLUSH (20) ++ ++#define NO_PROC_ID 0xFF /* No processor magic marker (from kernel) */ ++ ++/* ++ * Global "tt" points to task_table ++ */ ++#define CURRENT_CONTEXT() (tt->current) ++#define CURRENT_TASK() (tt->current->task) ++#define CURRENT_PID() (tt->current->pid) ++#define CURRENT_COMM() (tt->current->comm) ++#define RUNNING_TASKS() (tt->running_tasks) ++#define FIRST_CONTEXT() (tt->context_array) ++ ++#define NO_PID ((ulong)-1) ++#define NO_TASK (0) ++ ++#define IS_TASK_ADDR(X) (machdep->is_task_addr(X)) ++#define GET_STACKBASE(X) (machdep->get_stackbase(X)) ++#define GET_STACKTOP(X) (machdep->get_stacktop(X)) ++#define STACKSIZE() (machdep->stacksize) ++#define LONGS_PER_STACK (machdep->stacksize/sizeof(ulong)) ++ ++#define INSTACK(X,BT) \ ++ (((ulong)(X) >= (BT)->stackbase) && ((ulong)(X) < (BT)->stacktop)) ++ ++#define ALIGNED_STACK_OFFSET(task) ((ulong)(task) & (STACKSIZE()-1)) ++ ++#define BITS() (machdep->bits) ++#define BITS32() (machdep->bits == 32) ++#define BITS64() (machdep->bits == 64) ++#define IS_KVADDR(X) (machdep->is_kvaddr(X)) ++#define IS_UVADDR(X,C) (machdep->is_uvaddr(X,C)) ++ ++#define PID_ALIVE(x) (kill(x, 0) == 0) ++ ++struct kernel_list_head { ++ struct kernel_list_head *next, *prev; ++}; ++ ++struct stack_hook { ++ ulong esp; ++ ulong eip; ++}; ++ ++struct bt_info { ++ ulong task; ++ ulonglong flags; ++ ulong instptr; ++ ulong stkptr; ++ ulong bptr; ++ ulong stackbase; ++ ulong stacktop; ++ char *stackbuf; ++ struct task_context *tc; ++ struct stack_hook *hp; ++ struct stack_hook *textlist; ++ struct reference *ref; ++ ulong frameptr; ++ char *call_target; ++ void *machdep; ++ ulong debug; ++ ulong eframe_ip; ++ ulong radix; ++ ulong *cpumask; ++}; ++ ++#define STACK_OFFSET_TYPE(OFF) \ ++ (((ulong)(OFF) > STACKSIZE()) ? \ ++ (ulong)((ulong)(OFF) - (ulong)(bt->stackbase)) : (ulong)(OFF)) ++ ++#define GET_STACK_ULONG(OFF) \ ++ *((ulong *)((char *)(&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(OFF))]))) ++ ++#define GET_STACK_DATA(OFF, LOC, SZ) memcpy((void *)(LOC), \ ++ (void *)(&bt->stackbuf[(ulong)STACK_OFFSET_TYPE(OFF)]), (size_t)(SZ)) ++ ++struct machine_specific; /* uniquely defined below each machine's area */ ++struct xendump_data; ++struct xen_kdump_data; ++ ++struct vaddr_range { ++ ulong start; ++ ulong end; ++ ulong type; ++#define KVADDR_UNITY_MAP (1) ++#define KVADDR_VMALLOC (2) ++#define KVADDR_VMEMMAP (3) ++#define KVADDR_START_MAP (4) ++#define KVADDR_MODULES (5) ++#define MAX_KVADDR_RANGES KVADDR_MODULES ++}; ++ ++#define MAX_MACHDEP_ARGS 5 /* for --machdep/-m machine-specific args */ ++ ++struct machdep_table { ++ ulong flags; ++ ulong kvbase; ++ ulong identity_map_base; ++ uint pagesize; ++ uint pageshift; ++ ulonglong pagemask; ++ ulong pageoffset; ++ ulong stacksize; ++ uint hz; ++ ulong mhz; ++ int bits; ++ int nr_irqs; ++ uint64_t memsize; ++ int (*eframe_search)(struct bt_info *); ++ void (*back_trace)(struct bt_info *); ++ ulong (*processor_speed)(void); ++ int (*uvtop)(struct task_context *, ulong, physaddr_t *, int); ++ int (*kvtop)(struct task_context *, ulong, physaddr_t *, int); ++ ulong (*get_task_pgd)(ulong); ++ void (*dump_irq)(int); ++ void (*get_stack_frame)(struct bt_info *, ulong *, ulong *); ++ ulong (*get_stackbase)(ulong); ++ ulong (*get_stacktop)(ulong); ++ int (*translate_pte)(ulong, void *, ulonglong); ++ uint64_t (*memory_size)(void); ++ ulong (*vmalloc_start)(void); ++ int (*is_task_addr)(ulong); ++ int (*verify_symbol)(const char *, ulong, char); ++ int (*dis_filter)(ulong, char *, unsigned int); ++ int (*get_smp_cpus)(void); ++ int (*is_kvaddr)(ulong); ++ int (*is_uvaddr)(ulong, struct task_context *); ++ int (*verify_paddr)(uint64_t); ++ void (*cmd_mach)(void); ++ void (*init_kernel_pgd)(void); ++ struct syment *(*value_to_symbol)(ulong, ulong *); ++ struct line_number_hook { ++ char *func; ++ char **file; ++ } *line_number_hooks; ++ ulong last_pgd_read; ++ ulong last_pud_read; ++ ulong last_pmd_read; ++ ulong last_ptbl_read; ++ char *pgd; ++ char *pud; ++ char *pmd; ++ char *ptbl; ++ int ptrs_per_pgd; ++ char *cmdline_args[MAX_MACHDEP_ARGS]; ++ struct machine_specific *machspec; ++ ulong section_size_bits; ++ ulong max_physmem_bits; ++ ulong sections_per_root; ++ int (*xendump_p2m_create)(struct xendump_data *); ++ ulong (*xendump_panic_task)(struct xendump_data *); ++ void (*get_xendump_regs)(struct xendump_data *, struct bt_info *, ulong *, ulong *); ++ void (*clear_machdep_cache)(void); ++ int (*xen_kdump_p2m_create)(struct xen_kdump_data *); ++ int (*in_alternate_stack)(int, ulong); ++ void (*dumpfile_init)(int, void *); ++ void (*process_elf_notes)(void *, unsigned long); ++ int (*get_kvaddr_ranges)(struct vaddr_range *); ++ int (*verify_line_number)(ulong, ulong, ulong); ++ void (*get_irq_affinity)(int); ++ void (*show_interrupts)(int, ulong *); ++ int (*is_page_ptr)(ulong, physaddr_t *); ++}; ++ ++/* ++ * Processor-common flags; processor-specific flags use the lower bits ++ * as defined in their processor-specific files below. (see KSYMS_START defs). ++ */ ++#define HWRESET (0x80000000) ++#define OMIT_FRAME_PTR (0x40000000) ++#define FRAMESIZE_DEBUG (0x20000000) ++#define MACHDEP_BT_TEXT (0x10000000) ++#define DEVMEMRD (0x8000000) ++#define INIT (0x4000000) ++#define VM_4_LEVEL (0x2000000) ++#define MCA (0x1000000) ++#define PAE (0x800000) ++#define VMEMMAP (0x400000) ++ ++extern struct machdep_table *machdep; ++ ++#ifndef HZ ++#define HZ sysconf(_SC_CLK_TCK) ++#endif ++ ++#define IS_LAST_PGD_READ(pgd) ((ulong)(pgd) == machdep->last_pgd_read) ++#define IS_LAST_PMD_READ(pmd) ((ulong)(pmd) == machdep->last_pmd_read) ++#define IS_LAST_PTBL_READ(ptbl) ((ulong)(ptbl) == machdep->last_ptbl_read) ++#define IS_LAST_PUD_READ(pud) ((ulong)(pud) == machdep->last_pud_read) ++ ++#define FILL_PGD(PGD, TYPE, SIZE) \ ++ if (!IS_LAST_PGD_READ(PGD)) { \ ++ readmem((ulonglong)((ulong)(PGD)), TYPE, machdep->pgd, \ ++ SIZE, "pgd page", FAULT_ON_ERROR); \ ++ machdep->last_pgd_read = (ulong)(PGD); \ ++ } ++ ++#define FILL_PUD(PUD, TYPE, SIZE) \ ++ if (!IS_LAST_PUD_READ(PUD)) { \ ++ readmem((ulonglong)((ulong)(PUD)), TYPE, machdep->pud, \ ++ SIZE, "pud page", FAULT_ON_ERROR); \ ++ machdep->last_pud_read = (ulong)(PUD); \ ++ } ++ ++#define FILL_PMD(PMD, TYPE, SIZE) \ ++ if (!IS_LAST_PMD_READ(PMD)) { \ ++ readmem((ulonglong)(PMD), TYPE, machdep->pmd, \ ++ SIZE, "pmd page", FAULT_ON_ERROR); \ ++ machdep->last_pmd_read = (ulong)(PMD); \ ++ } ++ ++#define FILL_PTBL(PTBL, TYPE, SIZE) \ ++ if (!IS_LAST_PTBL_READ(PTBL)) { \ ++ readmem((ulonglong)(PTBL), TYPE, machdep->ptbl, \ ++ SIZE, "page table", FAULT_ON_ERROR); \ ++ machdep->last_ptbl_read = (ulong)(PTBL); \ ++ } ++ ++#define SETUP_ENV (0) ++#define PRE_SYMTAB (1) ++#define PRE_GDB (2) ++#define POST_GDB (3) ++#define POST_INIT (4) ++#define POST_VM (5) ++#define LOG_ONLY (6) ++#define POST_RELOC (7) ++ ++#define FOREACH_BT (1) ++#define FOREACH_VM (2) ++#define FOREACH_TASK (3) ++#define FOREACH_SET (4) ++#define FOREACH_FILES (5) ++#define FOREACH_NET (6) ++#define FOREACH_TEST (7) ++#define FOREACH_VTOP (8) ++#define FOREACH_SIG (9) ++#define FOREACH_PS (10) ++ ++#define MAX_FOREACH_KEYWORDS (10) ++#define MAX_FOREACH_TASKS (50) ++#define MAX_FOREACH_PIDS (50) ++#define MAX_FOREACH_COMMS (50) ++#define MAX_FOREACH_ARGS (50) ++#define MAX_REGEX_ARGS (10) ++ ++#define FOREACH_CMD (0x1) ++#define FOREACH_r_FLAG (0x2) ++#define FOREACH_s_FLAG (0x4) ++#define FOREACH_S_FLAG (0x8) ++#define FOREACH_i_FLAG (0x10) ++#define FOREACH_e_FLAG (0x20) ++#define FOREACH_g_FLAG (0x40) ++#define FOREACH_l_FLAG (0x80) ++#define FOREACH_p_FLAG (0x100) ++#define FOREACH_t_FLAG (0x200) ++#define FOREACH_u_FLAG (0x400) ++#define FOREACH_m_FLAG (0x800) ++#define FOREACH_v_FLAG (0x1000) ++#define FOREACH_KERNEL (0x2000) ++#define FOREACH_USER (0x4000) ++#define FOREACH_SPECIFIED (0x8000) ++#define FOREACH_ACTIVE (0x10000) ++#define FOREACH_k_FLAG (0x20000) ++#define FOREACH_c_FLAG (0x40000) ++#define FOREACH_f_FLAG (0x80000) ++#define FOREACH_o_FLAG (0x100000) ++#define FOREACH_T_FLAG (0x200000) ++#define FOREACH_F_FLAG (0x400000) ++#define FOREACH_x_FLAG (0x800000) ++#define FOREACH_d_FLAG (0x1000000) ++#define FOREACH_STATE (0x2000000) ++#define FOREACH_a_FLAG (0x4000000) ++#define FOREACH_G_FLAG (0x8000000) ++#define FOREACH_F_FLAG2 (0x10000000) ++#define FOREACH_y_FLAG (0x20000000) ++#define FOREACH_GLEADER (0x40000000) ++ ++#define FOREACH_PS_EXCLUSIVE \ ++ (FOREACH_g_FLAG|FOREACH_a_FLAG|FOREACH_t_FLAG|FOREACH_c_FLAG|FOREACH_p_FLAG|FOREACH_l_FLAG|FOREACH_r_FLAG|FOREACH_m_FLAG) ++ ++struct foreach_data { ++ ulong flags; ++ int keyword_array[MAX_FOREACH_KEYWORDS]; ++ ulong task_array[MAX_FOREACH_TASKS]; ++ char *comm_array[MAX_FOREACH_COMMS]; ++ ulong pid_array[MAX_FOREACH_PIDS]; ++ ulong arg_array[MAX_FOREACH_ARGS]; ++ struct regex_info { ++ char *pattern; ++ regex_t regex; ++ } regex_info[MAX_REGEX_ARGS]; ++ ulong state; ++ char *reference; ++ int keys; ++ int pids; ++ int tasks; ++ int comms; ++ int args; ++ int regexs; ++ int policy; ++}; ++ ++struct reference { ++ char *str; ++ ulong cmdflags; ++ ulong hexval; ++ ulong decval; ++ ulong ref1; ++ ulong ref2; ++ void *refp; ++}; ++ ++struct offset_table { /* stash of commonly-used offsets */ ++ long list_head_next; /* add new entries to end of table */ ++ long list_head_prev; ++ long task_struct_pid; ++ long task_struct_state; ++ long task_struct_comm; ++ long task_struct_mm; ++ long task_struct_tss; ++ long task_struct_thread; ++ long task_struct_active_mm; ++ long task_struct_tss_eip; ++ long task_struct_tss_esp; ++ long task_struct_tss_ksp; ++ long task_struct_processor; ++ long task_struct_p_pptr; ++ long task_struct_parent; ++ long task_struct_has_cpu; ++ long task_struct_cpus_runnable; ++ long task_struct_thread_eip; ++ long task_struct_thread_esp; ++ long task_struct_thread_ksp; ++ long task_struct_next_task; ++ long task_struct_files; ++ long task_struct_fs; ++ long task_struct_pidhash_next; ++ long task_struct_next_run; ++ long task_struct_flags; ++ long task_struct_sig; ++ long task_struct_signal; ++ long task_struct_blocked; ++ long task_struct_sigpending; ++ long task_struct_pending; ++ long task_struct_sigqueue; ++ long task_struct_sighand; ++ long task_struct_start_time; ++ long task_struct_times; ++ long task_struct_utime; ++ long task_struct_stime; ++ long task_struct_cpu; ++ long task_struct_run_list; ++ long task_struct_pgrp; ++ long task_struct_tgid; ++ long task_struct_namespace; ++ long task_struct_pids; ++ long task_struct_last_run; ++ long task_struct_timestamp; ++ long task_struct_thread_info; ++ long task_struct_nsproxy; ++ long task_struct_rlim; ++ long thread_info_task; ++ long thread_info_cpu; ++ long thread_info_previous_esp; ++ long thread_info_flags; ++ long nsproxy_mnt_ns; ++ long mnt_namespace_root; ++ long mnt_namespace_list; ++ long pid_link_pid; ++ long pid_hash_chain; ++ long hlist_node_next; ++ long hlist_node_pprev; ++ long pid_pid_chain; ++ long thread_struct_eip; ++ long thread_struct_esp; ++ long thread_struct_ksp; ++ long thread_struct_fph; ++ long thread_struct_rip; ++ long thread_struct_rsp; ++ long thread_struct_rsp0; ++ long tms_tms_utime; ++ long tms_tms_stime; ++ long signal_struct_count; ++ long signal_struct_action; ++ long signal_struct_shared_pending; ++ long signal_struct_rlim; ++ long k_sigaction_sa; ++ long sigaction_sa_handler; ++ long sigaction_sa_flags; ++ long sigaction_sa_mask; ++ long sigpending_head; ++ long sigpending_list; ++ long sigpending_signal; ++ long signal_queue_next; ++ long signal_queue_info; ++ long sigqueue_next; ++ long sigqueue_list; ++ long sigqueue_info; ++ long sighand_struct_action; ++ long siginfo_si_signo; ++ long thread_struct_cr3; ++ long thread_struct_ptbr; ++ long thread_struct_pg_tables; ++ long switch_stack_r26; ++ long switch_stack_b0; ++ long switch_stack_ar_bspstore; ++ long switch_stack_ar_pfs; ++ long switch_stack_ar_rnat; ++ long switch_stack_pr; ++ long cpuinfo_ia64_proc_freq; ++ long cpuinfo_ia64_unimpl_va_mask; ++ long cpuinfo_ia64_unimpl_pa_mask; ++ long device_node_type; ++ long device_node_allnext; ++ long device_node_properties; ++ long property_name; ++ long property_value; ++ long property_next; ++ long machdep_calls_setup_residual; ++ long RESIDUAL_VitalProductData; ++ long VPD_ProcessorHz; ++ long bd_info_bi_intfreq; ++ long hwrpb_struct_cycle_freq; ++ long hwrpb_struct_processor_offset; ++ long hwrpb_struct_processor_size; ++ long percpu_struct_halt_PC; ++ long percpu_struct_halt_ra; ++ long percpu_struct_halt_pv; ++ long mm_struct_mmap; ++ long mm_struct_pgd; ++ long mm_struct_rss; ++ long mm_struct_anon_rss; ++ long mm_struct_file_rss; ++ long mm_struct_total_vm; ++ long mm_struct_start_code; ++ long mm_struct_arg_start; ++ long mm_struct_arg_end; ++ long mm_struct_env_start; ++ long mm_struct_env_end; ++ long vm_area_struct_vm_mm; ++ long vm_area_struct_vm_next; ++ long vm_area_struct_vm_end; ++ long vm_area_struct_vm_start; ++ long vm_area_struct_vm_flags; ++ long vm_area_struct_vm_file; ++ long vm_area_struct_vm_offset; ++ long vm_area_struct_vm_pgoff; ++ long vm_struct_addr; ++ long vm_struct_size; ++ long vm_struct_next; ++ long module_size_of_struct; ++ long module_next; ++ long module_size; ++ long module_name; ++ long module_nsyms; ++ long module_syms; ++ long module_flags; ++ long module_num_syms; ++ long module_list; ++ long module_gpl_syms; ++ long module_num_gpl_syms; ++ long module_module_core; ++ long module_core_size; ++ long module_core_text_size; ++ long module_num_symtab; ++ long module_symtab; ++ long module_strtab; ++ ++ long module_kallsyms_start; ++ long kallsyms_header_sections; ++ long kallsyms_header_section_off; ++ long kallsyms_header_symbols; ++ long kallsyms_header_symbol_off; ++ long kallsyms_header_string_off; ++ long kallsyms_symbol_section_off; ++ long kallsyms_symbol_symbol_addr; ++ long kallsyms_symbol_name_off; ++ long kallsyms_section_start; ++ long kallsyms_section_size; ++ long kallsyms_section_name_off; ++ ++ long page_next; ++ long page_prev; ++ long page_next_hash; ++ long page_list; ++ long page_list_next; ++ long page_list_prev; ++ long page_inode; ++ long page_offset; ++ long page_count; ++ long page_flags; ++ long page_mapping; ++ long page_index; ++ long page_buffers; ++ long page_lru; ++ long page_pte; ++ long swap_info_struct_swap_file; ++ long swap_info_struct_swap_vfsmnt; ++ long swap_info_struct_flags; ++ long swap_info_struct_swap_map; ++ long swap_info_struct_swap_device; ++ long swap_info_struct_prio; ++ long swap_info_struct_max; ++ long swap_info_struct_pages; ++ long swap_info_struct_old_block_size; ++ long block_device_bd_inode; ++ long block_device_bd_list; ++ long block_device_bd_disk; ++ long irq_desc_t_status; ++ long irq_desc_t_handler; ++ long irq_desc_t_chip; ++ long irq_desc_t_action; ++ long irq_desc_t_depth; ++ long irqdesc_action; ++ long irqdesc_ctl; ++ long irqdesc_level; ++ long irqaction_handler; ++ long irqaction_flags; ++ long irqaction_mask; ++ long irqaction_name; ++ long irqaction_dev_id; ++ long irqaction_next; ++ long hw_interrupt_type_typename; ++ long hw_interrupt_type_startup; ++ long hw_interrupt_type_shutdown; ++ long hw_interrupt_type_handle; ++ long hw_interrupt_type_enable; ++ long hw_interrupt_type_disable; ++ long hw_interrupt_type_ack; ++ long hw_interrupt_type_end; ++ long hw_interrupt_type_set_affinity; ++ long irq_chip_typename; ++ long irq_chip_startup; ++ long irq_chip_shutdown; ++ long irq_chip_enable; ++ long irq_chip_disable; ++ long irq_chip_ack; ++ long irq_chip_end; ++ long irq_chip_set_affinity; ++ long irq_chip_mask; ++ long irq_chip_mask_ack; ++ long irq_chip_unmask; ++ long irq_chip_eoi; ++ long irq_chip_retrigger; ++ long irq_chip_set_type; ++ long irq_chip_set_wake; ++ long irq_cpustat_t___softirq_active; ++ long irq_cpustat_t___softirq_mask; ++ long fdtable_max_fds; ++ long fdtable_max_fdset; ++ long fdtable_open_fds; ++ long fdtable_fd; ++ long files_struct_fdt; ++ long files_struct_max_fds; ++ long files_struct_max_fdset; ++ long files_struct_open_fds; ++ long files_struct_fd; ++ long files_struct_open_fds_init; ++ long file_f_dentry; ++ long file_f_vfsmnt; ++ long file_f_count; ++ long file_f_path; ++ long path_mnt; ++ long path_dentry; ++ long fs_struct_root; ++ long fs_struct_pwd; ++ long fs_struct_rootmnt; ++ long fs_struct_pwdmnt; ++ long dentry_d_inode; ++ long dentry_d_parent; ++ long dentry_d_name; ++ long dentry_d_covers; ++ long dentry_d_iname; ++ long qstr_len; ++ long qstr_name; ++ long inode_i_mode; ++ long inode_i_op; ++ long inode_i_sb; ++ long inode_u; ++ long inode_i_flock; ++ long inode_i_fop; ++ long inode_i_mapping; ++ long address_space_nrpages; ++ long vfsmount_mnt_next; ++ long vfsmount_mnt_devname; ++ long vfsmount_mnt_dirname; ++ long vfsmount_mnt_sb; ++ long vfsmount_mnt_list; ++ long vfsmount_mnt_mountpoint; ++ long vfsmount_mnt_parent; ++ long namespace_root; ++ long namespace_list; ++ long super_block_s_dirty; ++ long super_block_s_type; ++ long super_block_s_files; ++ long file_system_type_name; ++ long nlm_file_f_file; ++ long file_lock_fl_owner; ++ long nlm_host_h_exportent; ++ long svc_client_cl_ident; ++ long kmem_cache_s_c_nextp; ++ long kmem_cache_s_c_name; ++ long kmem_cache_s_c_num; ++ long kmem_cache_s_c_org_size; ++ long kmem_cache_s_c_flags; ++ long kmem_cache_s_c_offset; ++ long kmem_cache_s_c_firstp; ++ long kmem_cache_s_c_gfporder; ++ long kmem_cache_s_c_magic; ++ long kmem_cache_s_num; ++ long kmem_cache_s_next; ++ long kmem_cache_s_name; ++ long kmem_cache_s_objsize; ++ long kmem_cache_s_flags; ++ long kmem_cache_s_gfporder; ++ long kmem_cache_s_slabs; ++ long kmem_cache_s_slabs_full; ++ long kmem_cache_s_slabs_partial; ++ long kmem_cache_s_slabs_free; ++ long kmem_cache_s_cpudata; ++ long kmem_cache_s_c_align; ++ long kmem_cache_s_colour_off; ++ long cpucache_s_avail; ++ long cpucache_s_limit; ++ long kmem_cache_s_array; ++ long array_cache_avail; ++ long array_cache_limit; ++ long kmem_cache_s_lists; ++ long kmem_list3_slabs_partial; ++ long kmem_list3_slabs_full; ++ long kmem_list3_slabs_free; ++ long kmem_list3_free_objects; ++ long kmem_list3_shared; ++ long kmem_slab_s_s_nextp; ++ long kmem_slab_s_s_freep; ++ long kmem_slab_s_s_inuse; ++ long kmem_slab_s_s_mem; ++ long kmem_slab_s_s_index; ++ long kmem_slab_s_s_offset; ++ long kmem_slab_s_s_magic; ++ long slab_s_list; ++ long slab_s_s_mem; ++ long slab_s_inuse; ++ long slab_s_free; ++ long slab_list; ++ long slab_s_mem; ++ long slab_inuse; ++ long slab_free; ++ long net_device_next; ++ long net_device_name; ++ long net_device_type; ++ long net_device_addr_len; ++ long net_device_ip_ptr; ++ long net_device_dev_list; ++ long net_dev_base_head; ++ long device_next; ++ long device_name; ++ long device_type; ++ long device_ip_ptr; ++ long device_addr_len; ++ long socket_sk; ++ long sock_daddr; ++ long sock_rcv_saddr; ++ long sock_dport; ++ long sock_sport; ++ long sock_num; ++ long sock_type; ++ long sock_family; ++ long sock_common_skc_family; ++ long sock_sk_type; ++ long inet_sock_inet; ++ long inet_opt_daddr; ++ long inet_opt_rcv_saddr; ++ long inet_opt_dport; ++ long inet_opt_sport; ++ long inet_opt_num; ++ long ipv6_pinfo_rcv_saddr; ++ long ipv6_pinfo_daddr; ++ long timer_list_list; ++ long timer_list_next; ++ long timer_list_entry; ++ long timer_list_expires; ++ long timer_list_function; ++ long timer_vec_root_vec; ++ long timer_vec_vec; ++ long tvec_root_s_vec; ++ long tvec_s_vec; ++ long tvec_t_base_s_tv1; ++ long wait_queue_task; ++ long wait_queue_next; ++ long __wait_queue_task; ++ long __wait_queue_head_task_list; ++ long __wait_queue_task_list; ++ long pglist_data_node_zones; ++ long pglist_data_node_mem_map; ++ long pglist_data_node_start_paddr; ++ long pglist_data_node_start_mapnr; ++ long pglist_data_node_size; ++ long pglist_data_node_id; ++ long pglist_data_node_next; ++ long pglist_data_nr_zones; ++ long pglist_data_node_start_pfn; ++ long pglist_data_pgdat_next; ++ long pglist_data_node_present_pages; ++ long pglist_data_node_spanned_pages; ++ long pglist_data_bdata; ++ long page_cache_bucket_chain; ++ long zone_struct_free_pages; ++ long zone_struct_free_area; ++ long zone_struct_zone_pgdat; ++ long zone_struct_name; ++ long zone_struct_size; ++ long zone_struct_memsize; ++ long zone_struct_zone_start_pfn; ++ long zone_struct_zone_start_paddr; ++ long zone_struct_zone_start_mapnr; ++ long zone_struct_zone_mem_map; ++ long zone_struct_inactive_clean_pages; ++ long zone_struct_inactive_clean_list; ++ long zone_struct_inactive_dirty_pages; ++ long zone_struct_active_pages; ++ long zone_struct_pages_min; ++ long zone_struct_pages_low; ++ long zone_struct_pages_high; ++ long zone_free_pages; ++ long zone_free_area; ++ long zone_zone_pgdat; ++ long zone_zone_mem_map; ++ long zone_name; ++ long zone_spanned_pages; ++ long zone_zone_start_pfn; ++ long zone_pages_min; ++ long zone_pages_low; ++ long zone_pages_high; ++ long zone_vm_stat; ++ long neighbour_next; ++ long neighbour_primary_key; ++ long neighbour_ha; ++ long neighbour_dev; ++ long neighbour_nud_state; ++ long neigh_table_hash_buckets; ++ long neigh_table_key_len; ++ long in_device_ifa_list; ++ long in_ifaddr_ifa_next; ++ long in_ifaddr_ifa_address; ++ long pci_dev_global_list; ++ long pci_dev_next; ++ long pci_dev_bus; ++ long pci_dev_devfn; ++ long pci_dev_class; ++ long pci_dev_device; ++ long pci_dev_vendor; ++ long pci_bus_number; ++ long resource_entry_t_from; ++ long resource_entry_t_num; ++ long resource_entry_t_name; ++ long resource_entry_t_next; ++ long resource_name; ++ long resource_start; ++ long resource_end; ++ long resource_sibling; ++ long resource_child; ++ long runqueue_curr; ++ long runqueue_idle; ++ long runqueue_active; ++ long runqueue_expired; ++ long runqueue_arrays; ++ long runqueue_cpu; ++ long cpu_s_idle; ++ long cpu_s_curr; ++ long prio_array_nr_active; ++ long prio_array_queue; ++ long user_regs_struct_ebp; ++ long user_regs_struct_esp; ++ long user_regs_struct_rip; ++ long user_regs_struct_cs; ++ long user_regs_struct_eflags; ++ long user_regs_struct_rsp; ++ long user_regs_struct_ss; ++ long e820map_nr_map; ++ long e820entry_addr; ++ long e820entry_size; ++ long e820entry_type; ++ long char_device_struct_next; ++ long char_device_struct_name; ++ long char_device_struct_fops; ++ long char_device_struct_major; ++ long gendisk_major; ++ long gendisk_disk_name; ++ long gendisk_fops; ++ long blk_major_name_next; ++ long blk_major_name_major; ++ long blk_major_name_name; ++ long radix_tree_root_height; ++ long radix_tree_root_rnode; ++ long x8664_pda_pcurrent; ++ long x8664_pda_data_offset; ++ long x8664_pda_kernelstack; ++ long x8664_pda_irqrsp; ++ long x8664_pda_irqstackptr; ++ long x8664_pda_level4_pgt; ++ long x8664_pda_cpunumber; ++ long x8664_pda_me; ++ long tss_struct_ist; ++ long mem_section_section_mem_map; ++ long vcpu_guest_context_user_regs; ++ long cpu_user_regs_eip; ++ long cpu_user_regs_esp; ++ long cpu_user_regs_rip; ++ long cpu_user_regs_rsp; ++ long unwind_table_core; ++ long unwind_table_init; ++ long unwind_table_address; ++ long unwind_table_size; ++ long unwind_table_link; ++ long unwind_table_name; ++ long rq_cfs; ++ long rq_rt; ++ long rq_nr_running; ++ long cfs_rq_rb_leftmost; ++ long cfs_rq_nr_running; ++ long cfs_rq_tasks_timeline; ++ long task_struct_se; ++ long sched_entity_run_node; ++ long rt_rq_active; ++ long kmem_cache_size; ++ long kmem_cache_objsize; ++ long kmem_cache_offset; ++ long kmem_cache_order; ++ long kmem_cache_local_node; ++ long kmem_cache_objects; ++ long kmem_cache_inuse; ++ long kmem_cache_align; ++ long kmem_cache_name; ++ long kmem_cache_list; ++ long kmem_cache_node; ++ long kmem_cache_cpu_slab; ++ long page_inuse; ++/* long page_offset; use "old" page->offset */ ++ long page_slab; ++ long page_first_page; ++ long page_freelist; ++ long kmem_cache_node_nr_partial; ++ long kmem_cache_node_nr_slabs; ++ long kmem_cache_node_partial; ++ long kmem_cache_node_full; ++ long pid_numbers; ++ long upid_nr; ++ long upid_ns; ++ long upid_pid_chain; ++ long pid_tasks; ++ long kmem_cache_cpu_freelist; ++ long kmem_cache_cpu_page; ++ long kmem_cache_cpu_node; ++ long kmem_cache_flags; ++ long zone_nr_active; ++ long zone_nr_inactive; ++ long zone_all_unreclaimable; ++ long zone_present_pages; ++ long zone_flags; ++ long zone_pages_scanned; ++ long pcpu_info_vcpu; ++ long pcpu_info_idle; ++ long vcpu_struct_rq; ++ long task_struct_sched_info; ++ long sched_info_last_arrival; ++ long page_objects; ++ long kmem_cache_oo; ++ long char_device_struct_cdev; ++ long char_device_struct_baseminor; ++ long cdev_ops; ++ long probe_next; ++ long probe_dev; ++ long probe_data; ++ long kobj_map_probes; ++ long task_struct_prio; ++ long zone_watermark; ++ long module_sect_attrs; ++ long module_sect_attrs_attrs; ++ long module_sect_attrs_nsections; ++ long module_sect_attr_mattr; ++ long module_sect_attr_name; ++ long module_sect_attr_address; ++ long module_attribute_attr; ++ long attribute_owner; ++ long module_sect_attr_attr; ++ long module_sections_attrs; ++ long swap_info_struct_inuse_pages; ++ long s390_lowcore_psw_save_area; ++ long mm_struct_rss_stat; ++ long mm_rss_stat_count; ++ long module_module_init; ++ long module_init_text_size; ++ long cpu_context_save_fp; ++ long cpu_context_save_sp; ++ long cpu_context_save_pc; ++ long elf_prstatus_pr_pid; ++ long elf_prstatus_pr_reg; ++ long irq_desc_t_name; ++ long thread_info_cpu_context; ++ long unwind_table_list; ++ long unwind_table_start; ++ long unwind_table_stop; ++ long unwind_table_begin_addr; ++ long unwind_table_end_addr; ++ long unwind_idx_addr; ++ long unwind_idx_insn; ++ long signal_struct_nr_threads; ++ long module_init_size; ++ long module_percpu; ++ long radix_tree_node_slots; ++ long s390_stack_frame_back_chain; ++ long s390_stack_frame_r14; ++ long user_regs_struct_eip; ++ long user_regs_struct_rax; ++ long user_regs_struct_eax; ++ long user_regs_struct_rbx; ++ long user_regs_struct_ebx; ++ long user_regs_struct_rcx; ++ long user_regs_struct_ecx; ++ long user_regs_struct_rdx; ++ long user_regs_struct_edx; ++ long user_regs_struct_rsi; ++ long user_regs_struct_esi; ++ long user_regs_struct_rdi; ++ long user_regs_struct_edi; ++ long user_regs_struct_ds; ++ long user_regs_struct_es; ++ long user_regs_struct_fs; ++ long user_regs_struct_gs; ++ long user_regs_struct_rbp; ++ long user_regs_struct_r8; ++ long user_regs_struct_r9; ++ long user_regs_struct_r10; ++ long user_regs_struct_r11; ++ long user_regs_struct_r12; ++ long user_regs_struct_r13; ++ long user_regs_struct_r14; ++ long user_regs_struct_r15; ++ long sched_entity_cfs_rq; ++ long sched_entity_my_q; ++ long sched_entity_on_rq; ++ long task_struct_on_rq; ++ long cfs_rq_curr; ++ long irq_desc_t_irq_data; ++ long irq_desc_t_kstat_irqs; ++ long irq_desc_t_affinity; ++ long irq_data_chip; ++ long irq_data_affinity; ++ long kernel_stat_irqs; ++ long socket_alloc_vfs_inode; ++ long class_devices; ++ long class_p; ++ long class_private_devices; ++ long device_knode_class; ++ long device_node; ++ long gendisk_dev; ++ long gendisk_kobj; ++ long gendisk_part0; ++ long gendisk_queue; ++ long hd_struct_dev; ++ long klist_k_list; ++ long klist_node_n_klist; ++ long klist_node_n_node; ++ long kobject_entry; ++ long kset_list; ++ long request_list_count; ++ long request_queue_in_flight; ++ long request_queue_rq; ++ long subsys_private_klist_devices; ++ long subsystem_kset; ++ long mount_mnt_parent; ++ long mount_mnt_mountpoint; ++ long mount_mnt_list; ++ long mount_mnt_devname; ++ long mount_mnt; ++ long task_struct_exit_state; ++ long timekeeper_xtime; ++ long file_f_op; ++ long file_private_data; ++ long hstate_order; ++ long hugetlbfs_sb_info_hstate; ++ long idr_layer_ary; ++ long idr_layer_layer; ++ long idr_layers; ++ long idr_top; ++ long ipc_id_ary_p; ++ long ipc_ids_entries; ++ long ipc_ids_max_id; ++ long ipc_ids_ipcs_idr; ++ long ipc_ids_in_use; ++ long ipc_namespace_ids; ++ long kern_ipc_perm_deleted; ++ long kern_ipc_perm_key; ++ long kern_ipc_perm_mode; ++ long kern_ipc_perm_uid; ++ long kern_ipc_perm_id; ++ long kern_ipc_perm_seq; ++ long nsproxy_ipc_ns; ++ long shmem_inode_info_swapped; ++ long shmem_inode_info_vfs_inode; ++ long shm_file_data_file; ++ long shmid_kernel_shm_file; ++ long shmid_kernel_shm_nattch; ++ long shmid_kernel_shm_perm; ++ long shmid_kernel_shm_segsz; ++ long shmid_kernel_id; ++ long sem_array_sem_perm; ++ long sem_array_sem_id; ++ long sem_array_sem_nsems; ++ long msg_queue_q_perm; ++ long msg_queue_q_id; ++ long msg_queue_q_cbytes; ++ long msg_queue_q_qnum; ++ long super_block_s_fs_info; ++ long rq_timestamp; ++ long radix_tree_node_height; ++ long rb_root_rb_node; ++ long rb_node_rb_left; ++ long rb_node_rb_right; ++ long rt_prio_array_queue; ++ long task_struct_rt; ++ long sched_rt_entity_run_list; ++ long log_ts_nsec; ++ long log_len; ++ long log_text_len; ++ long log_dict_len; ++ long log_level; ++ long log_flags_level; ++ long timekeeper_xtime_sec; ++ long neigh_table_hash_mask; ++ long sched_rt_entity_my_q; ++ long neigh_table_hash_shift; ++ long neigh_table_nht_ptr; ++ long task_group_parent; ++ long task_group_css; ++ long cgroup_subsys_state_cgroup; ++ long cgroup_dentry; ++ long task_group_rt_rq; ++ long rt_rq_tg; ++ long task_group_cfs_rq; ++ long cfs_rq_tg; ++ long task_group_siblings; ++ long task_group_children; ++ long task_group_cfs_bandwidth; ++ long cfs_rq_throttled; ++ long task_group_rt_bandwidth; ++ long rt_rq_rt_throttled; ++ long rt_rq_highest_prio; ++ long rt_rq_rt_nr_running; ++ long vmap_area_va_start; ++ long vmap_area_va_end; ++ long vmap_area_list; ++ long vmap_area_flags; ++ long vmap_area_vm; ++ long hrtimer_cpu_base_clock_base; ++ long hrtimer_clock_base_offset; ++ long hrtimer_clock_base_active; ++ long hrtimer_clock_base_first; ++ long hrtimer_clock_base_get_time; ++ long hrtimer_base_first; ++ long hrtimer_base_pending; ++ long hrtimer_base_get_time; ++ long hrtimer_node; ++ long hrtimer_list; ++ long hrtimer_softexpires; ++ long hrtimer_expires; ++ long hrtimer_function; ++ long timerqueue_head_next; ++ long timerqueue_node_expires; ++ long timerqueue_node_node; ++ long ktime_t_tv64; ++ long ktime_t_sec; ++ long ktime_t_nsec; ++ long module_taints; ++ long module_gpgsig_ok; ++ long module_license_gplok; ++ long tnt_bit; ++ long tnt_true; ++ long tnt_false; ++ long task_struct_thread_context_fp; ++ long task_struct_thread_context_sp; ++ long task_struct_thread_context_pc; ++ long page_slab_page; ++ long trace_print_flags_mask; ++ long trace_print_flags_name; ++ long task_struct_rss_stat; ++ long task_rss_stat_count; ++ long page_s_mem; ++ long page_active; ++ long hstate_nr_huge_pages; ++ long hstate_free_huge_pages; ++ long hstate_name; ++ long cgroup_kn; ++ long kernfs_node_name; ++ long kernfs_node_parent; ++ long kmem_cache_cpu_partial; ++ long kmem_cache_cpu_cache; ++ long nsproxy_net_ns; ++ long atomic_t_counter; ++ long percpu_counter_count; ++ long mm_struct_mm_count; ++ long task_struct_thread_reg29; ++ long task_struct_thread_reg31; ++ long pt_regs_regs; ++ long pt_regs_cp0_badvaddr; ++ long address_space_page_tree; ++ long page_compound_head; ++ long irq_desc_irq_data; ++ long kmem_cache_node_total_objects; ++ long timer_base_vectors; ++ long request_queue_mq_ops; ++ long request_queue_queue_ctx; ++ long blk_mq_ctx_rq_dispatched; ++ long blk_mq_ctx_rq_completed; ++ long task_struct_stack; ++ long tnt_mod; ++ long radix_tree_node_shift; ++ long kmem_cache_red_left_pad; ++ long inactive_task_frame_ret_addr; ++ long sk_buff_head_next; ++ long sk_buff_head_qlen; ++ long sk_buff_next; ++ long sk_buff_len; ++ long sk_buff_data; ++ long nlmsghdr_nlmsg_type; ++ long module_arch; ++ long mod_arch_specific_num_orcs; ++ long mod_arch_specific_orc_unwind_ip; ++ long mod_arch_specific_orc_unwind; ++ long task_struct_policy; ++ long kmem_cache_random; ++ long pid_namespace_idr; ++ long idr_idr_rt; ++ long bpf_prog_aux; ++ long bpf_prog_type; ++ long bpf_prog_tag; ++ long bpf_prog_jited_len; ++ long bpf_prog_bpf_func; ++ long bpf_prog_len; ++ long bpf_prog_insnsi; ++ long bpf_prog_pages; ++ long bpf_map_map_type; ++ long bpf_map_map_flags; ++ long bpf_map_pages; ++ long bpf_map_key_size; ++ long bpf_map_value_size; ++ long bpf_map_max_entries; ++ long bpf_map_user; ++ long bpf_map_name; ++ long bpf_prog_aux_used_map_cnt; ++ long bpf_prog_aux_used_maps; ++ long bpf_prog_aux_load_time; ++ long bpf_prog_aux_user; ++ long user_struct_uid; ++ long idr_cur; ++ long kmem_cache_memcg_params; ++ long memcg_cache_params___root_caches_node; ++ long memcg_cache_params_children; ++ long memcg_cache_params_children_node; ++ long task_struct_pid_links; ++ long kernel_symbol_value; ++ 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; ++ long memory_block_dev; ++ long memory_block_start_section_nr; ++ long memory_block_end_section_nr; ++ long memory_block_state; ++ long memory_block_nid; ++ long mem_section_pageblock_flags; ++ long bus_type_p; ++ long device_private_device; ++ long device_private_knode_bus; ++ long xarray_xa_head; ++ long xa_node_slots; ++ long xa_node_shift; ++ long hd_struct_dkstats; ++ long disk_stats_in_flight; ++ long cpu_context_save_r7; ++ long dentry_d_sb; ++ long device_private_knode_class; ++ long timerqueue_head_rb_root; ++ long rb_root_cached_rb_leftmost; ++ long bpf_map_memory; ++ long bpf_map_memory_pages; ++ long bpf_map_memory_user; ++ long bpf_prog_aux_name; ++ long page_private; ++ long swap_info_struct_bdev; ++ long zram_mempoll; ++ long zram_compressor; ++ long zram_table_flag; ++ long zspoll_size_class; ++ long size_class_size; ++ long gendisk_private_data; ++ long zram_table_entry; ++ long module_core_size_rw; ++ long module_core_size_rx; ++ long module_init_size_rw; ++ long module_init_size_rx; ++ long module_module_core_rw; ++ long module_module_core_rx; ++ long module_module_init_rw; ++ long module_module_init_rx; ++ long super_block_s_inodes; ++ long inode_i_sb_list; ++ long irq_common_data_affinity; ++ long irq_desc_irq_common_data; ++ long uts_namespace_name; ++ long printk_info_seq; ++ long printk_info_ts_nsec; ++ long printk_info_text_len; ++ long printk_info_level; ++ long printk_info_caller_id; ++ long printk_info_dev_info; ++ long dev_printk_info_subsystem; ++ long dev_printk_info_device; ++ long prb_desc_ring; ++ long prb_text_data_ring; ++ long prb_desc_ring_count_bits; ++ long prb_desc_ring_descs; ++ long prb_desc_ring_infos; ++ long prb_desc_ring_head_id; ++ long prb_desc_ring_tail_id; ++ long prb_desc_state_var; ++ long prb_desc_text_blk_lpos; ++ long prb_data_blk_lpos_begin; ++ long prb_data_blk_lpos_next; ++ long prb_data_ring_size_bits; ++ long prb_data_ring_data; ++ long atomic_long_t_counter; ++ long block_device_bd_device; ++ long block_device_bd_stats; ++}; ++ ++struct size_table { /* stash of commonly-used sizes */ ++ long page; ++ long free_area_struct; ++ long zone_struct; ++ long free_area; ++ long zone; ++ long kmem_slab_s; ++ long kmem_cache_s; ++ long kmem_bufctl_t; ++ long slab_s; ++ long slab; ++ long cpucache_s; ++ long array_cache; ++ long swap_info_struct; ++ long mm_struct; ++ long vm_area_struct; ++ long pglist_data; ++ long page_cache_bucket; ++ long pt_regs; ++ long task_struct; ++ long thread_info; ++ long softirq_state; ++ long desc_struct; ++ long umode_t; ++ long dentry; ++ long files_struct; ++ long fdtable; ++ long fs_struct; ++ long file; ++ long inode; ++ long vfsmount; ++ long super_block; ++ long irqdesc; ++ long module; ++ long list_head; ++ long hlist_node; ++ long hlist_head; ++ long irq_cpustat_t; ++ long cpuinfo_x86; ++ long cpuinfo_ia64; ++ long timer_list; ++ long timer_vec_root; ++ long timer_vec; ++ long tvec_root_s; ++ long tvec_s; ++ long tvec_t_base_s; ++ long wait_queue; ++ long __wait_queue; ++ long device; ++ long net_device; ++ long sock; ++ long signal_struct; ++ long sigpending_signal; ++ long signal_queue; ++ long sighand_struct; ++ long sigqueue; ++ long k_sigaction; ++ long resource_entry_t; ++ long resource; ++ long runqueue; ++ long irq_desc_t; ++ long task_union; ++ long thread_union; ++ long prio_array; ++ long user_regs_struct; ++ long switch_stack; ++ long vm_area_struct_vm_flags; ++ long e820map; ++ long e820entry; ++ long cpu_s; ++ long pgd_t; ++ long kallsyms_header; ++ long kallsyms_symbol; ++ long kallsyms_section; ++ long irq_ctx; ++ long block_device; ++ long blk_major_name; ++ long gendisk; ++ long address_space; ++ long char_device_struct; ++ long inet_sock; ++ long in6_addr; ++ long socket; ++ long spinlock_t; ++ long radix_tree_root; ++ long radix_tree_node; ++ long x8664_pda; ++ long ppc64_paca; ++ long gate_struct; ++ long tss_struct; ++ long task_struct_start_time; ++ long cputime_t; ++ long mem_section; ++ long pid_link; ++ long unwind_table; ++ long rlimit; ++ long kmem_cache; ++ long kmem_cache_node; ++ long upid; ++ long kmem_cache_cpu; ++ long cfs_rq; ++ long pcpu_info; ++ long vcpu_struct; ++ long cdev; ++ long probe; ++ long kobj_map; ++ long page_flags; ++ long module_sect_attr; ++ long task_struct_utime; ++ long task_struct_stime; ++ long cpu_context_save; ++ long elf_prstatus; ++ long note_buf; ++ long unwind_idx; ++ long softirq_action; ++ long irq_data; ++ long s390_stack_frame; ++ long percpu_data; ++ long sched_entity; ++ long kernel_stat; ++ long subsystem; ++ long class_private; ++ long rq_in_flight; ++ long class_private_devices; ++ long mount; ++ long hstate; ++ long ipc_ids; ++ long shmid_kernel; ++ long sem_array; ++ long msg_queue; ++ long log; ++ long log_level; ++ long rt_rq; ++ long task_group; ++ long vmap_area; ++ long hrtimer_clock_base; ++ long hrtimer_base; ++ long tnt; ++ long trace_print_flags; ++ long task_struct_flags; ++ long timer_base; ++ long taint_flag; ++ long nlmsghdr; ++ long nlmsghdr_nlmsg_type; ++ long sk_buff_head_qlen; ++ long sk_buff_len; ++ long orc_entry; ++ long task_struct_policy; ++ long pid; ++ long bpf_prog; ++ long bpf_prog_aux; ++ long bpf_map; ++ long bpf_insn; ++ long xarray; ++ long xa_node; ++ long zram_table_entry; ++ long irq_common_data; ++ long printk_info; ++ long printk_ringbuffer; ++ long prb_desc; ++}; ++ ++struct array_table { ++ int kmem_cache_s_name; ++ int kmem_cache_s_c_name; ++ int kmem_cache_s_array; ++ int kmem_cache_s_cpudata; ++ int irq_desc; ++ int irq_action; ++ int log_buf; ++ int timer_vec_vec; ++ int timer_vec_root_vec; ++ int tvec_s_vec; ++ int tvec_root_s_vec; ++ int page_hash_table; ++ int net_device_name; ++ int neigh_table_hash_buckets; ++ int neighbour_ha; ++ int swap_info; ++ int pglist_data_node_zones; ++ int zone_struct_free_area; ++ int zone_free_area; ++ int free_area; ++ int free_area_DIMENSION; ++ int prio_array_queue; ++ int height_to_maxindex; ++ int pid_hash; ++ int kmem_cache_node; ++ int kmem_cache_cpu_slab; ++ int rt_prio_array_queue; ++ int height_to_maxnodes; ++ int task_struct_rlim; ++ int signal_struct_rlim; ++ int vm_numa_stat; ++}; ++ ++/* ++ * The following set of macros use gdb to determine structure, union, ++ * or member sizes/offsets. They should be used only during initialization ++ * of the offset_table or size_table, or with data structures whose names ++ * or members are only known/specified during runtime. ++ */ ++#define MEMBER_SIZE_REQUEST ((struct datatype_member *)(-1)) ++#define ANON_MEMBER_OFFSET_REQUEST ((struct datatype_member *)(-2)) ++#define MEMBER_TYPE_REQUEST ((struct datatype_member *)(-3)) ++#define STRUCT_SIZE_REQUEST ((struct datatype_member *)(-4)) ++#define MEMBER_TYPE_NAME_REQUEST ((struct datatype_member *)(-5)) ++#define ANON_MEMBER_SIZE_REQUEST ((struct datatype_member *)(-6)) ++ ++#define STRUCT_SIZE(X) datatype_info((X), NULL, STRUCT_SIZE_REQUEST) ++#define UNION_SIZE(X) datatype_info((X), NULL, STRUCT_SIZE_REQUEST) ++#define STRUCT_EXISTS(X) (datatype_info((X), NULL, STRUCT_SIZE_REQUEST) >= 0) ++#define DATATYPE_SIZE(X) datatype_info((X)->name, NULL, (X)) ++#define MEMBER_OFFSET(X,Y) datatype_info((X), (Y), NULL) ++#define MEMBER_EXISTS(X,Y) (datatype_info((X), (Y), NULL) >= 0) ++#define MEMBER_SIZE(X,Y) datatype_info((X), (Y), MEMBER_SIZE_REQUEST) ++#define MEMBER_TYPE(X,Y) datatype_info((X), (Y), MEMBER_TYPE_REQUEST) ++#define MEMBER_TYPE_NAME(X,Y) ((char *)datatype_info((X), (Y), MEMBER_TYPE_NAME_REQUEST)) ++#define ANON_MEMBER_OFFSET(X,Y) datatype_info((X), (Y), ANON_MEMBER_OFFSET_REQUEST) ++#define ANON_MEMBER_SIZE(X,Y) datatype_info((X), (Y), ANON_MEMBER_SIZE_REQUEST) ++ ++/* ++ * The following set of macros can only be used with pre-intialized fields ++ * in the offset table, size table or array_table. ++ */ ++#define OFFSET(X) (OFFSET_verify(offset_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X)) ++#define MODULE_OFFSET(X,Y) (PAX_MODULE_SPLIT() ? OFFSET(Y) : OFFSET(X)) ++#define MODULE_OFFSET2(X,T) MODULE_OFFSET(X, X##_##T) ++#define SIZE(X) (SIZE_verify(size_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X)) ++#define INVALID_OFFSET (-1) ++#define INVALID_MEMBER(X) (offset_table.X == INVALID_OFFSET) ++#define INVALID_SIZE(X) (size_table.X == -1) ++#define VALID_SIZE(X) (size_table.X >= 0) ++#define VALID_STRUCT(X) (size_table.X >= 0) ++#define VALID_MEMBER(X) (offset_table.X >= 0) ++#define ARRAY_LENGTH(X) (array_table.X) ++#define ASSIGN_OFFSET(X) (offset_table.X) ++#define ASSIGN_SIZE(X) (size_table.X) ++#define OFFSET_OPTION(X,Y) (OFFSET_option(offset_table.X, offset_table.Y, (char *)__FUNCTION__, __FILE__, __LINE__, #X, #Y)) ++#define SIZE_OPTION(X,Y) (SIZE_option(size_table.X, size_table.Y, (char *)__FUNCTION__, __FILE__, __LINE__, #X, #Y)) ++ ++#define MEMBER_OFFSET_INIT(X, Y, Z) (ASSIGN_OFFSET(X) = MEMBER_OFFSET(Y, Z)) ++#define STRUCT_SIZE_INIT(X, Y) (ASSIGN_SIZE(X) = STRUCT_SIZE(Y)) ++#define ARRAY_LENGTH_INIT(A, B, C, D, E) ((A) = get_array_length(C, D, E)) ++#define ARRAY_LENGTH_INIT_ALT(A, B, C, D, E) ((A) = get_array_length_alt(B, C, D, E)) ++#define MEMBER_SIZE_INIT(X, Y, Z) (ASSIGN_SIZE(X) = MEMBER_SIZE(Y, Z)) ++#define ANON_MEMBER_OFFSET_INIT(X, Y, Z) (ASSIGN_OFFSET(X) = ANON_MEMBER_OFFSET(Y, Z)) ++ ++/* ++ * For use with non-debug kernels. ++ */ ++struct builtin_debug_table { ++ char *release; ++ char *machine_type; ++ struct offset_table *offset_table; ++ struct size_table *size_table; ++ struct array_table *array_table; ++}; ++ ++/* ++ * Facilitators for pulling correctly-sized data out of a buffer at a ++ * known address. ++ */ ++ ++#ifdef NEED_ALIGNED_MEM_ACCESS ++ ++#define DEF_LOADER(TYPE) \ ++static inline TYPE \ ++load_##TYPE (char *addr) \ ++{ \ ++ TYPE ret; \ ++ size_t i = sizeof(TYPE); \ ++ while (i--) \ ++ ((char *)&ret)[i] = addr[i]; \ ++ return ret; \ ++} ++ ++DEF_LOADER(int); ++DEF_LOADER(uint); ++DEF_LOADER(long); ++DEF_LOADER(ulong); ++DEF_LOADER(ulonglong); ++DEF_LOADER(ushort); ++DEF_LOADER(short); ++typedef void *pointer_t; ++DEF_LOADER(pointer_t); ++ ++#define LOADER(TYPE) load_##TYPE ++ ++#define INT(ADDR) LOADER(int) ((char *)(ADDR)) ++#define UINT(ADDR) LOADER(uint) ((char *)(ADDR)) ++#define LONG(ADDR) LOADER(long) ((char *)(ADDR)) ++#define ULONG(ADDR) LOADER(ulong) ((char *)(ADDR)) ++#define ULONGLONG(ADDR) LOADER(ulonglong) ((char *)(ADDR)) ++#define ULONG_PTR(ADDR) ((ulong *) (LOADER(pointer_t) ((char *)(ADDR)))) ++#define USHORT(ADDR) LOADER(ushort) ((char *)(ADDR)) ++#define SHORT(ADDR) LOADER(short) ((char *)(ADDR)) ++#define UCHAR(ADDR) *((unsigned char *)((char *)(ADDR))) ++#define VOID_PTR(ADDR) ((void *) (LOADER(pointer_t) ((char *)(ADDR)))) ++ ++#else ++ ++#define INT(ADDR) *((int *)((char *)(ADDR))) ++#define UINT(ADDR) *((uint *)((char *)(ADDR))) ++#define LONG(ADDR) *((long *)((char *)(ADDR))) ++#define ULONG(ADDR) *((ulong *)((char *)(ADDR))) ++#define ULONGLONG(ADDR) *((ulonglong *)((char *)(ADDR))) ++#define ULONG_PTR(ADDR) *((ulong **)((char *)(ADDR))) ++#define USHORT(ADDR) *((ushort *)((char *)(ADDR))) ++#define SHORT(ADDR) *((short *)((char *)(ADDR))) ++#define UCHAR(ADDR) *((unsigned char *)((char *)(ADDR))) ++#define VOID_PTR(ADDR) *((void **)((char *)(ADDR))) ++ ++#endif /* NEED_ALIGNED_MEM_ACCESS */ ++ ++struct node_table { ++ int node_id; ++ ulong pgdat; ++ ulong mem_map; ++ ulong size; ++ ulong present; ++ ulonglong start_paddr; ++ ulong start_mapnr; ++}; ++ ++struct meminfo; ++struct slab_data; ++ ++#define VMA_CACHE (20) ++ ++struct vm_table { /* kernel VM-related data */ ++ ulong flags; ++ ulong kernel_pgd[NR_CPUS]; ++ ulong high_memory; ++ ulong vmalloc_start; ++ ulong mem_map; ++ long total_pages; ++ ulong totalram_pages; ++ ulong totalhigh_pages; ++ ulong num_physpages; ++ ulong max_mapnr; ++ ulong kmem_max_c_num; ++ ulong kmem_max_limit; ++ ulong kmem_max_cpus; ++ ulong kmem_cache_count; ++ ulong kmem_cache_len_nodes; ++ ulong PG_reserved; ++ ulong PG_slab; ++ ulong PG_head_tail_mask; ++ int kmem_cache_namelen; ++ ulong page_hash_table; ++ int page_hash_table_len; ++ int paddr_prlen; ++ int numnodes; ++ int nr_zones; ++ int nr_free_areas; ++ struct node_table *node_table; ++ void (*dump_free_pages)(struct meminfo *); ++ void (*dump_kmem_cache)(struct meminfo *); ++ struct slab_data *slab_data; ++ uint nr_swapfiles; ++ ulong last_swap_read; ++ char *swap_info_struct; ++ char *vma_cache; ++ ulong cached_vma[VMA_CACHE]; ++ ulong cached_vma_hits[VMA_CACHE]; ++ int vma_cache_index; ++ ulong vma_cache_fills; ++ void *mem_sec; ++ char *mem_section; ++ int ZONE_HIGHMEM; ++ ulong *node_online_map; ++ int node_online_map_len; ++ int nr_vm_stat_items; ++ char **vm_stat_items; ++ int cpu_slab_type; ++ int nr_vm_event_items; ++ char **vm_event_items; ++ int nr_bad_slab_caches; ++ ulong *bad_slab_caches; ++ int nr_pageflags; ++ struct pageflags_data { ++ ulong mask; ++ char *name; ++ } *pageflags_data; ++ ulong max_mem_section_nr; ++}; ++ ++#define NODES (0x1) ++#define ZONES (0x2) ++#define PERCPU_KMALLOC_V1 (0x4) ++#define COMMON_VADDR (0x8) ++#define KMEM_CACHE_INIT (0x10) ++#define V_MEM_MAP (0x20) ++#define PERCPU_KMALLOC_V2 (0x40) ++#define KMEM_CACHE_UNAVAIL (0x80) ++#define FLATMEM (0x100) ++#define DISCONTIGMEM (0x200) ++#define SPARSEMEM (0x400) ++#define SPARSEMEM_EX (0x800) ++#define PERCPU_KMALLOC_V2_NODES (0x1000) ++#define KMEM_CACHE_DELAY (0x2000) ++#define NODES_ONLINE (0x4000) ++#define VM_STAT (0x8000) ++#define KMALLOC_SLUB (0x10000) ++#define CONFIG_NUMA (0x20000) ++#define VM_EVENT (0x40000) ++#define PGCNT_ADJ (0x80000) ++#define VM_INIT (0x100000) ++#define SWAPINFO_V1 (0x200000) ++#define SWAPINFO_V2 (0x400000) ++#define NODELISTS_IS_PTR (0x800000) ++#define KMALLOC_COMMON (0x1000000) ++#define USE_VMAP_AREA (0x2000000) ++#define PAGEFLAGS (0x4000000) ++#define SLAB_OVERLOAD_PAGE (0x8000000) ++#define SLAB_CPU_CACHE (0x10000000) ++#define SLAB_ROOT_CACHES (0x20000000) ++ ++#define IS_FLATMEM() (vt->flags & FLATMEM) ++#define IS_DISCONTIGMEM() (vt->flags & DISCONTIGMEM) ++#define IS_SPARSEMEM() (vt->flags & SPARSEMEM) ++#define IS_SPARSEMEM_EX() (vt->flags & SPARSEMEM_EX) ++ ++#define COMMON_VADDR_SPACE() (vt->flags & COMMON_VADDR) ++#define PADDR_PRLEN (vt->paddr_prlen) ++ ++struct datatype_member { /* minimal definition of a structure/union */ ++ char *name; /* and possibly a member within it */ ++ char *member; ++ ulong type; ++ long size; ++ long member_offset; ++ long member_size; ++ int member_typecode; ++ ulong flags; ++ char *tagname; /* tagname and value for enums */ ++ long value; ++ ulong vaddr; ++}; ++ ++#define union_name struct_name ++ ++struct list_data { /* generic structure used by do_list() to walk */ ++ ulong flags; /* through linked lists in the kernel */ ++ ulong start; ++ long member_offset; ++ long list_head_offset; ++ ulong end; ++ ulong searchfor; ++ char **structname; ++ int structname_args; ++ char *header; ++ ulong *list_ptr; ++ int (*callback_func)(void *, void *); ++ void *callback_data; ++ long struct_list_offset; ++}; ++#define LIST_OFFSET_ENTERED (VERBOSE << 1) ++#define LIST_START_ENTERED (VERBOSE << 2) ++#define LIST_HEAD_FORMAT (VERBOSE << 3) ++#define LIST_HEAD_POINTER (VERBOSE << 4) ++#define RETURN_ON_DUPLICATE (VERBOSE << 5) ++#define RETURN_ON_LIST_ERROR (VERBOSE << 6) ++#define LIST_STRUCT_RADIX_10 (VERBOSE << 7) ++#define LIST_STRUCT_RADIX_16 (VERBOSE << 8) ++#define LIST_HEAD_REVERSE (VERBOSE << 9) ++#define LIST_ALLOCATE (VERBOSE << 10) ++#define LIST_CALLBACK (VERBOSE << 11) ++#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; ++ ulong start; ++ long node_member_offset; ++ char **structname; ++ int structname_args; ++ int count; ++}; ++ ++#define TREE_ROOT_OFFSET_ENTERED (VERBOSE << 1) ++#define TREE_NODE_OFFSET_ENTERED (VERBOSE << 2) ++#define TREE_NODE_POINTER (VERBOSE << 3) ++#define TREE_POSITION_DISPLAY (VERBOSE << 4) ++#define TREE_STRUCT_RADIX_10 (VERBOSE << 5) ++#define TREE_STRUCT_RADIX_16 (VERBOSE << 6) ++#define TREE_PARSE_MEMBER (VERBOSE << 7) ++#define TREE_READ_MEMBER (VERBOSE << 8) ++#define TREE_LINEAR_ORDER (VERBOSE << 9) ++ ++#define ALIAS_RUNTIME (1) ++#define ALIAS_RCLOCAL (2) ++#define ALIAS_RCHOME (3) ++#define ALIAS_BUILTIN (4) ++ ++struct alias_data { /* command alias storage */ ++ struct alias_data *next; ++ char *alias; ++ int argcnt; ++ int size; ++ int origin; ++ char *args[MAXARGS]; ++ char argbuf[1]; ++}; ++ ++struct rb_node ++{ ++ unsigned long rb_parent_color; ++#define RB_RED 0 ++#define RB_BLACK 1 ++ struct rb_node *rb_right; ++ struct rb_node *rb_left; ++}; ++ ++struct rb_root ++{ ++ struct rb_node *rb_node; ++}; ++ ++#define NUMBER_STACKFRAMES 4 ++ ++#define SAVE_RETURN_ADDRESS(retaddr) \ ++{ \ ++ int i; \ ++ int saved_stacks; \ ++ \ ++ saved_stacks = backtrace((void **)retaddr, NUMBER_STACKFRAMES); \ ++ \ ++ /* explicitely zero out the invalid addresses */ \ ++ for (i = saved_stacks; i < NUMBER_STACKFRAMES; i++) \ ++ retaddr[i] = 0; \ ++} ++ ++#endif /* !GDB_COMMON */ ++ ++ ++#define SYMBOL_NAME_USED (0x1) ++#define MODULE_SYMBOL (0x2) ++#define IS_MODULE_SYMBOL(SYM) ((SYM)->flags & MODULE_SYMBOL) ++ ++struct syment { ++ ulong value; ++ char *name; ++ struct syment *val_hash_next; ++ struct syment *name_hash_next; ++ char type; ++ unsigned char cnt; ++ unsigned char flags; ++ unsigned char pad2; ++}; ++ ++#define NAMESPACE_INIT (1) ++#define NAMESPACE_REUSE (2) ++#define NAMESPACE_FREE (3) ++#define NAMESPACE_INSTALL (4) ++#define NAMESPACE_COMPLETE (5) ++ ++struct symbol_namespace { ++ char *address; ++ size_t size; ++ long index; ++ long cnt; ++}; ++ ++struct downsized { ++ char *name; ++ struct downsized *next; ++}; ++ ++#define SYMVAL_HASH (512) ++#define SYMVAL_HASH_INDEX(vaddr) \ ++ (((vaddr) >> machdep->pageshift) % SYMVAL_HASH) ++ ++#define SYMNAME_HASH (512) ++#define SYMNAME_HASH_INDEX(name) \ ++ ((name[0] ^ (name[strlen(name)-1] * name[strlen(name)/2])) % SYMNAME_HASH) ++ ++#define PATCH_KERNEL_SYMBOLS_START ((char *)(1)) ++#define PATCH_KERNEL_SYMBOLS_STOP ((char *)(2)) ++ ++#ifndef GDB_COMMON ++ ++struct symbol_table_data { ++ ulong flags; ++#ifdef GDB_5_3 ++ struct _bfd *bfd; ++#else ++ struct bfd *bfd; ++#endif ++ struct sec *sections; ++ struct syment *symtable; ++ struct syment *symend; ++ long symcnt; ++ ulong syment_size; ++ struct symval_hash_chain { ++ struct syment *val_hash_head; ++ struct syment *val_hash_last; ++ } symval_hash[SYMVAL_HASH]; ++ double val_hash_searches; ++ double val_hash_iterations; ++ struct syment *symname_hash[SYMNAME_HASH]; ++ struct symbol_namespace kernel_namespace; ++ struct syment *ext_module_symtable; ++ struct syment *ext_module_symend; ++ long ext_module_symcnt; ++ struct symbol_namespace ext_module_namespace; ++ int mods_installed; ++ struct load_module *current; ++ struct load_module *load_modules; ++ off_t dwarf_eh_frame_file_offset; ++ ulong dwarf_eh_frame_size; ++ ulong first_ksymbol; ++ ulong __per_cpu_start; ++ ulong __per_cpu_end; ++ off_t dwarf_debug_frame_file_offset; ++ ulong dwarf_debug_frame_size; ++ ulong first_section_start; ++ ulong last_section_end; ++ ulong _stext_vmlinux; ++ struct downsized downsized; ++ ulong divide_error_vmlinux; ++ ulong idt_table_vmlinux; ++ ulong saved_command_line_vmlinux; ++ ulong pti_init_vmlinux; ++ ulong kaiser_init_vmlinux; ++ int kernel_symbol_type; ++ ulong linux_banner_vmlinux; ++}; ++ ++/* flags for st */ ++#define KERNEL_SYMS (0x1) ++#define MODULE_SYMS (0x2) ++#define LOAD_MODULE_SYMS (0x4) ++#define INSMOD_BUILTIN (0x8) ++#define GDB_SYMS_PATCHED (0x10) ++#define GDB_PATCHED() (st->flags & GDB_SYMS_PATCHED) ++#define NO_SEC_LOAD (0x20) ++#define NO_SEC_CONTENTS (0x40) ++#define FORCE_DEBUGINFO (0x80) ++#define CRC_MATCHES (0x100) ++#define ADD_SYMBOL_FILE (0x200) ++#define USE_OLD_ADD_SYM (0x400) ++#define PERCPU_SYMS (0x800) ++#define MODSECT_UNKNOWN (0x1000) ++#define MODSECT_V1 (0x2000) ++#define MODSECT_V2 (0x4000) ++#define MODSECT_V3 (0x8000) ++#define MODSECT_VMASK (MODSECT_V1|MODSECT_V2|MODSECT_V3) ++#define NO_STRIP (0x10000) ++ ++#define NO_LINE_NUMBERS() ((st->flags & GDB_SYMS_PATCHED) && !(kt->flags2 & KASLR)) ++ ++#endif /* !GDB_COMMON */ ++ ++#define ALL_MODULES (0) ++ ++#define MAX_MOD_NAMELIST (256) ++#define MAX_MOD_NAME (64) ++#define MAX_MOD_SEC_NAME (64) ++ ++#define MOD_EXT_SYMS (0x1) ++#define MOD_LOAD_SYMS (0x2) ++#define MOD_REMOTE (0x4) ++#define MOD_KALLSYMS (0x8) ++#define MOD_INITRD (0x10) ++#define MOD_NOPATCH (0x20) ++#define MOD_INIT (0x40) ++#define MOD_DO_READNOW (0x80) ++ ++#define SEC_FOUND (0x10000) ++ ++struct mod_section_data { ++#if defined(GDB_5_3) || defined(GDB_6_0) ++ struct sec *section; ++#else ++ struct bfd_section *section; ++#endif ++ char name[MAX_MOD_SEC_NAME]; ++ ulong offset; ++ ulong size; ++ int priority; ++ int flags; ++}; ++ ++struct load_module { ++ ulong mod_base; ++ ulong module_struct; ++ long mod_size; ++ char mod_namelist[MAX_MOD_NAMELIST]; ++ char mod_name[MAX_MOD_NAME]; ++ ulong mod_flags; ++ struct syment *mod_symtable; ++ struct syment *mod_symend; ++ long mod_ext_symcnt; ++ struct syment *mod_ext_symtable; ++ struct syment *mod_ext_symend; ++ long mod_load_symcnt; ++ struct syment *mod_load_symtable; ++ struct syment *mod_load_symend; ++ long mod_symalloc; ++ struct symbol_namespace mod_load_namespace; ++ ulong mod_size_of_struct; ++ ulong mod_text_start; ++ ulong mod_etext_guess; ++ ulong mod_rodata_start; ++ ulong mod_data_start; ++ ulong mod_bss_start; ++ int mod_sections; ++ struct mod_section_data *mod_section_data; ++ ulong mod_init_text_size; ++ ulong mod_init_module_ptr; ++ ulong mod_init_size; ++ struct syment *mod_init_symtable; ++ struct syment *mod_init_symend; ++ ulong mod_percpu; ++ ulong mod_percpu_size; ++ struct objfile *loaded_objfile; ++}; ++ ++#define IN_MODULE(A,L) \ ++ (((ulong)(A) >= (L)->mod_base) && ((ulong)(A) < ((L)->mod_base+(L)->mod_size))) ++ ++#define IN_MODULE_INIT(A,L) \ ++ (((ulong)(A) >= (L)->mod_init_module_ptr) && ((ulong)(A) < ((L)->mod_init_module_ptr+(L)->mod_init_size))) ++ ++#define IN_MODULE_PERCPU(A,L) \ ++ (((ulong)(A) >= (L)->mod_percpu) && ((ulong)(A) < ((L)->mod_percpu+(L)->mod_percpu_size))) ++ ++#define MODULE_PERCPU_SYMS_LOADED(L) ((L)->mod_percpu && (L)->mod_percpu_size) ++ ++#ifndef GDB_COMMON ++ ++#define KVADDR (0x1) ++#define UVADDR (0x2) ++#define PHYSADDR (0x4) ++#define XENMACHADDR (0x8) ++#define FILEADDR (0x10) ++#define AMBIGUOUS (~0) ++ ++#define USE_USER_PGD (UVADDR << 2) ++ ++#define VERIFY_ADDR (0x8) /* vm_area_dump() flags -- must follow */ ++#define PRINT_INODES (0x10) /* KVADDR, UVADDR, and PHYSADDR */ ++#define PRINT_MM_STRUCT (0x20) ++#define PRINT_VMA_STRUCTS (0x40) ++#define PRINT_SINGLE_VMA (0x80) ++#define PRINT_RADIX_10 (0x100) ++#define PRINT_RADIX_16 (0x200) ++#define PRINT_NRPAGES (0x400) ++ ++#define MIN_PAGE_SIZE (4096) ++ ++#define PTOB(X) ((ulonglong)(X) << machdep->pageshift) ++#define BTOP(X) ((ulonglong)(X) >> machdep->pageshift) ++ ++#define PAGESIZE() (machdep->pagesize) ++#define PAGESHIFT() (machdep->pageshift) ++ ++#define PAGEOFFSET(X) (((ulong)(X)) & machdep->pageoffset) ++#define VIRTPAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) ++#define PHYSPAGEBASE(X) (((physaddr_t)(X)) & (physaddr_t)machdep->pagemask) ++ ++/* ++ * Sparse memory stuff ++ * These must follow the definitions in the kernel mmzone.h ++ */ ++#define SECTION_SIZE_BITS() (machdep->section_size_bits) ++#define MAX_PHYSMEM_BITS() (machdep->max_physmem_bits) ++#define SECTIONS_SHIFT() (MAX_PHYSMEM_BITS() - SECTION_SIZE_BITS()) ++#define PA_SECTION_SHIFT() (SECTION_SIZE_BITS()) ++#define PFN_SECTION_SHIFT() (SECTION_SIZE_BITS() - PAGESHIFT()) ++#define NR_MEM_SECTIONS() (1UL << SECTIONS_SHIFT()) ++#define PAGES_PER_SECTION() (1UL << PFN_SECTION_SHIFT()) ++#define PAGE_SECTION_MASK() (~(PAGES_PER_SECTION()-1)) ++ ++#define pfn_to_section_nr(pfn) ((pfn) >> PFN_SECTION_SHIFT()) ++#define section_nr_to_pfn(sec) ((sec) << PFN_SECTION_SHIFT()) ++ ++#define SECTIONS_PER_ROOT() (machdep->sections_per_root) ++ ++/* CONFIG_SPARSEMEM_EXTREME */ ++#define _SECTIONS_PER_ROOT_EXTREME() (PAGESIZE() / SIZE(mem_section)) ++/* !CONFIG_SPARSEMEM_EXTREME */ ++#define _SECTIONS_PER_ROOT() (1) ++ ++#define SECTION_NR_TO_ROOT(sec) ((sec) / SECTIONS_PER_ROOT()) ++#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) ++#define NR_SECTION_ROOTS() (DIV_ROUND_UP(NR_MEM_SECTIONS(), SECTIONS_PER_ROOT())) ++#define SECTION_ROOT_MASK() (SECTIONS_PER_ROOT() - 1) ++ ++struct QEMUCPUSegment { ++ uint32_t selector; ++ uint32_t limit; ++ uint32_t flags; ++ uint32_t pad; ++ uint64_t base; ++}; ++ ++typedef struct QEMUCPUSegment QEMUCPUSegment; ++ ++struct QEMUCPUState { ++ uint32_t version; ++ uint32_t size; ++ uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp; ++ uint64_t r8, r9, r10, r11, r12, r13, r14, r15; ++ uint64_t rip, rflags; ++ QEMUCPUSegment cs, ds, es, fs, gs, ss; ++ QEMUCPUSegment ldt, tr, gdt, idt; ++ uint64_t cr[5]; ++}; ++ ++typedef struct QEMUCPUState QEMUCPUState; ++ ++/* ++ * Machine specific stuff ++ */ ++ ++#ifdef ARM ++#define _32BIT_ ++#define MACHINE_TYPE "ARM" ++ ++#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) ++ ++#define PTOV(X) \ ++ ((unsigned long)(X)-(machdep->machspec->phys_base)+(machdep->kvbase)) ++#define VTOP(X) \ ++ ((unsigned long)(X)-(machdep->kvbase)+(machdep->machspec->phys_base)) ++ ++#define IS_VMALLOC_ADDR(X) arm_is_vmalloc_addr((ulong)(X)) ++ ++#define DEFAULT_MODULES_VADDR (machdep->kvbase - 16 * 1024 * 1024) ++#define MODULES_VADDR (machdep->machspec->modules_vaddr) ++#define MODULES_END (machdep->machspec->modules_end) ++#define VMALLOC_START (machdep->machspec->vmalloc_start_addr) ++#define VMALLOC_END (machdep->machspec->vmalloc_end) ++ ++#define PGDIR_SHIFT (21) ++#define PTRS_PER_PTE (512) ++#define PTRS_PER_PGD (2048) ++ ++#define PGD_OFFSET(vaddr) ((vaddr) >> PGDIR_SHIFT) ++#define PTE_OFFSET(vaddr) (((vaddr) >> PAGESHIFT()) & (PTRS_PER_PTE - 1)) ++ ++#define __SWP_TYPE_SHIFT 3 ++#define __SWP_TYPE_BITS 6 ++#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) ++#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) ++ ++#define SWP_TYPE(entry) (((entry) >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK) ++#define SWP_OFFSET(entry) ((entry) >> __SWP_OFFSET_SHIFT) ++ ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) ++ ++#define TIF_SIGPENDING (2) ++ ++#define _SECTION_SIZE_BITS 28 ++#define _MAX_PHYSMEM_BITS 32 ++ ++/*add for LPAE*/ ++typedef unsigned long long u64; ++typedef signed int s32; ++typedef u64 pgd_t; ++typedef u64 pmd_t; ++typedef u64 pte_t; ++ ++#define PMDSIZE() (PAGESIZE()) ++#define LPAE_PGDIR_SHIFT (30) ++#define LPAE_PMDIR_SHIFT (21) ++ ++#define LPAE_PGD_OFFSET(vaddr) ((vaddr) >> LPAE_PGDIR_SHIFT) ++#define LPAE_PMD_OFFSET(vaddr) (((vaddr) >> LPAE_PMDIR_SHIFT) & \ ++ ((1<<(LPAE_PGDIR_SHIFT-LPAE_PMDIR_SHIFT))-1)) ++ ++#define _SECTION_SIZE_BITS_LPAE 28 ++#define _MAX_PHYSMEM_BITS_LPAE 36 ++ ++/* ++ * #define PTRS_PER_PTE 512 ++ * #define PTRS_PER_PMD 512 ++ * #define PTRS_PER_PGD 4 ++ * ++ */ ++ ++#define LPAE_PGDIR_SIZE() 32 ++#define LPAE_PGDIR_OFFSET(X) (((ulong)(X)) & (LPAE_PGDIR_SIZE() - 1)) ++ ++#define LPAE_PMDIR_SIZE() 4096 ++#define LPAE_PMDIR_OFFSET(X) (((ulong)(X)) & (LPAE_PMDIR_SIZE() - 1)) ++ ++#define LPAE_PTEDIR_SIZE() 4096 ++#define LPAE_PTEDIR_OFFSET(X) (((ulong)(X)) & (LPAE_PTEDIR_SIZE() - 1)) ++ ++/*section size for LPAE is 2MiB*/ ++#define LPAE_SECTION_PAGE_MASK (~((MEGABYTES(2))-1)) ++ ++#define _PHYSICAL_MASK_LPAE ((1ULL << _MAX_PHYSMEM_BITS_LPAE) - 1) ++#define PAGE_BASE_MASK ((u64)((s32)machdep->pagemask & _PHYSICAL_MASK_LPAE)) ++#define LPAE_PAGEBASE(X) (((ulonglong)(X)) & PAGE_BASE_MASK) ++ ++#define LPAE_VTOP(X) \ ++ ((unsigned long long)(unsigned long)(X) - \ ++ (machdep->kvbase) + (machdep->machspec->phys_base)) ++ ++#define IS_LAST_PGD_READ_LPAE(pgd) ((pgd) == \ ++ machdep->machspec->last_pgd_read_lpae) ++#define IS_LAST_PMD_READ_LPAE(pmd) ((pmd) == \ ++ machdep->machspec->last_pmd_read_lpae) ++#define IS_LAST_PTBL_READ_LPAE(ptbl) ((ptbl) == \ ++ machdep->machspec->last_ptbl_read_lpae) ++ ++#define FILL_PGD_LPAE(PGD, TYPE, SIZE) \ ++ if (!IS_LAST_PGD_READ_LPAE(PGD)) { \ ++ readmem((ulonglong)(PGD), TYPE, machdep->pgd, \ ++ SIZE, "pmd page", FAULT_ON_ERROR); \ ++ machdep->machspec->last_pgd_read_lpae \ ++ = (ulonglong)(PGD); \ ++ } ++#define FILL_PMD_LPAE(PMD, TYPE, SIZE) \ ++ if (!IS_LAST_PMD_READ_LPAE(PMD)) { \ ++ readmem((ulonglong)(PMD), TYPE, machdep->pmd, \ ++ SIZE, "pmd page", FAULT_ON_ERROR); \ ++ machdep->machspec->last_pmd_read_lpae \ ++ = (ulonglong)(PMD); \ ++ } ++ ++#define FILL_PTBL_LPAE(PTBL, TYPE, SIZE) \ ++ if (!IS_LAST_PTBL_READ_LPAE(PTBL)) { \ ++ readmem((ulonglong)(PTBL), TYPE, machdep->ptbl, \ ++ SIZE, "page table", FAULT_ON_ERROR); \ ++ machdep->machspec->last_ptbl_read_lpae \ ++ = (ulonglong)(PTBL); \ ++ } ++#endif /* ARM */ ++ ++#ifndef EM_AARCH64 ++#define EM_AARCH64 183 ++#endif ++ ++#ifdef ARM64 ++#define _64BIT_ ++#define MACHINE_TYPE "ARM64" ++ ++#define USERSPACE_TOP (machdep->machspec->userspace_top) ++#define PAGE_OFFSET (machdep->machspec->page_offset) ++#define VMALLOC_START (machdep->machspec->vmalloc_start_addr) ++#define VMALLOC_END (machdep->machspec->vmalloc_end) ++#define VMEMMAP_VADDR (machdep->machspec->vmemmap_vaddr) ++#define VMEMMAP_END (machdep->machspec->vmemmap_end) ++#define MODULES_VADDR (machdep->machspec->modules_vaddr) ++#define MODULES_END (machdep->machspec->modules_end) ++ ++#define PTOV(X) arm64_PTOV((ulong)(X)) ++#define VTOP(X) arm64_VTOP((ulong)(X)) ++ ++#define IS_VMALLOC_ADDR(X) arm64_IS_VMALLOC_ADDR((ulong)(X)) ++ ++#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) ++ ++/* ++ * 48-bit physical address supported. ++ */ ++#define PHYS_MASK_SHIFT (48) ++#define PHYS_MASK (((1UL) << PHYS_MASK_SHIFT) - 1) ++ ++typedef signed int s32; ++ ++/* ++ * 3-levels / 4K pages ++ */ ++#define PTRS_PER_PGD_L3_4K (512) ++#define PTRS_PER_PMD_L3_4K (512) ++#define PTRS_PER_PTE_L3_4K (512) ++#define PGDIR_SHIFT_L3_4K (30) ++#define PGDIR_SIZE_L3_4K ((1UL) << PGDIR_SHIFT_L3_4K) ++#define PGDIR_MASK_L3_4K (~(PGDIR_SIZE_L3_4K-1)) ++#define PMD_SHIFT_L3_4K (21) ++#define PMD_SIZE_L3_4K (1UL << PMD_SHIFT_L3_4K) ++#define PMD_MASK_L3_4K (~(PMD_SIZE_L3_4K-1)) ++ ++/* ++ * 4-levels / 4K pages ++ * 48-bit VA ++ */ ++#define PTRS_PER_PGD_L4_4K ((1UL) << (48 - 39)) ++#define PTRS_PER_PUD_L4_4K (512) ++#define PTRS_PER_PMD_L4_4K (512) ++#define PTRS_PER_PTE_L4_4K (512) ++#define PGDIR_SHIFT_L4_4K (39) ++#define PGDIR_SIZE_L4_4K ((1UL) << PGDIR_SHIFT_L4_4K) ++#define PGDIR_MASK_L4_4K (~(PGDIR_SIZE_L4_4K-1)) ++#define PUD_SHIFT_L4_4K (30) ++#define PUD_SIZE_L4_4K ((1UL) << PUD_SHIFT_L4_4K) ++#define PUD_MASK_L4_4K (~(PUD_SIZE_L4_4K-1)) ++#define PMD_SHIFT_L4_4K (21) ++#define PMD_SIZE_L4_4K (1UL << PMD_SHIFT_L4_4K) ++#define PMD_MASK_L4_4K (~(PMD_SIZE_L4_4K-1)) ++ ++#define PGDIR_SIZE_48VA (1UL << ((48 - 39) + 3)) ++#define PGDIR_MASK_48VA (~(PGDIR_SIZE_48VA - 1)) ++#define PGDIR_OFFSET_48VA(X) (((ulong)(X)) & (PGDIR_SIZE_48VA - 1)) ++ ++/* ++ * 3-levels / 64K pages ++ */ ++#define PTRS_PER_PGD_L3_64K (64) ++#define PTRS_PER_PMD_L3_64K (8192) ++#define PTRS_PER_PTE_L3_64K (8192) ++#define PGDIR_SHIFT_L3_64K (42) ++#define PGDIR_SIZE_L3_64K ((1UL) << PGDIR_SHIFT_L3_64K) ++#define PGDIR_MASK_L3_64K (~(PGDIR_SIZE_L3_64K-1)) ++#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)) & ((machdep->ptrs_per_pgd * 8) - 1)) ++ ++/* ++ * 2-levels / 64K pages ++ */ ++#define PTRS_PER_PGD_L2_64K (8192) ++#define PTRS_PER_PTE_L2_64K (8192) ++#define PGDIR_SHIFT_L2_64K (29) ++#define PGDIR_SIZE_L2_64K ((1UL) << PGDIR_SHIFT_L2_64K) ++#define PGDIR_MASK_L2_64K (~(PGDIR_SIZE_L2_64K-1)) ++ ++/* ++ * Software defined PTE bits definition. ++ * (arch/arm64/include/asm/pgtable.h) ++ */ ++#define PTE_VALID (1UL << 0) ++#define PTE_DIRTY (1UL << 55) ++#define PTE_SPECIAL (1UL << 56) ++ ++/* ++ * Level 3 descriptor (PTE). ++ * (arch/arm64/include/asm/pgtable-hwdef.h) ++ */ ++#define PTE_TYPE_MASK (3UL << 0) ++#define PTE_TYPE_FAULT (0UL << 0) ++#define PTE_TYPE_PAGE (3UL << 0) ++#define PTE_USER (1UL << 6) /* AP[1] */ ++#define PTE_RDONLY (1UL << 7) /* AP[2] */ ++#define PTE_SHARED (3UL << 8) /* SH[1:0], inner shareable */ ++#define PTE_AF (1UL << 10) /* Access Flag */ ++#define PTE_NG (1UL << 11) /* nG */ ++#define PTE_PXN (1UL << 53) /* Privileged XN */ ++#define PTE_UXN (1UL << 54) /* User XN */ ++ ++#define __swp_type(x) arm64_swp_type(x) ++#define __swp_offset(x) arm64_swp_offset(x) ++#define SWP_TYPE(x) __swp_type(x) ++#define SWP_OFFSET(x) __swp_offset(x) ++ ++#define KSYMS_START (0x1) ++#define PHYS_OFFSET (0x2) ++#define VM_L2_64K (0x4) ++#define VM_L3_64K (0x8) ++#define VM_L3_4K (0x10) ++#define KDUMP_ENABLED (0x20) ++#define IRQ_STACKS (0x40) ++#define NEW_VMEMMAP (0x80) ++#define VM_L4_4K (0x100) ++#define UNW_4_14 (0x200) ++#define FLIPPED_VM (0x400) ++#define HAS_PHYSVIRT_OFFSET (0x800) ++ ++/* ++ * Get kimage_voffset from /dev/crash ++ */ ++#define DEV_CRASH_ARCH_DATA _IOR('c', 1, unsigned long) ++ ++/* ++ * sources: Documentation/arm64/memory.txt ++ * arch/arm64/include/asm/memory.h ++ * arch/arm64/include/asm/pgtable.h ++ */ ++#define ARM64_VA_START ((0xffffffffffffffffUL) \ ++ << machdep->machspec->VA_BITS) ++#define _VA_START(va) ((0xffffffffffffffffUL) - \ ++ ((1UL) << ((va) - 1)) + 1) ++#define TEXT_OFFSET_MASK (~((MEGABYTES(2UL))-1)) ++ ++#define ARM64_PAGE_OFFSET ((0xffffffffffffffffUL) \ ++ << (machdep->machspec->VA_BITS - 1)) ++/* kernels >= v5.4 the kernel VA space is flipped */ ++#define ARM64_FLIP_PAGE_OFFSET (-(1UL) << machdep->machspec->CONFIG_ARM64_VA_BITS) ++#define ARM64_FLIP_PAGE_OFFSET_ACTUAL ((0xffffffffffffffffUL) \ ++ - ((1UL) << machdep->machspec->VA_BITS_ACTUAL) + 1) ++ ++#define ARM64_USERSPACE_TOP ((1UL) << machdep->machspec->VA_BITS) ++#define ARM64_USERSPACE_TOP_ACTUAL ((1UL) << machdep->machspec->VA_BITS_ACTUAL) ++ ++/* only used for v4.6 or later */ ++#define ARM64_MODULES_VSIZE MEGABYTES(128) ++#define ARM64_KASAN_SHADOW_SIZE (1UL << (machdep->machspec->VA_BITS - 3)) ++ ++/* ++ * The following 3 definitions are the original values, but are obsolete ++ * for 3.17 and later kernels because they are now build-time calculations. ++ * They all depend on the kernel's new VMEMMAP_SIZE value, which is dependent ++ * upon the size of struct page. Accordingly, arm64_calc_virtual_memory_ranges() ++ * determines their values at POST_GDB time. ++ */ ++#define ARM64_VMALLOC_END (ARM64_PAGE_OFFSET - 0x400000000UL - KILOBYTES(64) - 1) ++#define ARM64_VMEMMAP_VADDR ((ARM64_VMALLOC_END+1) + KILOBYTES(64)) ++#define ARM64_VMEMMAP_END (ARM64_VMEMMAP_VADDR + GIGABYTES(8UL) - 1) ++ ++#define ARM64_STACK_SIZE (16384) ++#define ARM64_IRQ_STACK_SIZE ARM64_STACK_SIZE ++ ++#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; ++ ++struct arm64_user_pt_regs { ++ __u64 regs[31]; ++ __u64 sp; ++ __u64 pc; ++ __u64 pstate; ++}; ++ ++struct arm64_pt_regs { ++ union { ++ struct arm64_user_pt_regs user_regs; ++ struct { ++ u64 regs[31]; ++ u64 sp; ++ u64 pc; ++ u64 pstate; ++ }; ++ }; ++ u64 orig_x0; ++ u64 syscallno; ++}; ++ ++/* AArch32 CPSR bits */ ++#define PSR_MODE32_BIT 0x00000010 ++ ++#define TIF_SIGPENDING (0) ++#define display_idt_table() \ ++ error(FATAL, "-d option is not applicable to ARM64 architecture\n") ++ ++struct machine_specific { ++ ulong flags; ++ ulong userspace_top; ++ ulong page_offset; ++ ulong vmalloc_start_addr; ++ ulong vmalloc_end; ++ ulong vmemmap_vaddr; ++ ulong vmemmap_end; ++ ulong modules_vaddr; ++ ulong modules_end; ++ ulong phys_offset; ++ ulong __exception_text_start; ++ ulong __exception_text_end; ++ struct arm64_pt_regs *panic_task_regs; ++ ulong PTE_PROT_NONE; ++ ulong PTE_FILE; ++ ulong VA_BITS; ++ ulong __SWP_TYPE_BITS; ++ ulong __SWP_TYPE_SHIFT; ++ ulong __SWP_TYPE_MASK; ++ ulong __SWP_OFFSET_BITS; ++ ulong __SWP_OFFSET_SHIFT; ++ ulong __SWP_OFFSET_MASK; ++ ulong crash_kexec_start; ++ ulong crash_kexec_end; ++ ulong crash_save_cpu_start; ++ ulong crash_save_cpu_end; ++ ulong kernel_flags; ++ ulong irq_stack_size; ++ ulong *irq_stacks; ++ char *irq_stackbuf; ++ ulong sdei_stack_size; ++ ulong *sdei_stacks; ++ char *sdei_stackbuf; ++ ulong __irqentry_text_start; ++ ulong __irqentry_text_end; ++ /* for exception vector code */ ++ ulong exp_entry1_start; ++ ulong exp_entry1_end; ++ ulong exp_entry2_start; ++ ulong exp_entry2_end; ++ /* only needed for v4.6 or later kernel */ ++ ulong kimage_voffset; ++ ulong kimage_text; ++ ulong kimage_end; ++ ulong user_eframe_offset; ++ /* for v4.14 or later */ ++ ulong kern_eframe_offset; ++ ulong machine_kexec_start; ++ ulong machine_kexec_end; ++ ulong VA_BITS_ACTUAL; ++ ulong CONFIG_ARM64_VA_BITS; ++ ulong VA_START; ++ ulong CONFIG_ARM64_KERNELPACMASK; ++ ulong physvirt_offset; ++}; ++ ++struct arm64_stackframe { ++ unsigned long fp; ++ unsigned long sp; ++ unsigned long pc; ++}; ++ ++#endif /* ARM64 */ ++ ++#ifdef MIPS ++#define _32BIT_ ++#define MACHINE_TYPE "MIPS" ++ ++#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) ++ ++#define PTOV(X) ((unsigned long)(X) + 0x80000000lu) ++#define VTOP(X) ((unsigned long)(X) & 0x1ffffffflu) ++ ++#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) ++ ++#define DEFAULT_MODULES_VADDR (machdep->kvbase - 16 * 1024 * 1024) ++#define MODULES_VADDR (machdep->machspec->modules_vaddr) ++#define MODULES_END (machdep->machspec->modules_end) ++#define VMALLOC_START (machdep->machspec->vmalloc_start_addr) ++#define VMALLOC_END (machdep->machspec->vmalloc_end) ++ ++#define __SWP_TYPE_SHIFT 3 ++#define __SWP_TYPE_BITS 6 ++#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) ++#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) ++ ++#define SWP_TYPE(entry) (((entry) >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK) ++#define SWP_OFFSET(entry) ((entry) >> __SWP_OFFSET_SHIFT) ++ ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) ++ ++#define TIF_SIGPENDING (2) ++ ++#define _SECTION_SIZE_BITS 26 ++#define _MAX_PHYSMEM_BITS 32 ++#endif /* MIPS */ ++ ++#ifdef MIPS64 ++#define _64BIT_ ++#define MACHINE_TYPE "MIPS64" ++ ++#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) ++#define IS_CKPHYS(X) (((X) >= 0xffffffff80000000lu) && \ ++ ((X) < 0xffffffffc0000000lu)) ++#define IS_XKPHYS(X) (((X) >= 0x8000000000000000lu) && \ ++ ((X) < 0xc000000000000000lu)) ++ ++#define PTOV(X) ((ulong)(X) + 0x9800000000000000lu) ++#define VTOP(X) (IS_CKPHYS(X) ? ((ulong)(X) & 0x000000001ffffffflu) \ ++ : ((ulong)(X) & 0x0000fffffffffffflu)) ++ ++#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start && !IS_CKPHYS(X)) ++ ++#define DEFAULT_MODULES_VADDR 0xffffffffc0000000lu ++#define MODULES_VADDR (machdep->machspec->modules_vaddr) ++#define MODULES_END (machdep->machspec->modules_end) ++#define VMALLOC_START (machdep->machspec->vmalloc_start_addr) ++#define VMALLOC_END (machdep->machspec->vmalloc_end) ++ ++#define __SWP_TYPE_SHIFT 16 ++#define __SWP_TYPE_BITS 8 ++#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) ++#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) ++ ++#define SWP_TYPE(entry) (((entry) >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK) ++#define SWP_OFFSET(entry) ((entry) >> __SWP_OFFSET_SHIFT) ++ ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) ++ ++#define TIF_SIGPENDING (2) ++ ++#define _SECTION_SIZE_BITS 28 ++#define _MAX_PHYSMEM_BITS 48 ++#endif /* MIPS64 */ ++ ++#ifdef X86 ++#define _32BIT_ ++#define MACHINE_TYPE "X86" ++#define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) ++#define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) ++#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) ++#define KVBASE_MASK (0x1ffffff) ++ ++#define PGDIR_SHIFT_2LEVEL (22) ++#define PTRS_PER_PTE_2LEVEL (1024) ++#define PTRS_PER_PGD_2LEVEL (1024) ++ ++#define PGDIR_SHIFT_3LEVEL (30) ++#define PTRS_PER_PTE_3LEVEL (512) ++#define PTRS_PER_PGD_3LEVEL (4) ++#define PMD_SHIFT (21) /* only used by PAE translators */ ++#define PTRS_PER_PMD (512) /* only used by PAE translators */ ++ ++#define _PAGE_PRESENT 0x001 ++#define _PAGE_RW 0x002 ++#define _PAGE_USER 0x004 ++#define _PAGE_PWT 0x008 ++#define _PAGE_PCD 0x010 ++#define _PAGE_ACCESSED 0x020 ++#define _PAGE_DIRTY 0x040 ++#define _PAGE_4M 0x080 /* 4 MB page, Pentium+, if present.. */ ++#define _PAGE_PSE 0x080 /* 4 MB (or 2MB) page, Pentium+, if present.. */ ++#define _PAGE_GLOBAL 0x100 /* Global TLB entry PPro+ */ ++#define _PAGE_PROTNONE (machdep->machspec->page_protnone) ++#define _PAGE_NX (0x8000000000000000ULL) ++ ++#define NONPAE_PAGEBASE(X) (((unsigned long)(X)) & (unsigned long)machdep->pagemask) ++#define NX_BIT_MASK (0x7fffffffffffffffULL) ++#define PAE_PAGEBASE(X) (((unsigned long long)(X)) & ((unsigned long long)machdep->pagemask) & NX_BIT_MASK) ++ ++#define SWP_TYPE(entry) (((entry) >> 1) & 0x3f) ++#define SWP_OFFSET(entry) ((entry) >> 8) ++#define __swp_type_PAE(entry) (((entry) >> 32) & 0x1f) ++#define __swp_type_nonPAE(entry) (((entry) >> 1) & 0x1f) ++#define __swp_offset_PAE(entry) (((entry) >> 32) >> 5) ++#define __swp_offset_nonPAE(entry) ((entry) >> 8) ++#define __swp_type(entry) (machdep->flags & PAE ? \ ++ __swp_type_PAE(entry) : __swp_type_nonPAE(entry)) ++#define __swp_offset(entry) (machdep->flags & PAE ? \ ++ __swp_offset_PAE(entry) : __swp_offset_nonPAE(entry)) ++ ++#define TIF_SIGPENDING (2) ++ ++// CONFIG_X86_PAE ++#define _SECTION_SIZE_BITS_PAE_ORIG 30 ++#define _SECTION_SIZE_BITS_PAE_2_6_26 29 ++#define _MAX_PHYSMEM_BITS_PAE 36 ++ ++// !CONFIG_X86_PAE ++#define _SECTION_SIZE_BITS 26 ++#define _MAX_PHYSMEM_BITS 32 ++ ++#define IS_LAST_PMD_READ_PAE(pmd) ((ulong)(pmd) == machdep->machspec->last_pmd_read_PAE) ++#define IS_LAST_PTBL_READ_PAE(ptbl) ((ulong)(ptbl) == machdep->machspec->last_ptbl_read_PAE) ++ ++#define FILL_PMD_PAE(PMD, TYPE, SIZE) \ ++ if (!IS_LAST_PMD_READ_PAE(PMD)) { \ ++ readmem((ulonglong)(PMD), TYPE, machdep->pmd, \ ++ SIZE, "pmd page", FAULT_ON_ERROR); \ ++ machdep->machspec->last_pmd_read_PAE = (ulonglong)(PMD); \ ++ } ++ ++#define FILL_PTBL_PAE(PTBL, TYPE, SIZE) \ ++ if (!IS_LAST_PTBL_READ_PAE(PTBL)) { \ ++ readmem((ulonglong)(PTBL), TYPE, machdep->ptbl, \ ++ SIZE, "page table", FAULT_ON_ERROR); \ ++ machdep->machspec->last_ptbl_read_PAE = (ulonglong)(PTBL); \ ++ } ++ ++#endif /* X86 */ ++ ++#ifdef X86_64 ++#define _64BIT_ ++#define MACHINE_TYPE "X86_64" ++ ++#define USERSPACE_TOP (machdep->machspec->userspace_top) ++#define PAGE_OFFSET (machdep->machspec->page_offset) ++#define VMALLOC_START (machdep->machspec->vmalloc_start_addr) ++#define VMALLOC_END (machdep->machspec->vmalloc_end) ++#define VMEMMAP_VADDR (machdep->machspec->vmemmap_vaddr) ++#define VMEMMAP_END (machdep->machspec->vmemmap_end) ++#define MODULES_VADDR (machdep->machspec->modules_vaddr) ++#define MODULES_END (machdep->machspec->modules_end) ++ ++#define __START_KERNEL_map 0xffffffff80000000UL ++#define MODULES_LEN (MODULES_END - MODULES_VADDR) ++ ++#define USERSPACE_TOP_ORIG 0x0000008000000000 ++#define PAGE_OFFSET_ORIG 0x0000010000000000 ++#define VMALLOC_START_ADDR_ORIG 0xffffff0000000000 ++#define VMALLOC_END_ORIG 0xffffff7fffffffff ++#define MODULES_VADDR_ORIG 0xffffffffa0000000 ++#define MODULES_END_ORIG 0xffffffffafffffff ++ ++#define USERSPACE_TOP_2_6_11 0x0000800000000000 ++#define PAGE_OFFSET_2_6_11 0xffff810000000000 ++#define VMALLOC_START_ADDR_2_6_11 0xffffc20000000000 ++#define VMALLOC_END_2_6_11 0xffffe1ffffffffff ++#define MODULES_VADDR_2_6_11 0xffffffff88000000 ++#define MODULES_END_2_6_11 0xfffffffffff00000 ++ ++#define VMEMMAP_VADDR_2_6_24 0xffffe20000000000 ++#define VMEMMAP_END_2_6_24 0xffffe2ffffffffff ++ ++#define MODULES_VADDR_2_6_26 0xffffffffa0000000 ++ ++#define PAGE_OFFSET_2_6_27 0xffff880000000000 ++#define MODULES_END_2_6_27 0xffffffffff000000 ++ ++#define USERSPACE_TOP_XEN 0x0000800000000000 ++#define PAGE_OFFSET_XEN 0xffff880000000000 ++#define VMALLOC_START_ADDR_XEN 0xffffc20000000000 ++#define VMALLOC_END_XEN 0xffffe1ffffffffff ++#define MODULES_VADDR_XEN 0xffffffff88000000 ++#define MODULES_END_XEN 0xfffffffffff00000 ++ ++#define USERSPACE_TOP_XEN_RHEL4 0x0000008000000000 ++#define PAGE_OFFSET_XEN_RHEL4 0xffffff8000000000 ++#define VMALLOC_START_ADDR_XEN_RHEL4 0xffffff0000000000 ++#define VMALLOC_END_XEN_RHEL4 0xffffff7fffffffff ++#define MODULES_VADDR_XEN_RHEL4 0xffffffffa0000000 ++#define MODULES_END_XEN_RHEL4 0xffffffffafffffff ++ ++#define VMALLOC_START_ADDR_2_6_31 0xffffc90000000000 ++#define VMALLOC_END_2_6_31 0xffffe8ffffffffff ++#define VMEMMAP_VADDR_2_6_31 0xffffea0000000000 ++#define VMEMMAP_END_2_6_31 0xffffeaffffffffff ++#define MODULES_VADDR_2_6_31 0xffffffffa0000000 ++#define MODULES_END_2_6_31 0xffffffffff000000 ++ ++#define USERSPACE_TOP_5LEVEL 0x0100000000000000 ++#define PAGE_OFFSET_5LEVEL 0xff10000000000000 ++#define VMALLOC_START_ADDR_5LEVEL 0xffa0000000000000 ++#define VMALLOC_END_5LEVEL 0xffd1ffffffffffff ++#define MODULES_VADDR_5LEVEL 0xffffffffa0000000 ++#define MODULES_END_5LEVEL 0xffffffffff5fffff ++#define VMEMMAP_VADDR_5LEVEL 0xffd4000000000000 ++#define VMEMMAP_END_5LEVEL 0xffd5ffffffffffff ++ ++#define PAGE_OFFSET_4LEVEL_4_20 0xffff888000000000 ++#define PAGE_OFFSET_5LEVEL_4_20 0xff11000000000000 ++ ++#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)) ++ ++/* ++ * the default page table level for x86_64: ++ * 4 level page tables ++ */ ++#define PGDIR_SHIFT 39 ++#define PTRS_PER_PGD 512 ++#define PUD_SHIFT 30 ++#define PTRS_PER_PUD 512 ++#define PMD_SHIFT 21 ++#define PTRS_PER_PMD 512 ++#define PTRS_PER_PTE 512 ++ ++/* 5 level page */ ++#define PGDIR_SHIFT_5LEVEL 48 ++#define PTRS_PER_PGD_5LEVEL 512 ++#define P4D_SHIFT 39 ++#define PTRS_PER_P4D 512 ++ ++#define __PGDIR_SHIFT (machdep->machspec->pgdir_shift) ++#define __PTRS_PER_PGD (machdep->machspec->ptrs_per_pgd) ++ ++#define pgd_index(address) (((address) >> __PGDIR_SHIFT) & (__PTRS_PER_PGD-1)) ++#define p4d_index(address) (((address) >> P4D_SHIFT) & (PTRS_PER_P4D - 1)) ++#define pud_index(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) ++#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) ++#define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) ++ ++#define FILL_TOP_PGD() \ ++ if (!(pc->flags & RUNTIME) || ACTIVE()) { \ ++ FILL_PGD(vt->kernel_pgd[0], KVADDR, PAGESIZE()); \ ++ } ++ ++#define FILL_TOP_PGD_HYPER() \ ++ unsigned long idle_pg_table = symbol_exists("idle_pg_table_4") ? \ ++ symbol_value("idle_pg_table_4") : \ ++ symbol_value("idle_pg_table"); \ ++ FILL_PGD(idle_pg_table, KVADDR, PAGESIZE()); ++ ++#define IS_LAST_P4D_READ(p4d) ((ulong)(p4d) == machdep->machspec->last_p4d_read) ++ ++#define FILL_P4D(P4D, TYPE, SIZE) \ ++ if (!IS_LAST_P4D_READ(P4D)) { \ ++ readmem((ulonglong)((ulong)(P4D)), TYPE, machdep->machspec->p4d, \ ++ SIZE, "p4d page", FAULT_ON_ERROR); \ ++ machdep->machspec->last_p4d_read = (ulong)(P4D); \ ++ } ++ ++#define MAX_POSSIBLE_PHYSMEM_BITS 52 ++ ++/* ++ * PHYSICAL_PAGE_MASK changed (enlarged) between 2.4 and 2.6, so ++ * for safety, use the 2.6 values to generate it. ++ */ ++#define __PHYSICAL_MASK_SHIFT_XEN 52 ++#define __PHYSICAL_MASK_SHIFT_2_6 46 ++#define __PHYSICAL_MASK_SHIFT_5LEVEL 52 ++#define __PHYSICAL_MASK_SHIFT (machdep->machspec->physical_mask_shift) ++#define __PHYSICAL_MASK ((1UL << __PHYSICAL_MASK_SHIFT) - 1) ++#define __VIRTUAL_MASK_SHIFT 48 ++#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1) ++#define PAGE_SHIFT 12 ++#define PAGE_SIZE (1UL << PAGE_SHIFT) ++#define PHYSICAL_PAGE_MASK (~(PAGE_SIZE-1) & __PHYSICAL_MASK ) ++ ++#define _PAGE_BIT_NX 63 ++#define _PAGE_PRESENT 0x001 ++#define _PAGE_RW 0x002 ++#define _PAGE_USER 0x004 ++#define _PAGE_PWT 0x008 ++#define _PAGE_PCD 0x010 ++#define _PAGE_ACCESSED 0x020 ++#define _PAGE_DIRTY 0x040 ++#define _PAGE_PSE 0x080 /* 2MB page */ ++#define _PAGE_FILE 0x040 /* set:pagecache, unset:swap */ ++#define _PAGE_GLOBAL 0x100 /* Global TLB entry */ ++#define _PAGE_PROTNONE (machdep->machspec->page_protnone) ++#define _PAGE_NX (1UL<<_PAGE_BIT_NX) ++ ++#define SWP_TYPE(entry) (((entry) >> 1) & 0x3f) ++#define SWP_OFFSET(entry) ((entry) >> 8) ++#define __swp_type(entry) x86_64_swp_type(entry) ++#define __swp_offset(entry) x86_64_swp_offset(entry) ++ ++#define TIF_SIGPENDING (2) ++ ++#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) ++ ++#define _CPU_PDA_READ2(CPU, BUFFER) \ ++ ((readmem(symbol_value("_cpu_pda"), \ ++ KVADDR, &cpu_pda_addr, sizeof(unsigned long), \ ++ "_cpu_pda addr", RETURN_ON_ERROR)) && \ ++ (readmem(cpu_pda_addr + ((CPU) * sizeof(void *)), \ ++ KVADDR, &cpu_pda_addr, sizeof(unsigned long), \ ++ "_cpu_pda addr", RETURN_ON_ERROR)) && \ ++ (cpu_pda_addr) && \ ++ (readmem(cpu_pda_addr, KVADDR, (BUFFER), SIZE(x8664_pda), \ ++ "cpu_pda entry", RETURN_ON_ERROR))) ++ ++#define _CPU_PDA_READ(CPU, BUFFER) \ ++ ((STRNEQ("_cpu_pda", closest_symbol((symbol_value("_cpu_pda") + \ ++ ((CPU) * sizeof(unsigned long)))))) && \ ++ (readmem(symbol_value("_cpu_pda") + ((CPU) * sizeof(void *)), \ ++ KVADDR, &cpu_pda_addr, sizeof(unsigned long), \ ++ "_cpu_pda addr", RETURN_ON_ERROR)) && \ ++ (readmem(cpu_pda_addr, KVADDR, (BUFFER), SIZE(x8664_pda), \ ++ "cpu_pda entry", RETURN_ON_ERROR))) ++ ++#define CPU_PDA_READ(CPU, BUFFER) \ ++ (STRNEQ("cpu_pda", closest_symbol((symbol_value("cpu_pda") + \ ++ ((CPU) * SIZE(x8664_pda))))) && \ ++ readmem(symbol_value("cpu_pda") + ((CPU) * SIZE(x8664_pda)), \ ++ KVADDR, (BUFFER), SIZE(x8664_pda), "cpu_pda entry", \ ++ RETURN_ON_ERROR)) ++ ++#define VALID_LEVEL4_PGT_ADDR(X) \ ++ (((X) == VIRTPAGEBASE(X)) && IS_KVADDR(X) && !IS_VMALLOC_ADDR(X)) ++ ++#define _SECTION_SIZE_BITS 27 ++#define _MAX_PHYSMEM_BITS 40 ++#define _MAX_PHYSMEM_BITS_2_6_26 44 ++#define _MAX_PHYSMEM_BITS_2_6_31 46 ++#define _MAX_PHYSMEM_BITS_5LEVEL 52 ++ ++#endif /* X86_64 */ ++ ++#ifdef ALPHA ++#define _64BIT_ ++#define MACHINE_TYPE "ALPHA" ++ ++#define PAGEBASE(X) (((unsigned long)(X)) & (unsigned long)machdep->pagemask) ++ ++#define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) ++#define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) ++#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) ++#define KSEG_BASE_48_BIT (0xffff800000000000) ++#define KSEG_BASE (0xfffffc0000000000) ++#define _PFN_MASK (0xFFFFFFFF00000000) ++#define VMALLOC_START (0xFFFFFE0000000000) ++#define MIN_SYMBOL_VALUE (KSEG_BASE_48_BIT) ++ ++#define PGDIR_SHIFT (PAGESHIFT() + 2*(PAGESHIFT()-3)) ++#define PMD_SHIFT (PAGESHIFT() + (PAGESHIFT()-3)) ++#define PTRS_PER_PAGE (1024) ++ ++#define PTRS_PER_PGD (1UL << (PAGESHIFT()-3)) ++ ++/* ++ * OSF/1 PAL-code-imposed page table bits ++ */ ++#define _PAGE_VALID 0x0001 ++#define _PAGE_FOR 0x0002 /* used for page protection (fault on read) */ ++#define _PAGE_FOW 0x0004 /* used for page protection (fault on write) */ ++#define _PAGE_FOE 0x0008 /* used for page protection (fault on exec) */ ++#define _PAGE_ASM 0x0010 ++#define _PAGE_KRE 0x0100 /* xxx - see below on the "accessed" bit */ ++#define _PAGE_URE 0x0200 /* xxx */ ++#define _PAGE_KWE 0x1000 /* used to do the dirty bit in software */ ++#define _PAGE_UWE 0x2000 /* used to do the dirty bit in software */ ++ ++/* .. and these are ours ... */ ++#define _PAGE_DIRTY 0x20000 ++#define _PAGE_ACCESSED 0x40000 ++ ++#define SWP_TYPE(entry) (((entry) >> 32) & 0xff) ++#define SWP_OFFSET(entry) ((entry) >> 40) ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) ++ ++#define TIF_SIGPENDING (2) ++ ++#endif /* ALPHA */ ++ ++#ifdef PPC ++#define _32BIT_ ++#define MACHINE_TYPE "PPC" ++ ++#define PAGEBASE(X) ((X) & machdep->pagemask) ++ ++#define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) ++#define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) ++#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) ++ ++/* Holds the platform specific info for page translation */ ++struct machine_specific { ++ char *platform; ++ ++ /* page address translation bits */ ++ int pte_size; ++ int pte_rpn_shift; ++ ++ /* page flags */ ++ ulong _page_present; ++ ulong _page_user; ++ ulong _page_rw; ++ ulong _page_guarded; ++ ulong _page_coherent; ++ ulong _page_no_cache; ++ ulong _page_writethru; ++ ulong _page_dirty; ++ ulong _page_accessed; ++ ulong _page_hwwrite; ++ ulong _page_shared; ++ ulong _page_k_rw; ++ ++ /* platform special vtop */ ++ int (*vtop_special)(ulong vaddr, physaddr_t *paddr, int verbose); ++ void *mmu_special; ++}; ++ ++/* machdep flags for ppc32 specific */ ++#define IS_PAE() (machdep->flags & PAE) ++#define IS_BOOKE() (machdep->flags & CPU_BOOKE) ++/* Page translation bits */ ++#define PPC_PLATFORM (machdep->machspec->platform) ++#define PTE_SIZE (machdep->machspec->pte_size) ++#define PTE_RPN_SHIFT (machdep->machspec->pte_rpn_shift) ++#define PAGE_SHIFT (12) ++#define PTE_T_LOG2 (ffs(PTE_SIZE) - 1) ++#define PTE_SHIFT (PAGE_SHIFT - PTE_T_LOG2) ++#define PGDIR_SHIFT (PAGE_SHIFT + PTE_SHIFT) ++#define PTRS_PER_PGD (1 << (32 - PGDIR_SHIFT)) ++#define PTRS_PER_PTE (1 << PTE_SHIFT) ++/* special vtop */ ++#define VTOP_SPECIAL (machdep->machspec->vtop_special) ++#define MMU_SPECIAL (machdep->machspec->mmu_special) ++ ++/* PFN shifts */ ++#define BOOKE3E_PTE_RPN_SHIFT (24) ++ ++/* PAGE flags */ ++#define _PAGE_PRESENT (machdep->machspec->_page_present) /* software: pte contains a translation */ ++#define _PAGE_USER (machdep->machspec->_page_user) /* matches one of the PP bits */ ++#define _PAGE_RW (machdep->machspec->_page_rw) /* software: user write access allowed */ ++#define _PAGE_GUARDED (machdep->machspec->_page_guarded) ++#define _PAGE_COHERENT (machdep->machspec->_page_coherent /* M: enforce memory coherence (SMP systems) */) ++#define _PAGE_NO_CACHE (machdep->machspec->_page_no_cache) /* I: cache inhibit */ ++#define _PAGE_WRITETHRU (machdep->machspec->_page_writethru) /* W: cache write-through */ ++#define _PAGE_DIRTY (machdep->machspec->_page_dirty) /* C: page changed */ ++#define _PAGE_ACCESSED (machdep->machspec->_page_accessed) /* R: page referenced */ ++#define _PAGE_HWWRITE (machdep->machspec->_page_hwwrite) /* software: _PAGE_RW & _PAGE_DIRTY */ ++#define _PAGE_SHARED (machdep->machspec->_page_shared) ++#define _PAGE_K_RW (machdep->machspec->_page_k_rw) /* privilege only write access allowed */ ++ ++/* Default values for PAGE flags */ ++#define DEFAULT_PAGE_PRESENT 0x001 ++#define DEFAULT_PAGE_USER 0x002 ++#define DEFAULT_PAGE_RW 0x004 ++#define DEFAULT_PAGE_GUARDED 0x008 ++#define DEFAULT_PAGE_COHERENT 0x010 ++#define DEFAULT_PAGE_NO_CACHE 0x020 ++#define DEFAULT_PAGE_WRITETHRU 0x040 ++#define DEFAULT_PAGE_DIRTY 0x080 ++#define DEFAULT_PAGE_ACCESSED 0x100 ++#define DEFAULT_PAGE_HWWRITE 0x200 ++#define DEFAULT_PAGE_SHARED 0 ++ ++/* PPC44x PAGE flags: Values from kernel asm/pte-44x.h */ ++#define PPC44x_PAGE_PRESENT 0x001 ++#define PPC44x_PAGE_RW 0x002 ++#define PPC44x_PAGE_ACCESSED 0x008 ++#define PPC44x_PAGE_DIRTY 0x010 ++#define PPC44x_PAGE_USER 0x040 ++#define PPC44x_PAGE_GUARDED 0x100 ++#define PPC44x_PAGE_COHERENT 0x200 ++#define PPC44x_PAGE_NO_CACHE 0x400 ++#define PPC44x_PAGE_WRITETHRU 0x800 ++#define PPC44x_PAGE_HWWRITE 0 ++#define PPC44x_PAGE_SHARED 0 ++ ++/* BOOK3E */ ++#define BOOK3E_PAGE_PRESENT 0x000001 ++#define BOOK3E_PAGE_BAP_SR 0x000004 ++#define BOOK3E_PAGE_BAP_UR 0x000008 /* User Readable */ ++#define BOOK3E_PAGE_BAP_SW 0x000010 ++#define BOOK3E_PAGE_BAP_UW 0x000020 /* User Writable */ ++#define BOOK3E_PAGE_DIRTY 0x001000 ++#define BOOK3E_PAGE_ACCESSED 0x040000 ++#define BOOK3E_PAGE_GUARDED 0x100000 ++#define BOOK3E_PAGE_COHERENT 0x200000 ++#define BOOK3E_PAGE_NO_CACHE 0x400000 ++#define BOOK3E_PAGE_WRITETHRU 0x800000 ++#define BOOK3E_PAGE_HWWRITE 0 ++#define BOOK3E_PAGE_SHARED 0 ++#define BOOK3E_PAGE_USER (BOOK3E_PAGE_BAP_SR | BOOK3E_PAGE_BAP_UR) ++#define BOOK3E_PAGE_RW (BOOK3E_PAGE_BAP_SW | BOOK3E_PAGE_BAP_UW) ++#define BOOK3E_PAGE_KERNEL_RW (BOOK3E_PAGE_BAP_SW | BOOK3E_PAGE_BAP_SR | BOOK3E_PAGE_DIRTY) ++ ++/* FSL BOOKE */ ++#define FSL_BOOKE_PAGE_PRESENT 0x00001 ++#define FSL_BOOKE_PAGE_USER 0x00002 ++#define FSL_BOOKE_PAGE_RW 0x00004 ++#define FSL_BOOKE_PAGE_DIRTY 0x00008 ++#define FSL_BOOKE_PAGE_ACCESSED 0x00020 ++#define FSL_BOOKE_PAGE_GUARDED 0x00080 ++#define FSL_BOOKE_PAGE_COHERENT 0x00100 ++#define FSL_BOOKE_PAGE_NO_CACHE 0x00200 ++#define FSL_BOOKE_PAGE_WRITETHRU 0x00400 ++#define FSL_BOOKE_PAGE_HWWRITE 0 ++#define FSL_BOOKE_PAGE_SHARED 0 ++ ++#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f) ++#define SWP_OFFSET(entry) ((entry) >> 8) ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) ++ ++#define TIF_SIGPENDING (2) ++ ++#define _SECTION_SIZE_BITS 24 ++#define _MAX_PHYSMEM_BITS 44 ++ ++#define STACK_FRAME_OVERHEAD 16 ++#define STACK_FRAME_LR_SAVE (sizeof(ulong)) ++#define STACK_FRAME_MARKER (2 * sizeof(ulong)) ++#define STACK_FRAME_REGS_MARKER 0x72656773 ++#define PPC_STACK_SIZE 8192 ++ ++#endif /* PPC */ ++ ++#ifdef IA64 ++#define _64BIT_ ++#define MACHINE_TYPE "IA64" ++ ++#define PAGEBASE(X) (((unsigned long)(X)) & (unsigned long)machdep->pagemask) ++ ++#define REGION_SHIFT (61) ++#define VADDR_REGION(X) ((ulong)(X) >> REGION_SHIFT) ++ ++#define KERNEL_CACHED_REGION (7) ++#define KERNEL_UNCACHED_REGION (6) ++#define KERNEL_VMALLOC_REGION (5) ++#define USER_STACK_REGION (4) ++#define USER_DATA_REGION (3) ++#define USER_TEXT_REGION (2) ++#define USER_SHMEM_REGION (1) ++#define USER_IA32_EMUL_REGION (0) ++ ++#define KERNEL_VMALLOC_BASE ((ulong)KERNEL_VMALLOC_REGION << REGION_SHIFT) ++#define KERNEL_UNCACHED_BASE ((ulong)KERNEL_UNCACHED_REGION << REGION_SHIFT) ++#define KERNEL_CACHED_BASE ((ulong)KERNEL_CACHED_REGION << REGION_SHIFT) ++ ++#define _SECTION_SIZE_BITS 30 ++#define _MAX_PHYSMEM_BITS 50 ++ ++/* ++ * As of 2.6, these are no longer straight forward. ++ */ ++#define PTOV(X) ia64_PTOV((ulong)(X)) ++#define VTOP(X) ia64_VTOP((ulong)(X)) ++#define IS_VMALLOC_ADDR(X) ia64_IS_VMALLOC_ADDR((ulong)(X)) ++ ++#define SWITCH_STACK_ADDR(X) (ia64_get_switch_stack((ulong)(X))) ++ ++#define __IA64_UL(x) ((unsigned long)(x)) ++#define IA64_MAX_PHYS_BITS (50) /* max # of phys address bits (architected) */ ++ ++/* ++ * How many pointers will a page table level hold expressed in shift ++ */ ++#define PTRS_PER_PTD_SHIFT (PAGESHIFT()-3) ++ ++/* ++ * Definitions for fourth level: ++ */ ++#define PTRS_PER_PTE (__IA64_UL(1) << (PTRS_PER_PTD_SHIFT)) ++ ++/* ++ * Definitions for third level: ++ * ++ * PMD_SHIFT determines the size of the area a third-level page table ++ * can map. ++ */ ++#define PMD_SHIFT (PAGESHIFT() + (PTRS_PER_PTD_SHIFT)) ++#define PMD_SIZE (1UL << PMD_SHIFT) ++#define PMD_MASK (~(PMD_SIZE-1)) ++#define PTRS_PER_PMD (1UL << (PTRS_PER_PTD_SHIFT)) ++ ++/* ++ * PUD_SHIFT determines the size of the area a second-level page table ++ * can map ++ */ ++#define PUD_SHIFT (PMD_SHIFT + (PTRS_PER_PTD_SHIFT)) ++#define PUD_SIZE (1UL << PUD_SHIFT) ++#define PUD_MASK (~(PUD_SIZE-1)) ++#define PTRS_PER_PUD (1UL << (PTRS_PER_PTD_SHIFT)) ++ ++/* ++ * Definitions for first level: ++ * ++ * PGDIR_SHIFT determines what a first-level page table entry can map. ++ */ ++ ++#define PGDIR_SHIFT_4L (PUD_SHIFT + (PTRS_PER_PTD_SHIFT)) ++#define PGDIR_SHIFT_3L (PMD_SHIFT + (PTRS_PER_PTD_SHIFT)) ++/* Turns out 4L & 3L PGDIR_SHIFT are the same (for now) */ ++#define PGDIR_SHIFT PGDIR_SHIFT_4L ++#define PGDIR_SIZE (__IA64_UL(1) << PGDIR_SHIFT) ++#define PGDIR_MASK (~(PGDIR_SIZE-1)) ++#define PTRS_PER_PGD_SHIFT PTRS_PER_PTD_SHIFT ++#define PTRS_PER_PGD (1UL << PTRS_PER_PGD_SHIFT) ++#define USER_PTRS_PER_PGD (5*PTRS_PER_PGD/8) /* regions 0-4 are user regions */ ++#define FIRST_USER_ADDRESS 0 ++ ++/* ++ * First, define the various bits in a PTE. Note that the PTE format ++ * matches the VHPT short format, the firt doubleword of the VHPD long ++ * format, and the first doubleword of the TLB insertion format. ++ */ ++#define _PAGE_P (1 << 0) /* page present bit */ ++#define _PAGE_MA_WB (0x0 << 2) /* write back memory attribute */ ++#define _PAGE_MA_UC (0x4 << 2) /* uncacheable memory attribute */ ++#define _PAGE_MA_UCE (0x5 << 2) /* UC exported attribute */ ++#define _PAGE_MA_WC (0x6 << 2) /* write coalescing memory attribute */ ++#define _PAGE_MA_NAT (0x7 << 2) /* not-a-thing attribute */ ++#define _PAGE_MA_MASK (0x7 << 2) ++#define _PAGE_PL_0 (0 << 7) /* privilege level 0 (kernel) */ ++#define _PAGE_PL_1 (1 << 7) /* privilege level 1 (unused) */ ++#define _PAGE_PL_2 (2 << 7) /* privilege level 2 (unused) */ ++#define _PAGE_PL_3 (3 << 7) /* privilege level 3 (user) */ ++#define _PAGE_PL_MASK (3 << 7) ++#define _PAGE_AR_R (0 << 9) /* read only */ ++#define _PAGE_AR_RX (1 << 9) /* read & execute */ ++#define _PAGE_AR_RW (2 << 9) /* read & write */ ++#define _PAGE_AR_RWX (3 << 9) /* read, write & execute */ ++#define _PAGE_AR_R_RW (4 << 9) /* read / read & write */ ++#define _PAGE_AR_RX_RWX (5 << 9) /* read & exec / read, write & exec */ ++#define _PAGE_AR_RWX_RW (6 << 9) /* read, write & exec / read & write */ ++#define _PAGE_AR_X_RX (7 << 9) /* exec & promote / read & exec */ ++#define _PAGE_AR_MASK (7 << 9) ++#define _PAGE_AR_SHIFT 9 ++#define _PAGE_A (1 << 5) /* page accessed bit */ ++#define _PAGE_D (1 << 6) /* page dirty bit */ ++#define _PAGE_PPN_MASK (((__IA64_UL(1) << IA64_MAX_PHYS_BITS) - 1) & ~0xfffUL) ++#define _PAGE_ED (__IA64_UL(1) << 52) /* exception deferral */ ++#define _PAGE_PROTNONE (__IA64_UL(1) << 63) ++ ++#define _PFN_MASK _PAGE_PPN_MASK ++#define _PAGE_CHG_MASK (_PFN_MASK | _PAGE_A | _PAGE_D) ++ ++#define _PAGE_SIZE_4K 12 ++#define _PAGE_SIZE_8K 13 ++#define _PAGE_SIZE_16K 14 ++#define _PAGE_SIZE_64K 16 ++#define _PAGE_SIZE_256K 18 ++#define _PAGE_SIZE_1M 20 ++#define _PAGE_SIZE_4M 22 ++#define _PAGE_SIZE_16M 24 ++#define _PAGE_SIZE_64M 26 ++#define _PAGE_SIZE_256M 28 ++ ++#define __ACCESS_BITS _PAGE_ED | _PAGE_A | _PAGE_P | _PAGE_MA_WB ++#define __DIRTY_BITS_NO_ED _PAGE_A | _PAGE_P | _PAGE_D | _PAGE_MA_WB ++#define __DIRTY_BITS _PAGE_ED | __DIRTY_BITS_NO_ED ++ ++#define EFI_PAGE_SHIFT (12) ++ ++/* ++ * NOTE: #include'ing creates too many compiler problems, so ++ * this stuff is hardwired here; it's probably etched in stone somewhere. ++ */ ++struct efi_memory_desc_t { ++ uint32_t type; ++ uint32_t pad; ++ uint64_t phys_addr; ++ uint64_t virt_addr; ++ uint64_t num_pages; ++ uint64_t attribute; ++} desc; ++ ++/* Memory types: */ ++#define EFI_RESERVED_TYPE 0 ++#define EFI_LOADER_CODE 1 ++#define EFI_LOADER_DATA 2 ++#define EFI_BOOT_SERVICES_CODE 3 ++#define EFI_BOOT_SERVICES_DATA 4 ++#define EFI_RUNTIME_SERVICES_CODE 5 ++#define EFI_RUNTIME_SERVICES_DATA 6 ++#define EFI_CONVENTIONAL_MEMORY 7 ++#define EFI_UNUSABLE_MEMORY 8 ++#define EFI_ACPI_RECLAIM_MEMORY 9 ++#define EFI_ACPI_MEMORY_NVS 10 ++#define EFI_MEMORY_MAPPED_IO 11 ++#define EFI_MEMORY_MAPPED_IO_PORT_SPACE 12 ++#define EFI_PAL_CODE 13 ++#define EFI_MAX_MEMORY_TYPE 14 ++ ++/* Attribute values: */ ++#define EFI_MEMORY_UC 0x0000000000000001 /* uncached */ ++#define EFI_MEMORY_WC 0x0000000000000002 /* write-coalescing */ ++#define EFI_MEMORY_WT 0x0000000000000004 /* write-through */ ++#define EFI_MEMORY_WB 0x0000000000000008 /* write-back */ ++#define EFI_MEMORY_WP 0x0000000000001000 /* write-protect */ ++#define EFI_MEMORY_RP 0x0000000000002000 /* read-protect */ ++#define EFI_MEMORY_XP 0x0000000000004000 /* execute-protect */ ++#define EFI_MEMORY_RUNTIME 0x8000000000000000 /* range requires runtime mapping */ ++ ++#define SWP_TYPE(entry) (((entry) >> 1) & 0xff) ++#define SWP_OFFSET(entry) ((entry) >> 9) ++#define __swp_type(entry) ((entry >> 2) & 0x7f) ++#define __swp_offset(entry) ((entry << 1) >> 10) ++ ++#define TIF_SIGPENDING (1) ++ ++#define KERNEL_TR_PAGE_SIZE (1 << _PAGE_SIZE_64M) ++#define KERNEL_TR_PAGE_MASK (~(KERNEL_TR_PAGE_SIZE - 1)) ++ ++#define UNKNOWN_PHYS_START ((ulong)(-1)) ++#define DEFAULT_PHYS_START (KERNEL_TR_PAGE_SIZE * 1) ++ ++#define IA64_GET_STACK_ULONG(OFF) \ ++ ((INSTACK(OFF,bt)) ? (GET_STACK_ULONG(OFF)) : get_init_stack_ulong((unsigned long)OFF)) ++ ++#endif /* IA64 */ ++ ++#ifdef PPC64 ++#define _64BIT_ ++#define MACHINE_TYPE "PPC64" ++ ++#define PPC64_64K_PAGE_SIZE 65536 ++#define PPC64_STACK_SIZE 16384 ++ ++#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) ++ ++#define PTOV(X) ((unsigned long)(X)+(machdep->identity_map_base)) ++#define VTOP(X) ((unsigned long)(X)-(machdep->identity_map_base)) ++#define BOOK3E_VMBASE 0x8000000000000000 ++#define IS_VMALLOC_ADDR(X) machdep->machspec->is_vmaddr(X) ++#define KERNELBASE machdep->pageoffset ++ ++#define PGDIR_SHIFT (machdep->pageshift + (machdep->pageshift -3) + (machdep->pageshift - 2)) ++#define PMD_SHIFT (machdep->pageshift + (machdep->pageshift - 3)) ++ ++#define PGD_MASK (~((1UL << PGDIR_SHIFT) - 1)) ++#define PMD_MASK (~((1UL << PMD_SHIFT) - 1)) ++ ++/* shift to put page number into pte */ ++#define PTE_RPN_SHIFT_DEFAULT 16 ++#define PMD_TO_PTEPAGE_SHIFT 2 /* Used for 2.6 or later */ ++ ++#define PTE_INDEX_SIZE 9 ++#define PMD_INDEX_SIZE 10 ++#define PGD_INDEX_SIZE 10 ++ ++#define PTRS_PER_PTE (1 << PTE_INDEX_SIZE) ++#define PTRS_PER_PMD (1 << PMD_INDEX_SIZE) ++#define PTRS_PER_PGD (1 << PGD_INDEX_SIZE) ++ ++#define PGD_OFFSET_24(vaddr) ((vaddr >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) ++#define PGD_OFFSET(vaddr) ((vaddr >> PGDIR_SHIFT) & 0x7ff) ++#define PMD_OFFSET(vaddr) ((vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) ++ ++/* 4-level page table support */ ++ ++/* 4K pagesize */ ++#define PTE_INDEX_SIZE_L4_4K 9 ++#define PMD_INDEX_SIZE_L4_4K 7 ++#define PUD_INDEX_SIZE_L4_4K 7 ++#define PGD_INDEX_SIZE_L4_4K 9 ++#define PUD_INDEX_SIZE_L4_4K_3_7 9 ++#define PTE_INDEX_SIZE_RADIX_4K 9 ++#define PMD_INDEX_SIZE_RADIX_4K 9 ++#define PUD_INDEX_SIZE_RADIX_4K 9 ++#define PGD_INDEX_SIZE_RADIX_4K 13 ++#define PTE_RPN_SHIFT_L4_4K 17 ++#define PTE_RPN_SHIFT_L4_4K_4_5 18 ++#define PGD_MASKED_BITS_4K 0 ++#define PUD_MASKED_BITS_4K 0 ++#define PMD_MASKED_BITS_4K 0 ++ ++/* 64K pagesize */ ++#define PTE_INDEX_SIZE_L4_64K 12 ++#define PMD_INDEX_SIZE_L4_64K 12 ++#define PUD_INDEX_SIZE_L4_64K 0 ++#define PGD_INDEX_SIZE_L4_64K 4 ++#define PTE_INDEX_SIZE_L4_64K_3_10 8 ++#define PMD_INDEX_SIZE_L4_64K_3_10 10 ++#define PGD_INDEX_SIZE_L4_64K_3_10 12 ++#define PMD_INDEX_SIZE_L4_64K_4_6 5 ++#define PUD_INDEX_SIZE_L4_64K_4_6 5 ++#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 ++#define PGD_INDEX_SIZE_RADIX_64K 13 ++#define PTE_RPN_SHIFT_L4_64K_V1 32 ++#define PTE_RPN_SHIFT_L4_64K_V2 30 ++#define PTE_RPN_SHIFT_L4_BOOK3E_64K 28 ++#define PTE_RPN_SHIFT_L4_BOOK3E_4K 24 ++#define PGD_MASKED_BITS_64K 0 ++#define PUD_MASKED_BITS_64K 0x1ff ++#define PMD_MASKED_BITS_64K 0x1ff ++#define PMD_MASKED_BITS_64K_3_11 0xfff ++#define PMD_MASKED_BITS_BOOK3E_64K_4_5 0x7ff ++#define PGD_MASKED_BITS_64K_4_6 0xc0000000000000ffUL ++#define PUD_MASKED_BITS_64K_4_6 0xc0000000000000ffUL ++#define PMD_MASKED_BITS_64K_4_6 0xc0000000000000ffUL ++ ++#define PTE_RPN_MASK_DEFAULT 0xffffffffffffffffUL ++#define PAGE_PA_MAX_L4_4_6 (THIS_KERNEL_VERSION >= LINUX(4,11,0) ? 53 : 57) ++#define PTE_RPN_MASK_L4_4_6 \ ++ (((1UL << PAGE_PA_MAX_L4_4_6) - 1) & ~((1UL << PAGESHIFT()) - 1)) ++#define PTE_RPN_SHIFT_L4_4_6 PAGESHIFT() ++ ++#define PGD_MASKED_BITS_4_7 0xc0000000000000ffUL ++#define PUD_MASKED_BITS_4_7 0xc0000000000000ffUL ++#define PMD_MASKED_BITS_4_7 0xc0000000000000ffUL ++ ++#define PD_HUGE 0x8000000000000000 ++#define HUGE_PTE_MASK 0x03 ++#define HUGEPD_SHIFT_MASK 0x3f ++#define HUGEPD_ADDR_MASK (0x0fffffffffffffffUL & ~HUGEPD_SHIFT_MASK) ++ ++#define PGD_MASK_L4 \ ++ (THIS_KERNEL_VERSION >= LINUX(3,10,0) ? (machdep->ptrs_per_pgd - 1) : 0x1ff) ++ ++#define PGD_OFFSET_L4(vaddr) \ ++ ((vaddr >> (machdep->machspec->l4_shift)) & PGD_MASK_L4) ++ ++#define PUD_OFFSET_L4(vaddr) \ ++ ((vaddr >> (machdep->machspec->l3_shift)) & (machdep->machspec->ptrs_per_l3 - 1)) ++ ++#define PMD_OFFSET_L4(vaddr) \ ++ ((vaddr >> (machdep->machspec->l2_shift)) & (machdep->machspec->ptrs_per_l2 - 1)) ++ ++#define _PAGE_PTE (machdep->machspec->_page_pte) /* distinguishes PTEs from pointers */ ++#define _PAGE_PRESENT (machdep->machspec->_page_present) /* software: pte contains a translation */ ++#define _PAGE_USER (machdep->machspec->_page_user) /* matches one of the PP bits */ ++#define _PAGE_RW (machdep->machspec->_page_rw) /* software: user write access allowed */ ++#define _PAGE_GUARDED (machdep->machspec->_page_guarded) ++#define _PAGE_COHERENT (machdep->machspec->_page_coherent /* M: enforce memory coherence (SMP systems) */) ++#define _PAGE_NO_CACHE (machdep->machspec->_page_no_cache) /* I: cache inhibit */ ++#define _PAGE_WRITETHRU (machdep->machspec->_page_writethru) /* W: cache write-through */ ++#define _PAGE_DIRTY (machdep->machspec->_page_dirty) /* C: page changed */ ++#define _PAGE_ACCESSED (machdep->machspec->_page_accessed) /* R: page referenced */ ++ ++#define PTE_RPN_MASK (machdep->machspec->pte_rpn_mask) ++#define PTE_RPN_SHIFT (machdep->machspec->pte_rpn_shift) ++ ++#define TIF_SIGPENDING (2) ++ ++#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f) ++#define SWP_OFFSET(entry) ((entry) >> 8) ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) ++ ++#define MSR_PR_LG 14 /* Problem State / Privilege Level */ ++ /* Used to find the user or kernel-mode frame*/ ++ ++#define STACK_FRAME_OVERHEAD 112 ++#define EXCP_FRAME_MARKER 0x7265677368657265 ++ ++#define _SECTION_SIZE_BITS 24 ++#define _MAX_PHYSMEM_BITS 44 ++#define _MAX_PHYSMEM_BITS_3_7 46 ++#define _MAX_PHYSMEM_BITS_4_19 47 ++#define _MAX_PHYSMEM_BITS_4_20 51 ++ ++#endif /* PPC64 */ ++ ++#ifdef S390 ++#define _32BIT_ ++#define MACHINE_TYPE "S390" ++ ++#define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) ++#define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) ++#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) ++ ++#define PTRS_PER_PTE 1024 ++#define PTRS_PER_PMD 1 ++#define PTRS_PER_PGD 512 ++#define SEGMENT_TABLE_SIZE ((sizeof(ulong)*4) * PTRS_PER_PGD) ++ ++#define SWP_TYPE(entry) (((entry) >> 2) & 0x1f) ++#define SWP_OFFSET(entry) ((((entry) >> 11) & 0xfffffffe) | \ ++ (((entry) >> 7) & 0x1)) ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) ++ ++#define TIF_SIGPENDING (2) ++ ++#define _SECTION_SIZE_BITS 25 ++#define _MAX_PHYSMEM_BITS 31 ++ ++#endif /* S390 */ ++ ++#ifdef S390X ++#define _64BIT_ ++#define MACHINE_TYPE "S390X" ++ ++#define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) ++#define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) ++#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) ++#define PTRS_PER_PTE 512 ++#define PTRS_PER_PMD 1024 ++#define PTRS_PER_PGD 2048 ++#define SEGMENT_TABLE_SIZE ((sizeof(ulong)*2) * PTRS_PER_PMD) ++ ++#define SWP_TYPE(entry) (((entry) >> 2) & 0x1f) ++#define SWP_OFFSET(entry) ((((entry) >> 11) & 0xfffffffffffffffe) | \ ++ (((entry) >> 7) & 0x1)) ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) ++ ++#define TIF_SIGPENDING (2) ++ ++#define _SECTION_SIZE_BITS 28 ++#define _MAX_PHYSMEM_BITS_OLD 42 ++#define _MAX_PHYSMEM_BITS_NEW 46 ++ ++#endif /* S390X */ ++ ++#ifdef SPARC64 ++#define _64BIT_ ++#define MACHINE_TYPE "SPARC64" ++ ++#define PTOV(X) \ ++ ((unsigned long)(X) + machdep->machspec->page_offset) ++#define VTOP(X) \ ++ ((unsigned long)(X) - machdep->machspec->page_offset) ++ ++#define PAGE_OFFSET (machdep->machspec->page_offset) ++ ++extern int sparc64_IS_VMALLOC_ADDR(ulong vaddr); ++#define IS_VMALLOC_ADDR(X) sparc64_IS_VMALLOC_ADDR((ulong)(X)) ++#define PAGE_SHIFT (13) ++#define PAGE_SIZE (1UL << PAGE_SHIFT) ++#define PAGE_MASK (~(PAGE_SIZE - 1)) ++#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) ++#define THREAD_SIZE (2 * PAGE_SIZE) ++ ++/* S3 Core ++ * Core 48-bit physical address supported. ++ * Bit 47 distinguishes memory or I/O. When set to "1" it is I/O. ++ */ ++#define PHYS_MASK_SHIFT (47) ++#define PHYS_MASK (((1UL) << PHYS_MASK_SHIFT) - 1) ++ ++typedef signed int s32; ++ ++/* ++ * This next two defines are convenience defines for normal page table. ++ */ ++#define PTES_PER_PAGE (1UL << (PAGE_SHIFT - 3)) ++#define PTES_PER_PAGE_MASK (PTES_PER_PAGE - 1) ++ ++/* 4-level page table */ ++#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT-3)) ++#define PMD_SIZE (1UL << PMD_SHIFT) ++#define PMD_MASK (~(PMD_SIZE - 1)) ++#define PMD_BITS (PAGE_SHIFT - 3) ++ ++#define PUD_SHIFT (PMD_SHIFT + PMD_BITS) ++#define PUD_SIZE (1UL << PUD_SHIFT) ++#define PUD_MASK (~(PUD_SIZE - 1)) ++#define PUD_BITS (PAGE_SHIFT - 3) ++ ++#define PGDIR_SHIFT (PUD_SHIFT + PUD_BITS) ++#define PGDIR_SIZE (1UL << PGDIR_SHIFT) ++#define PGDIR_MASK (~(PGDIR_SIZE - 1)) ++#define PGDIR_BITS (PAGE_SHIFT - 3) ++ ++#define PTRS_PER_PTE (1UL << (PAGE_SHIFT - 3)) ++#define PTRS_PER_PMD (1UL << PMD_BITS) ++#define PTRS_PER_PUD (1UL << PUD_BITS) ++#define PTRS_PER_PGD (1UL << PGDIR_BITS) ++ ++#define HPAGE_SHIFT (23) ++/* Down one huge page */ ++#define SPARC64_USERSPACE_TOP (-(1UL << HPAGE_SHIFT)) ++#define PAGE_PMD_HUGE (0x0100000000000000UL) ++ ++/* These are for SUN4V. */ ++#define _PAGE_VALID (0x8000000000000000UL) ++#define _PAGE_NFO_4V (0x4000000000000000UL) ++#define _PAGE_MODIFIED_4V (0x2000000000000000UL) ++#define _PAGE_ACCESSED_4V (0x1000000000000000UL) ++#define _PAGE_READ_4V (0x0800000000000000UL) ++#define _PAGE_WRITE_4V (0x0400000000000000UL) ++#define _PAGE_PADDR_4V (0x00FFFFFFFFFFE000UL) ++#define _PAGE_PFN_MASK (_PAGE_PADDR_4V) ++#define _PAGE_P_4V (0x0000000000000100UL) ++#define _PAGE_EXEC_4V (0x0000000000000080UL) ++#define _PAGE_W_4V (0x0000000000000040UL) ++#define _PAGE_PRESENT_4V (0x0000000000000010UL) ++#define _PAGE_SZALL_4V (0x0000000000000007UL) ++/* There are other page sizes. Some supported. */ ++#define _PAGE_SZ4MB_4V (0x0000000000000003UL) ++#define _PAGE_SZ512K_4V (0x0000000000000002UL) ++#define _PAGE_SZ64K_4V (0x0000000000000001UL) ++#define _PAGE_SZ8K_4V (0x0000000000000000UL) ++ ++#define SPARC64_MODULES_VADDR (0x0000000010000000UL) ++#define SPARC64_MODULES_END (0x00000000f0000000UL) ++#define SPARC64_VMALLOC_START (0x0000000100000000UL) ++ ++#define SPARC64_STACK_SIZE 0x4000 ++ ++/* sparsemem */ ++#define _SECTION_SIZE_BITS 30 ++#define _MAX_PHYSMEM_BITS 53 ++ ++#define STACK_BIAS 2047 ++ ++struct machine_specific { ++ ulong page_offset; ++ ulong vmalloc_end; ++}; ++ ++#define TIF_SIGPENDING (2) ++#define SWP_OFFSET(E) ((E) >> (PAGE_SHIFT + 8UL)) ++#define SWP_TYPE(E) (((E) >> PAGE_SHIFT) & 0xffUL) ++#define __swp_type(E) SWP_TYPE(E) ++#define __swp_offset(E) SWP_OFFSET(E) ++#endif /* SPARC64 */ ++ ++#ifdef PLATFORM ++ ++#define SWP_TYPE(entry) (error("PLATFORM_SWP_TYPE: TBD\n")) ++#define SWP_OFFSET(entry) (error("PLATFORM_SWP_OFFSET: TBD\n")) ++#define __swp_type(entry) SWP_TYPE(entry) ++#define __swp_offset(entry) SWP_OFFSET(entry) ++ ++#endif /* PLATFORM */ ++ ++#define KILOBYTES(x) ((x) * (1024)) ++#define MEGABYTES(x) ((x) * (1048576)) ++#define GIGABYTES(x) ((x) * (1073741824)) ++#define TB_SHIFT (40) ++#define TERABYTES(x) ((x) * (1UL << TB_SHIFT)) ++ ++#define MEGABYTE_MASK (MEGABYTES(1)-1) ++ ++#define SIZEOF_64BIT (8) ++#define SIZEOF_32BIT (4) ++#define SIZEOF_16BIT (2) ++#define SIZEOF_8BIT (1) ++ ++#ifdef ARM ++#define MAX_HEXADDR_STRLEN (8) ++#define UVADDR_PRLEN (8) ++#endif ++#ifdef X86 ++#define MAX_HEXADDR_STRLEN (8) ++#define UVADDR_PRLEN (8) ++#endif ++#ifdef ALPHA ++#define MAX_HEXADDR_STRLEN (16) ++#define UVADDR_PRLEN (11) ++#endif ++#ifdef PPC ++#define MAX_HEXADDR_STRLEN (8) ++#define UVADDR_PRLEN (8) ++#endif ++#ifdef IA64 ++#define MAX_HEXADDR_STRLEN (16) ++#define UVADDR_PRLEN (16) ++#endif ++#ifdef S390 ++#define MAX_HEXADDR_STRLEN (8) ++#define UVADDR_PRLEN (8) ++#endif ++#ifdef S390X ++#define MAX_HEXADDR_STRLEN (16) ++#define UVADDR_PRLEN (16) ++#endif ++#ifdef X86_64 ++#define MAX_HEXADDR_STRLEN (16) ++#define UVADDR_PRLEN (10) ++#endif ++#ifdef PPC64 ++#define MAX_HEXADDR_STRLEN (16) ++#define UVADDR_PRLEN (16) ++#endif ++#ifdef ARM64 ++#define MAX_HEXADDR_STRLEN (16) ++#define UVADDR_PRLEN (10) ++#endif ++#ifdef MIPS ++#define MAX_HEXADDR_STRLEN (8) ++#define UVADDR_PRLEN (8) ++#endif ++#ifdef MIPS64 ++#define MAX_HEXADDR_STRLEN (16) ++#define UVADDR_PRLEN (16) ++#endif ++#ifdef SPARC64 ++#define MAX_HEXADDR_STRLEN (16) ++#define UVADDR_PRLEN (16) ++#endif ++ ++#define BADADDR ((ulong)(-1)) ++#define BADVAL ((ulong)(-1)) ++#define UNUSED (-1) ++ ++#define UNINITIALIZED (BADVAL) ++ ++#define BITS_PER_BYTE (8) ++#define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) ++#define NUM_TO_BIT(x) (1UL<<((x)%BITS_PER_LONG)) ++#define NUM_IN_BITMAP(bitmap, x) (bitmap[(x)/BITS_PER_LONG] & NUM_TO_BIT(x)) ++#define SET_BIT(bitmap, x) (bitmap[(x)/BITS_PER_LONG] |= NUM_TO_BIT(x)) ++ ++/* ++ * precision lengths for fprintf ++ */ ++#define VADDR_PRLEN (sizeof(char *) == 8 ? 16 : 8) ++#define LONG_LONG_PRLEN (16) ++#define LONG_PRLEN (sizeof(long) == 8 ? 16 : 8) ++#define INT_PRLEN (sizeof(int) == 8 ? 16 : 8) ++#define CHAR_PRLEN (2) ++#define SHORT_PRLEN (4) ++ ++#define MINSPACE (-100) ++ ++#define SYNOPSIS (0x1) ++#define COMPLETE_HELP (0x2) ++#define PIPE_TO_SCROLL (0x4) ++#define MUST_HELP (0x8) ++ ++#define LEFT_JUSTIFY (1) ++#define RIGHT_JUSTIFY (2) ++ ++#define CENTER (0x1) ++#define LJUST (0x2) ++#define RJUST (0x4) ++#define LONG_DEC (0x8) ++#define LONG_HEX (0x10) ++#define INT_DEC (0x20) ++#define INT_HEX (0x40) ++#define LONGLONG_HEX (0x80) ++#define ZERO_FILL (0x100) ++#define SLONG_DEC (0x200) ++ ++#define INIT_TIME (1) ++#define RUN_TIME (2) ++ ++/* ++ * IRQ line status. ++ * For kernels up to and including 2.6.17 ++ */ ++#define IRQ_INPROGRESS_2_6_17 1 /* IRQ handler active - do not enter! */ ++#define IRQ_DISABLED_2_6_17 2 /* IRQ disabled - do not enter! */ ++#define IRQ_PENDING_2_6_17 4 /* IRQ pending - replay on enable */ ++#define IRQ_REPLAY_2_6_17 8 /* IRQ has been replayed but not acked yet */ ++#define IRQ_AUTODETECT_2_6_17 16 /* IRQ is being autodetected */ ++#define IRQ_WAITING_2_6_17 32 /* IRQ not yet seen - for autodetection */ ++#define IRQ_LEVEL_2_6_17 64 /* IRQ level triggered */ ++#define IRQ_MASKED_2_6_17 128 /* IRQ masked - shouldn't be seen again */ ++ ++/* ++ * For kernel 2.6.21 and later ++ */ ++#define IRQ_TYPE_NONE_2_6_21 0x00000000 /* Default, unspecified type */ ++#define IRQ_TYPE_EDGE_RISING_2_6_21 0x00000001 /* Edge rising type */ ++#define IRQ_TYPE_EDGE_FALLING_2_6_21 0x00000002 /* Edge falling type */ ++#define IRQ_TYPE_EDGE_BOTH_2_6_21 (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) ++#define IRQ_TYPE_LEVEL_HIGH_2_6_21 0x00000004 /* Level high type */ ++#define IRQ_TYPE_LEVEL_LOW_2_6_21 0x00000008 /* Level low type */ ++#define IRQ_TYPE_SENSE_MASK_2_6_21 0x0000000f /* Mask of the above */ ++#define IRQ_TYPE_PROBE_2_6_21 0x00000010 /* Probing in progress */ ++ ++#define IRQ_INPROGRESS_2_6_21 0x00000100 /* IRQ handler active - do not enter! */ ++#define IRQ_DISABLED_2_6_21 0x00000200 /* IRQ disabled - do not enter! */ ++#define IRQ_PENDING_2_6_21 0x00000400 /* IRQ pending - replay on enable */ ++#define IRQ_REPLAY_2_6_21 0x00000800 /* IRQ has been replayed but not acked yet */ ++#define IRQ_AUTODETECT_2_6_21 0x00001000 /* IRQ is being autodetected */ ++#define IRQ_WAITING_2_6_21 0x00002000 /* IRQ not yet seen - for autodetection */ ++#define IRQ_LEVEL_2_6_21 0x00004000 /* IRQ level triggered */ ++#define IRQ_MASKED_2_6_21 0x00008000 /* IRQ masked - shouldn't be seen again */ ++#define IRQ_PER_CPU_2_6_21 0x00010000 /* IRQ is per CPU */ ++#define IRQ_NOPROBE_2_6_21 0x00020000 /* IRQ is not valid for probing */ ++#define IRQ_NOREQUEST_2_6_21 0x00040000 /* IRQ cannot be requested */ ++#define IRQ_NOAUTOEN_2_6_21 0x00080000 /* IRQ will not be enabled on request irq */ ++#define IRQ_WAKEUP_2_6_21 0x00100000 /* IRQ triggers system wakeup */ ++#define IRQ_MOVE_PENDING_2_6_21 0x00200000 /* need to re-target IRQ destination */ ++#define IRQ_NO_BALANCING_2_6_21 0x00400000 /* IRQ is excluded from balancing */ ++#define IRQ_SPURIOUS_DISABLED_2_6_21 0x00800000 /* IRQ was disabled by the spurious trap */ ++#define IRQ_MOVE_PCNTXT_2_6_21 0x01000000 /* IRQ migration from process context */ ++#define IRQ_AFFINITY_SET_2_6_21 0x02000000 /* IRQ affinity was set from userspace*/ ++ ++/* ++ * Select proper IRQ value depending on kernel version ++ */ ++#define IRQ_TYPE_NONE \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_NONE_2_6_21 : 0) ++#define IRQ_TYPE_EDGE_RISING \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_EDGE_RISING_2_6_21 : 0) ++#define IRQ_TYPE_EDGE_FALLING \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_EDGE_FALLING_2_6_21 : 0) ++#define IRQ_TYPE_EDGE_BOTH \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_EDGE_BOTH_2_6_21 : 0) ++#define IRQ_TYPE_LEVEL_HIGH \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_LEVEL_HIGH_2_6_21 : 0) ++#define IRQ_TYPE_LEVEL_LOW \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_LEVEL_LOW_2_6_21 : 0) ++#define IRQ_TYPE_SENSE_MASK \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_SENSE_MASK_2_6_21 : 0) ++#define IRQ_TYPE_PROBE \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_PROBE_2_6_21 : 0) ++ ++#define IRQ_INPROGRESS \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_INPROGRESS_2_6_21 : IRQ_INPROGRESS_2_6_17) ++#define IRQ_DISABLED \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_DISABLED_2_6_21 : IRQ_DISABLED_2_6_17) ++#define IRQ_PENDING \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_PENDING_2_6_21 : IRQ_PENDING_2_6_17) ++#define IRQ_REPLAY \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_REPLAY_2_6_21 : IRQ_REPLAY_2_6_17) ++#define IRQ_AUTODETECT \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_AUTODETECT_2_6_21 : IRQ_AUTODETECT_2_6_17) ++#define IRQ_WAITING \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_WAITING_2_6_21 : IRQ_WAITING_2_6_17) ++#define IRQ_LEVEL \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_LEVEL_2_6_21 : IRQ_LEVEL_2_6_17) ++#define IRQ_MASKED \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_MASKED_2_6_21 : IRQ_MASKED_2_6_17) ++#define IRQ_PER_CPU \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_PER_CPU_2_6_21 : 0) ++#define IRQ_NOPROBE \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_NOPROBE_2_6_21 : 0) ++#define IRQ_NOREQUEST \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_NOREQUEST_2_6_21 : 0) ++#define IRQ_NOAUTOEN \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_NOAUTOEN_2_6_21 : 0) ++#define IRQ_WAKEUP \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_WAKEUP_2_6_21 : 0) ++#define IRQ_MOVE_PENDING \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_MOVE_PENDING_2_6_21 : 0) ++#define IRQ_NO_BALANCING \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_NO_BALANCING_2_6_21 : 0) ++#define IRQ_SPURIOUS_DISABLED \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_SPURIOUS_DISABLED_2_6_21 : 0) ++#define IRQ_MOVE_PCNTXT \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_MOVE_PCNTXT_2_6_21 : 0) ++#define IRQ_AFFINITY_SET \ ++ (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_AFFINITY_SET_2_6_21 : 0) ++ ++#ifdef ARM ++#define SA_PROBE SA_ONESHOT ++#define SA_SAMPLE_RANDOM SA_RESTART ++#define SA_SHIRQ 0x04000000 ++#define SA_RESTORER 0x04000000 ++#endif ++ ++#ifdef X86 ++#define SA_PROBE SA_ONESHOT ++#define SA_SAMPLE_RANDOM SA_RESTART ++#define SA_SHIRQ 0x04000000 ++#define SA_RESTORER 0x04000000 ++#endif ++ ++#ifdef X86_64 ++#define SA_PROBE SA_ONESHOT ++#define SA_SAMPLE_RANDOM SA_RESTART ++#define SA_SHIRQ 0x04000000 ++#define SA_RESTORER 0x04000000 ++#endif ++ ++#ifdef ALPHA ++#define SA_PROBE SA_ONESHOT ++#define SA_SAMPLE_RANDOM SA_RESTART ++#define SA_SHIRQ 0x40000000 ++#endif ++ ++#ifdef PPC ++#define SA_PROBE SA_ONESHOT ++#define SA_SAMPLE_RANDOM SA_RESTART ++#define SA_SHIRQ 0x04000000 ++#define SA_RESTORER 0x04000000 ++#endif ++ ++#ifdef PPC64 ++#define SA_PROBE SA_ONESHOT ++#define SA_SAMPLE_RANDOM SA_RESTART ++#define SA_SHIRQ 0x04000000 ++#define SA_RESTORER 0x04000000u ++#endif ++ ++#ifdef IA64 ++#define SA_PROBE SA_ONESHOT ++#define SA_SAMPLE_RANDOM SA_RESTART ++#define SA_SHIRQ 0x04000000 ++#define SA_RESTORER 0x04000000 ++#endif ++ ++#ifdef S390 ++#define SA_PROBE SA_ONESHOT ++#define SA_SAMPLE_RANDOM SA_RESTART ++#define SA_SHIRQ 0x04000000 ++#define SA_RESTORER 0x04000000 ++#endif ++ ++#ifdef S390X ++#define SA_PROBE SA_ONESHOT ++#define SA_SAMPLE_RANDOM SA_RESTART ++#define SA_SHIRQ 0x04000000 ++#define SA_RESTORER 0x04000000 ++#endif ++ ++ ++#define ACTION_FLAGS (SA_INTERRUPT|SA_PROBE|SA_SAMPLE_RANDOM|SA_SHIRQ) ++ ++ ++#endif /* !GDB_COMMON */ ++ ++/* ++ * Common request structure for BFD or GDB data or commands. ++ */ ++struct gnu_request { ++ int command; ++ char *buf; ++ FILE *fp; ++ ulong addr; ++ ulong addr2; ++ ulong count; ++ ulong flags; ++ char *name; ++ ulong length; ++ int typecode; ++#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) || defined(GDB_7_0) ++ char *typename; ++#else ++ char *type_name; ++#endif ++ char *target_typename; ++ ulong target_length; ++ int target_typecode; ++ int is_typedef; ++ char *member; ++ long member_offset; ++ long member_length; ++ int member_typecode; ++ long value; ++ char *tagname; ++ ulong pc; ++ ulong sp; ++ ulong ra; ++ int curframe; ++ ulong frame; ++ ulong prevsp; ++ ulong prevpc; ++ ulong lastsp; ++ ulong task; ++ ulong debug; ++ struct stack_hook *hookp; ++ struct global_iterator { ++ int finished; ++ int block_index; ++ struct symtab *symtab; ++ struct symbol *sym; ++ struct objfile *obj; ++ } global_iterator; ++ struct load_module *lm; ++ char *member_main_type_name; ++ char *member_main_type_tag_name; ++ char *member_target_type_name; ++ char *member_target_type_tag_name; ++ char *type_tag_name; ++}; ++ ++/* ++ * GNU commands ++ */ ++#define GNU_DATATYPE_INIT (1) ++#define GNU_DISASSEMBLE (2) ++#define GNU_GET_LINE_NUMBER (3) ++#define GNU_PASS_THROUGH (4) ++#define GNU_GET_DATATYPE (5) ++#define GNU_COMMAND_EXISTS (6) ++#define GNU_STACK_TRACE (7) ++#define GNU_ALPHA_FRAME_OFFSET (8) ++#define GNU_FUNCTION_NUMARGS (9) ++#define GNU_RESOLVE_TEXT_ADDR (10) ++#define GNU_ADD_SYMBOL_FILE (11) ++#define GNU_DELETE_SYMBOL_FILE (12) ++#define GNU_VERSION (13) ++#define GNU_PATCH_SYMBOL_VALUES (14) ++#define GNU_GET_SYMBOL_TYPE (15) ++#define GNU_USER_PRINT_OPTION (16) ++#define GNU_SET_CRASH_BLOCK (17) ++#define GNU_GET_FUNCTION_RANGE (18) ++#define GNU_GET_NEXT_DATATYPE (19) ++#define GNU_LOOKUP_STRUCT_CONTENTS (20) ++#define GNU_DEBUG_COMMAND (100) ++/* ++ * GNU flags ++ */ ++#define GNU_PRINT_LINE_NUMBERS (0x1) ++#define GNU_FUNCTION_ONLY (0x2) ++#define GNU_PRINT_ENUMERATORS (0x4) ++#define GNU_RETURN_ON_ERROR (0x8) ++#define GNU_COMMAND_FAILED (0x10) ++#define GNU_FROM_TTY_OFF (0x20) ++#define GNU_NO_READMEM (0x40) ++#define GNU_VAR_LENGTH_TYPECODE (0x80) ++ ++#undef TRUE ++#undef FALSE ++ ++#define TRUE (1) ++#define FALSE (0) ++ ++#ifdef GDB_COMMON ++/* ++ * function prototypes required by modified gdb source files. ++ */ ++int console(char *, ...); ++int gdb_CRASHDEBUG(ulong); ++int gdb_readmem_callback(ulong, void *, int, int); ++void patch_load_module(struct objfile *objfile, struct minimal_symbol *msymbol); ++int patch_kernel_symbol(struct gnu_request *); ++struct syment *symbol_search(char *); ++int gdb_line_number_callback(ulong, ulong, ulong); ++int gdb_print_callback(ulong); ++#endif ++ ++#ifndef GDB_COMMON ++/* ++ * WARNING: the following type codes are type_code enums from gdb/gdbtypes.h ++ */ ++enum type_code { ++ TYPE_CODE_UNDEF, /* Not used; catches errors */ ++ TYPE_CODE_PTR, /* Pointer type */ ++ TYPE_CODE_ARRAY, /* Array type with lower & upper bounds. */ ++ TYPE_CODE_STRUCT, /* C struct or Pascal record */ ++ TYPE_CODE_UNION, /* C union or Pascal variant part */ ++ TYPE_CODE_ENUM, /* Enumeration type */ ++#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) || defined(GDB_7_0) || defined(GDB_7_3_1) || defined(GDB_7_6) ++#if defined(GDB_7_0) || defined(GDB_7_3_1) || defined(GDB_7_6) ++ TYPE_CODE_FLAGS, /* Bit flags type */ ++#endif ++ TYPE_CODE_FUNC, /* Function type */ ++ TYPE_CODE_INT, /* Integer type */ ++ ++ /* Floating type. This is *NOT* a complex type. Beware, there are parts ++ of GDB which bogusly assume that TYPE_CODE_FLT can mean complex. */ ++ TYPE_CODE_FLT, ++ ++ /* Void type. The length field specifies the length (probably always ++ one) which is used in pointer arithmetic involving pointers to ++ this type, but actually dereferencing such a pointer is invalid; ++ a void type has no length and no actual representation in memory ++ or registers. A pointer to a void type is a generic pointer. */ ++ TYPE_CODE_VOID, ++ ++ TYPE_CODE_SET, /* Pascal sets */ ++ TYPE_CODE_RANGE, /* Range (integers within spec'd bounds) */ ++ ++ /* ++ * NOTE: the remainder of the type codes are not list or used here... ++ */ ++ TYPE_CODE_BOOL = 20, ++#endif ++}; ++ ++/* ++ * include/linux/sched.h ++ */ ++#define PF_EXITING 0x00000004 /* getting shut down */ ++#define PF_KTHREAD 0x00200000 /* I am a kernel thread */ ++#define SCHED_NORMAL 0 ++#define SCHED_FIFO 1 ++#define SCHED_RR 2 ++#define SCHED_BATCH 3 ++#define SCHED_ISO 4 ++#define SCHED_IDLE 5 ++#define SCHED_DEADLINE 6 ++ ++extern long _ZOMBIE_; ++#define IS_ZOMBIE(task) (task_state(task) & _ZOMBIE_) ++#define IS_EXITING(task) (task_flags(task) & PF_EXITING) ++ ++/* ++ * ps command options. ++ */ ++#define PS_BY_PID (0x1) ++#define PS_BY_TASK (0x2) ++#define PS_BY_CMD (0x4) ++#define PS_SHOW_ALL (0x8) ++#define PS_PPID_LIST (0x10) ++#define PS_CHILD_LIST (0x20) ++#define PS_KERNEL (0x40) ++#define PS_USER (0x80) ++#define PS_TIMES (0x100) ++#define PS_KSTACKP (0x200) ++#define PS_LAST_RUN (0x400) ++#define PS_ARGV_ENVP (0x800) ++#define PS_TGID_LIST (0x1000) ++#define PS_RLIMIT (0x2000) ++#define PS_GROUP (0x4000) ++#define PS_BY_REGEX (0x8000) ++#define PS_NO_HEADER (0x10000) ++#define PS_MSECS (0x20000) ++#define PS_SUMMARY (0x40000) ++#define PS_POLICY (0x80000) ++#define PS_ACTIVE (0x100000) ++ ++#define PS_EXCLUSIVE (PS_TGID_LIST|PS_ARGV_ENVP|PS_TIMES|PS_CHILD_LIST|PS_PPID_LIST|PS_LAST_RUN|PS_RLIMIT|PS_MSECS|PS_SUMMARY|PS_ACTIVE) ++ ++#define MAX_PS_ARGS (100) /* maximum command-line specific requests */ ++ ++struct psinfo { ++ int argc; ++ ulong pid[MAX_PS_ARGS]; ++ int type[MAX_PS_ARGS]; ++ ulong task[MAX_PS_ARGS]; ++ char comm[MAX_PS_ARGS][TASK_COMM_LEN+1]; ++ struct regex_data { ++ char *pattern; ++ regex_t regex; ++ } regex_data[MAX_PS_ARGS]; ++ int regexs; ++ ulong *cpus; ++ int policy; ++}; ++ ++#define IS_A_NUMBER(X) (decimal(X, 0) || hexadecimal(X, 0)) ++#define AMBIGUOUS_NUMBER(X) (decimal(X, 0) && hexadecimal(X, 0)) ++ ++#define is_mclx_compressed_dump(X) (va_server_init((X), 0, 0, 0) == 0) ++ ++struct task_mem_usage { ++ ulong rss; ++ ulong total_vm; ++ double pct_physmem; ++ ulong mm_struct_addr; ++ ulong pgd_addr; ++}; ++ ++/* ++ * Global data (global_data.c) ++ */ ++extern FILE *fp; ++extern struct program_context program_context, *pc; ++extern struct task_table task_table, *tt; ++extern struct kernel_table kernel_table, *kt; ++extern struct command_table_entry linux_command_table[]; ++extern char *args[MAXARGS]; ++extern int argcnt; ++extern int argerrs; ++extern struct offset_table offset_table; ++extern struct size_table size_table; ++extern struct array_table array_table; ++extern struct vm_table vm_table, *vt; ++extern struct machdep_table *machdep; ++extern struct symbol_table_data symbol_table_data, *st; ++extern struct extension_table *extension_table; ++ ++/* ++ * Generated in build_data.c ++ */ ++extern char *build_command; ++extern char *build_data; ++extern char *build_target; ++extern char *build_version; ++extern char *compiler_version; ++ ++ ++/* ++ * command prototypes ++ */ ++void cmd_quit(void); /* main.c */ ++void cmd_mach(void); /* main.c */ ++void cmd_help(void); /* help.c */ ++void cmd_test(void); /* test.c */ ++void cmd_ascii(void); /* tools.c */ ++void cmd_bpf(void); /* bfp.c */ ++void cmd_set(void); /* tools.c */ ++void cmd_eval(void); /* tools.c */ ++void cmd_list(void); /* tools.c */ ++void cmd_tree(void); /* tools.c */ ++void cmd_template(void); /* tools.c */ ++void cmd_alias(void); /* cmdline.c */ ++void cmd_repeat(void); /* cmdline.c */ ++void cmd_rd(void); /* memory.c */ ++void cmd_wr(void); /* memory.c */ ++void cmd_ptov(void); /* memory.c */ ++void cmd_vtop(void); /* memory.c */ ++void cmd_vm(void); /* memory.c */ ++void cmd_ptob(void); /* memory.c */ ++void cmd_btop(void); /* memory.c */ ++void cmd_kmem(void); /* memory.c */ ++void cmd_search(void); /* memory.c */ ++void cmd_swap(void); /* memory.c */ ++void cmd_pte(void); /* memory.c */ ++void cmd_ps(void); /* task.c */ ++void cmd_task(void); /* task.c */ ++void cmd_foreach(void); /* task.c */ ++void cmd_runq(void); /* task.c */ ++void cmd_sig(void); /* task.c */ ++void cmd_bt(void); /* kernel.c */ ++void cmd_dis(void); /* kernel.c */ ++void cmd_mod(void); /* kernel.c */ ++void cmd_log(void); /* kernel.c */ ++void cmd_sys(void); /* kernel.c */ ++void cmd_irq(void); /* kernel.c */ ++void cmd_timer(void); /* kernel.c */ ++void cmd_waitq(void); /* kernel.c */ ++void cmd_sym(void); /* symbols.c */ ++void cmd_struct(void); /* symbols.c */ ++void cmd_union(void); /* symbols.c */ ++void cmd_pointer(void); /* symbols.c */ ++void cmd_whatis(void); /* symbols.c */ ++void cmd_p(void); /* symbols.c */ ++void cmd_mount(void); /* filesys.c */ ++void cmd_files(void); /* filesys.c */ ++void cmd_fuser(void); /* filesys.c */ ++void cmd_dev(void); /* dev.c */ ++void cmd_gdb(void); /* gdb_interface.c */ ++void cmd_net(void); /* net.c */ ++void cmd_extend(void); /* extensions.c */ ++#if defined(S390) || defined(S390X) ++void cmd_s390dbf(void); ++#endif ++void cmd_map(void); /* kvmdump.c */ ++void cmd_ipcs(void); /* ipcs.c */ ++ ++/* ++ * main.c ++ */ ++void main_loop(void); ++void exec_command(void); ++struct command_table_entry *get_command_table_entry(char *); ++void program_usage(int); ++#define LONG_FORM (1) ++#define SHORT_FORM (0) ++void dump_program_context(void); ++void dump_build_data(void); ++#ifdef ARM ++#define machdep_init(X) arm_init(X) ++#endif ++#ifdef ARM64 ++#define machdep_init(X) arm64_init(X) ++#endif ++#ifdef X86 ++#define machdep_init(X) x86_init(X) ++#endif ++#ifdef ALPHA ++#define machdep_init(X) alpha_init(X) ++#endif ++#ifdef PPC ++#define machdep_init(X) ppc_init(X) ++#endif ++#ifdef IA64 ++#define machdep_init(X) ia64_init(X) ++#endif ++#ifdef S390 ++#define machdep_init(X) s390_init(X) ++#endif ++#ifdef S390X ++#define machdep_init(X) s390x_init(X) ++#endif ++#ifdef X86_64 ++#define machdep_init(X) x86_64_init(X) ++#endif ++#ifdef PPC64 ++#define machdep_init(X) ppc64_init(X) ++#endif ++#ifdef MIPS ++#define machdep_init(X) mips_init(X) ++#endif ++#ifdef MIPS64 ++#define machdep_init(X) mips64_init(X) ++#endif ++#ifdef SPARC64 ++#define machdep_init(X) sparc64_init(X) ++#endif ++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 ++ */ ++void restart(int); ++void alias_init(char *); ++struct alias_data *is_alias(char *); ++void deallocate_alias(char *); ++void cmdline_init(void); ++void set_command_prompt(char *); ++void exec_input_file(void); ++void process_command_line(void); ++void dump_history(void); ++void resolve_rc_cmd(char *, int); ++void dump_alias_data(void); ++int output_open(void); ++#define output_closed() (!output_open()) ++void close_output(void); ++int interruptible(void); ++int received_SIGINT(void); ++void debug_redirect(char *); ++int CRASHPAGER_valid(void); ++char *setup_scroll_command(void); ++int minimal_functions(char *); ++int is_args_input_file(struct command_table_entry *, struct args_input_file *); ++void exec_args_input_file(struct command_table_entry *, struct args_input_file *); ++ ++/* ++ * tools.c ++ */ ++FILE *set_error(char *); ++int __error(int, char *, ...); ++#define error __error /* avoid conflict with gdb error() */ ++int console(char *, ...); ++void create_console_device(char *); ++int console_off(void); ++int console_on(int); ++int console_verbatim(char *); ++int whitespace(int); ++int ascii(int); ++int ascii_string(char *); ++int printable_string(char *); ++char *clean_line(char *); ++char *strip_line_end(char *); ++char *strip_linefeeds(char *); ++char *strip_beginning_whitespace(char *); ++char *strip_ending_whitespace(char *); ++char *strip_ending_char(char *, char); ++char *strip_beginning_char(char *, char); ++char *strip_comma(char *); ++char *strip_hex(char *); ++char *upper_case(const char *, char *); ++char *first_nonspace(char *); ++char *first_space(char *); ++char *replace_string(char *, char *, char); ++void string_insert(char *, char *); ++char *strstr_rightmost(char *, char *); ++char *null_first_space(char *); ++int parse_line(char *, char **); ++void print_verbatim(FILE *, char *); ++char *fixup_percent(char *); ++int can_eval(char *); ++ulong eval(char *, int, int *); ++ulonglong evall(char *, int, int *); ++int eval_common(char *, int, int *, struct number_option *); ++ulong htol(char *, int, int *); ++ulong dtol(char *, int, int *); ++unsigned int dtoi(char *, int, int *); ++ulong stol(char *, int, int *); ++ulonglong stoll(char *, int, int *); ++ulonglong htoll(char *, int, int *); ++ulonglong dtoll(char *, int, int *); ++int decimal(char *, int); ++int hexadecimal(char *, int); ++int hexadecimal_only(char *, int); ++ulong convert(char *, int, int *, ulong); ++void pad_line(FILE *, int, char); ++#define INDENT(x) pad_line(fp, x, ' ') ++char *mkstring(char *, int, ulong, const char *); ++#define MKSTR(X) ((const char *)(X)) ++int count_leading_spaces(char *); ++int count_chars(char *, char); ++long count_buffer_chars(char *, char, long); ++char *space(int); ++char *concat_args(char *, int, int); ++char *shift_string_left(char *, int); ++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); ++ uint radix; ++ void *private; ++}; ++int do_radix_tree_traverse(ulong ptr, int is_root, struct radix_tree_ops *ops); ++struct xarray_ops { ++ void (*entry)(ulong node, ulong slot, const char *path, ++ ulong index, void *private); ++ uint radix; ++ void *private; ++}; ++int do_xarray_traverse(ulong ptr, int is_root, struct xarray_ops *ops); ++int do_rdtree(struct tree_data *); ++int do_rbtree(struct tree_data *); ++int do_xatree(struct tree_data *); ++int retrieve_list(ulong *, int); ++long power(long, int); ++long long ll_power(long long, long long); ++void hq_init(void); ++int hq_open(void); ++int hq_close(void); ++int hq_enter(ulong); ++int hq_entry_exists(ulong); ++int hq_is_open(void); ++int hq_is_inuse(void); ++long get_embedded(void); ++void dump_embedded(char *); ++char *ordinal(ulong, char *); ++char *first_nonspace(char *); ++void dump_hash_table(int); ++void dump_shared_bufs(void); ++void drop_core(char *); ++int extract_hex(char *, ulong *, char, ulong); ++int count_bits_int(int); ++int count_bits_long(ulong); ++int highest_bit_long(ulong); ++int lowest_bit_long(ulong); ++void buf_init(void); ++void sym_buf_init(void); ++void free_all_bufs(void); ++char *getbuf(long); ++void freebuf(char *); ++char *resizebuf(char *, long, long); ++char *strdupbuf(char *); ++#define GETBUF(X) getbuf((long)(X)) ++#define FREEBUF(X) freebuf((char *)(X)) ++#define RESIZEBUF(X,Y,Z) (X) = (typeof(X))resizebuf((char *)(X), (long)(Y), (long)(Z)); ++#define STRDUPBUF(X) strdupbuf((char *)(X)) ++void sigsetup(int, void *, struct sigaction *, struct sigaction *); ++#define SIGACTION(s, h, a, o) sigsetup(s, h, a, o) ++char *convert_time(ulonglong, char *); ++char *ctime_tz(time_t *); ++void stall(ulong); ++char *pages_to_size(ulong, char *); ++int clean_arg(void); ++int empty_list(ulong); ++int machine_type(char *); ++int machine_type_mismatch(char *, char *, char *, ulong); ++void command_not_supported(void); ++void option_not_supported(int); ++void please_wait(char *); ++void please_wait_done(void); ++int pathcmp(char *, char *); ++int calculate(char *, ulong *, ulonglong *, ulong); ++int endian_mismatch(char *, char, ulong); ++uint16_t swap16(uint16_t, int); ++uint32_t swap32(uint32_t, int); ++uint64_t swap64(uint64_t, int); ++ulong *get_cpumask_buf(void); ++int make_cpumask(char *, ulong *, int, int *); ++size_t strlcpy(char *, char *, size_t); ++struct rb_node *rb_first(struct rb_root *); ++struct rb_node *rb_parent(struct rb_node *, struct rb_node *); ++struct rb_node *rb_right(struct rb_node *, struct rb_node *); ++struct rb_node *rb_left(struct rb_node *, struct rb_node *); ++struct rb_node *rb_next(struct rb_node *); ++struct rb_node *rb_last(struct rb_root *); ++ ++/* ++ * symbols.c ++ */ ++void symtab_init(void); ++char *check_specified_kernel_debug_file(void); ++void no_debugging_data(int); ++void get_text_init_space(void); ++int is_kernel_text(ulong); ++int is_kernel_data(ulong); ++int is_init_data(ulong value); ++int is_kernel_text_offset(ulong); ++int is_symbol_text(struct syment *); ++int is_rodata(ulong, struct syment **); ++int get_text_function_range(ulong, ulong *, ulong *); ++void datatype_init(void); ++struct syment *symbol_search(char *); ++struct syment *value_search(ulong, ulong *); ++struct syment *value_search_base_kernel(ulong, ulong *); ++struct syment *value_search_module(ulong, ulong *); ++struct syment *symbol_search_next(char *, struct syment *); ++ulong highest_bss_symbol(void); ++int in_ksymbol_range(ulong); ++int module_symbol(ulong, struct syment **, ++ struct load_module **, char *, ulong); ++#define IS_MODULE_VADDR(X) \ ++ (module_symbol((ulong)(X), NULL, NULL, NULL, *gdb_output_radix)) ++char *closest_symbol(ulong); ++ulong closest_symbol_value(ulong); ++#define SAME_FUNCTION(X,Y) (closest_symbol_value(X) == closest_symbol_value(Y)) ++void show_symbol(struct syment *, ulong, ulong); ++#define SHOW_LINENUM (0x1) ++#define SHOW_SECTION (0x2) ++#define SHOW_HEX_OFFS (0x4) ++#define SHOW_DEC_OFFS (0x8) ++#define SHOW_RADIX() (*gdb_output_radix == 16 ? SHOW_HEX_OFFS : SHOW_DEC_OFFS) ++#define SHOW_MODULE (0x10) ++int symbol_name_count(char *); ++int symbol_query(char *, char *, struct syment **); ++struct syment *next_symbol(char *, struct syment *); ++struct syment *prev_symbol(char *, struct syment *); ++void get_symbol_data(char *, long, void *); ++int try_get_symbol_data(char *, long, void *); ++char *value_to_symstr(ulong, char *, ulong); ++char *value_symbol(ulong); ++ulong symbol_value(char *); ++ulong symbol_value_module(char *, char *); ++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); ++void dump_struct(char *, ulong, unsigned); ++void dump_struct_member(char *, ulong, unsigned); ++void dump_union(char *, ulong, unsigned); ++void store_module_symbols_v1(ulong, int); ++void store_module_symbols_v2(ulong, int); ++int is_datatype_command(void); ++int is_typedef(char *); ++int arg_to_datatype(char *, struct datatype_member *, ulong); ++void dump_symbol_table(void); ++void dump_struct_table(ulong); ++void dump_offset_table(char *, ulong); ++int is_elf_file(char *); ++int is_kernel(char *); ++int is_shared_object(char *); ++int file_elf_version(char *); ++int is_system_map(char *); ++int is_compressed_kernel(char *, char **); ++int select_namelist(char *); ++int get_array_length(char *, int *, long); ++int get_array_length_alt(char *, char *, int *, long); ++int builtin_array_length(char *, int, int *); ++char *get_line_number(ulong, char *, int); ++char *get_build_directory(char *); ++int datatype_exists(char *); ++int get_function_numargs(ulong); ++int is_module_name(char *, ulong *, struct load_module **); ++int is_module_address(ulong, char *); ++ulong lowest_module_address(void); ++ulong highest_module_address(void); ++int load_module_symbols(char *, char *, ulong); ++void delete_load_module(ulong); ++ulong gdb_load_module_callback(ulong, char *); ++char *load_module_filter(char *, int); ++#define LM_P_FILTER (1) ++#define LM_DIS_FILTER (2) ++long datatype_info(char *, char *, struct datatype_member *); ++int get_symbol_type(char *, char *, struct gnu_request *); ++int get_symbol_length(char *); ++int text_value_cache(ulong, uint32_t, uint32_t *); ++int text_value_cache_byte(ulong, unsigned char *); ++void dump_text_value_cache(int); ++void clear_text_value_cache(void); ++void dump_numargs_cache(void); ++int patch_kernel_symbol(struct gnu_request *); ++struct syment *generic_machdep_value_to_symbol(ulong, ulong *); ++long OFFSET_verify(long, char *, char *, int, char *); ++long SIZE_verify(long, char *, char *, int, char *); ++long OFFSET_option(long, long, char *, char *, int, char *, char *); ++long SIZE_option(long, long, char *, char *, int, char *, char *); ++void dump_trace(void **); ++int enumerator_value(char *, long *); ++int dump_enumerator_list(char *); ++struct load_module *init_module_function(ulong); ++struct struct_member_data { ++ char *structure; ++ char *member; ++ long type; ++ long unsigned_type; ++ long length; ++ long offset; ++ long bitpos; ++ long bitsize; ++}; ++int fill_struct_member_data(struct struct_member_data *); ++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 ++ */ ++void mem_init(void); ++void vm_init(void); ++int readmem(ulonglong, int, void *, long, char *, ulong); ++int writemem(ulonglong, int, void *, long, char *, ulong); ++int generic_verify_paddr(uint64_t); ++int read_dev_mem(int, void *, int, ulong, physaddr_t); ++int read_memory_device(int, void *, int, ulong, physaddr_t); ++int read_mclx_dumpfile(int, void *, int, ulong, physaddr_t); ++int read_lkcd_dumpfile(int, void *, int, ulong, physaddr_t); ++int read_daemon(int, void *, int, ulong, physaddr_t); ++int write_dev_mem(int, void *, int, ulong, physaddr_t); ++int write_memory_device(int, void *, int, ulong, physaddr_t); ++int write_mclx_dumpfile(int, void *, int, ulong, physaddr_t); ++int write_lkcd_dumpfile(int, void *, int, ulong, physaddr_t); ++int write_daemon(int, void *, int, ulong, physaddr_t); ++int kvtop(struct task_context *, ulong, physaddr_t *, int); ++int uvtop(struct task_context *, ulong, physaddr_t *, int); ++void do_vtop(ulong, struct task_context *, ulong); ++void raw_stack_dump(ulong, ulong); ++void raw_data_dump(ulong, long, int); ++int accessible(ulong); ++ulong vm_area_dump(ulong, ulong, ulong, struct reference *); ++#define IN_TASK_VMA(TASK,VA) (vm_area_dump((TASK), UVADDR|VERIFY_ADDR, (VA), 0)) ++char *fill_vma_cache(ulong); ++void clear_vma_cache(void); ++void dump_vma_cache(ulong); ++int generic_is_page_ptr(ulong, physaddr_t *); ++int is_page_ptr(ulong, physaddr_t *); ++void dump_vm_table(int); ++int read_string(ulong, char *, int); ++void get_task_mem_usage(ulong, struct task_mem_usage *); ++char *get_memory_size(char *); ++uint64_t generic_memory_size(void); ++char *swap_location(ulonglong, char *); ++void clear_swap_info_cache(void); ++uint memory_page_size(void); ++void force_page_size(char *); ++ulong first_vmalloc_address(void); ++ulong last_vmalloc_address(void); ++int in_vmlist_segment(ulong); ++int phys_to_page(physaddr_t, ulong *); ++int generic_get_kvaddr_ranges(struct vaddr_range *); ++int l1_cache_size(void); ++int dumpfile_memory(int); ++#define DUMPFILE_MEM_USED (1) ++#define DUMPFILE_FREE_MEM (2) ++#define DUMPFILE_MEM_DUMP (3) ++#define DUMPFILE_ENVIRONMENT (4) ++uint64_t total_node_memory(void); ++int generic_is_kvaddr(ulong); ++int generic_is_uvaddr(ulong, struct task_context *); ++void fill_stackbuf(struct bt_info *); ++void alter_stackbuf(struct bt_info *); ++int vaddr_type(ulong, struct task_context *); ++char *format_stack_entry(struct bt_info *bt, char *, ulong, ulong); ++int in_user_stack(ulong, ulong); ++int dump_inode_page(ulong); ++ulong valid_section_nr(ulong); ++void display_memory_from_file_offset(ulonglong, long, void *); ++void swap_info_init(void); ++ ++/* ++ * filesys.c ++ */ ++void fd_init(void); ++void vfs_init(void); ++int is_a_tty(char *); ++int file_exists(char *, struct stat *); ++int file_readable(char *); ++int is_directory(char *); ++char *search_directory_tree(char *, char *, int); ++void open_tmpfile(void); ++void close_tmpfile(void); ++void open_tmpfile2(void); ++void set_tmpfile2(FILE *); ++void close_tmpfile2(void); ++void open_files_dump(ulong, int, struct reference *); ++void get_pathname(ulong, char *, int, int, ulong); ++ulong *get_mount_list(int *, struct task_context *); ++char *vfsmount_devname(ulong, char *, int); ++ulong file_to_dentry(ulong); ++ulong file_to_vfsmnt(ulong); ++int get_proc_version(void); ++int file_checksum(char *, long *); ++void dump_filesys_table(int); ++char *fill_file_cache(ulong); ++void clear_file_cache(void); ++char *fill_dentry_cache(ulong); ++void clear_dentry_cache(void); ++char *fill_inode_cache(ulong); ++void clear_inode_cache(void); ++int monitor_memory(long *, long *, long *, long *); ++int is_readable(char *); ++struct list_pair { ++ ulong index; ++ void *value; ++}; ++#define radix_tree_pair list_pair ++ulong do_radix_tree(ulong, int, struct list_pair *); ++#define RADIX_TREE_COUNT (1) ++#define RADIX_TREE_SEARCH (2) ++#define RADIX_TREE_DUMP (3) ++#define RADIX_TREE_GATHER (4) ++#define RADIX_TREE_DUMP_CB (5) ++/* ++ * from: "include/linux/radix-tree.h" ++ */ ++#define RADIX_TREE_ENTRY_MASK 3UL ++#define RADIX_TREE_EXCEPTIONAL_ENTRY 2 ++ ++ulong do_xarray(ulong, int, struct list_pair *); ++#define XARRAY_COUNT (1) ++#define XARRAY_SEARCH (2) ++#define XARRAY_DUMP (3) ++#define XARRAY_GATHER (4) ++#define XARRAY_DUMP_CB (5) ++#define XARRAY_TAG_MASK (3UL) ++#define XARRAY_TAG_INTERNAL (2UL) ++ ++int file_dump(ulong, ulong, ulong, int, int); ++#define DUMP_FULL_NAME 0x1 ++#define DUMP_INODE_ONLY 0x2 ++#define DUMP_DENTRY_ONLY 0x4 ++#define DUMP_EMPTY_FILE 0x8 ++#define DUMP_FILE_NRPAGES 0x10 ++#endif /* !GDB_COMMON */ ++int same_file(char *, char *); ++#ifndef GDB_COMMON ++int cleanup_memory_driver(void); ++ ++ ++/* ++ * help.c ++ */ ++#define HELP_COLUMNS 5 ++#define START_OF_HELP_DATA(X) "START_OF_HELP_DATA" X ++#define END_OF_HELP_DATA "END_OF_HELP_DATA" ++void help_init(void); ++void cmd_usage(char *, int); ++void display_version(void); ++void display_help_screen(char *); ++#ifdef ARM ++#define dump_machdep_table(X) arm_dump_machdep_table(X) ++#endif ++#ifdef ARM64 ++#define dump_machdep_table(X) arm64_dump_machdep_table(X) ++#endif ++#ifdef X86 ++#define dump_machdep_table(X) x86_dump_machdep_table(X) ++#endif ++#ifdef ALPHA ++#define dump_machdep_table(X) alpha_dump_machdep_table(X) ++#endif ++#ifdef PPC ++#define dump_machdep_table(X) ppc_dump_machdep_table(X) ++#endif ++#ifdef IA64 ++#define dump_machdep_table(X) ia64_dump_machdep_table(X) ++#endif ++#ifdef S390 ++#define dump_machdep_table(X) s390_dump_machdep_table(X) ++#endif ++#ifdef S390X ++#define dump_machdep_table(X) s390x_dump_machdep_table(X) ++#endif ++#ifdef X86_64 ++#define dump_machdep_table(X) x86_64_dump_machdep_table(X) ++#endif ++#ifdef PPC64 ++#define dump_machdep_table(X) ppc64_dump_machdep_table(X) ++#endif ++#ifdef MIPS ++#define dump_machdep_table(X) mips_dump_machdep_table(X) ++#endif ++#ifdef MIPS64 ++#define dump_machdep_table(X) mips64_dump_machdep_table(X) ++#endif ++#ifdef SPARC64 ++#define dump_machdep_table(X) sparc64_dump_machdep_table(X) ++#endif ++extern char *help_pointer[]; ++extern char *help_alias[]; ++extern char *help_ascii[]; ++extern char *help_bpf[]; ++extern char *help_bt[]; ++extern char *help_btop[]; ++extern char *help_dev[]; ++extern char *help_dis[]; ++extern char *help_eval[]; ++extern char *help_exit[]; ++extern char *help_extend[]; ++extern char *help_files[]; ++extern char *help_foreach[]; ++extern char *help_fuser[]; ++extern char *help_gdb[]; ++extern char *help_help[]; ++extern char *help_irq[]; ++extern char *help_kmem[]; ++extern char *help__list[]; ++extern char *help_tree[]; ++extern char *help_log[]; ++extern char *help_mach[]; ++extern char *help_mod[]; ++extern char *help_mount[]; ++extern char *help_net[]; ++extern char *help_p[]; ++extern char *help_ps[]; ++extern char *help_pte[]; ++extern char *help_ptob[]; ++extern char *help_ptov[]; ++extern char *help_quit[]; ++extern char *help_rd[]; ++extern char *help_repeat[]; ++extern char *help_runq[]; ++extern char *help_ipcs[]; ++extern char *help_search[]; ++extern char *help_set[]; ++extern char *help_sig[]; ++extern char *help_struct[]; ++extern char *help_swap[]; ++extern char *help_sym[]; ++extern char *help_sys[]; ++extern char *help_task[]; ++extern char *help_timer[]; ++extern char *help_union[]; ++extern char *help_vm[]; ++extern char *help_vtop[]; ++extern char *help_waitq[]; ++extern char *help_whatis[]; ++extern char *help_wr[]; ++#if defined(S390) || defined(S390X) ++extern char *help_s390dbf[]; ++#endif ++extern char *help_map[]; ++ ++/* ++ * task.c ++ */ ++void task_init(void); ++int set_context(ulong, ulong); ++void show_context(struct task_context *); ++ulong pid_to_task(ulong); ++ulong task_to_pid(ulong); ++int task_exists(ulong); ++int is_kernel_thread(ulong); ++int is_idle_thread(ulong); ++void get_idle_threads(ulong *, int); ++char *task_state_string(ulong, char *, int); ++ulong task_flags(ulong); ++ulong task_state(ulong); ++ulong task_mm(ulong, int); ++ulong task_tgid(ulong); ++ulonglong task_last_run(ulong); ++ulong vaddr_in_task_struct(ulong); ++int comm_exists(char *); ++struct task_context *task_to_context(ulong); ++struct task_context *pid_to_context(ulong); ++struct task_context *tgid_to_context(ulong); ++ulong stkptr_to_task(ulong); ++ulong task_to_thread_info(ulong); ++ulong task_to_stackbase(ulong); ++int str_to_context(char *, ulong *, struct task_context **); ++#define STR_PID (0x1) ++#define STR_TASK (0x2) ++#define STR_INVALID (0x4) ++char *get_panicmsg(char *); ++char *task_cpu(int, char *, int); ++void print_task_header(FILE *, struct task_context *, int); ++ulong get_active_task(int); ++int is_task_active(ulong); ++int is_panic_thread(ulong); ++int get_panic_ksp(struct bt_info *, ulong *); ++void foreach(struct foreach_data *); ++int pid_exists(ulong); ++#define TASKS_PER_PID(x) pid_exists(x) ++char *fill_task_struct(ulong); ++#define IS_LAST_TASK_READ(task) ((ulong)(task) == tt->last_task_read) ++char *fill_thread_info(ulong); ++#define IS_LAST_THREAD_INFO_READ(ti) ((ulong)(ti) == tt->last_thread_info_read) ++char *fill_mm_struct(ulong); ++#define IS_LAST_MM_READ(mm) ((ulong)(mm) == tt->last_mm_read) ++void do_task(ulong, ulong, struct reference *, unsigned int); ++void clear_task_cache(void); ++int get_active_set(void); ++void clear_active_set(void); ++void do_sig(ulong, ulong, struct reference *); ++void modify_signame(int, char *, char *); ++ulong generic_get_stackbase(ulong); ++ulong generic_get_stacktop(ulong); ++void dump_task_table(int); ++void sort_context_array(void); ++void sort_tgid_array(void); ++int sort_by_tgid(const void *, const void *); ++int in_irq_ctx(ulonglong, int, ulong); ++void check_stack_overflow(void); ++ ++/* ++ * extensions.c ++ */ ++void register_extension(struct command_table_entry *); ++void dump_extension_table(int); ++void load_extension(char *); ++void unload_extension(char *); ++void preload_extensions(void); ++/* Hooks for sial */ ++unsigned long get_curtask(void); ++char *crash_global_cmd(void); ++struct command_table_entry *crash_cmd_table(void); ++ ++/* ++ * kernel.c ++ */ ++void kernel_init(void); ++void module_init(void); ++void verify_version(void); ++void verify_spinlock(void); ++void non_matching_kernel(void); ++struct load_module *modref_to_load_module(char *); ++int load_module_symbols_helper(char *); ++void unlink_module(struct load_module *); ++int check_specified_module_tree(char *, char *); ++int is_system_call(char *, ulong); ++void generic_dump_irq(int); ++void generic_get_irq_affinity(int); ++void generic_show_interrupts(int, ulong *); ++int generic_dis_filter(ulong, char *, unsigned int); ++int kernel_BUG_encoding_bytes(void); ++void display_sys_stats(void); ++char *get_uptime(char *, ulonglong *); ++void clone_bt_info(struct bt_info *, struct bt_info *, struct task_context *); ++void dump_kernel_table(int); ++void dump_bt_info(struct bt_info *, char *where); ++void dump_log(int); ++#define LOG_LEVEL(v) ((v) & 0x07) ++#define SHOW_LOG_LEVEL (0x1) ++#define SHOW_LOG_DICT (0x2) ++#define SHOW_LOG_TEXT (0x4) ++#define SHOW_LOG_AUDIT (0x8) ++#define SHOW_LOG_CTIME (0x10) ++void set_cpu(int); ++void clear_machdep_cache(void); ++struct stack_hook *gather_text_list(struct bt_info *); ++int get_cpus_online(void); ++int get_cpus_active(void); ++int get_cpus_present(void); ++int get_cpus_possible(void); ++int check_offline_cpu(int); ++int hide_offline_cpu(int); ++int get_highest_cpu_online(void); ++int get_highest_cpu_present(void); ++int get_cpus_to_display(void); ++void get_log_from_vmcoreinfo(char *file); ++int in_cpu_map(int, int); ++void paravirt_init(void); ++void print_stack_text_syms(struct bt_info *, ulong, ulong); ++void back_trace(struct bt_info *); ++int in_alternate_stack(int, ulong); ++ulong cpu_map_addr(const char *type); ++#define BT_RAW (0x1ULL) ++#define BT_SYMBOLIC_ARGS (0x2ULL) ++#define BT_FULL (0x4ULL) ++#define BT_TEXT_SYMBOLS (0x8ULL) ++#define BT_TEXT_SYMBOLS_PRINT (0x10ULL) ++#define BT_TEXT_SYMBOLS_NOPRINT (0x20ULL) ++#define BT_USE_GDB (0x40ULL) ++#define BT_EXCEPTION_FRAME (0x80ULL) ++#define BT_LINE_NUMBERS (0x100ULL) ++#define BT_USER_EFRAME (0x200ULL) ++#define BT_INCOMPLETE_USER_EFRAME (BT_USER_EFRAME) ++#define BT_SAVE_LASTSP (0x400ULL) ++#define BT_FROM_EXCEPTION (0x800ULL) ++#define BT_FROM_CALLFRAME (0x1000ULL) ++#define BT_EFRAME_SEARCH (0x2000ULL) ++#define BT_SPECULATE (0x4000ULL) ++#define BT_FRAMESIZE_DISABLE (BT_SPECULATE) ++#define BT_RESCHEDULE (0x8000ULL) ++#define BT_SCHEDULE (BT_RESCHEDULE) ++#define BT_RET_FROM_SMP_FORK (0x10000ULL) ++#define BT_STRACE (0x20000ULL) ++#define BT_KDUMP_ADJUST (BT_STRACE) ++#define BT_KSTACKP (0x40000ULL) ++#define BT_LOOP_TRAP (0x80000ULL) ++#define BT_BUMP_FRAME_LEVEL (0x100000ULL) ++#define BT_EFRAME_COUNT (0x200000ULL) ++#define BT_CPU_IDLE (0x400000ULL) ++#define BT_WRAP_TRAP (0x800000ULL) ++#define BT_KERNEL_THREAD (0x1000000ULL) ++#define BT_ERROR_MASK (BT_LOOP_TRAP|BT_WRAP_TRAP|BT_KERNEL_THREAD|BT_CPU_IDLE) ++#define BT_UNWIND_ERROR (0x2000000ULL) ++#define BT_OLD_BACK_TRACE (0x4000000ULL) ++#define BT_OPT_BACK_TRACE (0x4000000ULL) ++#define BT_FRAMESIZE_DEBUG (0x8000000ULL) ++#define BT_CONTEXT_SWITCH (0x10000000ULL) ++#define BT_HARDIRQ (0x20000000ULL) ++#define BT_SOFTIRQ (0x40000000ULL) ++#define BT_CHECK_CALLER (0x80000000ULL) ++#define BT_NO_CHECK_CALLER (0x100000000ULL) ++#define BT_EXCEPTION_STACK (0x200000000ULL) ++#define BT_IRQSTACK (0x400000000ULL) ++#define BT_DUMPFILE_SEARCH (0x800000000ULL) ++#define BT_EFRAME_SEARCH2 (0x1000000000ULL) ++#define BT_START (0x2000000000ULL) ++#define BT_TEXT_SYMBOLS_ALL (0x4000000000ULL) ++#define BT_XEN_STOP_THIS_CPU (0x8000000000ULL) ++#define BT_THREAD_GROUP (0x10000000000ULL) ++#define BT_SAVE_EFRAME_IP (0x20000000000ULL) ++#define BT_FULL_SYM_SLAB (0x40000000000ULL) ++#define BT_KDUMP_ELF_REGS (0x80000000000ULL) ++#define BT_USER_SPACE (0x100000000000ULL) ++#define BT_KERNEL_SPACE (0x200000000000ULL) ++#define BT_FULL_SYM_SLAB2 (0x400000000000ULL) ++#define BT_EFRAME_TARGET (0x800000000000ULL) ++#define BT_CPUMASK (0x1000000000000ULL) ++#define BT_SHOW_ALL_REGS (0x2000000000000ULL) ++#define BT_REGS_NOT_FOUND (0x4000000000000ULL) ++#define BT_SYMBOL_OFFSET (BT_SYMBOLIC_ARGS) ++ ++#define BT_REF_HEXVAL (0x1) ++#define BT_REF_SYMBOL (0x2) ++#define BT_REF_FOUND (0x4) ++#define BT_REFERENCE_CHECK(X) ((X)->ref) ++#define BT_REFERENCE_FOUND(X) ((X)->ref && ((X)->ref->cmdflags & BT_REF_FOUND)) ++ ++#define NO_MODULES() \ ++ (!kt->module_list || (kt->module_list == kt->kernel_module)) ++ ++#define USER_EFRAME_ADDR(task) \ ++ ((ulong)task + UNION_SIZE("task_union") - SIZE(pt_regs)) ++ ++struct remote_file { ++ char *filename; ++ char *local; ++ int fd; ++ int flags; ++ int type; ++ long csum; ++ off_t size; ++}; ++ ++#define REMOTE_VERBOSE (O_RDWR << 1) ++#define REMOTE_COPY_DONE (REMOTE_VERBOSE << 1) ++#define TYPE_ELF (REMOTE_VERBOSE << 2) ++#define TYPE_DEVMEM (REMOTE_VERBOSE << 3) ++#define TYPE_MCLXCD (REMOTE_VERBOSE << 4) ++#define TYPE_LKCD (REMOTE_VERBOSE << 5) ++#define TYPE_S390D (REMOTE_VERBOSE << 6) ++#define TYPE_NETDUMP (REMOTE_VERBOSE << 7) ++ ++ulonglong xen_m2p(ulonglong); ++ ++void read_in_kernel_config(int); ++ ++#define IKCFG_INIT (0) ++#define IKCFG_READ (1) ++#define IKCFG_SETUP (2) ++#define IKCFG_FREE (3) ++ ++int get_kernel_config(char *, char **); ++enum { ++ IKCONFIG_N, ++ IKCONFIG_Y, ++ IKCONFIG_M, ++ IKCONFIG_STR, ++}; ++ ++#define MAGIC_START "IKCFG_ST" ++#define MAGIC_END "IKCFG_ED" ++#define MAGIC_SIZE (sizeof(MAGIC_START) - 1) ++ ++/* ++ * dev.c ++ */ ++void dev_init(void); ++void dump_dev_table(void); ++void devdump_extract(void *, ulonglong, char *, FILE *); ++void devdump_info(void *, ulonglong, FILE *); ++ ++/* ++ * ipcs.c ++ */ ++void ipcs_init(void); ++ulong idr_find(ulong, int); ++ ++#ifdef ARM ++void arm_init(int); ++void arm_dump_machdep_table(ulong); ++int arm_is_vmalloc_addr(ulong); ++void arm_dump_backtrace_entry(struct bt_info *, int, ulong, ulong); ++ ++#define display_idt_table() \ ++ error(FATAL, "-d option is not applicable to ARM architecture\n") ++ ++struct arm_pt_regs { ++ ulong uregs[18]; ++}; ++ ++#define ARM_cpsr uregs[16] ++#define ARM_pc uregs[15] ++#define ARM_lr uregs[14] ++#define ARM_sp uregs[13] ++#define ARM_ip uregs[12] ++#define ARM_fp uregs[11] ++#define ARM_r10 uregs[10] ++#define ARM_r9 uregs[9] ++#define ARM_r8 uregs[8] ++#define ARM_r7 uregs[7] ++#define ARM_r6 uregs[6] ++#define ARM_r5 uregs[5] ++#define ARM_r4 uregs[4] ++#define ARM_r3 uregs[3] ++#define ARM_r2 uregs[2] ++#define ARM_r1 uregs[1] ++#define ARM_r0 uregs[0] ++#define ARM_ORIG_r0 uregs[17] ++ ++#define KSYMS_START (0x1) ++#define PHYS_BASE (0x2) ++#define PGTABLE_V2 (0x4) ++#define IDMAP_PGD (0x8) ++ ++#define KVBASE_MASK (0x1ffffff) ++ ++struct machine_specific { ++ ulong phys_base; ++ ulong vmalloc_start_addr; ++ ulong modules_vaddr; ++ ulong modules_end; ++ ulong kernel_text_start; ++ ulong kernel_text_end; ++ ulong exception_text_start; ++ ulong exception_text_end; ++ ulonglong last_pgd_read_lpae; ++ ulonglong last_pmd_read_lpae; ++ ulonglong last_ptbl_read_lpae; ++ struct arm_pt_regs *crash_task_regs; ++ int unwind_index_prel31; ++}; ++ ++int init_unwind_tables(void); ++void unwind_backtrace(struct bt_info *); ++#endif /* ARM */ ++ ++/* ++ * arm64.c ++ */ ++#ifdef ARM64 ++void arm64_init(int); ++void arm64_dump_machdep_table(ulong); ++ulong arm64_VTOP(ulong); ++ulong arm64_PTOV(ulong); ++int arm64_IS_VMALLOC_ADDR(ulong); ++ulong arm64_swp_type(ulong); ++ulong arm64_swp_offset(ulong); ++#endif ++ ++/* ++ * alpha.c ++ */ ++#ifdef ALPHA ++void alpha_init(int); ++void alpha_dump_machdep_table(ulong); ++#define display_idt_table() \ ++ error(FATAL, "-d option is not applicable to alpha architecture\n") ++ ++#define HWRESET_TASK(X) ((machdep->flags & HWRESET) && is_task_active(X) && \ ++ (task_to_context(X)->processor == 0)) ++#endif ++ ++/* ++ * x86.c ++ */ ++#ifdef X86 ++void x86_init(int); ++void x86_dump_machdep_table(ulong); ++void x86_display_idt_table(void); ++#define display_idt_table() x86_display_idt_table() ++#define KSYMS_START (0x1) ++void x86_dump_eframe_common(struct bt_info *bt, ulong *, int); ++char *x86_function_called_by(ulong); ++struct syment *x86_jmp_error_code(ulong); ++struct syment *x86_text_lock_jmp(ulong, ulong *); ++ ++struct machine_specific { ++ ulong *idt_table; ++ ulong entry_tramp_start; ++ ulong entry_tramp_end; ++ physaddr_t entry_tramp_start_phys; ++ ulonglong last_pmd_read_PAE; ++ ulonglong last_ptbl_read_PAE; ++ ulong page_protnone; ++ int max_numnodes; ++ ulong *remap_start_vaddr; ++ ulong *remap_end_vaddr; ++ ulong *remap_start_pfn; ++}; ++ ++struct syment *x86_is_entry_tramp_address(ulong, ulong *); ++#endif ++ ++/* ++ * x86_64.c ++ */ ++#ifdef X86_64 ++void x86_64_init(int); ++void x86_64_dump_machdep_table(ulong); ++ulong x86_64_PTOV(ulong); ++ulong x86_64_VTOP(ulong); ++int x86_64_IS_VMALLOC_ADDR(ulong); ++ulong x86_64_swp_type(ulong); ++ulong x86_64_swp_offset(ulong); ++void x86_64_display_idt_table(void); ++#define display_idt_table() x86_64_display_idt_table() ++long x86_64_exception_frame(ulong, ulong, char *, struct bt_info *, FILE *); ++#define EFRAME_INIT (0) ++ ++struct x86_64_pt_regs_offsets { ++ long r15; ++ long r14; ++ long r13; ++ long r12; ++ long rbp; ++ long rbx; ++/* arguments: non interrupts/non tracing syscalls only save upto here*/ ++ long r11; ++ long r10; ++ long r9; ++ long r8; ++ long rax; ++ long rcx; ++ long rdx; ++ long rsi; ++ long rdi; ++ long orig_rax; ++/* end of arguments */ ++/* cpu exception frame or undefined */ ++ long rip; ++ long cs; ++ long eflags; ++ long rsp; ++ long ss; ++}; ++ ++#define MAX_EXCEPTION_STACKS 7 ++#define NMI_STACK (machdep->machspec->stkinfo.NMI_stack_index) ++ ++struct x86_64_stkinfo { ++ ulong ebase[NR_CPUS][MAX_EXCEPTION_STACKS]; ++ int esize[MAX_EXCEPTION_STACKS]; ++ char available[NR_CPUS][MAX_EXCEPTION_STACKS]; ++ ulong ibase[NR_CPUS]; ++ int isize; ++ int NMI_stack_index; ++ char *exception_stacks[MAX_EXCEPTION_STACKS]; ++}; ++ ++typedef struct __attribute__((__packed__)) { ++ signed short sp_offset; ++ signed short bp_offset; ++ unsigned int sp_reg:4; ++ unsigned int bp_reg:4; ++ unsigned int type:2; ++ unsigned int end:1; ++} kernel_orc_entry; ++ ++struct ORC_data { ++ int module_ORC; ++ uint lookup_num_blocks; ++ ulong __start_orc_unwind_ip; ++ ulong __stop_orc_unwind_ip; ++ ulong __start_orc_unwind; ++ ulong __stop_orc_unwind; ++ ulong orc_lookup; ++ ulong ip_entry; ++ ulong orc_entry; ++ kernel_orc_entry kernel_orc_entry; ++}; ++ ++#define ORC_TYPE_CALL 0 ++#define ORC_TYPE_REGS 1 ++#define ORC_TYPE_REGS_IRET 2 ++#define UNWIND_HINT_TYPE_SAVE 3 ++#define UNWIND_HINT_TYPE_RESTORE 4 ++ ++#define ORC_REG_UNDEFINED 0 ++#define ORC_REG_PREV_SP 1 ++#define ORC_REG_DX 2 ++#define ORC_REG_DI 3 ++#define ORC_REG_BP 4 ++#define ORC_REG_SP 5 ++#define ORC_REG_R10 6 ++#define ORC_REG_R13 7 ++#define ORC_REG_BP_INDIRECT 8 ++#define ORC_REG_SP_INDIRECT 9 ++#define ORC_REG_MAX 15 ++ ++struct machine_specific { ++ ulong userspace_top; ++ ulong page_offset; ++ ulong vmalloc_start_addr; ++ ulong vmalloc_end; ++ ulong vmemmap_vaddr; ++ ulong vmemmap_end; ++ ulong modules_vaddr; ++ ulong modules_end; ++ ulong phys_base; ++ char *pml4; ++ char *upml; ++ ulong last_upml_read; ++ ulong last_pml4_read; ++ char *irqstack; ++ ulong irq_eframe_link; ++ struct x86_64_pt_regs_offsets pto; ++ struct x86_64_stkinfo stkinfo; ++ ulong *current; ++ ulong *crash_nmi_rsp; ++ ulong vsyscall_page; ++ ulong thread_return; ++ ulong page_protnone; ++ ulong GART_start; ++ ulong GART_end; ++ ulong kernel_image_size; ++ ulong physical_mask_shift; ++ ulong pgdir_shift; ++ char *p4d; ++ ulong last_p4d_read; ++ struct ORC_data orc; ++ ulong irq_stack_gap; ++ ulong kpti_entry_stack; ++ ulong kpti_entry_stack_size; ++ ulong ptrs_per_pgd; ++ ulong cpu_entry_area_start; ++ ulong cpu_entry_area_end; ++ ulong page_offset_force; ++ char **exception_functions; ++}; ++ ++#define KSYMS_START (0x1) ++#define PT_REGS_INIT (0x2) ++#define VM_ORIG (0x4) ++#define VM_2_6_11 (0x8) ++#define VM_XEN (0x10) ++#define NO_TSS (0x20) ++#define SCHED_TEXT (0x40) ++#define PHYS_BASE (0x80) ++#define VM_XEN_RHEL4 (0x100) ++#define FRAMEPOINTER (0x200) ++#define GART_REGION (0x400) ++#define NESTED_NMI (0x800) ++#define RANDOMIZED (0x1000) ++#define VM_5LEVEL (0x2000) ++#define ORC (0x4000) ++#define KPTI (0x8000) ++#define L1TF (0x10000) ++ ++#define VM_FLAGS (VM_ORIG|VM_2_6_11|VM_XEN|VM_XEN_RHEL4|VM_5LEVEL) ++ ++#define _2MB_PAGE_MASK (~((MEGABYTES(2))-1)) ++#define _1GB_PAGE_MASK (~((GIGABYTES(1))-1)) ++ ++#endif ++ ++#if defined(X86) || defined(X86_64) ++ ++/* ++ * unwind_x86_32_64.c ++ */ ++void init_unwind_table(void); ++int dwarf_backtrace(struct bt_info *, int, ulong); ++void dwarf_debug(struct bt_info *); ++int dwarf_print_stack_entry(struct bt_info *, int); ++ ++#endif ++ ++ ++/* ++ * ppc64.c ++ */ ++ ++/* ++ * This structure was copied from kernel source ++ * in include/asm-ppc/ptrace.h ++ */ ++struct ppc64_pt_regs { ++ long gpr[32]; ++ long nip; ++ long msr; ++ long orig_gpr3; /* Used for restarting system calls */ ++ long ctr; ++ long link; ++ long xer; ++ long ccr; ++ long mq; /* 601 only (not used at present) */ ++ /* Used on APUS to hold IPL value. */ ++ long trap; /* Reason for being here */ ++ long dar; /* Fault registers */ ++ long dsisr; ++ long result; /* Result of a system call */ ++}; ++ ++struct ppc64_elf_siginfo { ++ int si_signo; ++ int si_code; ++ int si_errno; ++}; ++ ++struct ppc64_elf_prstatus { ++ struct ppc64_elf_siginfo pr_info; ++ short pr_cursig; ++ unsigned long pr_sigpend; ++ unsigned long pr_sighold; ++ pid_t pr_pid; ++ pid_t pr_ppid; ++ pid_t pr_pgrp; ++ pid_t pr_sid; ++ struct timeval pr_utime; ++ struct timeval pr_stime; ++ struct timeval pr_cutime; ++ struct timeval pr_cstime; ++ struct ppc64_pt_regs pr_reg; ++ int pr_fpvalid; ++}; ++ ++#ifdef PPC64 ++ ++struct ppc64_opal { ++ uint64_t base; ++ uint64_t entry; ++ uint64_t size; ++}; ++ ++struct ppc64_vmemmap { ++ unsigned long phys; ++ unsigned long virt; ++}; ++ ++/* ++ * Used to store the HW interrupt stack. It is only for 2.4. ++ */ ++struct machine_specific { ++ ulong hwintrstack[NR_CPUS]; ++ char *hwstackbuf; ++ uint hwstacksize; ++ ++ uint l4_index_size; ++ uint l3_index_size; ++ uint l2_index_size; ++ uint l1_index_size; ++ ++ uint ptrs_per_l4; ++ uint ptrs_per_l3; ++ uint ptrs_per_l2; ++ uint ptrs_per_l1; ++ ++ uint l4_shift; ++ uint l3_shift; ++ uint l2_shift; ++ uint l1_shift; ++ ++ uint pte_rpn_shift; ++ ulong pte_rpn_mask; ++ ulong pgd_masked_bits; ++ ulong pud_masked_bits; ++ ulong pmd_masked_bits; ++ ++ int vmemmap_cnt; ++ int vmemmap_psize; ++ ulong vmemmap_base; ++ struct ppc64_vmemmap *vmemmap_list; ++ ulong _page_pte; ++ ulong _page_present; ++ ulong _page_user; ++ ulong _page_rw; ++ ulong _page_guarded; ++ ulong _page_coherent; ++ ulong _page_no_cache; ++ ulong _page_writethru; ++ ulong _page_dirty; ++ ulong _page_accessed; ++ int (*is_kvaddr)(ulong); ++ int (*is_vmaddr)(ulong); ++ struct ppc64_opal opal; ++}; ++ ++void ppc64_init(int); ++void ppc64_dump_machdep_table(ulong); ++#define display_idt_table() \ ++ error(FATAL, "-d option is not applicable to PowerPC architecture\n") ++#define KSYMS_START (0x1) ++#define VM_ORIG (0x2) ++#define VMEMMAP_AWARE (0x4) ++#define BOOK3E (0x8) ++#define PHYS_ENTRY_L4 (0x10) ++#define SWAP_ENTRY_L4 (0x20) ++/* ++ * The flag bit for radix MMU in cpu_spec.mmu_features ++ * 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) ++#define VMEMMAP_REGION_ID (0xfUL) ++#endif ++ ++/* ++ * ppc.c ++ */ ++#ifdef PPC ++void ppc_init(int); ++void ppc_dump_machdep_table(ulong); ++void ppc_relocate_nt_prstatus_percpu(void **, uint *); ++#define display_idt_table() \ ++ error(FATAL, "-d option is not applicable to PowerPC architecture\n") ++#define KSYMS_START (0x1) ++/* This should match PPC_FEATURE_BOOKE from include/asm-powerpc/cputable.h */ ++#define CPU_BOOKE (0x00008000) ++#else ++#define ppc_relocate_nt_prstatus_percpu(X,Y) do {} while (0) ++#endif ++ ++/* ++ * lkcd_fix_mem.c ++ */ ++ ++struct _dump_header_asm_s; ++struct _dump_header_s; ++ulong get_lkcd_switch_stack(ulong); ++int fix_addr_v8(struct _dump_header_asm_s *); ++int lkcd_dump_init_v8_arch(struct _dump_header_s *dh); ++int fix_addr_v7(int); ++int get_lkcd_regs_for_cpu_arch(int cpu, ulong *eip, ulong *esp); ++int lkcd_get_kernel_start_v8(ulong *addr); ++ ++/* ++ * lkcd_v8.c ++ */ ++int get_lkcd_regs_for_cpu_v8(struct bt_info *bt, ulong *eip, ulong *esp); ++ ++/* ++ * ia64.c ++ */ ++#ifdef IA64 ++void ia64_init(int); ++void ia64_dump_machdep_table(ulong); ++void ia64_dump_line_number(ulong); ++ulong ia64_get_switch_stack(ulong); ++void ia64_exception_frame(ulong, struct bt_info *bt); ++ulong ia64_PTOV(ulong); ++ulong ia64_VTOP(ulong); ++int ia64_IS_VMALLOC_ADDR(ulong); ++#define display_idt_table() \ ++ error(FATAL, "-d option TBD on ia64 architecture\n"); ++int ia64_in_init_stack(ulong addr); ++int ia64_in_mca_stack_hyper(ulong addr, struct bt_info *bt); ++physaddr_t ia64_xen_kdump_p2m(struct xen_kdump_data *xkd, physaddr_t pseudo); ++ ++#define OLD_UNWIND (0x1) /* CONFIG_IA64_NEW_UNWIND not turned on */ ++#define NEW_UNWIND (0x2) /* CONFIG_IA64_NEW_UNWIND turned on */ ++#define NEW_UNW_V1 (0x4) ++#define NEW_UNW_V2 (0x8) ++#define NEW_UNW_V3 (0x10) ++#define UNW_OUT_OF_SYNC (0x20) /* shared data structures out of sync */ ++#define UNW_READ (0x40) /* kernel unw has been read successfully */ ++#define MEM_LIMIT (0x80) ++#define UNW_PTREGS (0x100) ++#define UNW_R0 (0x200) ++ ++#undef IA64_RBS_OFFSET ++#undef IA64_STK_OFFSET ++#define IA64_RBS_OFFSET ((SIZE(task_struct) + 15) & ~15) ++#define IA64_STK_OFFSET (STACKSIZE()) ++ ++struct machine_specific { ++ ulong cpu_data_address; ++ ulong unimpl_va_mask; ++ ulong unimpl_pa_mask; ++ long unw_tables_offset; ++ long unw_kernel_table_offset; ++ long unw_pt_regs_offsets; ++ int script_index; ++ struct unw_script *script_cache; ++ ulong script_cache_fills; ++ ulong script_cache_hits; ++ void *unw; ++ ulong mem_limit; ++ ulong kernel_region; ++ ulong kernel_start; ++ ulong phys_start; ++ ulong vmalloc_start; ++ char *ia64_memmap; ++ uint64_t efi_memmap_size; ++ uint64_t efi_memdesc_size; ++ void (*unwind_init)(void); ++ void (*unwind)(struct bt_info *); ++ void (*dump_unwind_stats)(void); ++ int (*unwind_debug)(ulong); ++ int ia64_init_stack_size; ++}; ++ ++ ++/* ++ * unwind.c ++ */ ++void unwind_init_v1(void); ++void unwind_v1(struct bt_info *); ++void dump_unwind_stats_v1(void); ++int unwind_debug_v1(ulong); ++ ++void unwind_init_v2(void); ++void unwind_v2(struct bt_info *); ++void dump_unwind_stats_v2(void); ++int unwind_debug_v2(ulong); ++ ++void unwind_init_v3(void); ++void unwind_v3(struct bt_info *); ++void dump_unwind_stats_v3(void); ++int unwind_debug_v3(ulong); ++ ++#endif /* IA64 */ ++ ++/* ++ * s390.c ++ */ ++#ifdef S390 ++void s390_init(int); ++void s390_dump_machdep_table(ulong); ++#define display_idt_table() \ ++ error(FATAL, "-d option is not applicable to S390 architecture\n") ++#define KSYMS_START (0x1) ++#endif ++ ++/* ++ * s390_dump.c ++ */ ++int is_s390_dump(char *); ++FILE* s390_dump_init(char *); ++int read_s390_dumpfile(int, void *, int, ulong, physaddr_t); ++int write_s390_dumpfile(int, void *, int, ulong, physaddr_t); ++uint s390_page_size(void); ++int s390_memory_used(void); ++int s390_free_memory(void); ++int s390_memory_dump(FILE *); ++ulong get_s390_panic_task(void); ++void get_s390_panicmsg(char *); ++ ++/* ++ * s390x.c ++ */ ++#ifdef S390X ++void s390x_init(int); ++void s390x_dump_machdep_table(ulong); ++#define display_idt_table() \ ++ error(FATAL, "-d option is not applicable to S390X architecture\n") ++#define KSYMS_START (0x1) ++#endif ++ ++/* ++ * mips.c ++ */ ++void mips_display_regs_from_elf_notes(int, FILE *); ++ ++#ifdef MIPS ++void mips_init(int); ++void mips_dump_machdep_table(ulong); ++ ++#define display_idt_table() \ ++ error(FATAL, "-d option is not applicable to MIPS architecture\n") ++ ++struct mips_regset { ++ ulong regs[45]; ++}; ++ ++struct mips_pt_regs_main { ++ ulong regs[32]; ++ ulong cp0_status; ++ ulong hi; ++ ulong lo; ++}; ++ ++struct mips_pt_regs_cp0 { ++ ulong cp0_badvaddr; ++ ulong cp0_cause; ++ ulong cp0_epc; ++}; ++ ++#define KSYMS_START (0x1) ++#define PHYS_BASE (0x2) ++ ++#define KVBASE_MASK (0x1ffffff) ++ ++struct machine_specific { ++ ulong phys_base; ++ ulong vmalloc_start_addr; ++ ulong modules_vaddr; ++ ulong modules_end; ++ ++ ulong _page_present; ++ ulong _page_read; ++ ulong _page_write; ++ ulong _page_accessed; ++ ulong _page_modified; ++ ulong _page_global; ++ ulong _page_valid; ++ ulong _page_no_read; ++ ulong _page_no_exec; ++ ulong _page_dirty; ++ ++ ulong _pfn_shift; ++ ++#define _PAGE_PRESENT (machdep->machspec->_page_present) ++#define _PAGE_READ (machdep->machspec->_page_read) ++#define _PAGE_WRITE (machdep->machspec->_page_write) ++#define _PAGE_ACCESSED (machdep->machspec->_page_accessed) ++#define _PAGE_MODIFIED (machdep->machspec->_page_modified) ++#define _PAGE_GLOBAL (machdep->machspec->_page_global) ++#define _PAGE_VALID (machdep->machspec->_page_valid) ++#define _PAGE_NO_READ (machdep->machspec->_page_no_read) ++#define _PAGE_NO_EXEC (machdep->machspec->_page_no_exec) ++#define _PAGE_DIRTY (machdep->machspec->_page_dirty) ++#define _PFN_SHIFT (machdep->machspec->_pfn_shift) ++ ++ struct mips_regset *crash_task_regs; ++}; ++#endif /* MIPS */ ++ ++/* ++ * mips64.c ++ */ ++void mips64_display_regs_from_elf_notes(int, FILE *); ++ ++#ifdef MIPS64 ++void mips64_init(int); ++void mips64_dump_machdep_table(ulong); ++ ++#define display_idt_table() \ ++ error(FATAL, "-d option is not applicable to MIPS64 architecture\n") ++ ++/* from arch/mips/include/uapi/asm/ptrace.h */ ++struct mips64_register { ++ ulong regs[45]; ++}; ++ ++struct mips64_pt_regs_main { ++ ulong regs[32]; ++ ulong cp0_status; ++ ulong hi; ++ ulong lo; ++}; ++ ++struct mips64_pt_regs_cp0 { ++ ulong cp0_badvaddr; ++ ulong cp0_cause; ++ ulong cp0_epc; ++}; ++ ++struct mips64_unwind_frame { ++ unsigned long sp; ++ unsigned long pc; ++ unsigned long ra; ++}; ++ ++#define KSYMS_START (0x1) ++ ++struct machine_specific { ++ ulong phys_base; ++ ulong vmalloc_start_addr; ++ ulong modules_vaddr; ++ ulong modules_end; ++ ++ ulong _page_present; ++ ulong _page_read; ++ ulong _page_write; ++ ulong _page_accessed; ++ ulong _page_modified; ++ ulong _page_huge; ++ ulong _page_special; ++ ulong _page_protnone; ++ ulong _page_global; ++ ulong _page_valid; ++ ulong _page_no_read; ++ ulong _page_no_exec; ++ ulong _page_dirty; ++ ++ ulong _pfn_shift; ++ ++ struct mips64_register *crash_task_regs; ++}; ++/* from arch/mips/include/asm/pgtable-bits.h */ ++#define _PAGE_PRESENT (machdep->machspec->_page_present) ++#define _PAGE_READ (machdep->machspec->_page_read) ++#define _PAGE_WRITE (machdep->machspec->_page_write) ++#define _PAGE_ACCESSED (machdep->machspec->_page_accessed) ++#define _PAGE_MODIFIED (machdep->machspec->_page_modified) ++#define _PAGE_HUGE (machdep->machspec->_page_huge) ++#define _PAGE_SPECIAL (machdep->machspec->_page_special) ++#define _PAGE_PROTNONE (machdep->machspec->_page_protnone) ++#define _PAGE_GLOBAL (machdep->machspec->_page_global) ++#define _PAGE_VALID (machdep->machspec->_page_valid) ++#define _PAGE_NO_READ (machdep->machspec->_page_no_read) ++#define _PAGE_NO_EXEC (machdep->machspec->_page_no_exec) ++#define _PAGE_DIRTY (machdep->machspec->_page_dirty) ++#define _PFN_SHIFT (machdep->machspec->_pfn_shift) ++ ++#endif /* MIPS64 */ ++ ++/* ++ * sparc64.c ++ */ ++#ifdef SPARC64 ++void sparc64_init(int); ++void sparc64_dump_machdep_table(ulong); ++int sparc64_vmalloc_addr(ulong); ++#define display_idt_table() \ ++ error(FATAL, "The -d option is not applicable to sparc64.\n") ++#endif ++ ++/* ++ * netdump.c ++ */ ++int is_netdump(char *, ulong); ++uint netdump_page_size(void); ++int read_netdump(int, void *, int, ulong, physaddr_t); ++int write_netdump(int, void *, int, ulong, physaddr_t); ++int netdump_free_memory(void); ++int netdump_memory_used(void); ++int netdump_init(char *, FILE *); ++ulong get_netdump_panic_task(void); ++ulong get_netdump_switch_stack(ulong); ++FILE *set_netdump_fp(FILE *); ++int netdump_memory_dump(FILE *); ++void get_netdump_regs(struct bt_info *, ulong *, ulong *); ++int is_partial_netdump(void); ++void get_netdump_regs_x86(struct bt_info *, ulong *, ulong *); ++void get_netdump_regs_x86_64(struct bt_info *, ulong *, ulong *); ++void dump_registers_for_elf_dumpfiles(void); ++struct vmcore_data; ++struct vmcore_data *get_kdump_vmcore_data(void); ++int read_kdump(int, void *, int, ulong, physaddr_t); ++int write_kdump(int, void *, int, ulong, physaddr_t); ++int is_kdump(char *, ulong); ++int kdump_init(char *, FILE *); ++ulong get_kdump_panic_task(void); ++uint kdump_page_size(void); ++int kdump_free_memory(void); ++int kdump_memory_used(void); ++int kdump_memory_dump(FILE *); ++void get_kdump_regs(struct bt_info *, ulong *, ulong *); ++void xen_kdump_p2m_mfn(char *); ++int is_sadump_xen(void); ++void set_xen_phys_start(char *); ++ulong xen_phys_start(void); ++int xen_major_version(void); ++int xen_minor_version(void); ++int get_netdump_arch(void); ++int exist_regs_in_elf_notes(struct task_context *); ++void *get_regs_from_elf_notes(struct task_context *); ++void map_cpus_to_prstatus(void); ++int kdump_phys_base(ulong *); ++int kdump_set_phys_base(ulong); ++int arm_kdump_phys_base(ulong *); ++int arm_kdump_phys_end(ulong *); ++int is_proc_kcore(char *, ulong); ++int proc_kcore_init(FILE *, int); ++int read_proc_kcore(int, void *, int, ulong, physaddr_t); ++int write_proc_kcore(int, void *, int, ulong, physaddr_t); ++int kcore_memory_dump(FILE *); ++void dump_registers_for_qemu_mem_dump(void); ++void kdump_backup_region_init(void); ++void display_regs_from_elf_notes(int, FILE *); ++void display_ELF_note(int, int, void *, FILE *); ++void *netdump_get_prstatus_percpu(int); ++int kdump_kaslr_check(void); ++void display_vmcoredd_note(void *ptr, FILE *ofp); ++int kdump_get_nr_cpus(void); ++QEMUCPUState *kdump_get_qemucpustate(int); ++void kdump_device_dump_info(FILE *); ++void kdump_device_dump_extract(int, char *, FILE *); ++#define PRSTATUS_NOTE (1) ++#define QEMU_NOTE (2) ++ ++/* ++ * ramdump.c ++ */ ++int is_ramdump(char *pattern); ++char *ramdump_to_elf(void); ++void ramdump_elf_output_file(char *opt); ++void ramdump_cleanup(void); ++int read_ramdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr); ++void show_ramdump_files(void); ++void dump_ramdump_data(void); ++int is_ramdump_image(void); ++ ++/* ++ * diskdump.c ++ */ ++int is_diskdump(char *); ++uint diskdump_page_size(void); ++int read_diskdump(int, void *, int, ulong, physaddr_t); ++int write_diskdump(int, void *, int, ulong, physaddr_t); ++int diskdump_free_memory(void); ++int diskdump_memory_used(void); ++int diskdump_init(char *, FILE *); ++ulong get_diskdump_panic_task(void); ++ulong get_diskdump_switch_stack(ulong); ++int diskdump_memory_dump(FILE *); ++FILE *set_diskdump_fp(FILE *); ++void get_diskdump_regs(struct bt_info *, ulong *, ulong *); ++int diskdump_phys_base(unsigned long *); ++int diskdump_set_phys_base(unsigned long); ++extern ulong *diskdump_flags; ++int is_partial_diskdump(void); ++int get_dump_level(void); ++int dumpfile_is_split(void); ++void show_split_dumpfiles(void); ++void x86_process_elf_notes(void *, unsigned long); ++void *diskdump_get_prstatus_percpu(int); ++void map_cpus_to_prstatus_kdump_cmprs(void); ++void diskdump_display_regs(int, FILE *); ++void process_elf32_notes(void *, ulong); ++void process_elf64_notes(void *, ulong); ++void dump_registers_for_compressed_kdump(void); ++int diskdump_kaslr_check(void); ++int diskdump_get_nr_cpus(void); ++QEMUCPUState *diskdump_get_qemucpustate(int); ++void diskdump_device_dump_info(FILE *); ++void diskdump_device_dump_extract(int, char *, FILE *); ++ulong readswap(ulonglong pte_val, char *buf, ulong len, ulonglong vaddr); ++/*support for zram*/ ++ulong try_zram_decompress(ulonglong pte_val, unsigned char *buf, ulong len, ulonglong vaddr); ++#define OBJ_TAG_BITS 1 ++#ifndef MAX_POSSIBLE_PHYSMEM_BITS ++#define MAX_POSSIBLE_PHYSMEM_BITS (MAX_PHYSMEM_BITS()) ++#endif ++#define _PFN_BITS (MAX_POSSIBLE_PHYSMEM_BITS - PAGESHIFT()) ++#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS - OBJ_TAG_BITS) ++#define OBJ_INDEX_MASK ((1 << OBJ_INDEX_BITS) - 1) ++#define ZS_HANDLE_SIZE (sizeof(unsigned long)) ++#define ZSPAGE_MAGIC 0x58 ++#define SWAP_ADDRESS_SPACE_SHIFT 14 ++#define SECTOR_SHIFT 9 ++#define SECTORS_PER_PAGE_SHIFT (PAGESHIFT() - SECTOR_SHIFT) ++#define SECTORS_PER_PAGE (1 << SECTORS_PER_PAGE_SHIFT) ++#define ZRAM_FLAG_SHIFT (1<<24) ++#define ZRAM_FLAG_SAME_BIT (1<<25) ++struct zspage { ++ struct { ++ unsigned int fullness : 2; ++ unsigned int class : 9; ++ unsigned int isolated : 3; ++ unsigned int magic : 8; ++ }; ++ unsigned int inuse; ++ unsigned int freeobj; ++}; ++ ++/* ++ * makedumpfile.c ++ */ ++void check_flattened_format(char *file); ++int is_flattened_format(char *file); ++int read_flattened_format(int fd, off_t offset, void *buf, size_t size); ++void dump_flat_header(FILE *); ++ ++/* ++ * xendump.c ++ */ ++int is_xendump(char *); ++int read_xendump(int, void *, int, ulong, physaddr_t); ++int write_xendump(int, void *, int, ulong, physaddr_t); ++uint xendump_page_size(void); ++int xendump_free_memory(void); ++int xendump_memory_used(void); ++int xendump_init(char *, FILE *); ++int xendump_memory_dump(FILE *); ++ulong get_xendump_panic_task(void); ++void get_xendump_regs(struct bt_info *, ulong *, ulong *); ++char *xc_core_mfn_to_page(ulong, char *); ++int xc_core_mfn_to_page_index(ulong); ++void xendump_panic_hook(char *); ++int read_xendump_hyper(int, void *, int, ulong, physaddr_t); ++struct xendump_data *get_xendump_data(void); ++ ++/* ++ * kvmdump.c ++ */ ++int is_kvmdump(char *); ++int is_kvmdump_mapfile(char *); ++int kvmdump_init(char *, FILE *); ++int read_kvmdump(int, void *, int, ulong, physaddr_t); ++int write_kvmdump(int, void *, int, ulong, physaddr_t); ++int kvmdump_free_memory(void); ++int kvmdump_memory_used(void); ++int kvmdump_memory_dump(FILE *); ++void get_kvmdump_regs(struct bt_info *, ulong *, ulong *); ++ulong get_kvmdump_panic_task(void); ++int kvmdump_phys_base(unsigned long *); ++void kvmdump_display_regs(int, FILE *); ++void set_kvmhost_type(char *); ++void set_kvm_iohole(char *); ++struct kvm_register_set { ++ union { ++ uint32_t cs; ++ uint32_t ss; ++ uint32_t ds; ++ uint32_t es; ++ uint32_t fs; ++ uint32_t gs; ++ uint64_t ip; ++ uint64_t flags; ++ uint64_t regs[16]; ++ } x86; ++}; ++int get_kvm_register_set(int, struct kvm_register_set *); ++ ++/* ++ * sadump.c ++ */ ++int is_sadump(char *); ++uint sadump_page_size(void); ++int read_sadump(int, void *, int, ulong, physaddr_t); ++int write_sadump(int, void *, int, ulong, physaddr_t); ++int sadump_init(char *, FILE *); ++int sadump_is_diskset(void); ++ulong get_sadump_panic_task(void); ++ulong get_sadump_switch_stack(ulong); ++int sadump_memory_used(void); ++int sadump_free_memory(void); ++int sadump_memory_dump(FILE *); ++FILE *set_sadump_fp(FILE *); ++void get_sadump_regs(struct bt_info *bt, ulong *ipp, ulong *spp); ++void sadump_display_regs(int, FILE *); ++int sadump_phys_base(ulong *); ++int sadump_set_phys_base(ulong); ++void sadump_show_diskset(void); ++int sadump_is_zero_excluded(void); ++void sadump_set_zero_excluded(void); ++void sadump_unset_zero_excluded(void); ++struct sadump_data; ++struct sadump_data *get_sadump_data(void); ++int sadump_calc_kaslr_offset(ulong *); ++int sadump_get_nr_cpus(void); ++int sadump_get_cr3_cr4_idtr(int, ulong *, ulong *, ulong *); ++ ++/* ++ * qemu.c ++ */ ++int qemu_init(char *); ++ ++/* ++ * qemu-load.c ++ */ ++int is_qemu_vm_file(char *); ++void dump_qemu_header(FILE *); ++ ++/* ++ * net.c ++ */ ++void net_init(void); ++void dump_net_table(void); ++void dump_sockets_workhorse(ulong, ulong, struct reference *); ++ ++/* ++ * remote.c ++ */ ++int is_remote_daemon(char *); ++physaddr_t get_remote_phys_base(physaddr_t, physaddr_t); ++physaddr_t remote_vtop(int, physaddr_t); ++int get_remote_regs(struct bt_info *, ulong *, ulong *); ++physaddr_t get_remote_cr3(int); ++void remote_fd_init(void); ++int get_remote_file(struct remote_file *); ++uint remote_page_size(void); ++int find_remote_module_objfile(struct load_module *lm, char *, char *); ++int remote_free_memory(void); ++int remote_memory_dump(int); ++int remote_memory_used(void); ++void remote_exit(void); ++int remote_execute(void); ++void remote_clear_pipeline(void); ++int remote_memory_read(int, char *, int, physaddr_t, int); ++ ++/* ++ * vmware_vmss.c ++ */ ++int is_vmware_vmss(char *filename); ++int vmware_vmss_init(char *filename, FILE *ofp); ++uint vmware_vmss_page_size(void); ++int read_vmware_vmss(int, void *, int, ulong, physaddr_t); ++int write_vmware_vmss(int, void *, int, ulong, physaddr_t); ++void vmware_vmss_display_regs(int, FILE *); ++void get_vmware_vmss_regs(struct bt_info *, ulong *, ulong *); ++int vmware_vmss_memory_dump(FILE *); ++void dump_registers_for_vmss_dump(void); ++int vmware_vmss_valid_regs(struct bt_info *); ++int vmware_vmss_get_nr_cpus(void); ++int vmware_vmss_get_cr3_cr4_idtr(int, ulong *, ulong *, ulong *); ++int vmware_vmss_phys_base(ulong *phys_base); ++int vmware_vmss_set_phys_base(ulong); ++ ++/* ++ * vmware_guestdump.c ++ */ ++int is_vmware_guestdump(char *filename); ++int vmware_guestdump_init(char *filename, FILE *ofp); ++int vmware_guestdump_memory_dump(FILE *); ++ ++/* ++ * kaslr_helper.c ++ */ ++int calc_kaslr_offset(ulong *, ulong *); ++ ++/* ++ * printk.c ++ */ ++void dump_lockless_record_log(int); ++ ++/* ++ * gnu_binutils.c ++ */ ++ ++/* NO LONGER IN USE */ ++ ++/* ++ * test.c ++ */ ++void cmd_template(void); ++void foreach_test(ulong, ulong); ++ ++/* ++ * va_server.c ++ */ ++int mclx_page_size(void); ++int vas_memory_used(void); ++int vas_memory_dump(FILE *); ++int vas_free_memory(char *); ++void set_vas_debug(ulong); ++size_t vas_write(void *, size_t); ++int va_server_init(char *, ulong *, ulong *, ulong *); ++size_t vas_read(void *, size_t); ++int vas_lseek(ulong, int); ++ ++/* ++ * lkcd_x86_trace.c ++ */ ++int lkcd_x86_back_trace(struct bt_info *, int, FILE *); ++ ++/* ++ * lkcd_common.c ++ */ ++int lkcd_dump_init(FILE *, int, char *); ++ulong get_lkcd_panic_task(void); ++void get_lkcd_panicmsg(char *); ++int is_lkcd_compressed_dump(char *); ++void dump_lkcd_environment(ulong); ++int lkcd_lseek(physaddr_t); ++long lkcd_read(void *, long); ++void set_lkcd_debug(ulong); ++FILE *set_lkcd_fp(FILE *); ++uint lkcd_page_size(void); ++int lkcd_memory_used(void); ++int lkcd_memory_dump(FILE *); ++int lkcd_free_memory(void); ++void lkcd_print(char *, ...); ++void set_remote_lkcd_panic_data(ulong, char *); ++void set_lkcd_nohash(void); ++int lkcd_load_dump_page_header(void *, ulong); ++void lkcd_dumpfile_complaint(uint32_t, uint32_t, int); ++int set_mb_benchmark(ulong); ++ulonglong fix_lkcd_address(ulonglong); ++int lkcd_get_kernel_start(ulong *addr); ++int get_lkcd_regs_for_cpu(struct bt_info *bt, ulong *eip, ulong *esp); ++ ++/* ++ * lkcd_v1.c ++ */ ++int lkcd_dump_init_v1(FILE *, int); ++void dump_dump_page_v1(char *, void *); ++void dump_lkcd_environment_v1(ulong); ++uint32_t get_dp_size_v1(void); ++uint32_t get_dp_flags_v1(void); ++uint64_t get_dp_address_v1(void); ++ ++/* ++ * lkcd_v2_v3.c ++ */ ++int lkcd_dump_init_v2_v3(FILE *, int); ++void dump_dump_page_v2_v3(char *, void *); ++void dump_lkcd_environment_v2_v3(ulong); ++uint32_t get_dp_size_v2_v3(void); ++uint32_t get_dp_flags_v2_v3(void); ++uint64_t get_dp_address_v2_v3(void); ++ ++/* ++ * lkcd_v5.c ++ */ ++int lkcd_dump_init_v5(FILE *, int); ++void dump_dump_page_v5(char *, void *); ++void dump_lkcd_environment_v5(ulong); ++uint32_t get_dp_size_v5(void); ++uint32_t get_dp_flags_v5(void); ++uint64_t get_dp_address_v5(void); ++ ++/* ++ * lkcd_v7.c ++ */ ++int lkcd_dump_init_v7(FILE *, int, char *); ++void dump_dump_page_v7(char *, void *); ++void dump_lkcd_environment_v7(ulong); ++uint32_t get_dp_size_v7(void); ++uint32_t get_dp_flags_v7(void); ++uint64_t get_dp_address_v7(void); ++ ++/* ++ * lkcd_v8.c ++ */ ++int lkcd_dump_init_v8(FILE *, int, char *); ++void dump_dump_page_v8(char *, void *); ++void dump_lkcd_environment_v8(ulong); ++uint32_t get_dp_size_v8(void); ++uint32_t get_dp_flags_v8(void); ++uint64_t get_dp_address_v8(void); ++ ++#ifdef LKCD_COMMON ++/* ++ * Until they differ across versions, these remain usable in the common ++ * routines in lkcd_common.c ++ */ ++#define LKCD_DUMP_MAGIC_NUMBER (0xa8190173618f23edULL) ++#define LKCD_DUMP_MAGIC_LIVE (0xa8190173618f23cdULL) ++ ++#define LKCD_DUMP_V1 (0x1) /* DUMP_VERSION_NUMBER */ ++#define LKCD_DUMP_V2 (0x2) /* DUMP_VERSION_NUMBER */ ++#define LKCD_DUMP_V3 (0x3) /* DUMP_VERSION_NUMBER */ ++#define LKCD_DUMP_V5 (0x5) /* DUMP_VERSION_NUMBER */ ++#define LKCD_DUMP_V6 (0x6) /* DUMP_VERSION_NUMBER */ ++#define LKCD_DUMP_V7 (0x7) /* DUMP_VERSION_NUMBER */ ++#define LKCD_DUMP_V8 (0x8) /* DUMP_VERSION_NUMBER */ ++#define LKCD_DUMP_V9 (0x9) /* DUMP_VERSION_NUMBER */ ++#define LKCD_DUMP_V10 (0xa) /* DUMP_VERSION_NUMBER */ ++ ++#define LKCD_DUMP_VERSION_NUMBER_MASK (0xf) ++#define LKCD_DUMP_RAW (0x1) /* DUMP_[DH_]RAW */ ++#define LKCD_DUMP_COMPRESSED (0x2) /* DUMP_[DH_]COMPRESSED */ ++#define LKCD_DUMP_END (0x4) /* DUMP_[DH_]END */ ++ ++#define LKCD_DUMP_COMPRESS_NONE (0x0) /* DUMP_COMPRESS_NONE */ ++#define LKCD_DUMP_COMPRESS_RLE (0x1) /* DUMP_COMPRESS_RLE */ ++#define LKCD_DUMP_COMPRESS_GZIP (0x2) /* DUMP_COMPRESS_GZIP */ ++ ++#define LKCD_DUMP_MCLX_V0 (0x80000000) /* MCLX mod of LKCD */ ++#define LKCD_DUMP_MCLX_V1 (0x40000000) /* Extra page header data */ ++#define LKCD_OFFSET_TO_FIRST_PAGE (65536) ++ ++#define MCLX_PAGE_HEADERS (4096) ++#define MCLX_V1_PAGE_HEADER_CACHE ((sizeof(uint64_t)) * MCLX_PAGE_HEADERS) ++ ++/* ++ * lkcd_load_dump_page_header() return values ++ */ ++#define LKCD_DUMPFILE_OK (0) ++#define LKCD_DUMPFILE_EOF (1) ++#define LKCD_DUMPFILE_END (2) ++ ++/* ++ * Common handling of LKCD dump environment ++ */ ++#define LKCD_CACHED_PAGES (16) ++#define LKCD_PAGE_HASH (32) ++#define LKCD_DUMP_HEADER_ONLY (1) /* arguments to lkcd_dump_environment */ ++#define LKCD_DUMP_PAGE_ONLY (2) ++ ++#define LKCD_VALID (0x1) /* flags */ ++#define LKCD_REMOTE (0x2) ++#define LKCD_NOHASH (0x4) ++#define LKCD_MCLX (0x8) ++#define LKCD_BAD_DUMP (0x10) ++ ++struct page_hash_entry { ++ uint32_t pg_flags; ++ uint64_t pg_addr; ++ off_t pg_hdr_offset; ++ struct page_hash_entry *next; ++}; ++ ++struct page_desc { ++ off_t offset; /* lseek offset in dump file */ ++}; ++ ++struct physmem_zone { ++ uint64_t start; ++ struct page_desc *pages; ++}; ++ ++struct fix_addrs { ++ ulong task; ++ ulong saddr; ++ ulong sw; ++}; ++ ++ ++struct lkcd_environment { ++ int fd; /* dumpfile file descriptor */ ++ ulong flags; /* flags from above */ ++ ulong debug; /* shadow of pc->debug */ ++ FILE *fp; /* abstracted fp for fprintf */ ++ void *dump_header; /* header stash, v1 or v2 */ ++ void *dump_header_asm; /* architecture specific header for v2 */ ++ void *dump_header_asm_smp; /* architecture specific header for v7 & v8 */ ++ void *dump_page; /* current page header holder */ ++ uint32_t version; /* version number of this dump */ ++ uint32_t page_size; /* size of a Linux memory page */ ++ int page_shift; /* byte address to page */ ++ int bits; /* processor bitsize */ ++ ulong panic_task; /* panic task address */ ++ char *panic_string; /* pointer to stashed panic string */ ++ uint32_t compression; /* compression type */ ++ uint32_t (*get_dp_size)(void); /* returns current page's dp_size */ ++ uint32_t (*get_dp_flags)(void); /* returns current page's dp_size */ ++ uint64_t (*get_dp_address)(void); /* returns current page's dp_address*/ ++ size_t page_header_size; /* size of version's page header */ ++ unsigned long curpos; /* offset into current page */ ++ uint64_t curpaddr; /* current page's physical address */ ++ off_t curhdroffs; /* current page's header offset */ ++ char *curbufptr; /* pointer to uncompressed page buffer */ ++ uint64_t kvbase; /* physical-to-LKCD page address format*/ ++ char *page_cache_buf; /* base of cached buffer pages */ ++ char *compressed_page; /* copy of compressed page data */ ++ int evict_index; /* next page to evict */ ++ ulong evictions; /* total evictions done */ ++ struct page_cache_hdr { /* header for each cached page */ ++ uint32_t pg_flags; ++ uint64_t pg_addr; ++ char *pg_bufptr; ++ ulong pg_hit_count; ++ } page_cache_hdr[LKCD_CACHED_PAGES]; ++ struct page_hash_entry *page_hash; ++ ulong total_pages; ++ ulong benchmark_pages; ++ ulong benchmarks_done; ++ off_t *mb_hdr_offsets; ++ ulong total_reads; ++ ulong cached_reads; ++ ulong hashed_reads; ++ ulong hashed; ++ ulong compressed; ++ ulong raw; ++ ++ /* lkcd_v7 additions */ ++ char *dumpfile_index; /* array of offsets for each page */ ++ int ifd; /* index file for dump (LKCD V7+) */ ++ long memory_pages; /* Mamimum index of dump pages */ ++ off_t page_offset_max; /* Offset of page with greatest offset seen so far */ ++ long page_index_max; /* Index of page with greatest offset seen so far */ ++ off_t *page_offsets; /* Pointer to huge array with seek offsets */ ++ /* NB: There are no holes in the array */ ++ ++ struct physmem_zone *zones; /* Array of physical memory zones */ ++ int num_zones; /* Number of zones initialized */ ++ int max_zones; /* Size of the zones array */ ++ long zoned_offsets; /* Number of stored page offsets */ ++ uint64_t zone_mask; ++ int zone_shift; ++ ++ int fix_addr_num; /* Number of active stacks to switch to saved values */ ++ struct fix_addrs *fix_addr; /* Array of active stacks to switch to saved values */ ++ ++ ++}; ++ ++#define ZONE_ALLOC 128 ++#define ZONE_SIZE (MEGABYTES(512)) ++ ++#define MEGABYTE_ALIGNED(vaddr) (!((uint64_t)(vaddr) & MEGABYTE_MASK)) ++ ++#define LKCD_PAGE_HASH_INDEX(paddr) \ ++ (((paddr) >> lkcd->page_shift) % LKCD_PAGE_HASH) ++#define LKCD_PAGES_PER_MEGABYTE() (MEGABYTES(1) / lkcd->page_size) ++#define LKCD_PAGE_MEGABYTE(page) ((page) / LKCD_PAGES_PER_MEGABYTE()) ++#define LKCD_BENCHMARKS_DONE() (lkcd->benchmarks_done >= lkcd->benchmark_pages) ++#define LKCD_VALID_PAGE(flags) ((flags) & LKCD_VALID) ++ ++extern struct lkcd_environment *lkcd; ++ ++#define LKCD_DEBUG(x) (lkcd->debug >= (x)) ++#undef BITS ++#undef BITS32 ++#undef BITS64 ++#define BITS() (lkcd->bits) ++#define BITS32() (lkcd->bits == 32) ++#define BITS64() (lkcd->bits == 64) ++ ++#endif /* LKCD_COMMON */ ++ ++/* ++ * gdb_interface.c ++ */ ++void gdb_main_loop(int, char **); ++void display_gdb_banner(void); ++void get_gdb_version(void); ++void gdb_session_init(void); ++void gdb_interface(struct gnu_request *); ++int gdb_pass_through(char *, FILE *, ulong); ++int gdb_readmem_callback(ulong, void *, int, int); ++int gdb_line_number_callback(ulong, ulong, ulong); ++int gdb_print_callback(ulong); ++void gdb_error_hook(void); ++void restore_gdb_sanity(void); ++int is_gdb_command(int, ulong); ++char *gdb_command_string(int, char *, int); ++void dump_gnu_request(struct gnu_request *, int); ++int gdb_CRASHDEBUG(ulong); ++void dump_gdb_data(void); ++void update_gdb_hooks(void); ++void gdb_readnow_warning(void); ++int gdb_set_crash_scope(ulong, char *); ++extern int *gdb_output_format; ++extern unsigned int *gdb_print_max; ++extern int *gdb_prettyprint_structs; ++extern int *gdb_prettyprint_arrays; ++extern int *gdb_repeat_count_threshold; ++extern int *gdb_stop_print_at_null; ++extern unsigned int *gdb_output_radix; ++ ++/* ++ * gdb/top.c ++ */ ++extern void execute_command (char *, int); ++#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) ++extern void (*command_loop_hook)(void); ++extern void (*error_hook)(void); ++#else ++extern void (*deprecated_command_loop_hook)(void); ++ ++/* ++ * gdb/exceptions.c ++ */ ++extern void (*error_hook)(void); ++#endif ++ ++/* ++ * gdb/symtab.c ++ */ ++extern void gdb_command_funnel(struct gnu_request *); ++ ++/* ++ * gdb/symfile.c ++ */ ++#if defined(GDB_6_0) || defined(GDB_6_1) ++struct objfile; ++extern void (*target_new_objfile_hook)(struct objfile *); ++#endif ++ ++/* ++ * gdb/valprint.c ++ */ ++extern unsigned output_radix; ++#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) ++extern int output_format; ++extern int prettyprint_structs; ++extern int prettyprint_arrays; ++extern int repeat_count_threshold; ++extern unsigned int print_max; ++extern int stop_print_at_null; ++#endif ++ ++#ifdef GDB_7_6 ++/* ++ * gdb/cleanups.c ++ */ ++struct cleanup; ++extern struct cleanup *all_cleanups(void); ++extern void do_cleanups(struct cleanup *); ++#else ++/* ++ * gdb/utils.c ++ */ ++extern void do_cleanups(void *); ++#endif ++ ++/* ++ * gdb/version.c ++ */ ++extern char *version; ++ ++/* ++ * gdb/disasm.c ++ */ ++#ifdef GDB_5_3 ++extern int gdb_disassemble_from_exec; ++#endif ++ ++/* ++ * readline/readline.c ++ */ ++#ifdef GDB_5_3 ++extern char *readline(char *); ++#else ++extern char *readline(const char *); ++#endif ++extern int rl_editing_mode; ++ ++/* ++ * readline/history.c ++ */ ++extern int history_offset; ++ ++/* ++ * external gdb routines ++ */ ++extern int gdb_main_entry(int, char **); ++#ifdef GDB_5_3 ++extern unsigned long calc_crc32(unsigned long, unsigned char *, size_t); ++#else ++extern unsigned long gnu_debuglink_crc32 (unsigned long, unsigned char *, size_t); ++#endif ++extern int have_partial_symbols(void); ++extern int have_full_symbols(void); ++ ++#if defined(X86) || defined(X86_64) || defined(IA64) ++#define XEN_HYPERVISOR_ARCH ++#endif ++ ++#endif /* !GDB_COMMON */ +diff -Nur crash-7.3.0-orig/diskdump.c crash-7.3.0/diskdump.c +--- crash-7.3.0-orig/diskdump.c 2023-07-07 14:06:14.177365972 +0800 ++++ crash-7.3.0/diskdump.c 2023-07-07 14:08:21.999028204 +0800 +@@ -76,6 +76,7 @@ + ulong evictions; /* total evictions done */ + ulong cached_reads; + ulong *valid_pages; ++ int max_sect_len; /* highest bucket of valid_pages */ + ulong accesses; + ulong snapshot_task; + }; +@@ -510,6 +511,27 @@ + } + #endif /* __i386__ && (ARM || MIPS) */ + ++/* ++ * Read page descriptor. ++ */ ++static int ++read_pd(int fd, off_t offset, page_desc_t *pd) ++{ ++ const off_t failed = (off_t)-1; ++ ++ if (FLAT_FORMAT()) { ++ if (!read_flattened_format(fd, offset, pd, sizeof(*pd))) ++ return READ_ERROR; ++ } else { ++ if (lseek(fd, offset, SEEK_SET) == failed) ++ return SEEK_ERROR; ++ if (read(fd, pd, sizeof(*pd)) != sizeof(*pd)) ++ return READ_ERROR; ++ } ++ ++ return 0; ++} ++ + static int + read_dump_header(char *file) + { +@@ -878,6 +900,7 @@ + } + + dd->valid_pages = calloc(sizeof(ulong), max_sect_len + 1); ++ dd->max_sect_len = max_sect_len; + for (i = 1; i < max_sect_len + 1; i++) { + dd->valid_pages[i] = dd->valid_pages[i - 1]; + for (j = 0; j < BITMAP_SECT_LEN; j++, pfn++) +@@ -979,6 +1002,9 @@ + #ifdef SNAPPY + dd->flags |= SNAPPY_SUPPORTED; + #endif ++#ifdef ZSTD ++ dd->flags |= ZSTD_SUPPORTED; ++#endif + + pc->read_vmcoreinfo = vmcoreinfo_read_string; + +@@ -1102,6 +1128,9 @@ + const int block_size = dd->block_size; + const off_t failed = (off_t)-1; + ulong retlen; ++#ifdef ZSTD ++ static ZSTD_DCtx *dctx = NULL; ++#endif + + for (i = found = 0; i < DISKDUMP_CACHED_PAGES; i++) { + if (DISKDUMP_VALID_PAGE(dd->page_cache_hdr[i].pg_flags)) +@@ -1129,15 +1158,9 @@ + + (off_t)(desc_pos - 1)*sizeof(page_desc_t); + + /* read page descriptor */ +- if (FLAT_FORMAT()) { +- if (!read_flattened_format(dd->dfd, seek_offset, &pd, sizeof(pd))) +- return READ_ERROR; +- } else { +- if (lseek(dd->dfd, seek_offset, SEEK_SET) == failed) +- return SEEK_ERROR; +- if (read(dd->dfd, &pd, sizeof(pd)) != sizeof(pd)) +- return READ_ERROR; +- } ++ ret = read_pd(dd->dfd, seek_offset, &pd); ++ if (ret) ++ return ret; + + /* sanity check */ + if (pd.size > block_size) +@@ -1147,10 +1170,9 @@ + if (FLAT_FORMAT()) { + if (!read_flattened_format(dd->dfd, pd.offset, dd->compressed_page, pd.size)) + return READ_ERROR; +- } else if (is_incomplete_dump() && (0 == pd.offset)) { ++ } else if (0 == pd.offset) { + /* +- * If the incomplete flag has been set in the header, +- * first check whether zero_excluded has been set. ++ * First check whether zero_excluded has been set. + */ + if (*diskdump_flags & ZERO_EXCLUDED) { + if (CRASHDEBUG(8)) +@@ -1159,8 +1181,15 @@ + "paddr/pfn: %llx/%lx\n", + (ulonglong)paddr, pfn); + memset(dd->compressed_page, 0, dd->block_size); +- } else +- return READ_ERROR; ++ } else { ++ if (CRASHDEBUG(8)) ++ fprintf(fp, ++ "read_diskdump/cache_page: " ++ "descriptor with zero offset found at " ++ "paddr/pfn/pos: %llx/%lx/%lx\n", ++ (ulonglong)paddr, pfn, desc_pos); ++ return PAGE_INCOMPLETE; ++ } + } else { + if (lseek(dd->dfd, pd.offset, SEEK_SET) == failed) + return SEEK_ERROR; +@@ -1230,6 +1259,33 @@ + return READ_ERROR; + } + #endif ++ } else if (pd.flags & DUMP_DH_COMPRESSED_ZSTD) { ++ ++ if (!(dd->flags & ZSTD_SUPPORTED)) { ++ error(INFO, "%s: uncompess failed: no zstd compression support\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); ++ return READ_ERROR; ++ } ++#ifdef ZSTD ++ if (!dctx) { ++ dctx = ZSTD_createDCtx(); ++ if (!dctx) { ++ error(INFO, "%s: uncompess failed: cannot create ZSTD_DCtx\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); ++ return READ_ERROR; ++ } ++ } ++ ++ retlen = ZSTD_decompressDCtx(dctx, ++ dd->page_cache_hdr[i].pg_bufptr, block_size, ++ dd->compressed_page, pd.size); ++ if (ZSTD_isError(retlen) || (retlen != block_size)) { ++ error(INFO, "%s: uncompress failed: %d (%s)\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump", ++ retlen, ZSTD_getErrorName(retlen)); ++ return READ_ERROR; ++ } ++#endif + } else + memcpy(dd->page_cache_hdr[i].pg_bufptr, + dd->compressed_page, block_size); +@@ -1784,6 +1840,8 @@ + fprintf(fp, "%sLZO_SUPPORTED", others++ ? "|" : ""); + if (dd->flags & SNAPPY_SUPPORTED) + fprintf(fp, "%sSNAPPY_SUPPORTED", others++ ? "|" : ""); ++ if (dd->flags & ZSTD_SUPPORTED) ++ fprintf(fp, "%sZSTD_SUPPORTED", others++ ? "|" : ""); + fprintf(fp, ") %s\n", FLAT_FORMAT() ? "[FLAT]" : ""); + fprintf(fp, " dfd: %d\n", dd->dfd); + fprintf(fp, " ofp: %lx\n", (ulong)dd->ofp); +@@ -1850,6 +1908,8 @@ + fprintf(fp, "DUMP_DH_COMPRESSED_LZO"); + if (dh->status & DUMP_DH_COMPRESSED_SNAPPY) + fprintf(fp, "DUMP_DH_COMPRESSED_SNAPPY"); ++ if (dh->status & DUMP_DH_COMPRESSED_ZSTD) ++ fprintf(fp, "DUMP_DH_COMPRESSED_ZSTD"); + if (dh->status & DUMP_DH_COMPRESSED_INCOMPLETE) + fprintf(fp, "DUMP_DH_COMPRESSED_INCOMPLETE"); + if (dh->status & DUMP_DH_EXCLUDED_VMEMMAP) +@@ -2084,6 +2144,7 @@ + else + fprintf(fp, "\n"); + fprintf(fp, " valid_pages: %lx\n", (ulong)dd->valid_pages); ++ fprintf(fp, " total_valid_pages: %ld\n", dd->valid_pages[dd->max_sect_len]); + + return 0; + } +@@ -2533,13 +2594,22 @@ + return FALSE; + } + +-#ifdef X86_64 + int + diskdump_get_nr_cpus(void) + { +- return dd->num_qemu_notes; ++ if (dd->num_prstatus_notes) ++ return dd->num_prstatus_notes; ++ else if (dd->num_qemu_notes) ++ return dd->num_qemu_notes; ++ else if (dd->num_vmcoredd_notes) ++ return dd->num_vmcoredd_notes; ++ else if (dd->header->nr_cpus) ++ return dd->header->nr_cpus; ++ ++ return 1; + } + ++#ifdef X86_64 + QEMUCPUState * + diskdump_get_qemucpustate(int cpu) + { +diff -Nur crash-7.3.0-orig/diskdump.c.orig crash-7.3.0/diskdump.c.orig +--- crash-7.3.0-orig/diskdump.c.orig 1970-01-01 08:00:00.000000000 +0800 ++++ crash-7.3.0/diskdump.c.orig 2023-07-07 14:05:59.063287668 +0800 +@@ -0,0 +1,2896 @@ ++/* ++ * diskdump.c ++ * ++ * The diskdump module optionally creates either ELF vmcore ++ * dumpfiles, or compressed dumpfiles derived from the LKCD format. ++ * In the case of ELF vmcore files, since they are identical to ++ * netdump dumpfiles, the facilities in netdump.c are used. For ++ * compressed dumpfiles, the facilities in this file are used. ++ * ++ * Copyright (C) 2004-2015 David Anderson ++ * Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2005 FUJITSU LIMITED ++ * Copyright (C) 2005 NEC Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#define LZO ++#define SNAPPY ++#include "defs.h" ++#include "diskdump.h" ++#include "xen_dom0.h" ++#include "vmcore.h" ++ ++#define BITMAP_SECT_LEN 4096 ++ ++struct diskdump_data { ++ char *filename; ++ ulong flags; /* DISKDUMP_LOCAL, plus anything else... */ ++ int dfd; /* dumpfile file descriptor */ ++ FILE *ofp; /* fprintf(dd->ofp, "xxx"); */ ++ int machine_type; /* machine type identifier */ ++ ++ /* header */ ++ struct disk_dump_header *header; ++ struct disk_dump_sub_header *sub_header; ++ struct kdump_sub_header *sub_header_kdump; ++ ++ unsigned long long max_mapnr; /* 64bit max_mapnr */ ++ ++ size_t data_offset; ++ int block_size; ++ int block_shift; ++ char *bitmap; ++ off_t bitmap_len; ++ char *dumpable_bitmap; ++ int byte, bit; ++ char *compressed_page; /* copy of compressed page data */ ++ char *curbufptr; /* ptr to uncompressed page buffer */ ++ unsigned char *notes_buf; /* copy of elf notes */ ++ void **nt_prstatus_percpu; ++ uint num_prstatus_notes; ++ void **nt_qemu_percpu; ++ void **nt_qemucs_percpu; ++ uint num_qemu_notes; ++ void **nt_vmcoredd_array; ++ uint num_vmcoredd_notes; ++ ++ /* page cache */ ++ struct page_cache_hdr { /* header for each cached page */ ++ uint32_t pg_flags; ++ uint64_t pg_addr; ++ char *pg_bufptr; ++ ulong pg_hit_count; ++ } page_cache_hdr[DISKDUMP_CACHED_PAGES]; ++ char *page_cache_buf; /* base of cached buffer pages */ ++ int evict_index; /* next page to evict */ ++ ulong evictions; /* total evictions done */ ++ ulong cached_reads; ++ ulong *valid_pages; ++ ulong accesses; ++ ulong snapshot_task; ++}; ++ ++static struct diskdump_data diskdump_data = { 0 }; ++static struct diskdump_data *dd = &diskdump_data; ++ ++ulong *diskdump_flags = &diskdump_data.flags; ++ ++static int __diskdump_memory_dump(FILE *); ++static void dump_vmcoreinfo(FILE *); ++static void dump_note_offsets(FILE *); ++static char *vmcoreinfo_read_string(const char *); ++static void diskdump_get_osrelease(void); ++static int valid_note_address(unsigned char *); ++ ++/* For split dumpfile */ ++static struct diskdump_data **dd_list = NULL; ++static int num_dd = 0; ++static int num_dumpfiles = 0; ++ ++int dumpfile_is_split(void) ++{ ++ return KDUMP_SPLIT(); ++} ++ ++void ++map_cpus_to_prstatus_kdump_cmprs(void) ++{ ++ void **nt_ptr; ++ int online, i, j, nrcpus; ++ size_t size; ++ ++ if (pc->flags2 & QEMU_MEM_DUMP_COMPRESSED) /* notes exist for all cpus */ ++ goto resize_note_pointers; ++ ++ if (!(online = get_cpus_online()) || (online == kt->cpus)) ++ goto resize_note_pointers; ++ ++ if (CRASHDEBUG(1)) ++ error(INFO, ++ "cpus: %d online: %d NT_PRSTATUS notes: %d (remapping)\n", ++ kt->cpus, online, dd->num_prstatus_notes); ++ ++ size = NR_CPUS * sizeof(void *); ++ ++ nt_ptr = (void **)GETBUF(size); ++ BCOPY(dd->nt_prstatus_percpu, nt_ptr, size); ++ BZERO(dd->nt_prstatus_percpu, size); ++ ++ /* ++ * Re-populate the array with the notes mapping to online cpus ++ */ ++ nrcpus = (kt->kernel_NR_CPUS ? kt->kernel_NR_CPUS : NR_CPUS); ++ ++ for (i = 0, j = 0; i < nrcpus; i++) { ++ if (in_cpu_map(ONLINE_MAP, i)) { ++ dd->nt_prstatus_percpu[i] = nt_ptr[j++]; ++ dd->num_prstatus_notes = ++ MAX(dd->num_prstatus_notes, i+1); ++ } ++ } ++ ++ FREEBUF(nt_ptr); ++ ++resize_note_pointers: ++ /* ++ * For architectures that only utilize the note pointers ++ * within this file, resize the arrays accordingly. ++ */ ++ if (machine_type("X86_64") || machine_type("X86") || ++ machine_type("ARM64")) { ++ if ((dd->nt_prstatus_percpu = realloc(dd->nt_prstatus_percpu, ++ dd->num_prstatus_notes * sizeof(void *))) == NULL) ++ error(FATAL, ++ "compressed kdump: cannot realloc NT_PRSTATUS note pointers\n"); ++ if (dd->num_qemu_notes) { ++ if ((dd->nt_qemu_percpu = realloc(dd->nt_qemu_percpu, ++ dd->num_qemu_notes * sizeof(void *))) == NULL) ++ error(FATAL, ++ "compressed kdump: cannot realloc QEMU note pointers\n"); ++ if ((dd->nt_qemucs_percpu = realloc(dd->nt_qemucs_percpu, ++ dd->num_qemu_notes * sizeof(void *))) == NULL) ++ error(FATAL, ++ "compressed kdump: cannot realloc QEMU note pointers\n"); ++ } else { ++ free(dd->nt_qemu_percpu); ++ free(dd->nt_qemucs_percpu); ++ } ++ } ++} ++ ++static void ++add_diskdump_data(char* name) ++{ ++#define DDL_SIZE 16 ++ int i; ++ int sz = sizeof(void *); ++ struct diskdump_data *ddp; ++ ++ if (dd_list == NULL) { ++ dd_list = calloc(DDL_SIZE, sz); ++ num_dd = DDL_SIZE; ++ } else { ++ for (i = 0; i < num_dumpfiles; i++) { ++ ddp = dd_list[i]; ++ if (same_file(ddp->filename, name)) ++ error(FATAL, ++ "split dumpfiles are identical:\n" ++ " %s\n %s\n", ++ ddp->filename, name); ++ if (memcmp(ddp->header, dd->header, ++ sizeof(struct disk_dump_header))) ++ error(FATAL, ++ "split dumpfiles derived from different vmcores:\n" ++ " %s\n %s\n", ++ ddp->filename, name); ++ } ++ } ++ ++ if (num_dumpfiles == num_dd) { ++ /* expand list */ ++ struct diskdump_data **tmp; ++ tmp = calloc(num_dd*2, sz); ++ memcpy(tmp, dd_list, sz*num_dd); ++ free(dd_list); ++ dd_list = tmp; ++ num_dd *= 2; ++ } ++ ++ dd_list[num_dumpfiles] = dd; ++ dd->flags |= DUMPFILE_SPLIT; ++ dd->filename = name; ++ ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "%s: start_pfn=%llu, end_pfn=%llu\n", name, ++ dd->sub_header_kdump->start_pfn_64, ++ dd->sub_header_kdump->end_pfn_64); ++} ++ ++static void ++clean_diskdump_data(void) ++{ ++ int i; ++ ++ if (dd_list == NULL) ++ return; ++ ++ for (i=1; ibitmap, nr >> 3, nr & 7); ++} ++ ++static inline int ++page_is_dumpable(unsigned long nr) ++{ ++ return dd->dumpable_bitmap[nr>>3] & (1 << (nr & 7)); ++} ++ ++static inline int ++dump_is_partial(const struct disk_dump_header *header) ++{ ++ return header->bitmap_blocks >= ++ divideup(divideup(dd->max_mapnr, 8), dd->block_size) * 2; ++} ++ ++static int ++open_dump_file(char *file) ++{ ++ int fd; ++ ++ fd = open(file, O_RDONLY); ++ if (fd < 0) { ++ error(INFO, "diskdump / compressed kdump: unable to open dump file %s\n", file); ++ return FALSE; ++ } ++ ++ if (KDUMP_SPLIT()) ++ dd = calloc(1, sizeof(*dd)); ++ ++ dd->dfd = fd; ++ return TRUE; ++} ++ ++void ++process_elf32_notes(void *note_buf, unsigned long size_note) ++{ ++ Elf32_Nhdr *nt; ++ size_t index, len = 0; ++ int num = 0; ++ int vmcoredd_num = 0; ++ int qemu_num = 0; ++ ++ for (index = 0; index < size_note; index += len) { ++ nt = note_buf + index; ++ ++ if (nt->n_type == NT_PRSTATUS) { ++ dd->nt_prstatus_percpu[num] = nt; ++ num++; ++ } ++ len = sizeof(Elf32_Nhdr); ++ if (STRNEQ((char *)nt + len, "QEMU")) { ++ ulong *ptr = ++ (ulong *)((char *)nt + sizeof(Elf32_Nhdr) + nt->n_namesz); ++ dd->nt_qemucs_percpu[qemu_num] = ++ (ulong *)roundup((ulong) ptr, 4); ++ dd->nt_qemu_percpu[qemu_num] = nt; ++ qemu_num++; ++ } ++ if (nt->n_type == NT_XEN_KDUMP_CR3 || ++ nt->n_type == XEN_ELFNOTE_CRASH_INFO) { ++ void *data = (char*)(nt + 1) + ++ roundup(nt->n_namesz, 4); ++ process_xen_note(nt->n_type, data, nt->n_descsz); ++ } ++ ++ if (nt->n_type == NT_VMCOREDD && ++ vmcoredd_num < NR_DEVICE_DUMPS) { ++ dd->nt_vmcoredd_array[vmcoredd_num] = nt; ++ vmcoredd_num++; ++ } ++ ++ len = roundup(len + nt->n_namesz, 4); ++ len = roundup(len + nt->n_descsz, 4); ++ } ++ ++ if (num > 0) { ++ pc->flags2 |= ELF_NOTES; ++ dd->num_prstatus_notes = num; ++ } ++ ++ if (qemu_num > 0) { ++ pc->flags2 |= QEMU_MEM_DUMP_COMPRESSED; ++ dd->num_qemu_notes = qemu_num; ++ } ++ if (vmcoredd_num > 0) ++ dd->num_vmcoredd_notes = vmcoredd_num; ++ ++ return; ++} ++ ++void ++process_elf64_notes(void *note_buf, unsigned long size_note) ++{ ++ Elf64_Nhdr *nt; ++ size_t index, len = 0; ++ int num = 0; ++ int vmcoredd_num = 0; ++ int qemu_num = 0; ++ ++ for (index = 0; index < size_note; index += len) { ++ nt = note_buf + index; ++ ++ if (nt->n_type == NT_PRSTATUS) { ++ dd->nt_prstatus_percpu[num] = nt; ++ num++; ++ } ++ if ((nt->n_type == NT_TASKSTRUCT) && ++ (STRNEQ((char *)nt + sizeof(Elf64_Nhdr), "SNAP"))) { ++ pc->flags2 |= (LIVE_DUMP|SNAP); ++ dd->snapshot_task = ++ *((ulong *)((char *)nt + sizeof(Elf64_Nhdr) + nt->n_namesz)); ++ } ++ len = sizeof(Elf64_Nhdr); ++ if (STRNEQ((char *)nt + len, "QEMU")) { ++ ulong *ptr = ++ (ulong *)((char *)nt + sizeof(Elf64_Nhdr) + nt->n_namesz); ++ dd->nt_qemucs_percpu[qemu_num] = ++ (ulong *)roundup((ulong) ptr, 4); ++ dd->nt_qemu_percpu[qemu_num] = nt; ++ qemu_num++; ++ } ++ if (nt->n_type == NT_XEN_KDUMP_CR3 || ++ nt->n_type == XEN_ELFNOTE_CRASH_INFO) { ++ void *data = (char*)(nt + 1) + ++ roundup(nt->n_namesz, 4); ++ process_xen_note(nt->n_type, data, nt->n_descsz); ++ } ++ ++ if (nt->n_type == NT_VMCOREDD && ++ vmcoredd_num < NR_DEVICE_DUMPS) { ++ dd->nt_vmcoredd_array[vmcoredd_num] = nt; ++ vmcoredd_num++; ++ } ++ ++ len = roundup(len + nt->n_namesz, 4); ++ len = roundup(len + nt->n_descsz, 4); ++ } ++ ++ if (num > 0) { ++ pc->flags2 |= ELF_NOTES; ++ dd->num_prstatus_notes = num; ++ } ++ ++ if (qemu_num > 0) { ++ pc->flags2 |= QEMU_MEM_DUMP_COMPRESSED; ++ dd->num_qemu_notes = qemu_num; ++ } ++ if (vmcoredd_num > 0) ++ dd->num_vmcoredd_notes = vmcoredd_num; ++ ++ return; ++} ++ ++void ++x86_process_elf_notes(void *note_ptr, unsigned long size_note) ++{ ++ if (machine_type("X86_64")) ++ process_elf64_notes(note_ptr, size_note); ++ else if (machine_type("X86")) ++ process_elf32_notes(note_ptr, size_note); ++} ++ ++#if defined(__i386__) && (defined(ARM) || defined(MIPS)) ++/* ++ * The kdump_sub_header member offsets are different when the crash ++ * binary is built natively on an ARM host vs. when built with ++ * "make target=ARM" on an x86/x86_64 host. This is because the ++ * off_t structure members will be aligned on an 8-byte boundary when ++ * compiled as an ARM binary -- which will be reflected in the ++ * kdump_sub_header in a compressed ARM kdump. ++ * ++ * When crash is compiled as an x86 binary, these are the ++ * structure's offsets: ++ * ++ * struct kdump_sub_header { ++ * [0] unsigned long phys_base; ++ * [4] int dump_level; / header_version 1 and later / ++ * [8] int split; / header_version 2 and later / ++ * [12] unsigned long start_pfn; / header_version 2 and later / ++ * [16] unsigned long end_pfn; / header_version 2 and later / ++ * [20] off_t offset_vmcoreinfo; / header_version 3 and later / ++ * [28] unsigned long size_vmcoreinfo; / header_version 3 and later / ++ * [32] off_t offset_note; / header_version 4 and later / ++ * [40] unsigned long size_note; / header_version 4 and later / ++ * [44] off_t offset_eraseinfo; / header_version 5 and later / ++ * [52] unsigned long size_eraseinfo; / header_version 5 and later / ++ * [56] unsigned long long start_pfn_64; / header_version 6 and later / ++ * [64] unsigned long long end_pfn_64; / header_version 6 and later / ++ * [72] unsigned long long max_mapnr_64; / header_version 6 and later / ++ * }; ++ * ++ * But when compiled on an ARM processor, each 64-bit "off_t" would be pushed ++ * up to an 8-byte boundary: ++ * ++ * struct kdump_sub_header { ++ * [0] unsigned long phys_base; ++ * [4] int dump_level; / header_version 1 and later / ++ * [8] int split; / header_version 2 and later / ++ * [12] unsigned long start_pfn; / header_version 2 and later / ++ * [16] unsigned long end_pfn; / header_version 2 and later / ++ * [24] off_t offset_vmcoreinfo; / header_version 3 and later / ++ * [32] unsigned long size_vmcoreinfo; / header_version 3 and later / ++ * [40] off_t offset_note; / header_version 4 and later / ++ * [48] unsigned long size_note; / header_version 4 and later / ++ * [56] off_t offset_eraseinfo; / header_version 5 and later / ++ * [64] unsigned long size_eraseinfo; / header_version 5 and later / ++ * [72] unsigned long long start_pfn_64; / header_version 6 and later / ++ * [80] unsigned long long end_pfn_64; / header_version 6 and later / ++ * [88] unsigned long long max_mapnr_64; / header_version 6 and later / ++ * }; ++ * ++ */ ++ ++struct kdump_sub_header_ARM_target { ++ unsigned long phys_base; ++ int dump_level; /* header_version 1 and later */ ++ int split; /* header_version 2 and later */ ++ unsigned long start_pfn; /* header_version 2 and later */ ++ unsigned long end_pfn; /* header_version 2 and later */ ++ int pad1; ++ off_t offset_vmcoreinfo; /* header_version 3 and later */ ++ unsigned long size_vmcoreinfo; /* header_version 3 and later */ ++ int pad2; ++ off_t offset_note; /* header_version 4 and later */ ++ unsigned long size_note; /* header_version 4 and later */ ++ int pad3; ++ off_t offset_eraseinfo; /* header_version 5 and later */ ++ unsigned long size_eraseinfo; /* header_version 5 and later */ ++ int pad4; ++ unsigned long long start_pfn_64; /* header_version 6 and later */ ++ unsigned long long end_pfn_64; /* header_version 6 and later */ ++ unsigned long long max_mapnr_64; /* header_version 6 and later */ ++}; ++ ++static void ++arm_kdump_header_adjust(int header_version) ++{ ++ struct kdump_sub_header *kdsh; ++ struct kdump_sub_header_ARM_target *kdsh_ARM_target; ++ ++ kdsh = dd->sub_header_kdump; ++ kdsh_ARM_target = (struct kdump_sub_header_ARM_target *)kdsh; ++ ++ if (header_version >= 3) { ++ kdsh->offset_vmcoreinfo = kdsh_ARM_target->offset_vmcoreinfo; ++ kdsh->size_vmcoreinfo = kdsh_ARM_target->size_vmcoreinfo; ++ } ++ if (header_version >= 4) { ++ kdsh->offset_note = kdsh_ARM_target->offset_note; ++ kdsh->size_note = kdsh_ARM_target->size_note; ++ } ++ if (header_version >= 5) { ++ kdsh->offset_eraseinfo = kdsh_ARM_target->offset_eraseinfo; ++ kdsh->size_eraseinfo = kdsh_ARM_target->size_eraseinfo; ++ } ++ if (header_version >= 6) { ++ kdsh->start_pfn_64 = kdsh_ARM_target->start_pfn_64; ++ kdsh->end_pfn_64 = kdsh_ARM_target->end_pfn_64; ++ kdsh->max_mapnr_64 = kdsh_ARM_target->max_mapnr_64; ++ } else { ++ kdsh->start_pfn_64 = kdsh_ARM_target->start_pfn; ++ kdsh->end_pfn_64 = kdsh_ARM_target->end_pfn; ++ kdsh->max_mapnr_64 = dd->max_mapnr; ++ } ++} ++#endif /* __i386__ && (ARM || MIPS) */ ++ ++static int ++read_dump_header(char *file) ++{ ++ struct disk_dump_header *header = NULL; ++ struct disk_dump_sub_header *sub_header = NULL; ++ struct kdump_sub_header *sub_header_kdump = NULL; ++ size_t size; ++ off_t bitmap_len; ++ char *bufptr; ++ size_t len; ++ ssize_t bytes_read; ++ int block_size = (int)sysconf(_SC_PAGESIZE); ++ off_t offset; ++ const off_t failed = (off_t)-1; ++ ulong pfn; ++ int i, j, max_sect_len; ++ int is_split = 0; ++ ++ if (block_size < 0) ++ return FALSE; ++ ++restart: ++ if ((header = realloc(header, block_size)) == NULL) ++ error(FATAL, "diskdump / compressed kdump: cannot malloc block_size buffer\n"); ++ ++ if (FLAT_FORMAT()) { ++ if (!read_flattened_format(dd->dfd, 0, header, block_size)) { ++ error(FATAL, "diskdump / compressed kdump: cannot read header\n"); ++ goto err; ++ } ++ } else { ++ if (lseek(dd->dfd, 0, SEEK_SET) == failed) { ++ if (CRASHDEBUG(1)) ++ error(INFO, "diskdump / compressed kdump: cannot lseek dump header\n"); ++ goto err; ++ } ++ if (read(dd->dfd, header, block_size) < block_size) { ++ if (CRASHDEBUG(1)) ++ error(INFO, "diskdump / compressed kdump: cannot read dump header\n"); ++ goto err; ++ } ++ } ++ ++ /* validate dump header */ ++ if (!memcmp(header->signature, DISK_DUMP_SIGNATURE, ++ sizeof(header->signature))) { ++ dd->flags |= DISKDUMP_LOCAL; ++ } else if (!memcmp(header->signature, KDUMP_SIGNATURE, ++ sizeof(header->signature))) { ++ dd->flags |= KDUMP_CMPRS_LOCAL; ++ if (header->header_version >= 1) ++ dd->flags |= ERROR_EXCLUDED; ++ } else { ++ if (CRASHDEBUG(1)) ++ error(INFO, ++ "diskdump / compressed kdump: dump does not have panic dump header\n"); ++ goto err; ++ } ++ ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "%s: header->utsname.machine: %s\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump", ++ header->utsname.machine); ++ ++ if (STRNEQ(header->utsname.machine, "i686") && ++ machine_type_mismatch(file, "X86", NULL, 0)) ++ goto err; ++ else if (STRNEQ(header->utsname.machine, "x86_64") && ++ machine_type_mismatch(file, "X86_64", NULL, 0)) ++ goto err; ++ else if (STRNEQ(header->utsname.machine, "ia64") && ++ machine_type_mismatch(file, "IA64", NULL, 0)) ++ goto err; ++ else if (STREQ(header->utsname.machine, "ppc") && ++ machine_type_mismatch(file, "PPC", NULL, 0)) ++ goto err; ++ else if (STRNEQ(header->utsname.machine, "ppc64") && ++ machine_type_mismatch(file, "PPC64", NULL, 0)) ++ goto err; ++ else if (STRNEQ(header->utsname.machine, "arm") && ++ machine_type_mismatch(file, "ARM", NULL, 0)) ++ goto err; ++ else if (STREQ(header->utsname.machine, "mips") && ++ machine_type_mismatch(file, "MIPS", NULL, 0)) ++ goto err; ++ else if (STRNEQ(header->utsname.machine, "mips64") && ++ machine_type_mismatch(file, "MIPS64", NULL, 0)) ++ goto err; ++ else if (STRNEQ(header->utsname.machine, "s390x") && ++ machine_type_mismatch(file, "S390X", NULL, 0)) ++ goto err; ++ else if (STRNEQ(header->utsname.machine, "aarch64") && ++ machine_type_mismatch(file, "ARM64", NULL, 0)) ++ goto err; ++ ++ if (header->block_size != block_size) { ++ block_size = header->block_size; ++ if (CRASHDEBUG(1)) ++ fprintf(fp, ++ "retrying with different block/page size: %d\n", ++ header->block_size); ++ goto restart; ++ } ++ dd->block_size = header->block_size; ++ dd->block_shift = ffs(header->block_size) - 1; ++ ++ if ((DISKDUMP_VALID() && ++ (sizeof(*header) + sizeof(void *) * header->nr_cpus > block_size)) || ++ header->nr_cpus <= 0) { ++ error(WARNING, "%s: invalid nr_cpus value: %d\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump", ++ header->nr_cpus); ++ if (!machine_type("S390") && !machine_type("S390X") && ++ !machine_type("X86") && !machine_type("X86_64")) { ++ if (DISKDUMP_VALID()) ++ goto err; ++ } ++ } ++ ++ /* read sub header */ ++ offset = (off_t)block_size; ++ ++ if (DISKDUMP_VALID()) { ++ if ((sub_header = malloc(block_size)) == NULL) ++ error(FATAL, "diskdump: cannot malloc sub_header buffer\n"); ++ ++ if (FLAT_FORMAT()) { ++ if (!read_flattened_format(dd->dfd, offset, sub_header, block_size)) { ++ error(INFO, "diskdump: cannot read dump sub header\n"); ++ goto err; ++ } ++ } else { ++ if (lseek(dd->dfd, offset, SEEK_SET) == failed) { ++ error(INFO, "diskdump: cannot lseek dump sub header\n"); ++ goto err; ++ } ++ if (read(dd->dfd, sub_header, block_size) < block_size) { ++ error(INFO, "diskdump: cannot read dump sub header\n"); ++ goto err; ++ } ++ } ++ dd->sub_header = sub_header; ++ ++ /* the 64bit max_mapnr only exists in sub-header of compressed ++ * kdump file, if it's not a compressed kdump file, we have to ++ * use the old 32bit max_mapnr in dumpfile header. ++ * max_mapnr may be truncated here. ++ */ ++ dd->max_mapnr = header->max_mapnr; ++ } else if (KDUMP_CMPRS_VALID()) { ++ if ((sub_header_kdump = malloc(block_size)) == NULL) ++ error(FATAL, "compressed kdump: cannot malloc sub_header_kdump buffer\n"); ++ ++ if (FLAT_FORMAT()) { ++ if (!read_flattened_format(dd->dfd, offset, sub_header_kdump, block_size)) { ++ error(INFO, "compressed kdump: cannot read dump sub header\n"); ++ goto err; ++ } ++ } else { ++ if (lseek(dd->dfd, offset, SEEK_SET) == failed) { ++ error(INFO, "compressed kdump: cannot lseek dump sub header\n"); ++ goto err; ++ } ++ if (read(dd->dfd, sub_header_kdump, block_size) < block_size) { ++ error(INFO, "compressed kdump: cannot read dump sub header\n"); ++ goto err; ++ } ++ } ++ dd->sub_header_kdump = sub_header_kdump; ++ ++#if defined(__i386__) && (defined(ARM) || defined(MIPS)) ++ arm_kdump_header_adjust(header->header_version); ++#endif ++ /* use 64bit max_mapnr in compressed kdump file sub-header */ ++ if (header->header_version >= 6) ++ dd->max_mapnr = dd->sub_header_kdump->max_mapnr_64; ++ else { ++ dd->sub_header_kdump->start_pfn_64 ++ = dd->sub_header_kdump->start_pfn; ++ dd->sub_header_kdump->end_pfn_64 ++ = dd->sub_header_kdump->end_pfn; ++ } ++ } ++ ++ if (header->header_version < 6) ++ dd->max_mapnr = header->max_mapnr; ++ ++ /* read memory bitmap */ ++ bitmap_len = (off_t)block_size * header->bitmap_blocks; ++ dd->bitmap_len = bitmap_len; ++ ++ offset = (off_t)block_size * (1 + header->sub_hdr_size); ++ ++ if ((dd->bitmap = malloc(bitmap_len)) == NULL) ++ error(FATAL, "%s: cannot malloc bitmap buffer\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); ++ ++ dd->dumpable_bitmap = calloc(bitmap_len, 1); ++ ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "%s: memory bitmap offset: %llx\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump", ++ (ulonglong)offset); ++ ++ if (FLAT_FORMAT()) { ++ if (!read_flattened_format(dd->dfd, offset, dd->bitmap, bitmap_len)) { ++ error(INFO, "%s: cannot read memory bitmap\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); ++ goto err; ++ } ++ } else { ++ if (lseek(dd->dfd, offset, SEEK_SET) == failed) { ++ error(INFO, "%s: cannot lseek memory bitmap\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); ++ goto err; ++ } ++ bufptr = dd->bitmap; ++ len = bitmap_len; ++ while (len) { ++ bytes_read = read(dd->dfd, bufptr, len); ++ if (bytes_read <= 0) { ++ error(INFO, "%s: cannot read memory bitmap\n", ++ DISKDUMP_VALID() ? "diskdump" ++ : "compressed kdump"); ++ goto err; ++ } ++ len -= bytes_read; ++ bufptr += bytes_read; ++ } ++ } ++ ++ if (dump_is_partial(header)) ++ memcpy(dd->dumpable_bitmap, dd->bitmap + bitmap_len/2, ++ bitmap_len/2); ++ else ++ memcpy(dd->dumpable_bitmap, dd->bitmap, bitmap_len); ++ ++ dd->data_offset ++ = (1UL + header->sub_hdr_size + header->bitmap_blocks) ++ * header->block_size; ++ ++ dd->header = header; ++ ++ if (machine_type("ARM")) ++ dd->machine_type = EM_ARM; ++ else if (machine_type("MIPS") || machine_type("MIPS64")) ++ dd->machine_type = EM_MIPS; ++ else if (machine_type("X86")) ++ dd->machine_type = EM_386; ++ else if (machine_type("X86_64")) ++ dd->machine_type = EM_X86_64; ++ else if (machine_type("IA64")) ++ dd->machine_type = EM_IA_64; ++ else if (machine_type("PPC")) ++ dd->machine_type = EM_PPC; ++ else if (machine_type("PPC64")) ++ dd->machine_type = EM_PPC64; ++ else if (machine_type("S390X")) ++ dd->machine_type = EM_S390; ++ else if (machine_type("ARM64")) ++ dd->machine_type = EM_AARCH64; ++ else if (machine_type("SPARC64")) ++ dd->machine_type = EM_SPARCV9; ++ else { ++ error(INFO, "%s: unsupported machine type: %s\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump", ++ MACHINE_TYPE); ++ goto err; ++ } ++ ++ /* process elf notes data */ ++ if (KDUMP_CMPRS_VALID() && !(dd->flags & NO_ELF_NOTES) && ++ (dd->header->header_version >= 4) && ++ (sub_header_kdump->offset_note) && ++ (sub_header_kdump->size_note) && (machdep->process_elf_notes)) { ++ size = sub_header_kdump->size_note; ++ offset = sub_header_kdump->offset_note; ++ ++ if ((dd->notes_buf = malloc(size)) == NULL) ++ error(FATAL, "compressed kdump: cannot malloc notes" ++ " buffer\n"); ++ ++ if ((dd->nt_prstatus_percpu = malloc(NR_CPUS * sizeof(void *))) == NULL) ++ error(FATAL, "compressed kdump: cannot malloc pointer" ++ " to NT_PRSTATUS notes\n"); ++ ++ if ((dd->nt_qemu_percpu = malloc(NR_CPUS * sizeof(void *))) == NULL) ++ error(FATAL, "qemu mem dump compressed: cannot malloc pointer" ++ " to QEMU notes\n"); ++ ++ if ((dd->nt_qemucs_percpu = malloc(NR_CPUS * sizeof(void *))) == NULL) ++ error(FATAL, "qemu mem dump compressed: cannot malloc pointer" ++ " to QEMUCS notes\n"); ++ ++ if ((dd->nt_vmcoredd_array = malloc(NR_DEVICE_DUMPS * sizeof(void *))) == NULL) ++ error(FATAL, "compressed kdump: cannot malloc array for " ++ "vmcore device dump notes\n"); ++ ++ if (FLAT_FORMAT()) { ++ if (!read_flattened_format(dd->dfd, offset, dd->notes_buf, size)) { ++ error(INFO, "compressed kdump: cannot read notes data" ++ "\n"); ++ goto err; ++ } ++ } else { ++ if (lseek(dd->dfd, offset, SEEK_SET) == failed) { ++ error(INFO, "compressed kdump: cannot lseek notes data\n"); ++ goto err; ++ } ++ if (read(dd->dfd, dd->notes_buf, size) < size) { ++ error(INFO, "compressed kdump: cannot read notes data" ++ "\n"); ++ goto err; ++ } ++ } ++ ++ machdep->process_elf_notes(dd->notes_buf, size); ++ } ++ ++ /* Check if dump file contains erasesinfo data */ ++ if (KDUMP_CMPRS_VALID() && (dd->header->header_version >= 5) && ++ (sub_header_kdump->offset_eraseinfo) && ++ (sub_header_kdump->size_eraseinfo)) ++ pc->flags2 |= ERASEINFO_DATA; ++ ++ if (KDUMP_CMPRS_VALID() && (dd->header->header_version >= 3) && ++ dd->sub_header_kdump->offset_vmcoreinfo && ++ dd->sub_header_kdump->size_vmcoreinfo) ++ pc->flags2 |= VMCOREINFO; ++ ++ if (KDUMP_CMPRS_VALID() && ++ (dd->header->status & DUMP_DH_COMPRESSED_INCOMPLETE)) ++ pc->flags2 |= INCOMPLETE_DUMP; ++ ++ if (KDUMP_CMPRS_VALID() && ++ (dd->header->status & DUMP_DH_EXCLUDED_VMEMMAP)) ++ pc->flags2 |= EXCLUDED_VMEMMAP; ++ ++ /* For split dumpfile */ ++ if (KDUMP_CMPRS_VALID()) { ++ is_split = ((dd->header->header_version >= 2) && ++ (sub_header_kdump->split)); ++ ++ if ((is_split && (num_dumpfiles != 0) && (dd_list == NULL))|| ++ (!is_split && (num_dumpfiles != 0))) { ++ clean_diskdump_data(); ++ goto err; ++ } ++ ++ if (is_split) ++ add_diskdump_data(file); ++ ++ num_dumpfiles++; ++ } ++ ++ if (!is_split) { ++ max_sect_len = divideup(dd->max_mapnr, BITMAP_SECT_LEN); ++ pfn = 0; ++ dd->filename = file; ++ } ++ else { ++ unsigned long long start = sub_header_kdump->start_pfn_64; ++ unsigned long long end = sub_header_kdump->end_pfn_64; ++ max_sect_len = divideup(end - start + 1, BITMAP_SECT_LEN); ++ pfn = start; ++ } ++ ++ dd->valid_pages = calloc(sizeof(ulong), max_sect_len + 1); ++ for (i = 1; i < max_sect_len + 1; i++) { ++ dd->valid_pages[i] = dd->valid_pages[i - 1]; ++ for (j = 0; j < BITMAP_SECT_LEN; j++, pfn++) ++ if (page_is_dumpable(pfn)) ++ dd->valid_pages[i]++; ++ } ++ ++ return TRUE; ++ ++err: ++ free(header); ++ if (sub_header) ++ free(sub_header); ++ if (sub_header_kdump) ++ free(sub_header_kdump); ++ if (dd->bitmap) ++ free(dd->bitmap); ++ if (dd->dumpable_bitmap) ++ free(dd->dumpable_bitmap); ++ if (dd->notes_buf) ++ free(dd->notes_buf); ++ if (dd->nt_prstatus_percpu) ++ free(dd->nt_prstatus_percpu); ++ if (dd->nt_qemu_percpu) ++ free(dd->nt_qemu_percpu); ++ if (dd->nt_qemucs_percpu) ++ free(dd->nt_qemucs_percpu); ++ if (dd->nt_vmcoredd_array) ++ free(dd->nt_vmcoredd_array); ++ ++ dd->flags &= ~(DISKDUMP_LOCAL|KDUMP_CMPRS_LOCAL); ++ pc->flags2 &= ~ELF_NOTES; ++ return FALSE; ++} ++ ++static ulong ++pfn_to_pos(ulong pfn) ++{ ++ ulong desc_pos, j, valid; ++ ulong p1, p2; ++ ++ if (KDUMP_SPLIT()) { ++ p1 = pfn - dd->sub_header_kdump->start_pfn_64; ++ p2 = round(p1, BITMAP_SECT_LEN) ++ + dd->sub_header_kdump->start_pfn_64; ++ } ++ else { ++ p1 = pfn; ++ p2 = round(pfn, BITMAP_SECT_LEN); ++ } ++ ++ valid = dd->valid_pages[p1 / BITMAP_SECT_LEN]; ++ ++ for (j = p2, desc_pos = valid; j <= pfn; j++) ++ if (page_is_dumpable(j)) ++ desc_pos++; ++ ++ return desc_pos; ++} ++ ++ ++/* ++ * Determine whether a file is a diskdump creation, and if TRUE, ++ * initialize the diskdump_data structure based upon the contents ++ * of the diskdump header data. ++ */ ++int ++is_diskdump(char *file) ++{ ++ int sz, i; ++ ++ if (!open_dump_file(file) || !read_dump_header(file)) ++ return FALSE; ++ ++ sz = dd->block_size * (DISKDUMP_CACHED_PAGES); ++ if ((dd->page_cache_buf = malloc(sz)) == NULL) ++ error(FATAL, "%s: cannot malloc compressed page_cache_buf\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); ++ ++ for (i = 0; i < DISKDUMP_CACHED_PAGES; i++) ++ dd->page_cache_hdr[i].pg_bufptr = ++ &dd->page_cache_buf[i * dd->block_size]; ++ ++ if ((dd->compressed_page = (char *)malloc(dd->block_size)) == NULL) ++ error(FATAL, "%s: cannot malloc compressed page space\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); ++ ++ if (CRASHDEBUG(1)) ++ __diskdump_memory_dump(fp); ++ ++ if (pc->flags2 & GET_OSRELEASE) ++ diskdump_get_osrelease(); ++ ++#ifdef LZO ++ if (lzo_init() == LZO_E_OK) ++ dd->flags |= LZO_SUPPORTED; ++#endif ++ ++#ifdef SNAPPY ++ dd->flags |= SNAPPY_SUPPORTED; ++#endif ++ ++ pc->read_vmcoreinfo = vmcoreinfo_read_string; ++ ++ if ((pc->flags2 & GET_LOG) && KDUMP_CMPRS_VALID()) { ++ pc->dfd = dd->dfd; ++ pc->readmem = read_diskdump; ++ pc->flags |= DISKDUMP; ++ get_log_from_vmcoreinfo(file); ++ } ++ ++ return TRUE; ++} ++ ++/* ++ * Perform any post-dumpfile determination stuff here. ++ * At a minimum ++ */ ++int ++diskdump_init(char *unused, FILE *fptr) ++{ ++ if (!DISKDUMP_VALID() && !KDUMP_CMPRS_VALID()) ++ return FALSE; ++ ++ dd->ofp = fptr; ++ return TRUE; ++} ++ ++/* ++ * Get the relocational offset from the sub header of kdump. ++ */ ++int ++diskdump_phys_base(unsigned long *phys_base) ++{ ++ if (KDUMP_CMPRS_VALID()) { ++ *phys_base = dd->sub_header_kdump->phys_base; ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++int ++diskdump_set_phys_base(unsigned long phys_base) ++{ ++ if (diskdump_kaslr_check()) { ++ dd->sub_header_kdump->phys_base = phys_base; ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/* ++ * Check whether paddr is already cached. ++ */ ++static int ++page_is_cached(physaddr_t paddr) ++{ ++ int i; ++ struct page_cache_hdr *pgc; ++ ++ dd->accesses++; ++ ++ for (i = 0; i < DISKDUMP_CACHED_PAGES; i++) { ++ ++ pgc = &dd->page_cache_hdr[i]; ++ ++ if (!DISKDUMP_VALID_PAGE(pgc->pg_flags)) ++ continue; ++ ++ if (pgc->pg_addr == paddr) { ++ pgc->pg_hit_count++; ++ dd->curbufptr = pgc->pg_bufptr; ++ dd->cached_reads++; ++ return TRUE; ++ } ++ } ++ return FALSE; ++} ++ ++/* ++ * Translate physical address in paddr to PFN number. This means normally that ++ * we just shift paddr by some constant. Some architectures need special ++ * handling for this, however. ++ */ ++static ulong ++paddr_to_pfn(physaddr_t paddr) ++{ ++#ifdef ARM ++ /* ++ * In ARM, PFN 0 means first page in kernel direct-mapped view. ++ * This is also first page in mem_map as well. ++ */ ++ return (paddr - machdep->machspec->phys_base) >> dd->block_shift; ++#else ++ return paddr >> dd->block_shift; ++#endif ++} ++ ++/* ++ * Cache the page's data. ++ * ++ * If an empty page cache location is available, take it. Otherwise, evict ++ * the entry indexed by evict_index, and then bump evict index. The hit_count ++ * is only gathered for dump_diskdump_environment(). ++ * ++ * If the page is compressed, uncompress it into the selected page cache entry. ++ * If the page is raw, just copy it into the selected page cache entry. ++ * If all works OK, update diskdump->curbufptr to point to the page's ++ * uncompressed data. ++ */ ++static int ++cache_page(physaddr_t paddr) ++{ ++ int i, ret; ++ int found; ++ ulong pfn; ++ ulong desc_pos; ++ off_t seek_offset; ++ page_desc_t pd; ++ const int block_size = dd->block_size; ++ const off_t failed = (off_t)-1; ++ ulong retlen; ++ ++ for (i = found = 0; i < DISKDUMP_CACHED_PAGES; i++) { ++ if (DISKDUMP_VALID_PAGE(dd->page_cache_hdr[i].pg_flags)) ++ continue; ++ found = TRUE; ++ break; ++ } ++ ++ if (!found) { ++ i = dd->evict_index; ++ dd->page_cache_hdr[i].pg_hit_count = 0; ++ dd->evict_index = ++ (dd->evict_index+1) % DISKDUMP_CACHED_PAGES; ++ dd->evictions++; ++ } ++ ++ dd->page_cache_hdr[i].pg_flags = 0; ++ dd->page_cache_hdr[i].pg_addr = paddr; ++ dd->page_cache_hdr[i].pg_hit_count++; ++ ++ /* find page descriptor */ ++ pfn = paddr_to_pfn(paddr); ++ desc_pos = pfn_to_pos(pfn); ++ seek_offset = dd->data_offset ++ + (off_t)(desc_pos - 1)*sizeof(page_desc_t); ++ ++ /* read page descriptor */ ++ if (FLAT_FORMAT()) { ++ if (!read_flattened_format(dd->dfd, seek_offset, &pd, sizeof(pd))) ++ return READ_ERROR; ++ } else { ++ if (lseek(dd->dfd, seek_offset, SEEK_SET) == failed) ++ return SEEK_ERROR; ++ if (read(dd->dfd, &pd, sizeof(pd)) != sizeof(pd)) ++ return READ_ERROR; ++ } ++ ++ /* sanity check */ ++ if (pd.size > block_size) ++ return READ_ERROR; ++ ++ /* read page data */ ++ if (FLAT_FORMAT()) { ++ if (!read_flattened_format(dd->dfd, pd.offset, dd->compressed_page, pd.size)) ++ return READ_ERROR; ++ } else if (is_incomplete_dump() && (0 == pd.offset)) { ++ /* ++ * If the incomplete flag has been set in the header, ++ * first check whether zero_excluded has been set. ++ */ ++ if (*diskdump_flags & ZERO_EXCLUDED) { ++ if (CRASHDEBUG(8)) ++ fprintf(fp, ++ "read_diskdump/cache_page: zero-fill: " ++ "paddr/pfn: %llx/%lx\n", ++ (ulonglong)paddr, pfn); ++ memset(dd->compressed_page, 0, dd->block_size); ++ } else ++ return READ_ERROR; ++ } else { ++ if (lseek(dd->dfd, pd.offset, SEEK_SET) == failed) ++ return SEEK_ERROR; ++ if (read(dd->dfd, dd->compressed_page, pd.size) != pd.size) ++ return READ_ERROR; ++ } ++ ++ if (pd.flags & DUMP_DH_COMPRESSED_ZLIB) { ++ retlen = block_size; ++ ret = uncompress((unsigned char *)dd->page_cache_hdr[i].pg_bufptr, ++ &retlen, ++ (unsigned char *)dd->compressed_page, ++ pd.size); ++ if ((ret != Z_OK) || (retlen != block_size)) { ++ error(INFO, "%s: uncompress failed: %d\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump", ++ ret); ++ return READ_ERROR; ++ } ++ } else if (pd.flags & DUMP_DH_COMPRESSED_LZO) { ++ ++ if (!(dd->flags & LZO_SUPPORTED)) { ++ error(INFO, "%s: uncompress failed: no lzo compression support\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); ++ return READ_ERROR; ++ } ++ ++#ifdef LZO ++ retlen = block_size; ++ ret = lzo1x_decompress_safe((unsigned char *)dd->compressed_page, ++ pd.size, ++ (unsigned char *)dd->page_cache_hdr[i].pg_bufptr, ++ &retlen, ++ LZO1X_MEM_DECOMPRESS); ++ if ((ret != LZO_E_OK) || (retlen != block_size)) { ++ error(INFO, "%s: uncompress failed: %d\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump", ++ ret); ++ return READ_ERROR; ++ } ++#endif ++ } else if (pd.flags & DUMP_DH_COMPRESSED_SNAPPY) { ++ ++ if (!(dd->flags & SNAPPY_SUPPORTED)) { ++ error(INFO, "%s: uncompress failed: no snappy compression support\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); ++ return READ_ERROR; ++ } ++ ++#ifdef SNAPPY ++ ret = snappy_uncompressed_length((char *)dd->compressed_page, ++ pd.size, (size_t *)&retlen); ++ if (ret != SNAPPY_OK) { ++ error(INFO, "%s: uncompress failed: %d\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump", ++ ret); ++ return READ_ERROR; ++ } ++ ++ ret = snappy_uncompress((char *)dd->compressed_page, pd.size, ++ (char *)dd->page_cache_hdr[i].pg_bufptr, ++ (size_t *)&retlen); ++ if ((ret != SNAPPY_OK) || (retlen != block_size)) { ++ error(INFO, "%s: uncompress failed: %d\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump", ++ ret); ++ return READ_ERROR; ++ } ++#endif ++ } else ++ memcpy(dd->page_cache_hdr[i].pg_bufptr, ++ dd->compressed_page, block_size); ++ ++ dd->page_cache_hdr[i].pg_flags |= PAGE_VALID; ++ dd->curbufptr = dd->page_cache_hdr[i].pg_bufptr; ++ ++ return TRUE; ++} ++ ++/* ++ * Read from a diskdump-created dumpfile. ++ */ ++int ++read_diskdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) ++{ ++ int ret; ++ physaddr_t curpaddr; ++ ulong pfn, page_offset; ++ physaddr_t paddr_in = paddr; ++ ++ if (XEN_CORE_DUMPFILE() && !XEN_HYPER_MODE()) { ++ if ((paddr = xen_kdump_p2m(paddr)) == P2M_FAILURE) { ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "read_diskdump: xen_kdump_p2m(%llx): " ++ "P2M_FAILURE\n", (ulonglong)paddr_in); ++ return READ_ERROR; ++ } ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "read_diskdump: xen_kdump_p2m(%llx): %llx\n", ++ (ulonglong)paddr_in, (ulonglong)paddr); ++ } ++ ++ pfn = paddr_to_pfn(paddr); ++ ++ if (KDUMP_SPLIT()) { ++ /* Find proper dd */ ++ int i; ++ unsigned long long start_pfn; ++ unsigned long long end_pfn; ++ ++ for (i=0; isub_header_kdump->start_pfn_64; ++ end_pfn = dd_list[i]->sub_header_kdump->end_pfn_64; ++ if ((pfn >= start_pfn) && (pfn < end_pfn)) { ++ dd = dd_list[i]; ++ break; ++ } ++ } ++ ++ if (i == num_dumpfiles) { ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "read_diskdump: SEEK_ERROR: " ++ "paddr/pfn %llx/%lx beyond last dumpfile\n", ++ (ulonglong)paddr, pfn); ++ return SEEK_ERROR; ++ } ++ } ++ ++ curpaddr = paddr & ~((physaddr_t)(dd->block_size-1)); ++ page_offset = paddr & ((physaddr_t)(dd->block_size-1)); ++ ++ if ((pfn >= dd->max_mapnr) || !page_is_ram(pfn)) { ++ if (CRASHDEBUG(8)) { ++ fprintf(fp, "read_diskdump: SEEK_ERROR: " ++ "paddr/pfn: %llx/%lx ", ++ (ulonglong)paddr, pfn); ++ if (pfn >= dd->max_mapnr) ++ fprintf(fp, "max_mapnr: %llx\n", ++ dd->max_mapnr); ++ else ++ fprintf(fp, "!page_is_ram\n"); ++ } ++ ++ return SEEK_ERROR; ++ } ++ ++ if (!page_is_dumpable(pfn)) { ++ if ((dd->flags & (ZERO_EXCLUDED|ERROR_EXCLUDED)) == ++ ERROR_EXCLUDED) { ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "read_diskdump: PAGE_EXCLUDED: " ++ "paddr/pfn: %llx/%lx\n", ++ (ulonglong)paddr, pfn); ++ return PAGE_EXCLUDED; ++ } ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "read_diskdump: zero-fill: " ++ "paddr/pfn: %llx/%lx\n", ++ (ulonglong)paddr, pfn); ++ memset(bufptr, 0, cnt); ++ return cnt; ++ } ++ ++ if (!page_is_cached(curpaddr)) { ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "read_diskdump: paddr/pfn: %llx/%lx" ++ " -> cache physical page: %llx\n", ++ (ulonglong)paddr, pfn, (ulonglong)curpaddr); ++ ++ if ((ret = cache_page(curpaddr)) < 0) { ++ if (CRASHDEBUG(8)) ++ fprintf(fp, "read_diskdump: " ++ "%s: cannot cache page: %llx\n", ++ ret == SEEK_ERROR ? ++ "SEEK_ERROR" : "READ_ERROR", ++ (ulonglong)curpaddr); ++ return ret; ++ } ++ } else if (CRASHDEBUG(8)) ++ fprintf(fp, "read_diskdump: paddr/pfn: %llx/%lx" ++ " -> physical page is cached: %llx\n", ++ (ulonglong)paddr, pfn, (ulonglong)curpaddr); ++ ++ memcpy(bufptr, dd->curbufptr + page_offset, cnt); ++ return cnt; ++} ++ ++/* ++ * Write to a diskdump-created dumpfile. ++ */ ++int ++write_diskdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) ++{ ++ return 0; ++} ++ ++ulong ++get_diskdump_panic_task(void) ++{ ++ int i; ++ ++ if ((!DISKDUMP_VALID() && !KDUMP_CMPRS_VALID()) ++ || !get_active_set()) ++ return NO_TASK; ++ ++ if (pc->flags2 & SNAP) ++ return (task_exists(dd->snapshot_task) ? dd->snapshot_task : NO_TASK); ++ ++ if (DISKDUMP_VALID()) ++ return (ulong)dd->header->tasks[dd->header->current_cpu]; ++ ++ if (KDUMP_CMPRS_VALID()) { ++ if (kernel_symbol_exists("crashing_cpu") && ++ cpu_map_addr("online")) { ++ get_symbol_data("crashing_cpu", sizeof(int), &i); ++ if ((i >= 0) && in_cpu_map(ONLINE_MAP, i)) { ++ if (CRASHDEBUG(1)) ++ error(INFO, "get_diskdump_panic_task: " ++ "active_set[%d]: %lx\n", ++ i, tt->active_set[i]); ++ return (tt->active_set[i]); ++ } ++ } ++ } ++ ++ return NO_TASK; ++} ++ ++extern void get_netdump_regs_x86(struct bt_info *, ulong *, ulong *); ++extern void get_netdump_regs_x86_64(struct bt_info *, ulong *, ulong *); ++ ++static void ++get_diskdump_regs_32(struct bt_info *bt, ulong *eip, ulong *esp) ++{ ++ Elf32_Nhdr *note; ++ int len; ++ ++ if (KDUMP_CMPRS_VALID() && ++ (bt->task == tt->panic_task || ++ (is_task_active(bt->task) && dd->num_prstatus_notes > 1))) { ++ note = (Elf32_Nhdr*) dd->nt_prstatus_percpu[bt->tc->processor]; ++ if (!note) ++ error(FATAL, ++ "cannot determine NT_PRSTATUS ELF note " ++ "for %s task: %lx\n", ++ (bt->task == tt->panic_task) ? ++ "panic" : "active", bt->task); ++ len = sizeof(Elf32_Nhdr); ++ len = roundup(len + note->n_namesz, 4); ++ bt->machdep = (void *)((char *)note + len + ++ MEMBER_OFFSET("elf_prstatus", "pr_reg")); ++ } ++ ++ machdep->get_stack_frame(bt, eip, esp); ++} ++ ++static void ++get_diskdump_regs_ppc(struct bt_info *bt, ulong *eip, ulong *esp) ++{ ++ if (KDUMP_CMPRS_VALID()) ++ ppc_relocate_nt_prstatus_percpu(dd->nt_prstatus_percpu, ++ &dd->num_prstatus_notes); ++ ++ get_diskdump_regs_32(bt, eip, esp); ++} ++ ++static void ++get_diskdump_regs_ppc64(struct bt_info *bt, ulong *eip, ulong *esp) ++{ ++ int cpu; ++ Elf64_Nhdr *note; ++ size_t len; ++ ++ if ((bt->task == tt->panic_task) && DISKDUMP_VALID()) ++ bt->machdep = &dd->sub_header->elf_regs; ++ else if (KDUMP_CMPRS_VALID() && ++ (bt->task == tt->panic_task || ++ (is_task_active(bt->task) && dd->num_prstatus_notes > 1))) { ++ cpu = bt->tc->processor; ++ if (dd->nt_prstatus_percpu[cpu] == NULL) { ++ if(CRASHDEBUG(1)) ++ error(INFO, ++ "registers not collected for cpu %d\n", ++ cpu); ++ } else { ++ note = (Elf64_Nhdr *) ++ dd->nt_prstatus_percpu[cpu]; ++ len = sizeof(Elf64_Nhdr); ++ len = roundup(len + note->n_namesz, 4); ++ bt->machdep = (void *)((char *)note + len + ++ MEMBER_OFFSET("elf_prstatus", "pr_reg")); ++ } ++ } ++ ++ machdep->get_stack_frame(bt, eip, esp); ++} ++ ++static void ++get_diskdump_regs_arm(struct bt_info *bt, ulong *eip, ulong *esp) ++{ ++ machdep->get_stack_frame(bt, eip, esp); ++} ++ ++static void ++get_diskdump_regs_arm64(struct bt_info *bt, ulong *eip, ulong *esp) ++{ ++ machdep->get_stack_frame(bt, eip, esp); ++} ++ ++static void ++get_diskdump_regs_mips(struct bt_info *bt, ulong *eip, ulong *esp) ++{ ++ machdep->get_stack_frame(bt, eip, esp); ++} ++ ++static void ++get_diskdump_regs_sparc64(struct bt_info *bt, ulong *eip, ulong *esp) ++{ ++ Elf64_Nhdr *note; ++ int len; ++ ++ if (KDUMP_CMPRS_VALID() && ++ (bt->task == tt->panic_task || ++ (is_task_active(bt->task) && dd->num_prstatus_notes > 1))) { ++ note = (Elf64_Nhdr *)dd->nt_prstatus_percpu[bt->tc->processor]; ++ if (!note) ++ error(FATAL, ++ "cannot determine NT_PRSTATUS ELF note " ++ "for %s task: %lx\n", ++ (bt->task == tt->panic_task) ? ++ "panic" : "active", bt->task); ++ len = sizeof(Elf64_Nhdr); ++ len = roundup(len + note->n_namesz, 4); ++ bt->machdep = (void *)((char *)note + len + ++ MEMBER_OFFSET("elf_prstatus", "pr_reg")); ++ } ++ ++ machdep->get_stack_frame(bt, eip, esp); ++} ++ ++/* ++ * Send the request to the proper architecture hander. ++ */ ++ ++void ++get_diskdump_regs(struct bt_info *bt, ulong *eip, ulong *esp) ++{ ++ switch (dd->machine_type) ++ { ++ case EM_ARM: ++ get_diskdump_regs_arm(bt, eip, esp); ++ break; ++ ++ case EM_MIPS: ++ return get_diskdump_regs_mips(bt, eip, esp); ++ break; ++ ++ case EM_386: ++ return get_netdump_regs_x86(bt, eip, esp); ++ break; ++ ++ case EM_IA_64: ++ /* For normal backtraces, this information will be obtained ++ * frome the switch_stack structure, which is pointed to by ++ * the thread.ksp field of the task_struct. But it's still ++ * needed by the "bt -t" option. ++ */ ++ machdep->get_stack_frame(bt, eip, esp); ++ break; ++ ++ case EM_PPC: ++ return get_diskdump_regs_ppc(bt, eip, esp); ++ break; ++ ++ case EM_PPC64: ++ return get_diskdump_regs_ppc64(bt, eip, esp); ++ break; ++ ++ case EM_X86_64: ++ return get_netdump_regs_x86_64(bt, eip, esp); ++ break; ++ ++ case EM_S390: ++ return machdep->get_stack_frame(bt, eip, esp); ++ break; ++ ++ case EM_AARCH64: ++ get_diskdump_regs_arm64(bt, eip, esp); ++ break; ++ ++ case EM_SPARCV9: ++ get_diskdump_regs_sparc64(bt, eip, esp); ++ break; ++ ++ default: ++ error(FATAL, "%s: unsupported machine type: %s\n", ++ DISKDUMP_VALID() ? "diskdump" : "compressed kdump", ++ MACHINE_TYPE); ++ } ++} ++ ++/* ++ * Return the processor page size. ++ */ ++uint ++diskdump_page_size(void) ++{ ++ if (!DISKDUMP_VALID() && !KDUMP_CMPRS_VALID()) ++ return 0; ++ ++ return dd->header->block_size; ++} ++ ++/* ++ * diskdump_free_memory(), and diskdump_memory_used() ++ * are debug only, and probably unnecessary to implement. ++ */ ++int ++diskdump_free_memory(void) ++{ ++ return 0; ++} ++ ++int ++diskdump_memory_used(void) ++{ ++ return 0; ++} ++ ++static void ++dump_vmcoreinfo(FILE *fp) ++{ ++ char *buf = NULL; ++ unsigned long i = 0; ++ unsigned long size_vmcoreinfo = dd->sub_header_kdump->size_vmcoreinfo; ++ off_t offset = dd->sub_header_kdump->offset_vmcoreinfo; ++ const off_t failed = (off_t)-1; ++ ++ if ((buf = malloc(size_vmcoreinfo)) == NULL) { ++ error(FATAL, "compressed kdump: cannot malloc vmcoreinfo" ++ " buffer\n"); ++ } ++ ++ if (FLAT_FORMAT()) { ++ if (!read_flattened_format(dd->dfd, offset, buf, size_vmcoreinfo)) { ++ error(INFO, "compressed kdump: cannot read vmcoreinfo data\n"); ++ goto err; ++ } ++ } else { ++ if (lseek(dd->dfd, offset, SEEK_SET) == failed) { ++ error(INFO, "compressed kdump: cannot lseek dump vmcoreinfo\n"); ++ goto err; ++ } ++ if (read(dd->dfd, buf, size_vmcoreinfo) < size_vmcoreinfo) { ++ error(INFO, "compressed kdump: cannot read vmcoreinfo data\n"); ++ goto err; ++ } ++ } ++ ++ fprintf(fp, " "); ++ for (i = 0; i < size_vmcoreinfo; i++) { ++ fprintf(fp, "%c", buf[i]); ++ if ((buf[i] == '\n') && ((i+1) != size_vmcoreinfo)) ++ fprintf(fp, " "); ++ } ++ if (buf[i-1] != '\n') ++ fprintf(fp, "\n"); ++err: ++ if (buf) ++ free(buf); ++ return; ++} ++ ++static void ++dump_eraseinfo(FILE *fp) ++{ ++ char *buf = NULL; ++ unsigned long i = 0; ++ unsigned long size_eraseinfo = dd->sub_header_kdump->size_eraseinfo; ++ off_t offset = dd->sub_header_kdump->offset_eraseinfo; ++ const off_t failed = (off_t)-1; ++ ++ if ((buf = malloc(size_eraseinfo)) == NULL) { ++ error(FATAL, "compressed kdump: cannot malloc eraseinfo" ++ " buffer\n"); ++ } ++ ++ if (FLAT_FORMAT()) { ++ if (!read_flattened_format(dd->dfd, offset, buf, size_eraseinfo)) { ++ error(INFO, "compressed kdump: cannot read eraseinfo data\n"); ++ goto err; ++ } ++ } else { ++ if (lseek(dd->dfd, offset, SEEK_SET) == failed) { ++ error(INFO, "compressed kdump: cannot lseek dump eraseinfo\n"); ++ goto err; ++ } ++ if (read(dd->dfd, buf, size_eraseinfo) < size_eraseinfo) { ++ error(INFO, "compressed kdump: cannot read eraseinfo data\n"); ++ goto err; ++ } ++ } ++ ++ fprintf(fp, " "); ++ for (i = 0; i < size_eraseinfo; i++) { ++ fprintf(fp, "%c", buf[i]); ++ if (buf[i] == '\n') ++ fprintf(fp, " "); ++ } ++ if (buf[i - 1] != '\n') ++ fprintf(fp, "\n"); ++err: ++ if (buf) ++ free(buf); ++ return; ++} ++ ++static void ++dump_note_offsets(FILE *fp) ++{ ++ struct kdump_sub_header *sub_header_kdump = dd->sub_header_kdump; ++ size_t size; ++ off_t offset; ++ Elf32_Nhdr *note32 = NULL; ++ Elf64_Nhdr *note64 = NULL; ++ size_t tot, len = 0; ++ int qemu, cnt; ++ ++ if (KDUMP_CMPRS_VALID() && !(dd->flags & NO_ELF_NOTES) && ++ (dd->header->header_version >= 4) && ++ (sub_header_kdump->offset_note) && ++ (sub_header_kdump->size_note) && (machdep->process_elf_notes)) { ++ size = sub_header_kdump->size_note; ++ offset = sub_header_kdump->offset_note; ++ ++ fprintf(fp, " NOTE offsets: "); ++ for (tot = cnt = 0; tot < size; tot += len) { ++ qemu = FALSE; ++ if (machine_type("X86_64") || machine_type("S390X") || ++ machine_type("ARM64") || machine_type("PPC64") || ++ machine_type("SPARC64")) { ++ note64 = (void *)dd->notes_buf + tot; ++ len = sizeof(Elf64_Nhdr); ++ if (STRNEQ((char *)note64 + len, "QEMU")) ++ qemu = TRUE; ++ len = roundup(len + note64->n_namesz, 4); ++ len = roundup(len + note64->n_descsz, 4); ++ ++ if (note64->n_type == NT_PRSTATUS) { ++ fprintf(fp, "%s%lx (NT_PRSTATUS)\n", ++ tot ? space(22) : "", ++ (ulong)(offset + tot)); ++ cnt++; ++ } ++ if (qemu) { ++ fprintf(fp, "%s%lx (QEMU)\n", ++ tot ? space(22) : "", ++ (ulong)(offset + tot)); ++ cnt++; ++ } ++ ++ } else if (machine_type("X86") || machine_type("PPC")) { ++ note32 = (void *)dd->notes_buf + tot; ++ len = sizeof(Elf32_Nhdr); ++ if (STRNEQ((char *)note32 + len, "QEMU")) ++ qemu = TRUE; ++ len = roundup(len + note32->n_namesz, 4); ++ len = roundup(len + note32->n_descsz, 4); ++ ++ if (note32->n_type == NT_PRSTATUS) { ++ fprintf(fp, "%s%lx (NT_PRSTATUS)\n", ++ tot ? space(22) : "", ++ (ulong)(offset + tot)); ++ cnt++; ++ } ++ if (qemu) { ++ fprintf(fp, "%s%lx (QEMU)\n", ++ tot ? space(22) : "", ++ (ulong)(offset + tot)); ++ cnt++; ++ } ++ } ++ } ++ if (!cnt) ++ fprintf(fp, "\n"); ++ } ++} ++ ++/* ++ * This function is dump-type independent, and could be used ++ * to dump the diskdump_data structure contents and perhaps ++ * the diskdump header data. ++ */ ++int ++__diskdump_memory_dump(FILE *fp) ++{ ++ int i, others, dump_level; ++ struct disk_dump_header *dh; ++ struct disk_dump_sub_header *dsh; ++ struct kdump_sub_header *kdsh; ++ ulong *tasks; ++ ++ if (FLAT_FORMAT()) ++ dump_flat_header(fp); ++ ++ fprintf(fp, "diskdump_data: \n"); ++ fprintf(fp, " filename: %s\n", dd->filename); ++ fprintf(fp, " flags: %lx (", dd->flags); ++ others = 0; ++ if (dd->flags & DISKDUMP_LOCAL) ++ fprintf(fp, "%sDISKDUMP_LOCAL", others++ ? "|" : ""); ++ if (dd->flags & KDUMP_CMPRS_LOCAL) ++ fprintf(fp, "%sKDUMP_CMPRS_LOCAL", others++ ? "|" : ""); ++ if (dd->flags & ERROR_EXCLUDED) ++ fprintf(fp, "%sERROR_EXCLUDED", others++ ? "|" : ""); ++ if (dd->flags & ZERO_EXCLUDED) ++ fprintf(fp, "%sZERO_EXCLUDED", others++ ? "|" : ""); ++ if (dd->flags & NO_ELF_NOTES) ++ fprintf(fp, "%sNO_ELF_NOTES", others++ ? "|" : ""); ++ if (dd->flags & LZO_SUPPORTED) ++ fprintf(fp, "%sLZO_SUPPORTED", others++ ? "|" : ""); ++ if (dd->flags & SNAPPY_SUPPORTED) ++ fprintf(fp, "%sSNAPPY_SUPPORTED", others++ ? "|" : ""); ++ fprintf(fp, ") %s\n", FLAT_FORMAT() ? "[FLAT]" : ""); ++ fprintf(fp, " dfd: %d\n", dd->dfd); ++ fprintf(fp, " ofp: %lx\n", (ulong)dd->ofp); ++ fprintf(fp, " machine_type: %d ", dd->machine_type); ++ switch (dd->machine_type) ++ { ++ case EM_ARM: ++ fprintf(fp, "(EM_ARM)\n"); break; ++ case EM_MIPS: ++ fprintf(fp, "(EM_MIPS)\n"); break; ++ case EM_386: ++ fprintf(fp, "(EM_386)\n"); break; ++ case EM_X86_64: ++ fprintf(fp, "(EM_X86_64)\n"); break; ++ case EM_IA_64: ++ fprintf(fp, "(EM_IA_64)\n"); break; ++ case EM_PPC: ++ fprintf(fp, "(EM_PPC)\n"); break; ++ case EM_PPC64: ++ fprintf(fp, "(EM_PPC64)\n"); break; ++ case EM_S390: ++ fprintf(fp, "(EM_S390)\n"); break; ++ case EM_AARCH64: ++ fprintf(fp, "(EM_AARCH64)\n"); break; ++ case EM_SPARCV9: ++ fprintf(fp, "(EM_SPARCV9)\n"); break; ++ default: ++ fprintf(fp, "(unknown)\n"); break; ++ } ++ ++ fprintf(fp, "\n header: %lx\n", (ulong)dd->header); ++ dh = dd->header; ++ fprintf(fp, " signature: \""); ++ for (i = 0; i < SIG_LEN; i++) ++ if (dh->signature[i]) ++ fprintf(fp, "%c", dh->signature[i]); ++ fprintf(fp, "\"\n"); ++ fprintf(fp, " header_version: %d\n", dh->header_version); ++ fprintf(fp, " utsname:\n"); ++ fprintf(fp, " sysname: %s\n", dh->utsname.sysname); ++ fprintf(fp, " nodename: %s\n", dh->utsname.nodename); ++ fprintf(fp, " release: %s\n", dh->utsname.release); ++ fprintf(fp, " version: %s\n", dh->utsname.version); ++ fprintf(fp, " machine: %s\n", dh->utsname.machine); ++ fprintf(fp, " domainname: %s\n", dh->utsname.domainname); ++ fprintf(fp, " timestamp:\n"); ++ fprintf(fp, " tv_sec: %lx\n", dh->timestamp.tv_sec); ++ fprintf(fp, " tv_usec: %lx\n", dh->timestamp.tv_usec); ++ fprintf(fp, " status: %x (", dh->status); ++ switch (dd->flags & (DISKDUMP_LOCAL|KDUMP_CMPRS_LOCAL)) ++ { ++ case DISKDUMP_LOCAL: ++ if (dh->status == DUMP_HEADER_COMPLETED) ++ fprintf(fp, "DUMP_HEADER_COMPLETED"); ++ else if (dh->status == DUMP_HEADER_INCOMPLETED) ++ fprintf(fp, "DUMP_HEADER_INCOMPLETED"); ++ else if (dh->status == DUMP_HEADER_COMPRESSED) ++ fprintf(fp, "DUMP_HEADER_COMPRESSED"); ++ break; ++ case KDUMP_CMPRS_LOCAL: ++ if (dh->status & DUMP_DH_COMPRESSED_ZLIB) ++ fprintf(fp, "DUMP_DH_COMPRESSED_ZLIB"); ++ if (dh->status & DUMP_DH_COMPRESSED_LZO) ++ fprintf(fp, "DUMP_DH_COMPRESSED_LZO"); ++ if (dh->status & DUMP_DH_COMPRESSED_SNAPPY) ++ fprintf(fp, "DUMP_DH_COMPRESSED_SNAPPY"); ++ if (dh->status & DUMP_DH_COMPRESSED_INCOMPLETE) ++ fprintf(fp, "DUMP_DH_COMPRESSED_INCOMPLETE"); ++ if (dh->status & DUMP_DH_EXCLUDED_VMEMMAP) ++ fprintf(fp, "DUMP_DH_EXCLUDED_VMEMMAP"); ++ break; ++ } ++ fprintf(fp, ")\n"); ++ fprintf(fp, " block_size: %d\n", dh->block_size); ++ fprintf(fp, " sub_hdr_size: %d\n", dh->sub_hdr_size); ++ fprintf(fp, " bitmap_blocks: %u\n", dh->bitmap_blocks); ++ fprintf(fp, " max_mapnr: %u\n", dh->max_mapnr); ++ fprintf(fp, " total_ram_blocks: %u\n", dh->total_ram_blocks); ++ fprintf(fp, " device_blocks: %u\n", dh->device_blocks); ++ fprintf(fp, " written_blocks: %u\n", dh->written_blocks); ++ fprintf(fp, " current_cpu: %u\n", dh->current_cpu); ++ fprintf(fp, " nr_cpus: %d\n", dh->nr_cpus); ++ tasks = (ulong *)&dh->tasks[0]; ++ fprintf(fp, " tasks[nr_cpus]: %lx\n", *tasks); ++ for (tasks++, i = 1; i < dh->nr_cpus; i++) { ++ fprintf(fp, " %lx\n", *tasks); ++ tasks++; ++ } ++ fprintf(fp, "\n"); ++ fprintf(fp, " sub_header: %lx ", (ulong)dd->sub_header); ++ if ((dsh = dd->sub_header)) { ++ fprintf(fp, "\n elf_regs: %lx\n", ++ (ulong)&dsh->elf_regs); ++ fprintf(fp, " dump_level: "); ++ if ((pc->flags & RUNTIME) && ++ ((dump_level = get_dump_level()) >= 0)) { ++ fprintf(fp, "%d (0x%x) %s", dump_level, dump_level, ++ dump_level ? "(" : ""); ++ ++#define DUMP_EXCLUDE_CACHE 0x00000001 /* Exclude LRU & SwapCache pages*/ ++#define DUMP_EXCLUDE_CLEAN 0x00000002 /* Exclude all-zero pages */ ++#define DUMP_EXCLUDE_FREE 0x00000004 /* Exclude free pages */ ++#define DUMP_EXCLUDE_ANON 0x00000008 /* Exclude Anon pages */ ++#define DUMP_SAVE_PRIVATE 0x00000010 /* Save private pages */ ++ ++ others = 0; ++ if (dump_level & DUMP_EXCLUDE_CACHE) ++ fprintf(fp, "%sDUMP_EXCLUDE_CACHE", ++ others++ ? "|" : ""); ++ if (dump_level & DUMP_EXCLUDE_CLEAN) ++ fprintf(fp, "%sDUMP_EXCLUDE_CLEAN", ++ others++ ? "|" : ""); ++ if (dump_level & DUMP_EXCLUDE_FREE) ++ fprintf(fp, "%sDUMP_EXCLUDE_FREE", ++ others++ ? "|" : ""); ++ if (dump_level & DUMP_EXCLUDE_ANON) ++ fprintf(fp, "%sDUMP_EXCLUDE_ANON", ++ others++ ? "|" : ""); ++ if (dump_level & DUMP_SAVE_PRIVATE) ++ fprintf(fp, "%sDUMP_SAVE_PRIVATE", ++ others++ ? "|" : ""); ++ fprintf(fp, "%s\n\n", dump_level ? ")" : ""); ++ } else ++ fprintf(fp, "%s\n\n", pc->flags & RUNTIME ? ++ "(unknown)" : "(undetermined)"); ++ ++ } else ++ fprintf(fp, "(n/a)\n\n"); ++ ++ fprintf(fp, " sub_header_kdump: %lx ", (ulong)dd->sub_header_kdump); ++ if ((kdsh = dd->sub_header_kdump)) { ++ fprintf(fp, "\n phys_base: %lx\n", ++ (ulong)kdsh->phys_base); ++ fprintf(fp, " dump_level: "); ++ if ((dump_level = get_dump_level()) >= 0) { ++ fprintf(fp, "%d (0x%x) %s", dump_level, dump_level, ++ dump_level ? "(" : ""); ++ ++#define DL_EXCLUDE_ZERO (0x001) /* Exclude Pages filled with Zeros */ ++#define DL_EXCLUDE_CACHE (0x002) /* Exclude Cache Pages without Private Pages */ ++#define DL_EXCLUDE_CACHE_PRI (0x004) /* Exclude Cache Pages with Private Pages */ ++#define DL_EXCLUDE_USER_DATA (0x008) /* Exclude UserProcessData Pages */ ++#define DL_EXCLUDE_FREE (0x010) /* Exclude Free Pages */ ++ ++ others = 0; ++ if (dump_level & DL_EXCLUDE_ZERO) ++ fprintf(fp, "%sDUMP_EXCLUDE_ZERO", ++ others++ ? "|" : ""); ++ if (dump_level & DL_EXCLUDE_CACHE) ++ fprintf(fp, "%sDUMP_EXCLUDE_CACHE", ++ others++ ? "|" : ""); ++ if (dump_level & DL_EXCLUDE_CACHE_PRI) ++ fprintf(fp, "%sDUMP_EXCLUDE_CACHE_PRI", ++ others++ ? "|" : ""); ++ if (dump_level & DL_EXCLUDE_USER_DATA) ++ fprintf(fp, "%sDUMP_EXCLUDE_USER_DATA", ++ others++ ? "|" : ""); ++ if (dump_level & DL_EXCLUDE_FREE) ++ fprintf(fp, "%sDUMP_EXCLUDE_FREE", ++ others++ ? "|" : ""); ++ others = 0; ++ ++ fprintf(fp, "%s\n", dump_level ? ")" : ""); ++ } else ++ fprintf(fp, "(unknown)\n"); ++ ++ if (dh->header_version >= 2) { ++ fprintf(fp, " split: %d\n", kdsh->split); ++ fprintf(fp, " start_pfn: "); ++ if (KDUMP_SPLIT()) ++ fprintf(fp, "%ld (0x%lx)\n", ++ kdsh->start_pfn, kdsh->start_pfn); ++ else ++ fprintf(fp, "(unused)\n"); ++ fprintf(fp, " end_pfn: "); ++ if (KDUMP_SPLIT()) ++ fprintf(fp, "%ld (0x%lx)\n", ++ kdsh->end_pfn, kdsh->end_pfn); ++ else ++ fprintf(fp, "(unused)\n"); ++ } ++ if (dh->header_version >= 3) { ++ fprintf(fp, " offset_vmcoreinfo: %llu (0x%llx)\n", ++ (ulonglong)dd->sub_header_kdump->offset_vmcoreinfo, ++ (ulonglong)dd->sub_header_kdump->offset_vmcoreinfo); ++ fprintf(fp, " size_vmcoreinfo: %lu (0x%lx)\n", ++ dd->sub_header_kdump->size_vmcoreinfo, ++ dd->sub_header_kdump->size_vmcoreinfo); ++ if (dd->sub_header_kdump->offset_vmcoreinfo && ++ dd->sub_header_kdump->size_vmcoreinfo) { ++ dump_vmcoreinfo(fp); ++ } ++ } ++ if (dh->header_version >= 4) { ++ fprintf(fp, " offset_note: %llu (0x%llx)\n", ++ (ulonglong)dd->sub_header_kdump->offset_note, ++ (ulonglong)dd->sub_header_kdump->offset_note); ++ fprintf(fp, " size_note: %lu (0x%lx)\n", ++ dd->sub_header_kdump->size_note, ++ dd->sub_header_kdump->size_note); ++ fprintf(fp, " notes_buf: %lx\n", ++ (ulong)dd->notes_buf); ++ fprintf(fp, " num_vmcoredd_notes: %d\n", ++ dd->num_vmcoredd_notes); ++ for (i = 0; i < dd->num_vmcoredd_notes; i++) { ++ fprintf(fp, " notes[%d]: %lx %s\n", ++ i, (ulong)dd->nt_vmcoredd_array[i], ++ dd->nt_vmcoredd_array[i] ? "(NT_VMCOREDD)" : ""); ++ display_vmcoredd_note(dd->nt_vmcoredd_array[i], fp); ++ } ++ ++ fprintf(fp, " num_prstatus_notes: %d\n", ++ dd->num_prstatus_notes); ++ for (i = 0; i < dd->num_prstatus_notes; i++) { ++ fprintf(fp, " notes[%d]: %lx %s\n", ++ i, (ulong)dd->nt_prstatus_percpu[i], ++ dd->nt_prstatus_percpu[i] ? "(NT_PRSTATUS)" : ""); ++ display_ELF_note(dd->machine_type, PRSTATUS_NOTE, ++ dd->nt_prstatus_percpu[i], fp); ++ } ++ fprintf(fp, " snapshot_task: %lx %s\n", dd->snapshot_task, ++ dd->snapshot_task ? "(NT_TASKSTRUCT)" : ""); ++ fprintf(fp, " num_qemu_notes: %d\n", ++ dd->num_qemu_notes); ++ for (i = 0; i < dd->num_qemu_notes; i++) { ++ fprintf(fp, " notes[%d]: %lx (QEMUCPUState)\n", ++ i, (ulong)dd->nt_qemu_percpu[i]); ++ display_ELF_note(dd->machine_type, QEMU_NOTE, ++ dd->nt_qemu_percpu[i], fp); ++ } ++ dump_note_offsets(fp); ++ } ++ if (dh->header_version >= 5) { ++ fprintf(fp, " offset_eraseinfo: %llu (0x%llx)\n", ++ (ulonglong)dd->sub_header_kdump->offset_eraseinfo, ++ (ulonglong)dd->sub_header_kdump->offset_eraseinfo); ++ fprintf(fp, " size_eraseinfo: %lu (0x%lx)\n", ++ dd->sub_header_kdump->size_eraseinfo, ++ dd->sub_header_kdump->size_eraseinfo); ++ if (dd->sub_header_kdump->offset_eraseinfo && ++ dd->sub_header_kdump->size_eraseinfo) { ++ dump_eraseinfo(fp); ++ } ++ } ++ if (dh->header_version >= 6) { ++ fprintf(fp, " start_pfn_64: "); ++ if (KDUMP_SPLIT()) ++ fprintf(fp, "%lld (0x%llx)\n", ++ kdsh->start_pfn_64, kdsh->start_pfn_64); ++ else ++ fprintf(fp, "(unused)\n"); ++ fprintf(fp, " end_pfn_64: "); ++ if (KDUMP_SPLIT()) ++ fprintf(fp, "%lld (0x%llx)\n", ++ kdsh->end_pfn_64, kdsh->end_pfn_64); ++ else ++ fprintf(fp, "(unused)\n"); ++ ++ fprintf(fp, " max_mapnr_64: %llu (0x%llx)\n", ++ kdsh->max_mapnr_64, kdsh->max_mapnr_64); ++ } ++ fprintf(fp, "\n"); ++ } else ++ fprintf(fp, "(n/a)\n\n"); ++ ++ fprintf(fp, " data_offset: %lx\n", (ulong)dd->data_offset); ++ fprintf(fp, " block_size: %d\n", dd->block_size); ++ fprintf(fp, " block_shift: %d\n", dd->block_shift); ++ fprintf(fp, " bitmap: %lx\n", (ulong)dd->bitmap); ++ fprintf(fp, " bitmap_len: %lld\n", (ulonglong)dd->bitmap_len); ++ fprintf(fp, " max_mapnr: %lld (0x%llx)\n", dd->max_mapnr, dd->max_mapnr); ++ fprintf(fp, " dumpable_bitmap: %lx\n", (ulong)dd->dumpable_bitmap); ++ fprintf(fp, " byte: %d\n", dd->byte); ++ fprintf(fp, " bit: %d\n", dd->bit); ++ fprintf(fp, " compressed_page: %lx\n", (ulong)dd->compressed_page); ++ fprintf(fp, " curbufptr: %lx\n\n", (ulong)dd->curbufptr); ++ ++ for (i = 0; i < DISKDUMP_CACHED_PAGES; i++) { ++ fprintf(fp, "%spage_cache_hdr[%d]:\n", i < 10 ? " " : "", i); ++ fprintf(fp, " pg_flags: %x (", dd->page_cache_hdr[i].pg_flags); ++ others = 0; ++ if (dd->page_cache_hdr[i].pg_flags & PAGE_VALID) ++ fprintf(fp, "%sPAGE_VALID", others++ ? "|" : ""); ++ fprintf(fp, ")\n"); ++ fprintf(fp, " pg_addr: %llx\n", (ulonglong)dd->page_cache_hdr[i].pg_addr); ++ fprintf(fp, " pg_bufptr: %lx\n", (ulong)dd->page_cache_hdr[i].pg_bufptr); ++ fprintf(fp, " pg_hit_count: %ld\n", dd->page_cache_hdr[i].pg_hit_count); ++ } ++ ++ fprintf(fp, "\n page_cache_buf: %lx\n", (ulong)dd->page_cache_buf); ++ fprintf(fp, " evict_index: %d\n", dd->evict_index); ++ fprintf(fp, " evictions: %ld\n", dd->evictions); ++ fprintf(fp, " accesses: %ld\n", dd->accesses); ++ fprintf(fp, " cached_reads: %ld ", dd->cached_reads); ++ if (dd->accesses) ++ fprintf(fp, "(%ld%%)\n", ++ dd->cached_reads * 100 / dd->accesses); ++ else ++ fprintf(fp, "\n"); ++ fprintf(fp, " valid_pages: %lx\n", (ulong)dd->valid_pages); ++ ++ return 0; ++} ++ ++/* ++ * Wrapper of __diskdump_memory_dump() ++ */ ++int ++diskdump_memory_dump(FILE *fp) ++{ ++ int i; ++ ++ if (KDUMP_SPLIT() && (dd_list != NULL)) ++ for (i = 0; i < num_dumpfiles; i++) { ++ dd = dd_list[i]; ++ __diskdump_memory_dump(fp); ++ fprintf(fp, "\n"); ++ } ++ else ++ __diskdump_memory_dump(fp); ++ ++ return 0; ++} ++ ++ ++/* ++ * Get the switch_stack address of the passed-in task. ++ */ ++ulong ++get_diskdump_switch_stack(ulong task) ++{ ++ return 0; ++} ++ ++/* ++ * Versions of disk_dump that support it contain the "dump_level" symbol. ++ * Version 1 and later compressed kdump dumpfiles contain the dump level ++ * in an additional field of the sub_header_kdump structure. ++ */ ++int ++get_dump_level(void) ++{ ++ int dump_level; ++ ++ if (DISKDUMP_VALID()) { ++ if (symbol_exists("dump_level") && ++ readmem(symbol_value("dump_level"), KVADDR, &dump_level, ++ sizeof(dump_level), "dump_level", QUIET|RETURN_ON_ERROR)) ++ return dump_level; ++ } else if (KDUMP_CMPRS_VALID()) { ++ if (dd->header->header_version >= 1) ++ return dd->sub_header_kdump->dump_level; ++ } ++ ++ return -1; ++} ++ ++/* ++ * Used by the "sys" command to display [PARTIAL DUMP] ++ * after the dumpfile name. ++ */ ++int ++is_partial_diskdump(void) ++{ ++ return (get_dump_level() > 0 ? TRUE : FALSE); ++} ++ ++/* ++ * Used by "sys" command to dump multiple split dumpfiles. ++ */ ++void ++show_split_dumpfiles(void) ++{ ++ int i; ++ struct diskdump_data *ddp; ++ struct disk_dump_header *dh; ++ ++ for (i = 0; i < num_dumpfiles; i++) { ++ ddp = dd_list[i]; ++ dh = ddp->header; ++ fprintf(fp, "%s%s%s%s%s", ++ i ? " " : "", ++ ddp->filename, ++ is_partial_diskdump() ? " [PARTIAL DUMP]" : "", ++ dh->status & DUMP_DH_COMPRESSED_INCOMPLETE ? ++ " [INCOMPLETE]" : "", ++ dh->status & DUMP_DH_EXCLUDED_VMEMMAP ? ++ " [EXCLUDED VMEMMAP]" : ""); ++ if ((i+1) < num_dumpfiles) ++ fprintf(fp, "\n"); ++ } ++} ++ ++void * ++diskdump_get_prstatus_percpu(int cpu) ++{ ++ int online; ++ ++ if ((cpu < 0) || (cpu >= dd->num_prstatus_notes)) ++ return NULL; ++ ++ /* ++ * If no cpu mapping was done, then there must be ++ * a one-to-one relationship between the number ++ * of online cpus and the number of notes. ++ */ ++ if ((online = get_cpus_online()) && ++ (online == kt->cpus) && ++ (online != dd->num_prstatus_notes)) ++ return NULL; ++ ++ return dd->nt_prstatus_percpu[cpu]; ++} ++ ++/* ++ * Reads a string value from VMCOREINFO. ++ * ++ * 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; ++ ulong size_vmcoreinfo; ++ off_t offset; ++ char keybuf[BUFSIZE]; ++ const off_t failed = (off_t)-1; ++ ++ if (dd->header->header_version < 3) ++ return NULL; ++ ++ buf = value_string = NULL; ++ size_vmcoreinfo = dd->sub_header_kdump->size_vmcoreinfo; ++ offset = dd->sub_header_kdump->offset_vmcoreinfo; ++ sprintf(keybuf, "%s=", key); ++ ++ if ((buf = malloc(size_vmcoreinfo+1)) == NULL) { ++ error(INFO, "compressed kdump: cannot malloc vmcoreinfo" ++ " buffer\n"); ++ goto err; ++ } ++ ++ if (FLAT_FORMAT()) { ++ if (!read_flattened_format(dd->dfd, offset, buf, size_vmcoreinfo)) { ++ error(INFO, "compressed kdump: cannot read vmcoreinfo data\n"); ++ goto err; ++ } ++ } else { ++ if (lseek(dd->dfd, offset, SEEK_SET) == failed) { ++ error(INFO, "compressed kdump: cannot lseek dump vmcoreinfo\n"); ++ goto err; ++ } ++ if (read(dd->dfd, buf, size_vmcoreinfo) < size_vmcoreinfo) { ++ error(INFO, "compressed kdump: cannot read vmcoreinfo data\n"); ++ goto err; ++ } ++ } ++ ++ buf[size_vmcoreinfo] = '\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 ++diskdump_get_osrelease(void) ++{ ++ char *string; ++ ++ if ((string = vmcoreinfo_read_string("OSRELEASE"))) { ++ fprintf(fp, "%s\n", string); ++ free(string); ++ } ++ else ++ pc->flags2 &= ~GET_OSRELEASE; ++} ++ ++static int ++valid_note_address(unsigned char *offset) ++{ ++ if (offset > (dd->notes_buf + dd->sub_header_kdump->size_note)) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++void ++diskdump_display_regs(int cpu, FILE *ofp) ++{ ++ Elf32_Nhdr *note32; ++ Elf64_Nhdr *note64; ++ char *user_regs; ++ size_t len; ++ ++ if ((cpu < 0) || (cpu >= dd->num_prstatus_notes) || ++ (dd->nt_prstatus_percpu[cpu] == NULL)) { ++ error(INFO, "registers not collected for cpu %d\n", cpu); ++ return; ++ } ++ ++ if (machine_type("X86_64")) { ++ note64 = dd->nt_prstatus_percpu[cpu]; ++ len = sizeof(Elf64_Nhdr); ++ len = roundup(len + note64->n_namesz, 4); ++ len = roundup(len + note64->n_descsz, 4); ++ if (!valid_note_address((unsigned char *)note64 + len)) { ++ error(INFO, "invalid NT_PRSTATUS note for cpu %d\n", cpu); ++ return; ++ } ++ user_regs = (char *)note64 + len - SIZE(user_regs_struct) - sizeof(long); ++ fprintf(ofp, ++ " RIP: %016llx RSP: %016llx RFLAGS: %08llx\n" ++ " RAX: %016llx RBX: %016llx RCX: %016llx\n" ++ " RDX: %016llx RSI: %016llx RDI: %016llx\n" ++ " RBP: %016llx R8: %016llx R9: %016llx\n" ++ " R10: %016llx R11: %016llx R12: %016llx\n" ++ " R13: %016llx R14: %016llx R15: %016llx\n" ++ " CS: %04x SS: %04x\n", ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_rip)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_rsp)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_eflags)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_rax)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_rbx)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_rcx)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_rdx)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_rsi)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_rdi)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_rbp)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_r8)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_r9)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_r10)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_r11)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_r12)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_r13)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_r14)), ++ ULONGLONG(user_regs + OFFSET(user_regs_struct_r15)), ++ USHORT(user_regs + OFFSET(user_regs_struct_cs)), ++ USHORT(user_regs + OFFSET(user_regs_struct_ss)) ++ ); ++ } ++ ++ if (machine_type("PPC64")) { ++ struct ppc64_elf_prstatus *prs; ++ struct ppc64_pt_regs *pr; ++ ++ note64 = dd->nt_prstatus_percpu[cpu]; ++ len = sizeof(Elf64_Nhdr); ++ len = roundup(len + note64->n_namesz, 4); ++ len = roundup(len + note64->n_descsz, 4); ++ if (!valid_note_address((unsigned char *)note64 + len)) { ++ error(INFO, "invalid NT_PRSTATUS note for cpu %d\n", cpu); ++ return; ++ } ++ ++ prs = (struct ppc64_elf_prstatus *) ++ ((char *)note64 + sizeof(Elf64_Nhdr) + note64->n_namesz); ++ prs = (struct ppc64_elf_prstatus *)roundup((ulong)prs, 4); ++ pr = &prs->pr_reg; ++ ++ fprintf(ofp, ++ " R0: %016lx R1: %016lx R2: %016lx\n" ++ " R3: %016lx R4: %016lx R5: %016lx\n" ++ " R6: %016lx R7: %016lx R8: %016lx\n" ++ " R9: %016lx R10: %016lx R11: %016lx\n" ++ " R12: %016lx R13: %016lx R14: %016lx\n" ++ " R15: %016lx R16: %016lx R16: %016lx\n" ++ " R18: %016lx R19: %016lx R20: %016lx\n" ++ " R21: %016lx R22: %016lx R23: %016lx\n" ++ " R24: %016lx R25: %016lx R26: %016lx\n" ++ " R27: %016lx R28: %016lx R29: %016lx\n" ++ " R30: %016lx R31: %016lx\n" ++ " NIP: %016lx MSR: %016lx\n" ++ " OGPR3: %016lx CTR: %016lx\n" ++ " LINK: %016lx XER: %016lx\n" ++ " CCR: %016lx MQ: %016lx\n" ++ " TRAP: %016lx DAR: %016lx\n" ++ " DSISR: %016lx RESULT: %016lx\n", ++ pr->gpr[0], pr->gpr[1], pr->gpr[2], ++ pr->gpr[3], pr->gpr[4], pr->gpr[5], ++ pr->gpr[6], pr->gpr[7], pr->gpr[8], ++ pr->gpr[9], pr->gpr[10], pr->gpr[11], ++ pr->gpr[12], pr->gpr[13], pr->gpr[14], ++ pr->gpr[15], pr->gpr[16], pr->gpr[17], ++ pr->gpr[18], pr->gpr[19], pr->gpr[20], ++ pr->gpr[21], pr->gpr[22], pr->gpr[23], ++ pr->gpr[24], pr->gpr[25], pr->gpr[26], ++ pr->gpr[27], pr->gpr[28], pr->gpr[29], ++ pr->gpr[30], pr->gpr[31], ++ pr->nip, pr->msr, ++ pr->orig_gpr3, pr->ctr, ++ pr->link, pr->xer, ++ pr->ccr, pr->mq, ++ pr->trap, pr->dar, ++ pr->dsisr, pr->result); ++ } ++ ++ if (machine_type("ARM64")) { ++ note64 = dd->nt_prstatus_percpu[cpu]; ++ len = sizeof(Elf64_Nhdr); ++ len = roundup(len + note64->n_namesz, 4); ++ len = roundup(len + note64->n_descsz, 4); ++ if (!valid_note_address((unsigned char *)note64 + len)) { ++ error(INFO, "invalid NT_PRSTATUS note for cpu %d\n", cpu); ++ return; ++ } ++ user_regs = (char *)note64 + len - SIZE(elf_prstatus) + OFFSET(elf_prstatus_pr_reg); ++ fprintf(ofp, ++ " X0: %016lx X1: %016lx X2: %016lx\n" ++ " X3: %016lx X4: %016lx X5: %016lx\n" ++ " X6: %016lx X7: %016lx X8: %016lx\n" ++ " X9: %016lx X10: %016lx X11: %016lx\n" ++ " X12: %016lx X13: %016lx X14: %016lx\n" ++ " X15: %016lx X16: %016lx X17: %016lx\n" ++ " X18: %016lx X19: %016lx X20: %016lx\n" ++ " X21: %016lx X22: %016lx X23: %016lx\n" ++ " X24: %016lx X25: %016lx X26: %016lx\n" ++ " X27: %016lx X28: %016lx X29: %016lx\n" ++ " LR: %016lx SP: %016lx PC: %016lx\n" ++ " PSTATE: %08lx FPVALID: %08x\n", ++ ULONG(user_regs + sizeof(ulong) * 0), ++ ULONG(user_regs + sizeof(ulong) * 1), ++ ULONG(user_regs + sizeof(ulong) * 2), ++ ULONG(user_regs + sizeof(ulong) * 3), ++ ULONG(user_regs + sizeof(ulong) * 4), ++ ULONG(user_regs + sizeof(ulong) * 5), ++ ULONG(user_regs + sizeof(ulong) * 6), ++ ULONG(user_regs + sizeof(ulong) * 7), ++ ULONG(user_regs + sizeof(ulong) * 8), ++ ULONG(user_regs + sizeof(ulong) * 9), ++ ULONG(user_regs + sizeof(ulong) * 10), ++ ULONG(user_regs + sizeof(ulong) * 11), ++ ULONG(user_regs + sizeof(ulong) * 12), ++ ULONG(user_regs + sizeof(ulong) * 13), ++ ULONG(user_regs + sizeof(ulong) * 14), ++ ULONG(user_regs + sizeof(ulong) * 15), ++ ULONG(user_regs + sizeof(ulong) * 16), ++ ULONG(user_regs + sizeof(ulong) * 17), ++ ULONG(user_regs + sizeof(ulong) * 18), ++ ULONG(user_regs + sizeof(ulong) * 19), ++ ULONG(user_regs + sizeof(ulong) * 20), ++ ULONG(user_regs + sizeof(ulong) * 21), ++ ULONG(user_regs + sizeof(ulong) * 22), ++ ULONG(user_regs + sizeof(ulong) * 23), ++ ULONG(user_regs + sizeof(ulong) * 24), ++ ULONG(user_regs + sizeof(ulong) * 25), ++ ULONG(user_regs + sizeof(ulong) * 26), ++ ULONG(user_regs + sizeof(ulong) * 27), ++ ULONG(user_regs + sizeof(ulong) * 28), ++ ULONG(user_regs + sizeof(ulong) * 29), ++ ULONG(user_regs + sizeof(ulong) * 30), ++ ULONG(user_regs + sizeof(ulong) * 31), ++ ULONG(user_regs + sizeof(ulong) * 32), ++ ULONG(user_regs + sizeof(ulong) * 33), ++ UINT(user_regs + sizeof(ulong) * 34)); ++ } ++ ++ if (machine_type("X86")) { ++ note32 = dd->nt_prstatus_percpu[cpu]; ++ len = sizeof(Elf32_Nhdr); ++ len = roundup(len + note32->n_namesz, 4); ++ len = roundup(len + note32->n_descsz, 4); ++ user_regs = (char *)note32 + len - SIZE(user_regs_struct) - sizeof(int); ++ if (!valid_note_address((unsigned char *)note32 + len)) { ++ error(INFO, "invalid NT_PRSTATUS note for cpu %d\n", cpu); ++ return; ++ } ++ fprintf(ofp, ++ " EAX: %08x EBX: %08x ECX: %08x EDX: %08x\n" ++ " ESP: %08x EIP: %08x ESI: %08x EDI: %08x\n" ++ " CS: %04x DS: %04x ES: %04x FS: %04x\n" ++ " GS: %04x SS: %04x\n" ++ " EBP: %08x EFLAGS: %08x\n", ++ UINT(user_regs + OFFSET(user_regs_struct_eax)), ++ UINT(user_regs + OFFSET(user_regs_struct_ebx)), ++ UINT(user_regs + OFFSET(user_regs_struct_ecx)), ++ UINT(user_regs + OFFSET(user_regs_struct_edx)), ++ UINT(user_regs + OFFSET(user_regs_struct_esp)), ++ UINT(user_regs + OFFSET(user_regs_struct_eip)), ++ UINT(user_regs + OFFSET(user_regs_struct_esi)), ++ UINT(user_regs + OFFSET(user_regs_struct_edi)), ++ USHORT(user_regs + OFFSET(user_regs_struct_cs)), ++ USHORT(user_regs + OFFSET(user_regs_struct_ds)), ++ USHORT(user_regs + OFFSET(user_regs_struct_es)), ++ USHORT(user_regs + OFFSET(user_regs_struct_fs)), ++ USHORT(user_regs + OFFSET(user_regs_struct_gs)), ++ USHORT(user_regs + OFFSET(user_regs_struct_ss)), ++ UINT(user_regs + OFFSET(user_regs_struct_ebp)), ++ UINT(user_regs + OFFSET(user_regs_struct_eflags)) ++ ); ++ } ++ ++ if (machine_type("MIPS")) ++ mips_display_regs_from_elf_notes(cpu, ofp); ++ ++ if (machine_type("MIPS64")) ++ mips64_display_regs_from_elf_notes(cpu, ofp); ++} ++ ++void ++dump_registers_for_compressed_kdump(void) ++{ ++ int c; ++ ++ if (!KDUMP_CMPRS_VALID() || (dd->header->header_version < 4) || ++ !(machine_type("X86") || machine_type("X86_64") || ++ machine_type("ARM64") || machine_type("PPC64") || ++ machine_type("MIPS") || machine_type("MIPS64"))) ++ error(FATAL, "-r option not supported for this dumpfile\n"); ++ ++ if (machine_type("ARM64") && (kt->cpus != dd->num_prstatus_notes)) ++ fprintf(fp, "NOTE: cpus: %d NT_PRSTATUS notes: %d " ++ "(note-to-cpu mapping is questionable)\n\n", ++ kt->cpus, dd->num_prstatus_notes); ++ ++ for (c = 0; c < kt->cpus; c++) { ++ if (hide_offline_cpu(c)) { ++ fprintf(fp, "%sCPU %d: [OFFLINE]\n", c ? "\n" : "", c); ++ continue; ++ } else ++ fprintf(fp, "%sCPU %d:\n", c ? "\n" : "", c); ++ diskdump_display_regs(c, fp); ++ } ++} ++ ++int ++diskdump_kaslr_check() ++{ ++ if (!QEMU_MEM_DUMP_NO_VMCOREINFO()) ++ return FALSE; ++ ++ if (dd->num_qemu_notes) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++#ifdef X86_64 ++int ++diskdump_get_nr_cpus(void) ++{ ++ return dd->num_qemu_notes; ++} ++ ++QEMUCPUState * ++diskdump_get_qemucpustate(int cpu) ++{ ++ if (cpu >= dd->num_qemu_notes) { ++ if (CRASHDEBUG(1)) ++ error(INFO, ++ "Invalid index for QEMU Note: %d (>= %d)\n", ++ cpu, dd->num_qemu_notes); ++ return NULL; ++ } ++ ++ if (dd->machine_type != EM_X86_64) { ++ if (CRASHDEBUG(1)) ++ error(INFO, "Only x86_64 64bit is supported.\n"); ++ return NULL; ++ } ++ ++ return (QEMUCPUState *)dd->nt_qemucs_percpu[cpu]; ++} ++#endif ++ ++/* ++ * extract hardware specific device dumps from coredump. ++ */ ++void ++diskdump_device_dump_extract(int index, char *outfile, FILE *ofp) ++{ ++ ulonglong offset; ++ ++ if (!dd->num_vmcoredd_notes) ++ error(FATAL, "no device dumps found in this dumpfile\n"); ++ else if (index >= dd->num_vmcoredd_notes) ++ error(FATAL, "no device dump found at index: %d", index); ++ ++ offset = dd->sub_header_kdump->offset_note + ++ ((unsigned char *)dd->nt_vmcoredd_array[index] - ++ dd->notes_buf); ++ ++ devdump_extract(dd->nt_vmcoredd_array[index], offset, outfile, ofp); ++} ++ ++/* ++ * list all hardware specific device dumps present in coredump. ++ */ ++void ++diskdump_device_dump_info(FILE *ofp) ++{ ++ ulonglong offset; ++ char buf[BUFSIZE]; ++ ulong i; ++ ++ if (!dd->num_vmcoredd_notes) ++ error(FATAL, "no device dumps found in this dumpfile\n"); ++ ++ fprintf(fp, "%s ", mkstring(buf, strlen("INDEX"), LJUST, "INDEX")); ++ fprintf(fp, " %s ", mkstring(buf, LONG_LONG_PRLEN, LJUST, "OFFSET")); ++ fprintf(fp, " %s ", mkstring(buf, LONG_PRLEN, LJUST, "SIZE")); ++ fprintf(fp, "NAME\n"); ++ ++ for (i = 0; i < dd->num_vmcoredd_notes; i++) { ++ fprintf(fp, "%s ", mkstring(buf, strlen("INDEX"), CENTER | INT_DEC, MKSTR(i))); ++ offset = dd->sub_header_kdump->offset_note + ++ ((unsigned char *)dd->nt_vmcoredd_array[i] - ++ dd->notes_buf); ++ devdump_info(dd->nt_vmcoredd_array[i], offset, ofp); ++ } ++} ++ ++static void ++zram_init(void) ++{ ++ MEMBER_OFFSET_INIT(zram_mempoll, "zram", "mem_pool"); ++ MEMBER_OFFSET_INIT(zram_compressor, "zram", "compressor"); ++ MEMBER_OFFSET_INIT(zram_table_flag, "zram_table_entry", "flags"); ++ if (INVALID_MEMBER(zram_table_flag)) ++ MEMBER_OFFSET_INIT(zram_table_flag, "zram_table_entry", "value"); ++ STRUCT_SIZE_INIT(zram_table_entry, "zram_table_entry"); ++} ++ ++static unsigned char * ++zram_object_addr(ulong pool, ulong handle, unsigned char *zram_buf) ++{ ++ ulong obj, off, class, page, zspage; ++ struct zspage zspage_s; ++ physaddr_t paddr; ++ unsigned int obj_idx, class_idx, size; ++ ulong pages[2], sizes[2]; ++ ++ readmem(handle, KVADDR, &obj, sizeof(void *), "zram entry", FAULT_ON_ERROR); ++ obj >>= OBJ_TAG_BITS; ++ phys_to_page(PTOB(obj >> OBJ_INDEX_BITS), &page); ++ obj_idx = (obj & OBJ_INDEX_MASK); ++ ++ readmem(page + OFFSET(page_private), KVADDR, &zspage, ++ sizeof(void *), "page_private", FAULT_ON_ERROR); ++ readmem(zspage, KVADDR, &zspage_s, sizeof(struct zspage), "zspage", FAULT_ON_ERROR); ++ ++ class_idx = zspage_s.class; ++ if (zspage_s.magic != ZSPAGE_MAGIC) ++ error(FATAL, "zspage magic incorrect: %x\n", zspage_s.magic); ++ ++ class = pool + OFFSET(zspoll_size_class); ++ class += (class_idx * sizeof(void *)); ++ readmem(class, KVADDR, &class, sizeof(void *), "size_class", FAULT_ON_ERROR); ++ readmem(class + OFFSET(size_class_size), KVADDR, ++ &size, sizeof(unsigned int), "size of class_size", FAULT_ON_ERROR); ++ off = (size * obj_idx) & (~machdep->pagemask); ++ if (off + size <= PAGESIZE()) { ++ if (!is_page_ptr(page, &paddr)) { ++ error(WARNING, "zspage: %lx: not a page pointer\n", page); ++ return NULL; ++ } ++ readmem(paddr + off, PHYSADDR, zram_buf, size, "zram buffer", FAULT_ON_ERROR); ++ goto out; ++ } ++ ++ pages[0] = page; ++ readmem(page + OFFSET(page_freelist), KVADDR, &pages[1], ++ sizeof(void *), "page_freelist", FAULT_ON_ERROR); ++ sizes[0] = PAGESIZE() - off; ++ sizes[1] = size - sizes[0]; ++ if (!is_page_ptr(pages[0], &paddr)) { ++ error(WARNING, "pages[0]: %lx: not a page pointer\n", pages[0]); ++ return NULL; ++ } ++ ++ readmem(paddr + off, PHYSADDR, zram_buf, sizes[0], "zram buffer[0]", FAULT_ON_ERROR); ++ if (!is_page_ptr(pages[1], &paddr)) { ++ error(WARNING, "pages[1]: %lx: not a page pointer\n", pages[1]); ++ return NULL; ++ } ++ ++ readmem(paddr, PHYSADDR, zram_buf + sizes[0], sizes[1], "zram buffer[1]", FAULT_ON_ERROR); ++ ++out: ++ readmem(page, KVADDR, &obj, sizeof(void *), "page flags", FAULT_ON_ERROR); ++ if (!(obj & (1<<10))) { //PG_OwnerPriv1 flag ++ return (zram_buf + ZS_HANDLE_SIZE); ++ } ++ ++ return zram_buf; ++} ++ ++static unsigned char * ++lookup_swap_cache(ulonglong pte_val, unsigned char *zram_buf) ++{ ++ ulonglong swp_offset; ++ ulong swp_type, swp_space, page; ++ struct list_pair lp; ++ physaddr_t paddr; ++ static int is_xarray = -1; ++ ++ if (is_xarray < 0) { ++ is_xarray = STREQ(MEMBER_TYPE_NAME("address_space", "i_pages"), "xarray"); ++ } ++ ++ swp_type = __swp_type(pte_val); ++ if (THIS_KERNEL_VERSION >= LINUX(2,6,0)) { ++ swp_offset = (ulonglong)__swp_offset(pte_val); ++ } else { ++ swp_offset = (ulonglong)SWP_OFFSET(pte_val); ++ } ++ ++ if (!symbol_exists("swapper_spaces")) ++ return NULL; ++ swp_space = symbol_value("swapper_spaces"); ++ swp_space += swp_type * sizeof(void *); ++ ++ readmem(swp_space, KVADDR, &swp_space, sizeof(void *), ++ "swp_spaces", FAULT_ON_ERROR); ++ swp_space += (swp_offset >> SWAP_ADDRESS_SPACE_SHIFT) * SIZE(address_space); ++ ++ lp.index = swp_offset; ++ if ((is_xarray ? do_xarray : do_radix_tree)(swp_space, RADIX_TREE_SEARCH, &lp)) { ++ readmem((ulong)lp.value, KVADDR, &page, sizeof(void *), ++ "swap_cache page", FAULT_ON_ERROR); ++ if (!is_page_ptr(page, &paddr)) { ++ error(WARNING, "radix page: %lx: not a page pointer\n", lp.value); ++ return NULL; ++ } ++ readmem(paddr, PHYSADDR, zram_buf, PAGESIZE(), "zram buffer", FAULT_ON_ERROR); ++ return zram_buf; ++ } ++ return NULL; ++} ++ ++static int get_disk_name_private_data(ulonglong pte_val, ulonglong vaddr, ++ char *name, ulong *private_data) ++{ ++ ulong swap_info, bdev, bd_disk; ++ ++ if (!symbol_exists("swap_info")) ++ return FALSE; ++ ++ swap_info = symbol_value("swap_info"); ++ ++ swap_info_init(); ++ if (vt->flags & SWAPINFO_V2) { ++ swap_info += (__swp_type(pte_val) * sizeof(void *)); ++ readmem(swap_info, KVADDR, &swap_info, ++ sizeof(void *), "swap_info", FAULT_ON_ERROR); ++ } else { ++ swap_info += (SIZE(swap_info_struct) * __swp_type(pte_val)); ++ } ++ ++ readmem(swap_info + OFFSET(swap_info_struct_bdev), KVADDR, &bdev, ++ sizeof(void *), "swap_info_struct_bdev", FAULT_ON_ERROR); ++ readmem(bdev + OFFSET(block_device_bd_disk), KVADDR, &bd_disk, ++ sizeof(void *), "block_device_bd_disk", FAULT_ON_ERROR); ++ if (name) ++ readmem(bd_disk + OFFSET(gendisk_disk_name), KVADDR, name, ++ strlen("zram"), "gendisk_disk_name", FAULT_ON_ERROR); ++ if (private_data) ++ readmem(bd_disk + OFFSET(gendisk_private_data), KVADDR, ++ private_data, sizeof(void *), "gendisk_private_data", ++ FAULT_ON_ERROR); ++ ++ return TRUE; ++} ++ ++ulong readswap(ulonglong pte_val, char *buf, ulong len, ulonglong vaddr) ++{ ++ char name[32] = {0}; ++ ++ if (!get_disk_name_private_data(pte_val, vaddr, name, NULL)) ++ return 0; ++ ++ if (!strncmp(name, "zram", 4)) { ++ return try_zram_decompress(pte_val, (unsigned char *)buf, len, vaddr); ++ } else { ++ if (CRASHDEBUG(2)) ++ error(WARNING, "this page has been swapped to %s\n", name); ++ return 0; ++ } ++} ++ ++ulong (*decompressor)(unsigned char *in_addr, ulong in_size, unsigned char *out_addr, ++ ulong *out_size, void *other/* NOT USED */); ++/* ++ * If userspace address was swapped out to zram, this function is called to decompress the object. ++ * try_zram_decompress returns decompressed page data and data length ++ */ ++ulong ++try_zram_decompress(ulonglong pte_val, unsigned char *buf, ulong len, ulonglong vaddr) ++{ ++ char name[32] = {0}; ++ ulonglong swp_offset; ++ unsigned char *obj_addr = NULL; ++ unsigned char *zram_buf = NULL; ++ unsigned char *outbuf = NULL; ++ ulong zram, zram_table_entry, sector, index, entry, flags, size, ++ outsize, off; ++ ++ if (INVALID_MEMBER(zram_compressor)) { ++ zram_init(); ++ if (INVALID_MEMBER(zram_compressor)) { ++ error(WARNING, ++ "Some pages are swapped out to zram. " ++ "Please run mod -s zram.\n"); ++ return 0; ++ } ++ } ++ ++ if (CRASHDEBUG(2)) ++ error(WARNING, "this page has swapped to zram\n"); ++ ++ if (!get_disk_name_private_data(pte_val, vaddr, NULL, &zram)) ++ return 0; ++ ++ readmem(zram + OFFSET(zram_compressor), KVADDR, name, ++ sizeof(name), "zram compressor", FAULT_ON_ERROR); ++ if (STREQ(name, "lzo")) { ++#ifdef LZO ++ if (!(dd->flags & LZO_SUPPORTED)) { ++ if (lzo_init() == LZO_E_OK) ++ dd->flags |= LZO_SUPPORTED; ++ else ++ return 0; ++ } ++ decompressor = (void *)lzo1x_decompress_safe; ++#else ++ error(WARNING, ++ "zram decompress error: this executable needs to be built" ++ " with lzo library\n"); ++ return 0; ++#endif ++ } else { /* todo: support more compressor */ ++ error(WARNING, "only the lzo compressor is supported\n"); ++ return 0; ++ } ++ ++ if (THIS_KERNEL_VERSION >= LINUX(2, 6, 0)) { ++ swp_offset = (ulonglong)__swp_offset(pte_val); ++ } else { ++ swp_offset = (ulonglong)SWP_OFFSET(pte_val); ++ } ++ ++ zram_buf = (unsigned char *)GETBUF(PAGESIZE()); ++ /* lookup page from swap cache */ ++ off = PAGEOFFSET(vaddr); ++ obj_addr = lookup_swap_cache(pte_val, zram_buf); ++ if (obj_addr != NULL) { ++ memcpy(buf, obj_addr + off, len); ++ goto out; ++ } ++ ++ sector = swp_offset << (PAGESHIFT() - 9); ++ index = sector >> SECTORS_PER_PAGE_SHIFT; ++ readmem(zram, KVADDR, &zram_table_entry, ++ sizeof(void *), "zram_table_entry", FAULT_ON_ERROR); ++ zram_table_entry += (index * SIZE(zram_table_entry)); ++ readmem(zram_table_entry, KVADDR, &entry, ++ sizeof(void *), "entry of table", FAULT_ON_ERROR); ++ readmem(zram_table_entry + OFFSET(zram_table_flag), KVADDR, &flags, ++ sizeof(void *), "zram_table_flag", FAULT_ON_ERROR); ++ if (!entry || (flags & ZRAM_FLAG_SAME_BIT)) { ++ memset(buf, entry, len); ++ goto out; ++ } ++ size = flags & (ZRAM_FLAG_SHIFT -1); ++ if (size == 0) { ++ len = 0; ++ goto out; ++ } ++ ++ readmem(zram + OFFSET(zram_mempoll), KVADDR, &zram, ++ sizeof(void *), "zram_mempoll", FAULT_ON_ERROR); ++ ++ obj_addr = zram_object_addr(zram, entry, zram_buf); ++ if (obj_addr == NULL) { ++ len = 0; ++ goto out; ++ } ++ ++ if (size == PAGESIZE()) { ++ memcpy(buf, obj_addr + off, len); ++ } else { ++ outbuf = (unsigned char *)GETBUF(PAGESIZE()); ++ outsize = PAGESIZE(); ++ if (!decompressor(obj_addr, size, outbuf, &outsize, NULL)) ++ memcpy(buf, outbuf + off, len); ++ else { ++ error(WARNING, "zram decompress error\n"); ++ len = 0; ++ } ++ FREEBUF(outbuf); ++ } ++ ++out: ++ if (len && CRASHDEBUG(2)) ++ error(INFO, "%lx: zram decompress success\n", vaddr); ++ FREEBUF(zram_buf); ++ return len; ++} +diff -Nur crash-7.3.0-orig/diskdump.h crash-7.3.0/diskdump.h +--- crash-7.3.0-orig/diskdump.h 2023-07-07 14:06:14.164365905 +0800 ++++ crash-7.3.0/diskdump.h 2023-07-07 14:08:21.999028204 +0800 +@@ -86,6 +86,7 @@ + #define DUMP_DH_COMPRESSED_SNAPPY 0x4 /* page is compressed with snappy */ + #define DUMP_DH_COMPRESSED_INCOMPLETE 0x8 /* dumpfile is incomplete */ + #define DUMP_DH_EXCLUDED_VMEMMAP 0x10 /* unused vmemmap pages are excluded */ ++#define DUMP_DH_COMPRESSED_ZSTD 0x20 /* page is compressed with zstd */ + + /* descriptor of each page for vmcore */ + typedef struct page_desc { +diff -Nur crash-7.3.0-orig/gdb-10.2.patch crash-7.3.0/gdb-10.2.patch +--- crash-7.3.0-orig/gdb-10.2.patch 1970-01-01 08:00:00.000000000 +0800 ++++ crash-7.3.0/gdb-10.2.patch 2023-07-07 14:08:22.000028210 +0800 +@@ -0,0 +1,1593 @@ ++ ++# When this file is updated in an existing source tree, it gets re-applied ++# during the next build using "patch -N --fuzz=0", which ignores patches ++# that have already been applied. However, if a gdb file has been modified ++# multiple times, the subsequent patching may fail to recognize that a ++# given patch has been previously applied, and will attempt to re-apply it. ++# To prevent any uninintended consequences, this file also acts as a ++# shell script that can restore any gdb file to its original state prior ++# to all subsequent patch applications. ++ ++--- gdb-10.2/Makefile.in.orig +++++ gdb-10.2/Makefile.in ++@@ -340,6 +340,9 @@ AR_FOR_BUILD = @AR_FOR_BUILD@ ++ AS_FOR_BUILD = @AS_FOR_BUILD@ ++ CC_FOR_BUILD = @CC_FOR_BUILD@ ++ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +++ifeq (${CRASH_TARGET}, PPC64) +++CFLAGS_FOR_BUILD += -m64 -fPIC +++endif ++ CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ ++ CXX_FOR_BUILD = @CXX_FOR_BUILD@ ++ DLLTOOL_FOR_BUILD = @DLLTOOL_FOR_BUILD@ ++@@ -406,6 +409,9 @@ GNATBIND = @GNATBIND@ ++ GNATMAKE = @GNATMAKE@ ++ ++ CFLAGS = @CFLAGS@ +++ifeq (${CRASH_TARGET}, PPC64) +++CFLAGS += -m64 -fPIC +++endif ++ LDFLAGS = @LDFLAGS@ ++ LIBCFLAGS = $(CFLAGS) ++ CXXFLAGS = @CXXFLAGS@ ++--- gdb-10.2/gdb/Makefile.in.orig +++++ gdb-10.2/gdb/Makefile.in ++@@ -571,7 +571,7 @@ CONFIG_DEP_SUBDIR = $(addsuffix /$(DEPDIR),$(CONFIG_SRC_SUBDIR)) ++ # It is also possible that you will need to add -I/usr/include/sys if ++ # your system doesn't have fcntl.h in /usr/include (which is where it ++ # should be according to Posix). ++-DEFS = @DEFS@ +++DEFS = -DCRASH_MERGE @DEFS@ ++ GDB_CFLAGS = -I. -I$(srcdir) -I$(srcdir)/config \ ++ -DLOCALEDIR="\"$(localedir)\"" $(DEFS) ++ ++@@ -1135,6 +1135,7 @@ COMMON_SFILES = \ ++ symmisc.c \ ++ symtab.c \ ++ target.c \ +++ ../../crash_target.c \ ++ target-connection.c \ ++ target-dcache.c \ ++ target-descriptions.c \ ++@@ -1564,7 +1565,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ ++ $(SUBDIR_TARGET_OBS) \ ++ $(SUBDIR_GCC_COMPILE_OBS) ++ ++-SUBDIRS = doc @subdirs@ data-directory +++SUBDIRS = build_no_subdirs ++ CLEANDIRS = $(SUBDIRS) ++ ++ # List of subdirectories in the build tree that must exist. ++@@ -1606,8 +1607,8 @@ generated_files = \ ++ # Flags needed to compile Python code ++ PYTHON_CFLAGS = @PYTHON_CFLAGS@ ++ ++-all: gdb$(EXEEXT) $(CONFIG_ALL) gdb-gdb.py gdb-gdb.gdb ++- @$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do +++all: gdb$(EXEEXT) gdb-gdb.py gdb-gdb.gdb +++ @$(MAKE) -s $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do ++ ++ # Rule for compiling .c files in the top-level gdb directory. ++ # The order-only dependencies ensure that we create the build subdirectories. ++@@ -1864,9 +1865,10 @@ libgdb.a: $(LIBGDB_OBS) ++ # Removing the old gdb first works better if it is running, at least on SunOS. ++ gdb$(EXEEXT): gdb.o $(LIBGDB_OBS) $(CDEPS) $(TDEPLIBS) ++ $(SILENCE) rm -f gdb$(EXEEXT) +++ @(cd ../..; make --no-print-directory GDB_FLAGS=-DGDB_10_2 library) ++ $(ECHO_CXXLD) $(CC_LD) $(INTERNAL_LDFLAGS) $(WIN32LDAPP) \ ++- -o gdb$(EXEEXT) gdb.o $(LIBGDB_OBS) \ ++- $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES) +++ -o $(shell /bin/cat mergeobj) $(LIBGDB_OBS) \ +++ $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES) $(shell /bin/cat mergelibs) ++ ifneq ($(CODESIGN_CERT),) ++ $(ECHO_SIGN) $(CODESIGN) -s $(CODESIGN_CERT) gdb$(EXEEXT) ++ endif ++@@ -2530,9 +2532,9 @@ ifeq ($(DEPMODE),depmode=gcc3) ++ # into place if the compile succeeds. We need this because gcc does ++ # not atomically write the dependency output file. ++ override COMPILE.post = -c -o $@ -MT $@ -MMD -MP \ ++- -MF $(@D)/$(DEPDIR)/$(basename $(@F)).Tpo ++-override POSTCOMPILE = @mv $(@D)/$(DEPDIR)/$(basename $(@F)).Tpo \ ++- $(@D)/$(DEPDIR)/$(basename $(@F)).Po +++ -MF $(subst ../..,.,$(@D))/$(DEPDIR)/$(basename $(@F)).Tpo +++override POSTCOMPILE = @mv $(subst ../..,.,$(@D))/$(DEPDIR)/$(basename $(@F)).Tpo \ +++ $(subst ../..,.,$(@D))/$(DEPDIR)/$(basename $(@F)).Po ++ else ++ override COMPILE.pre = source='$<' object='$@' libtool=no \ ++ DEPDIR=$(DEPDIR) $(DEPMODE) $(depcomp) \ ++--- gdb-10.2/gdb/cli/cli-cmds.c.orig +++++ gdb-10.2/gdb/cli/cli-cmds.c ++@@ -435,6 +435,11 @@ complete_command (const char *arg, int from_tty) ++ } ++ } ++ +++#ifdef CRASH_MERGE +++static int crash_from_tty = 0; +++extern "C" void untrusted_file(FILE *, char *); +++#endif +++ ++ int ++ is_complete_command (struct cmd_list_element *c) ++ { ++@@ -654,8 +659,32 @@ find_and_open_script (const char *script_file, int search_path) ++ close (fd); ++ errno = save_errno; ++ } ++- else ++- opened.emplace (gdb_file_up (result), std::move (full_path)); +++#ifdef CRASH_MERGE +++ /* +++ * Only allow trusted versions of .gdbinit files to be +++ * sourced during session initialization. +++ */ +++ if (crash_from_tty == -1) +++ { +++ struct stat statbuf; +++ FILE *stream = result; +++ int _fd = fileno (stream); +++ if (fstat (_fd, &statbuf) < 0) +++ { +++ perror_with_name (full_path.get()); +++ fclose (stream); +++ return opened; +++ } +++ if (statbuf.st_uid != getuid () || (statbuf.st_mode & S_IWOTH)) +++ { +++ untrusted_file(NULL, full_path.get()); +++ fclose (stream); +++ return opened; +++ } +++ } +++#endif +++ opened.emplace (gdb_file_up (result), std::move (full_path)); +++ ++ ++ return opened; ++ } ++@@ -719,7 +748,11 @@ source_script_with_search (const char *file, int from_tty, int search_path) ++ If the source command was invoked interactively, throw an ++ error. Otherwise (e.g. if it was invoked by a script), ++ just emit a warning, rather than cause an error. */ +++#ifdef CRASH_MERGE +++ if (from_tty > 0) +++#else ++ if (from_tty) +++#endif ++ perror_with_name (file); ++ else ++ { ++@@ -743,7 +776,14 @@ source_script_with_search (const char *file, int from_tty, int search_path) ++ void ++ source_script (const char *file, int from_tty) ++ { +++#ifdef CRASH_MERGE +++ crash_from_tty = from_tty; +++#endif ++ source_script_with_search (file, from_tty, 0); +++#ifdef CRASH_MERGE +++ crash_from_tty = 0; +++#endif +++ ++ } ++ ++ static void ++--- gdb-10.2/gdb/defs.h.orig +++++ gdb-10.2/gdb/defs.h ++@@ -629,4 +629,7 @@ DEF_ENUM_FLAGS_TYPE (enum user_selected_what_flag, user_selected_what); ++ ++ #include "utils.h" ++ +++#ifdef CRASH_MERGE +++extern "C" int gdb_main_entry(int, char **); +++#endif ++ #endif /* #ifndef DEFS_H */ ++--- gdb-10.2/gdb/dwarf2/read.c.orig +++++ gdb-10.2/gdb/dwarf2/read.c ++@@ -3015,7 +3015,11 @@ read_gdb_index_from_buffer (const char *filename, ++ indices. */ ++ if (version < 4) ++ { +++#ifdef CRASH_MERGE +++ static int warning_printed = 1; +++#else ++ static int warning_printed = 0; +++#endif ++ if (!warning_printed) ++ { ++ warning (_("Skipping obsolete .gdb_index section in %s."), ++@@ -3034,7 +3038,11 @@ read_gdb_index_from_buffer (const char *filename, ++ "set use-deprecated-index-sections on". */ ++ if (version < 6 && !deprecated_ok) ++ { +++#ifdef CRASH_MERGE +++ static int warning_printed = 1; +++#else ++ static int warning_printed = 0; +++#endif ++ if (!warning_printed) ++ { ++ warning (_("\ ++--- gdb-10.2/gdb/main.c.orig +++++ gdb-10.2/gdb/main.c ++@@ -392,6 +392,14 @@ start_event_loop () ++ return; ++ } ++ +++#ifdef CRASH_MERGE +++extern "C" void update_gdb_hooks(void); +++extern "C" void main_loop(void); +++extern "C" unsigned long crash_get_kaslr_offset(void); +++extern "C" int console(const char *, ...); +++void crash_target_init (void); +++#endif +++ ++ /* Call command_loop. */ ++ ++ /* Prevent inlining this function for the benefit of GDB's selftests ++@@ -925,7 +933,11 @@ captured_main_1 (struct captured_main_args *context) ++ } ++ } ++ +++#ifdef CRASH_MERGE +++ save_original_signals_state (1); +++#else ++ save_original_signals_state (quiet); +++#endif ++ ++ /* Try to set up an alternate signal stack for SIGSEGV handlers. */ ++ gdb::alternate_signal_stack signal_stack; ++@@ -999,7 +1011,7 @@ captured_main_1 (struct captured_main_args *context) ++ { ++ print_gdb_version (gdb_stdout, false); ++ wrap_here (""); ++- printf_filtered ("\n"); +++ printf_filtered ("\n\n"); ++ exit (0); ++ } ++ ++@@ -1038,6 +1050,10 @@ captured_main_1 (struct captured_main_args *context) ++ look at things by now. Initialize the default interpreter. */ ++ set_top_level_interpreter (interpreter_p); ++ +++#ifdef CRASH_MERGE +++ update_gdb_hooks(); +++#endif +++ ++ /* FIXME: cagney/2003-02-03: The big hack (part 2 of 2) that lets ++ GDB retain the old MI1 interpreter startup behavior. Output the ++ copyright message after the interpreter is installed when it is ++@@ -1066,7 +1082,11 @@ captured_main_1 (struct captured_main_args *context) ++ if (!system_gdbinit.empty () && !inhibit_gdbinit) ++ { ++ for (const std::string &file : system_gdbinit) +++#ifdef CRASH_MERGE +++ ret = catch_command_errors (source_script, file.c_str (), -1); +++#else ++ ret = catch_command_errors (source_script, file.c_str (), 0); +++#endif ++ } ++ ++ /* Read and execute $HOME/.gdbinit file, if it exists. This is done ++@@ -1075,7 +1095,11 @@ captured_main_1 (struct captured_main_args *context) ++ debugging or what directory you are in. */ ++ ++ if (!home_gdbinit.empty () && !inhibit_gdbinit && !inhibit_home_gdbinit) +++#ifdef CRASH_MERGE +++ ret = catch_command_errors (source_script, home_gdbinit.c_str (), -1); +++#else ++ ret = catch_command_errors (source_script, home_gdbinit.c_str (), 0); +++#endif ++ ++ /* Process '-ix' and '-iex' options early. */ ++ for (i = 0; i < cmdarg_vec.size (); i++) ++@@ -1121,7 +1145,11 @@ captured_main_1 (struct captured_main_args *context) ++ !batch_flag); ++ if (ret != 0) ++ ret = catch_command_errors (symbol_file_add_main_adapter, +++#ifdef CRASH_MERGE +++ symarg, 0); +++#else ++ symarg, !batch_flag); +++#endif ++ } ++ else ++ { ++@@ -1191,7 +1219,11 @@ captured_main_1 (struct captured_main_args *context) ++ { ++ auto_load_local_gdbinit_loaded = 1; ++ +++#ifdef CRASH_MERGE +++ ret = catch_command_errors (source_script, local_gdbinit.c_str (), -1); +++#else ++ ret = catch_command_errors (source_script, local_gdbinit.c_str (), 0); +++#endif ++ } ++ } ++ ++@@ -1242,6 +1274,16 @@ captured_main (void *data) ++ ++ captured_main_1 (context); ++ +++#ifdef CRASH_MERGE +++ /* Relocate the vmlinux. */ +++ objfile_rebase (symfile_objfile, crash_get_kaslr_offset()); +++ +++ crash_target_init(); +++ +++ /* Back to crash. */ +++ main_loop(); +++#endif +++ ++ /* NOTE: cagney/1999-11-07: There is probably no reason for not ++ moving this loop and the code found in captured_command_loop() ++ into the command_loop() proper. The main thing holding back that ++@@ -1256,6 +1298,9 @@ captured_main (void *data) ++ { ++ exception_print (gdb_stderr, ex); ++ } +++#ifdef CRASH_MERGE +++ console("\n"); +++#endif ++ } ++ /* No exit -- exit is through quit_command. */ ++ } ++@@ -1277,6 +1322,22 @@ gdb_main (struct captured_main_args *args) ++ return 1; ++ } ++ +++#ifdef CRASH_MERGE +++/* +++ * NOTE: adapted from gdb.c, which is no longer built in; changed name of +++ * original main() to gdb_main_entry() for use as crash entry point +++ */ +++int +++gdb_main_entry (int argc, char **argv) +++{ +++ struct captured_main_args args; +++ memset (&args, 0, sizeof args); +++ args.argc = argc; +++ args.argv = argv; +++ args.interpreter_p = INTERP_CONSOLE; +++ return gdb_main (&args); +++} +++#endif ++ ++ /* Don't use *_filtered for printing help. We don't want to prompt ++ for continue no matter how small the screen or how much we're going ++--- gdb-10.2/gdb/objfiles.h.orig +++++ gdb-10.2/gdb/objfiles.h ++@@ -747,9 +747,9 @@ extern int objfile_has_full_symbols (struct objfile *objfile); ++ ++ extern int objfile_has_symbols (struct objfile *objfile); ++ ++-extern int have_partial_symbols (void); +++extern "C" int have_partial_symbols (void); ++ ++-extern int have_full_symbols (void); +++extern "C" int have_full_symbols (void); ++ ++ extern void objfile_set_sym_fns (struct objfile *objfile, ++ const struct sym_fns *sf); ++--- gdb-10.2/gdb/printcmd.c.orig +++++ gdb-10.2/gdb/printcmd.c ++@@ -524,6 +524,9 @@ set_next_address (struct gdbarch *gdbarch, CORE_ADDR addr) ++ form. However note that DO_DEMANGLE can be overridden by the specific ++ settings of the demangle and asm_demangle variables. Returns ++ non-zero if anything was printed; zero otherwise. */ +++#ifdef CRASH_MERGE +++extern "C" int gdb_print_callback(unsigned long); +++#endif ++ ++ int ++ print_address_symbolic (struct gdbarch *gdbarch, CORE_ADDR addr, ++@@ -535,6 +538,12 @@ print_address_symbolic (struct gdbarch *gdbarch, CORE_ADDR addr, ++ int offset = 0; ++ int line = 0; ++ +++#ifdef CRASH_MERGE +++ if (!gdb_print_callback(addr)) { +++ return 0; +++ } +++#endif +++ ++ if (build_address_symbolic (gdbarch, addr, do_demangle, false, &name, ++ &offset, &filename, &line, &unmapped)) ++ return 0; ++@@ -1221,6 +1230,43 @@ print_command_1 (const char *args, int voidprint) ++ print_value (val, print_opts); ++ } ++ +++static void +++print_command_2 (const char *args, int voidprint) +++{ +++ struct value *val; +++ value_print_options print_opts; +++ +++ get_user_print_options (&print_opts); +++ /* Override global settings with explicit options, if any. */ +++ auto group = make_value_print_options_def_group (&print_opts); +++ gdb::option::process_options +++ (&args, gdb::option::PROCESS_OPTIONS_REQUIRE_DELIMITER, group); +++ +++ print_command_parse_format (&args, "print", &print_opts); +++ +++ const char *exp = args; +++ +++ if (exp != nullptr && *exp) +++ { +++ expression_up expr = parse_expression (exp); +++ val = evaluate_expression (expr.get ()); +++ } +++ else +++ val = access_value_history (0); +++ +++ printf_filtered ("%d %d %ld %ld %ld %ld\n", +++ check_typedef(value_type (val))->code(), +++ TYPE_UNSIGNED (check_typedef(value_type (val))), +++ TYPE_LENGTH (check_typedef(value_type(val))), +++ value_offset (val), value_bitpos (val), value_bitsize(val)); +++} +++ +++static void +++printm_command (const char *exp, int from_tty) +++{ +++ print_command_2 (exp, 1); +++} +++ ++ /* See valprint.h. */ ++ ++ void ++@@ -2855,6 +2901,12 @@ but no count or size letter (see \"x\" command)."), ++ c = add_com ("print", class_vars, print_command, print_help.c_str ()); ++ set_cmd_completer_handle_brkchars (c, print_command_completer); ++ add_com_alias ("p", "print", class_vars, 1); +++ +++ c = add_com ("printm", class_vars, printm_command, _("\ +++Similar to \"print\" command, but it used to print the type, size, offset,\n\ +++bitpos and bitsize of the expression EXP.")); +++ set_cmd_completer (c, expression_completer); +++ ++ add_com_alias ("inspect", "print", class_vars, 1); ++ ++ add_setshow_uinteger_cmd ("max-symbolic-offset", no_class, ++--- gdb-10.2/gdb/psymtab.c.orig +++++ gdb-10.2/gdb/psymtab.c ++@@ -283,6 +283,9 @@ find_pc_sect_psymtab_closer (struct objfile *objfile, ++ return best_pst; ++ } ++ +++#ifdef CRASH_MERGE +++ extern "C" int gdb_line_number_callback(unsigned long, unsigned long, unsigned long); +++#endif ++ /* Find which partial symtab contains PC and SECTION. Return NULL if ++ none. We return the psymtab that contains a symbol whose address ++ exactly matches PC, or, if we cannot find an exact match, the ++@@ -363,7 +366,12 @@ find_pc_sect_psymtab (struct objfile *objfile, CORE_ADDR pc, ++ ++ best_pst = find_pc_sect_psymtab_closer (objfile, pc, section, pst, ++ msymbol); +++#ifdef CRASH_MERGE +++ if ((best_pst != NULL) && +++ gdb_line_number_callback(pc, pst->text_low (objfile), pst->text_high (objfile))) +++#else ++ if (best_pst != NULL) +++#endif ++ return best_pst; ++ } ++ ++--- gdb-10.2/gdb/symfile.c.orig +++++ gdb-10.2/gdb/symfile.c ++@@ -652,7 +652,26 @@ default_symfile_offsets (struct objfile *objfile, ++ for (cur_sec = abfd->sections; cur_sec != NULL; cur_sec = cur_sec->next) ++ /* We do not expect this to happen; just skip this step if the ++ relocatable file has a section with an assigned VMA. */ ++- if (bfd_section_vma (cur_sec) != 0) +++ if (bfd_section_vma (cur_sec) != 0 +++ /* +++ * Kernel modules may have some non-zero VMAs, i.e., like the +++ * __ksymtab and __ksymtab_gpl sections in this example: +++ * +++ * Section Headers: +++ * [Nr] Name Type Address Offset +++ * Size EntSize Flags Link Info Align +++ * ... +++ * [ 8] __ksymtab PROGBITS 0000000000000060 0000ad90 +++ * 0000000000000010 0000000000000000 A 0 0 16 +++ * [ 9] .rela__ksymtab RELA 0000000000000000 0000ada0 +++ * 0000000000000030 0000000000000018 43 8 8 +++ * [10] __ksymtab_gpl PROGBITS 0000000000000070 0000add0 +++ * 00000000000001a0 0000000000000000 A 0 0 16 +++ * ... +++ * +++ * but they should be treated as if they are NULL. +++ */ +++ && strncmp (bfd_section_name (cur_sec), "__k", 3) != 0) ++ break; ++ ++ if (cur_sec == NULL) ++@@ -1083,6 +1102,12 @@ symbol_file_add_with_addrs (bfd *abfd, const char *name, ++ if (mainline) ++ flags |= OBJF_MAINLINE; ++ objfile = objfile::make (abfd, name, flags, parent); +++#ifdef CRASH_MERGE +++ if (add_flags & SYMFILE_MAINLINE) { +++ extern struct objfile *gdb_kernel_objfile; +++ gdb_kernel_objfile = objfile; +++ } +++#endif ++ ++ /* We either created a new mapped symbol table, mapped an existing ++ symbol table file which has not had initial symbol reading ++@@ -1375,6 +1400,10 @@ show_debug_file_directory (struct ui_file *file, int from_tty, ++ #if ! defined (DEBUG_SUBDIRECTORY) ++ #define DEBUG_SUBDIRECTORY ".debug" ++ #endif +++#ifdef CRASH_MERGE +++extern "C" int check_specified_module_tree(const char *, const char *); +++extern "C" char *check_specified_kernel_debug_file(); +++#endif ++ ++ /* Find a separate debuginfo file for OBJFILE, using DIR as the directory ++ where the original file resides (may not be the same as ++@@ -1410,6 +1439,15 @@ find_separate_debug_file (const char *dir, ++ if (separate_debug_file_exists (debugfile, crc32, objfile)) ++ return debugfile; ++ +++#ifdef CRASH_MERGE +++{ +++ if (check_specified_module_tree(objfile_name (objfile), debugfile.c_str()) && +++ separate_debug_file_exists(debugfile, crc32, objfile)) { +++ return debugfile; +++ } +++} +++#endif +++ ++ /* Then try in the global debugfile directories. ++ ++ Keep backward compatibility so that DEBUG_FILE_DIRECTORY being "" will ++@@ -1568,6 +1606,14 @@ find_separate_debug_file_by_debuglink (struct objfile *objfile) ++ } ++ } ++ +++#ifdef CRASH_MERGE +++ if (debugfile.empty ()) { +++ char *name_copy; +++ name_copy = check_specified_kernel_debug_file(); +++ return std::string (name_copy); +++ } +++#endif +++ ++ return debugfile; ++ } ++ ++@@ -2334,8 +2380,10 @@ add_symbol_file_command (const char *args, int from_tty) ++ else if (section_addrs.empty ()) ++ printf_unfiltered ("\n"); ++ +++#ifndef CRASH_MERGE ++ if (from_tty && (!query ("%s", ""))) ++ error (_("Not confirmed.")); +++#endif ++ ++ objf = symbol_file_add (filename.get (), add_flags, §ion_addrs, ++ flags); ++@@ -3622,6 +3670,15 @@ bfd_byte * ++ symfile_relocate_debug_section (struct objfile *objfile, ++ asection *sectp, bfd_byte *buf) ++ { +++#ifdef CRASH_MERGE +++ /* Executable files have all the relocations already resolved. +++ * Handle files linked with --emit-relocs. +++ * http://sources.redhat.com/ml/gdb/2006-08/msg00137.html +++ */ +++ bfd *abfd = objfile->obfd; +++ if ((abfd->flags & EXEC_P) != 0) +++ return NULL; +++#endif ++ gdb_assert (objfile->sf->sym_relocate); ++ ++ return (*objfile->sf->sym_relocate) (objfile, sectp, buf); ++--- gdb-10.2/gdb/symtab.c.orig +++++ gdb-10.2/gdb/symtab.c ++@@ -1870,27 +1870,46 @@ search_name_hash (enum language language, const char *search_name) ++ variable and thus can probably assume it will never hit the C++ ++ code). */ ++ +++#ifdef CRASH_MERGE +++static void gdb_bait_and_switch(char *, struct symbol *); +++#endif +++ ++ struct block_symbol ++ lookup_symbol_in_language (const char *name, const struct block *block, ++ const domain_enum domain, enum language lang, ++ struct field_of_this_result *is_a_field_of_this) ++ { +++ struct block_symbol result; ++ demangle_result_storage storage; ++ const char *modified_name = demangle_for_lookup (name, lang, storage); ++ ++- return lookup_symbol_aux (modified_name, +++ result = lookup_symbol_aux (modified_name, ++ symbol_name_match_type::FULL, ++ block, domain, lang, ++ is_a_field_of_this); +++#ifdef CRASH_MERGE +++ if (result.symbol && (domain == VAR_DOMAIN)) +++ gdb_bait_and_switch((char *)modified_name, result.symbol); +++#endif +++ return result; ++ } ++ ++ /* See symtab.h. */ ++ +++#ifdef CRASH_MERGE +++static const struct block *gdb_get_crash_block(void); +++#endif +++ ++ struct block_symbol ++ lookup_symbol (const char *name, const struct block *block, ++ domain_enum domain, ++ struct field_of_this_result *is_a_field_of_this) ++ { +++#ifdef CRASH_MERGE +++ if (!block) +++ block = gdb_get_crash_block(); +++#endif +++ ++ return lookup_symbol_in_language (name, block, domain, ++ current_language->la_language, ++ is_a_field_of_this); ++@@ -6886,3 +6905,806 @@ If zero then the symbol cache is disabled."), ++ gdb::observers::new_objfile.attach (symtab_new_objfile_observer); ++ gdb::observers::free_objfile.attach (symtab_free_objfile_observer); ++ } +++ +++#ifdef CRASH_MERGE +++#include "gdb-stabs.h" +++#include "gdbsupport/version.h" +++#define GDB_COMMON +++#include "../../defs.h" +++ +++static void get_member_data(struct gnu_request *, struct type *, long, int); +++static void dump_enum(struct type *, struct gnu_request *); +++static void eval_enum(struct type *, struct gnu_request *); +++static void gdb_get_line_number(struct gnu_request *); +++static void gdb_get_datatype(struct gnu_request *); +++static void gdb_get_symbol_type(struct gnu_request *); +++static void gdb_command_exists(struct gnu_request *); +++static void gdb_debug_command(struct gnu_request *); +++static void gdb_function_numargs(struct gnu_request *); +++static void gdb_add_symbol_file(struct gnu_request *); +++static void gdb_delete_symbol_file(struct gnu_request *); +++static void gdb_patch_symbol_values(struct gnu_request *); +++static void get_user_print_option_address(struct gnu_request *); +++extern int get_frame_offset(CORE_ADDR); +++static void gdb_set_crash_block(struct gnu_request *); +++extern "C" void gdb_command_funnel(struct gnu_request *); +++void gdb_command_funnel_1(struct gnu_request *); +++static long lookup_struct_contents(struct gnu_request *); +++static void iterate_datatypes(struct gnu_request *); +++ +++struct objfile *gdb_kernel_objfile = { 0 }; +++ +++static ulong gdb_merge_flags = 0; +++#define KERNEL_SYMBOLS_PATCHED (0x1) +++ +++#undef STREQ +++#define STREQ(A, B) (A && B && (strcmp(A, B) == 0)) +++#define TYPE_CODE(t) (t->code ()) +++#define TYPE_TAG_NAME(t) (TYPE_MAIN_TYPE(t)->name) +++#define TYPE_NFIELDS(t) (t->num_fields ()) +++#define TYPE_NAME(t) (t->name ()) +++ +++/* +++ * All commands from above come through here. +++ */ +++void +++gdb_command_funnel(struct gnu_request *req) +++{ +++ try { +++ gdb_command_funnel_1(req); +++ } catch (const gdb_exception &ex) { +++ if (req->flags & GNU_RETURN_ON_ERROR) +++ req->flags |= GNU_COMMAND_FAILED; +++ else +++ throw ex; +++ } +++} +++ +++void +++gdb_command_funnel_1(struct gnu_request *req) +++{ +++ struct symbol *sym; +++ +++ if (req->command != GNU_VERSION && req->command != GNU_USER_PRINT_OPTION) { +++ (dynamic_castgdb_stdout)->set_stream(req->fp); +++ (dynamic_castgdb_stderr)->set_stream(req->fp); +++ } +++ +++ switch (req->command) +++ { +++ case GNU_VERSION: +++ req->buf = (char *)version; +++ break; +++ +++ case GNU_PASS_THROUGH: +++ execute_command(req->buf, +++ req->flags & GNU_FROM_TTY_OFF ? FALSE : TRUE); +++ break; +++ +++ case GNU_USER_PRINT_OPTION: +++ get_user_print_option_address(req); +++ break; +++ +++ case GNU_RESOLVE_TEXT_ADDR: +++ sym = find_pc_function(req->addr); +++ if (!sym || TYPE_CODE(sym->type) != TYPE_CODE_FUNC) +++ req->flags |= GNU_COMMAND_FAILED; +++ break; +++ +++ case GNU_DISASSEMBLE: +++ if (req->addr2) +++ sprintf(req->buf, "disassemble 0x%lx 0x%lx", +++ req->addr, req->addr2); +++ else +++ sprintf(req->buf, "disassemble 0x%lx", req->addr); +++ execute_command(req->buf, TRUE); +++ break; +++ +++ case GNU_ADD_SYMBOL_FILE: +++ gdb_add_symbol_file(req); +++ break; +++ +++ case GNU_DELETE_SYMBOL_FILE: +++ gdb_delete_symbol_file(req); +++ break; +++ +++ case GNU_GET_LINE_NUMBER: +++ gdb_get_line_number(req); +++ break; +++ +++ case GNU_GET_DATATYPE: +++ gdb_get_datatype(req); +++ break; +++ +++ case GNU_GET_SYMBOL_TYPE: +++ gdb_get_symbol_type(req); +++ break; +++ +++ case GNU_COMMAND_EXISTS: +++ gdb_command_exists(req); +++ break; +++ +++ case GNU_ALPHA_FRAME_OFFSET: +++ req->value = 0; +++ break; +++ +++ case GNU_FUNCTION_NUMARGS: +++ gdb_function_numargs(req); +++ break; +++ +++ case GNU_DEBUG_COMMAND: +++ gdb_debug_command(req); +++ break; +++ +++ case GNU_PATCH_SYMBOL_VALUES: +++ gdb_patch_symbol_values(req); +++ break; +++ +++ case GNU_SET_CRASH_BLOCK: +++ gdb_set_crash_block(req); +++ break; +++ +++ case GNU_GET_FUNCTION_RANGE: +++ { +++ CORE_ADDR start, end; +++ if (!find_pc_partial_function(req->pc, NULL, &start, &end)) +++ req->flags |= GNU_COMMAND_FAILED; +++ else { +++ req->addr = (ulong)start; +++ req->addr2 = (ulong)end; +++ } +++ } +++ break; +++ +++ case GNU_LOOKUP_STRUCT_CONTENTS: +++ req->value = lookup_struct_contents(req); +++ break; +++ +++ case GNU_ITERATE_DATATYPES: +++ iterate_datatypes(req); +++ break; +++ +++ default: +++ req->flags |= GNU_COMMAND_FAILED; +++ break; +++ } +++} +++ +++/* +++ * Given a PC value, return the file and line number. +++ */ +++static void +++gdb_get_line_number(struct gnu_request *req) +++{ +++ struct symtab_and_line sal; +++ struct objfile *objfile; +++ CORE_ADDR pc; +++ +++#define LASTCHAR(s) (s[strlen(s)-1]) +++ +++ /* +++ * Prime the addrmap pump. +++ */ +++ pc = req->addr; +++ +++ sal = find_pc_line(pc, 0); +++ +++ if (!sal.symtab) { +++ /* +++ * If a module address line number can't be found, it's typically +++ * due to its addrmap still containing offset values because its +++ * objfile doesn't have full symbols loaded. +++ */ +++ if (req->lm) { +++ objfile = req->lm->loaded_objfile; +++ if (!objfile_has_full_symbols(objfile) && objfile->sf) { +++ objfile->sf->qf->expand_all_symtabs(objfile); +++ sal = find_pc_line(pc, 0); +++ } +++ } +++ if (!sal.symtab) { +++ req->buf[0] = '\0'; +++ return; +++ } +++ } +++ +++ if (sal.symtab->filename && SYMTAB_DIRNAME(sal.symtab)) { +++ if (sal.symtab->filename[0] == '/') +++ sprintf(req->buf, "%s: %d", +++ sal.symtab->filename, sal.line); +++ else +++ sprintf(req->buf, "%s%s%s: %d", +++ SYMTAB_DIRNAME(sal.symtab), +++ LASTCHAR(SYMTAB_DIRNAME(sal.symtab)) == '/' ? "" : "/", +++ sal.symtab->filename, sal.line); +++ } +++} +++ +++ +++/* +++ * General purpose routine for determining datatypes. +++ */ +++ +++static void +++gdb_get_datatype(struct gnu_request *req) +++{ +++ register struct type *type; +++ register struct type *typedef_type; +++ expression_up expr; +++ struct symbol *sym; +++ struct value *val; +++ +++ if (gdb_CRASHDEBUG(2)) +++ console("gdb_get_datatype [%s] (a)\n", req->name); +++ +++ req->typecode = TYPE_CODE_UNDEF; +++ +++ /* +++ * lookup_symbol() will pick up struct and union names. +++ */ +++ sym = lookup_symbol(req->name, 0, STRUCT_DOMAIN, 0).symbol; +++ if (sym) { +++ req->typecode = TYPE_CODE(sym->type); +++ req->length = TYPE_LENGTH(sym->type); +++ if (req->member) +++ get_member_data(req, sym->type, 0, 1); +++ +++ if (TYPE_CODE(sym->type) == TYPE_CODE_ENUM) { +++ if (req->flags & GNU_PRINT_ENUMERATORS) +++ dump_enum(sym->type, req); +++ } +++ +++ return; +++ } +++ +++ /* +++ * Otherwise parse the expression. +++ */ +++ if (gdb_CRASHDEBUG(2)) +++ console("gdb_get_datatype [%s] (b)\n", req->name); +++ +++ expr = parse_expression(req->name); +++ +++ +++ switch (expr.get()->elts[0].opcode) +++ { +++ case OP_VAR_VALUE: +++ if (gdb_CRASHDEBUG(2)) +++ console("expr->elts[0].opcode: OP_VAR_VALUE\n"); +++ type = expr.get()->elts[2].symbol->type; +++ if (req->flags & GNU_VAR_LENGTH_TYPECODE) { +++ req->typecode = TYPE_CODE(type); +++ req->length = TYPE_LENGTH(type); +++ } +++ if (TYPE_CODE(type) == TYPE_CODE_ENUM) { +++ req->typecode = TYPE_CODE(type); +++ req->value = SYMBOL_VALUE(expr.get()->elts[2].symbol); +++ req->tagname = (char *)TYPE_TAG_NAME(type); +++ if (!req->tagname) { +++ val = evaluate_type(expr.get()); +++ eval_enum(value_type(val), req); +++ } +++ } +++ break; +++ +++ case OP_TYPE: +++ if (gdb_CRASHDEBUG(2)) +++ console("expr->elts[0].opcode: OP_TYPE\n"); +++ type = expr.get()->elts[1].type; +++ +++ req->typecode = TYPE_CODE(type); +++ req->length = TYPE_LENGTH(type); +++ +++ if (TYPE_CODE(type) == TYPE_CODE_TYPEDEF) { +++ req->is_typedef = TYPE_CODE_TYPEDEF; +++ if ((typedef_type = check_typedef(type))) { +++ req->typecode = TYPE_CODE(typedef_type); +++ req->length = TYPE_LENGTH(typedef_type); +++ type = typedef_type; +++ } +++ } +++ +++ if (TYPE_CODE(type) == TYPE_CODE_ENUM) { +++ if (req->is_typedef) +++ if (req->flags & GNU_PRINT_ENUMERATORS) { +++ if (req->is_typedef) +++ fprintf_filtered(gdb_stdout, +++ "typedef "); +++ dump_enum(type, req); +++ } +++ } +++ +++ if (req->member) +++ get_member_data(req, type, 0, 1); +++ +++ break; +++ +++ default: +++ if (gdb_CRASHDEBUG(2)) +++ console("expr.get()->elts[0].opcode: %d (?)\n", +++ expr.get()->elts[0].opcode); +++ break; +++ +++ } +++} +++ +++/* +++ * More robust enum list dump that gdb's, showing the value of each +++ * identifier, each on its own line. +++ */ +++static void +++dump_enum(struct type *type, struct gnu_request *req) +++{ +++ register int i; +++ int len; +++ long long lastval; +++ +++ len = TYPE_NFIELDS (type); +++ lastval = 0; +++ if (TYPE_TAG_NAME(type)) +++ fprintf_filtered(gdb_stdout, +++ "enum %s {\n", TYPE_TAG_NAME (type)); +++ else +++ fprintf_filtered(gdb_stdout, "enum {\n"); +++ +++ for (i = 0; i < len; i++) { +++ fprintf_filtered(gdb_stdout, " %s", +++ TYPE_FIELD_NAME (type, i)); +++ if (lastval != TYPE_FIELD_ENUMVAL (type, i)) { +++ fprintf_filtered (gdb_stdout, " = %s", +++ plongest(TYPE_FIELD_ENUMVAL (type, i))); +++ lastval = TYPE_FIELD_ENUMVAL (type, i); +++ } else +++ fprintf_filtered(gdb_stdout, " = %s", plongest(lastval)); +++ fprintf_filtered(gdb_stdout, "\n"); +++ lastval++; +++ } +++ if (TYPE_TAG_NAME(type)) +++ fprintf_filtered(gdb_stdout, "};\n"); +++ else +++ fprintf_filtered(gdb_stdout, "} %s;\n", req->name); +++} +++ +++/* +++ * Given an enum type with no tagname, determine its value. +++ */ +++static void +++eval_enum(struct type *type, struct gnu_request *req) +++{ +++ register int i; +++ int len; +++ long long lastval; +++ +++ len = TYPE_NFIELDS (type); +++ lastval = 0; +++ +++ for (i = 0; i < len; i++) { +++ if (lastval != TYPE_FIELD_ENUMVAL (type, i)) +++ lastval = TYPE_FIELD_ENUMVAL (type, i); +++ +++ if (STREQ(TYPE_FIELD_NAME(type, i), req->name)) { +++ req->tagname = "(unknown)"; +++ req->value = lastval; +++ return; +++ } +++ lastval++; +++ } +++} +++ +++/* +++ * Walk through a struct type's list of fields looking for the desired +++ * member field, and when found, return its relevant data. +++ */ +++static void +++get_member_data(struct gnu_request *req, struct type *type, long offset, int is_first) +++{ +++ register short i; +++ struct field *nextfield; +++ short nfields; +++ struct type *typedef_type, *target_type; +++ +++ req->member_offset = -1; +++ +++ nfields = TYPE_MAIN_TYPE(type)->nfields; +++ nextfield = TYPE_MAIN_TYPE(type)->flds_bnds.fields; +++ +++ if (nfields == 0 && is_first /* The first call */) { +++ struct type *newtype; +++ newtype = lookup_transparent_type(req->name); +++ if (newtype) { +++ console("get_member_data(%s.%s): switching type from %lx to %lx\n", +++ req->name, req->member, type, newtype); +++ nfields = TYPE_MAIN_TYPE(newtype)->nfields; +++ nextfield = TYPE_MAIN_TYPE(newtype)->flds_bnds.fields; +++ } +++ } +++ +++ for (i = 0; i < nfields; i++) { +++ if (STREQ(req->member, nextfield->name)) { +++ req->member_offset = offset + nextfield->loc.bitpos; +++ req->member_length = TYPE_LENGTH(nextfield->type()); +++ req->member_typecode = TYPE_CODE(nextfield->type()); +++ req->member_main_type_name = (char *)TYPE_NAME(nextfield->type()); +++ req->member_main_type_tag_name = (char *)TYPE_TAG_NAME(nextfield->type()); +++ target_type = TYPE_TARGET_TYPE(nextfield->type()); +++ if (target_type) { +++ req->member_target_type_name = (char *)TYPE_NAME(target_type); +++ req->member_target_type_tag_name = (char *)TYPE_TAG_NAME(target_type); +++ } +++ if ((req->member_typecode == TYPE_CODE_TYPEDEF) && +++ (typedef_type = check_typedef(nextfield->type()))) +++ req->member_length = TYPE_LENGTH(typedef_type); +++ return; +++ } else if (*nextfield->name == 0) { /* Anonymous struct/union */ +++ get_member_data(req, nextfield->type(), +++ offset + nextfield->loc.bitpos, 0); +++ if (req->member_offset != -1) +++ return; +++ } +++ nextfield++; +++ } +++} +++ +++/* +++ * Check whether a command exists. If it doesn't, the command will be +++ * returned indirectly via the error_hook. +++ */ +++static void +++gdb_command_exists(struct gnu_request *req) +++{ +++ extern struct cmd_list_element *cmdlist; +++ +++ req->value = FALSE; +++ lookup_cmd((const char **)&req->name, cmdlist, "", NULL, 0, 1); +++ req->value = TRUE; +++} +++ +++static void +++gdb_function_numargs(struct gnu_request *req) +++{ +++ struct symbol *sym; +++ +++ sym = find_pc_function(req->pc); +++ +++ if (!sym || TYPE_CODE(sym->type) != TYPE_CODE_FUNC) { +++ req->flags |= GNU_COMMAND_FAILED; +++ return; +++ } +++ +++ req->value = (ulong)TYPE_NFIELDS(sym->type); +++} +++ +++struct load_module *gdb_current_load_module = NULL; +++ +++static void +++gdb_add_symbol_file(struct gnu_request *req) +++{ +++ struct load_module *lm; +++ int i; +++ int allsect = 0; +++ char *secname; +++ char buf[80]; +++ +++ gdb_current_load_module = lm = (struct load_module *)req->addr; +++ +++ req->name = lm->mod_namelist; +++ gdb_delete_symbol_file(req); +++ lm->loaded_objfile = NULL; +++ +++ if ((lm->mod_flags & MOD_NOPATCH) == 0) { +++ for (i = 0 ; i < lm->mod_sections; i++) { +++ if (STREQ(lm->mod_section_data[i].name, ".text") && +++ (lm->mod_section_data[i].flags & SEC_FOUND)) +++ allsect = 1; +++ } +++ +++ if (!allsect) { +++ sprintf(req->buf, "add-symbol-file %s 0x%lx %s", lm->mod_namelist, +++ lm->mod_text_start ? lm->mod_text_start : lm->mod_base, +++ lm->mod_flags & MOD_DO_READNOW ? "-readnow" : ""); +++ if (lm->mod_data_start) { +++ sprintf(buf, " -s .data 0x%lx", lm->mod_data_start); +++ strcat(req->buf, buf); +++ } +++ if (lm->mod_bss_start) { +++ sprintf(buf, " -s .bss 0x%lx", lm->mod_bss_start); +++ strcat(req->buf, buf); +++ } +++ if (lm->mod_rodata_start) { +++ sprintf(buf, " -s .rodata 0x%lx", lm->mod_rodata_start); +++ strcat(req->buf, buf); +++ } +++ } else { +++ sprintf(req->buf, "add-symbol-file %s 0x%lx %s", lm->mod_namelist, +++ lm->mod_text_start, lm->mod_flags & MOD_DO_READNOW ? +++ "-readnow" : ""); +++ for (i = 0; i < lm->mod_sections; i++) { +++ secname = lm->mod_section_data[i].name; +++ if ((lm->mod_section_data[i].flags & SEC_FOUND) && +++ !STREQ(secname, ".text")) { +++ sprintf(buf, " -s %s 0x%lx", secname, +++ lm->mod_section_data[i].offset + lm->mod_base); +++ strcat(req->buf, buf); +++ } +++ } +++ } +++ } +++ +++ if (gdb_CRASHDEBUG(1)) +++ fprintf_filtered(gdb_stdout, "%s\n", req->buf); +++ +++ execute_command(req->buf, FALSE); +++ +++ for (objfile *objfile : current_program_space->objfiles ()) { +++ if (same_file((char *)objfile_name(objfile), lm->mod_namelist)) { +++ if (objfile->separate_debug_objfile) +++ lm->loaded_objfile = objfile->separate_debug_objfile; +++ else +++ lm->loaded_objfile = objfile; +++ break; +++ } +++ } +++ +++ if (!lm->loaded_objfile) +++ req->flags |= GNU_COMMAND_FAILED; +++} +++ +++static void +++gdb_delete_symbol_file(struct gnu_request *req) +++{ +++ for (objfile *objfile : current_program_space->objfiles ()) { +++ if (STREQ(objfile_name(objfile), req->name) || +++ same_file((char *)objfile_name(objfile), req->name)) { +++ objfile->unlink (); +++ break; +++ } +++ } +++ +++ if (gdb_CRASHDEBUG(2)) { +++ fprintf_filtered(gdb_stdout, "current object files:\n"); +++ for (objfile *objfile : current_program_space->objfiles ()) +++ fprintf_filtered(gdb_stdout, " %s\n", objfile_name(objfile)); +++ } +++} +++ +++/* +++ * Walk through all minimal_symbols, patching their values with the +++ * correct addresses. +++ */ +++static void +++gdb_patch_symbol_values(struct gnu_request *req) +++{ +++ req->name = PATCH_KERNEL_SYMBOLS_START; +++ patch_kernel_symbol(req); +++ +++ for (objfile *objfile : current_program_space->objfiles ()) +++ for (minimal_symbol *msymbol : objfile->msymbols ()) +++ { +++ req->name = (char *)msymbol->m_name; +++ req->addr = (ulong)(&MSYMBOL_VALUE(msymbol)); +++ if (!patch_kernel_symbol(req)) { +++ req->flags |= GNU_COMMAND_FAILED; +++ break; +++ } +++ } +++ +++ req->name = PATCH_KERNEL_SYMBOLS_STOP; +++ patch_kernel_symbol(req); +++ +++ clear_symtab_users(0); +++ gdb_merge_flags |= KERNEL_SYMBOLS_PATCHED; +++} +++ +++static void +++gdb_get_symbol_type(struct gnu_request *req) +++{ +++ expression_up expr; +++ struct value *val; +++ struct type *type; +++ struct type *target_type; +++ +++ req->typecode = TYPE_CODE_UNDEF; +++ +++ expr = parse_expression (req->name); +++ val = evaluate_type (expr.get()); +++ +++ type = value_type(val); +++ +++ req->type_name = (char *)TYPE_MAIN_TYPE(type)->name; +++ req->typecode = TYPE_MAIN_TYPE(type)->code; +++ req->length = type->length; +++ req->type_tag_name = (char *)TYPE_TAG_NAME(type); +++ target_type = TYPE_MAIN_TYPE(type)->target_type; +++ +++ if (target_type) { +++ req->target_typename = (char *)TYPE_MAIN_TYPE(target_type)->name; +++ req->target_typecode = TYPE_MAIN_TYPE(target_type)->code; +++ req->target_length = target_type->length; +++ } +++ +++ if (req->member) +++ get_member_data(req, type, 0, 1); +++} +++ +++static void +++gdb_debug_command(struct gnu_request *req) +++{ +++ +++} +++ +++/* +++ * Only necessary on "patched" kernel symbol sessions, and called only by +++ * lookup_symbol(), pull a symbol value bait-and-switch operation by altering +++ * either a data symbol's address value or a text symbol's block start address. +++ */ +++static void +++gdb_bait_and_switch(char *name, struct symbol *sym) +++{ +++ struct bound_minimal_symbol msym; +++ struct block *block; +++ +++ if ((gdb_merge_flags & KERNEL_SYMBOLS_PATCHED) && +++ (msym = lookup_minimal_symbol(name, NULL, gdb_kernel_objfile)).minsym) { +++ if (SYMBOL_CLASS(sym) == LOC_BLOCK) { +++ block = (struct block *)SYMBOL_BLOCK_VALUE(sym); +++ BLOCK_START(block) = BMSYMBOL_VALUE_ADDRESS(msym); +++ } else +++ SET_SYMBOL_VALUE_ADDRESS(sym, BMSYMBOL_VALUE_ADDRESS(msym)); +++ } +++} +++ +++#include "valprint.h" +++ +++void +++get_user_print_option_address(struct gnu_request *req) +++{ +++ extern struct value_print_options user_print_options; +++ +++ req->addr = 0; +++ +++ if (strcmp(req->name, "output_format") == 0) +++ req->addr = (ulong)&user_print_options.output_format; +++ if (strcmp(req->name, "print_max") == 0) +++ req->addr = (ulong)&user_print_options.print_max; +++ if (strcmp(req->name, "prettyprint_structs") == 0) +++ req->addr = (ulong)&user_print_options.prettyformat_structs; +++ if (strcmp(req->name, "prettyprint_arrays") == 0) +++ req->addr = (ulong)&user_print_options.prettyformat_arrays; +++ if (strcmp(req->name, "repeat_count_threshold") == 0) +++ req->addr = (ulong)&user_print_options.repeat_count_threshold; +++ if (strcmp(req->name, "stop_print_at_null") == 0) +++ req->addr = (ulong)&user_print_options.stop_print_at_null; +++ if (strcmp(req->name, "output_radix") == 0) +++ req->addr = (ulong)&output_radix; +++} +++ +++CORE_ADDR crash_text_scope; +++ +++static void +++gdb_set_crash_block(struct gnu_request *req) +++{ +++ if (!req->addr) { /* debug */ +++ crash_text_scope = 0; +++ return; +++ } +++ +++ if ((req->addr2 = (ulong)block_for_pc(req->addr))) +++ crash_text_scope = req->addr; +++ else { +++ crash_text_scope = 0; +++ req->flags |= GNU_COMMAND_FAILED; +++ } +++} +++ +++static const struct block * +++gdb_get_crash_block(void) +++{ +++ if (crash_text_scope) +++ return block_for_pc(crash_text_scope); +++ else +++ return NULL; +++} +++ +++static long +++lookup_struct_contents(struct gnu_request *req) +++{ +++ int i; +++ long r; +++ struct field *f; +++ struct main_type *m; +++ const char *n; +++ struct main_type *top_m = (struct main_type *)req->addr; +++ char *type_name = req->type_name; +++ +++ if (!top_m || !type_name) +++ return 0; +++ +++ for (i = 0; i < top_m->nfields; i++) +++ { +++ f = top_m->flds_bnds.fields + i; +++ if (!f->type()) +++ continue; +++ m = f->type()->main_type; +++ +++ // If the field is an array, check the target type - +++ // it might be structure, or might not be. +++ // - struct request_sock *syn_table[0]; +++ // here m->target_type->main_type->code is expected +++ // to be TYPE_CODE_PTR +++ // - struct list_head vec[TVN_SIZE]; +++ // here m->target_type->main_type->code should be +++ // TYPE_CODE_STRUCT +++ if (m->code == TYPE_CODE_ARRAY && m->target_type) +++ m = m->target_type->main_type; +++ +++ /* Here is a recursion. +++ * If we have struct variable (not pointer), +++ * scan this inner structure +++ */ +++ if (m->code == TYPE_CODE_STRUCT) { +++ req->addr = (ulong)m; +++ r = lookup_struct_contents(req); +++ req->addr = (ulong)top_m; +++ if (r) +++ return 1; +++ } +++ +++ if (m->code == TYPE_CODE_PTR && m->target_type) +++ m = m->target_type->main_type; +++ if (m->name) +++ n = m->name; +++ else +++ continue; +++ +++ if (strstr(n, type_name)) +++ return 1; +++ } +++ +++ return 0; +++} +++ +++static void +++iterate_datatypes (struct gnu_request *req) +++{ +++ for (objfile *objfile : current_program_space->objfiles ()) +++ { +++ if (objfile->sf) +++ objfile->sf->qf->expand_all_symtabs(objfile); +++ +++ for (compunit_symtab *cust : objfile->compunits ()) +++ { +++ const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (cust); +++ +++ for (int i = GLOBAL_BLOCK; i <= STATIC_BLOCK; ++i) +++ { +++ const struct block *b = BLOCKVECTOR_BLOCK (bv, i); +++ struct block_iterator iter; +++ struct symbol *sym; +++ +++ ALL_BLOCK_SYMBOLS (b, iter, sym) +++ { +++ QUIT; +++ +++ if (SYMBOL_CLASS (sym) != LOC_TYPEDEF) +++ continue; +++ +++ if (req->highest && +++ !(req->lowest <= sym->type->length && sym->type->length <= req->highest)) +++ continue; +++ +++ req->addr = (ulong)(sym->type->main_type); +++ req->name = (char *)(sym->m_name); +++ req->length = sym->type->length; +++ +++ if (req->member) { +++ req->value = lookup_struct_contents(req); +++ if (!req->value) +++ continue; +++ } +++ req->callback(req, req->callback_data); +++ } +++ } +++ } +++ } +++} +++#endif ++--- gdb-10.2/gdb/ui-file.h.orig +++++ gdb-10.2/gdb/ui-file.h ++@@ -195,10 +195,10 @@ class stdio_file : public ui_file ++ ++ bool can_emit_style_escape () override; ++ ++-private: ++ /* Sets the internal stream to FILE, and saves the FILE's file ++ descriptor in M_FD. */ ++ void set_stream (FILE *file); +++private: ++ ++ /* The file. */ ++ FILE *m_file; ++--- gdb-10.2/gdb/xml-syscall.c.orig +++++ gdb-10.2/gdb/xml-syscall.c ++@@ -37,7 +37,11 @@ ++ static void ++ syscall_warn_user (void) ++ { +++#ifdef CRASH_MERGE +++ static int have_warned = 1; +++#else ++ static int have_warned = 0; +++#endif ++ if (!have_warned) ++ { ++ have_warned = 1; ++--- gdb-10.2/libiberty/Makefile.in.orig +++++ gdb-10.2/libiberty/Makefile.in ++@@ -180,6 +180,7 @@ REQUIRED_OFILES = \ ++ ./getruntime.$(objext) ./hashtab.$(objext) ./hex.$(objext) \ ++ ./lbasename.$(objext) ./lrealpath.$(objext) \ ++ ./make-relative-prefix.$(objext) ./make-temp-file.$(objext) \ +++ ./mkstemps.$(objext) \ ++ ./objalloc.$(objext) \ ++ ./obstack.$(objext) \ ++ ./partition.$(objext) ./pexecute.$(objext) ./physmem.$(objext) \ ++@@ -213,7 +214,7 @@ CONFIGURED_OFILES = ./asprintf.$(objext) ./atexit.$(objext) \ ++ ./index.$(objext) ./insque.$(objext) \ ++ ./memchr.$(objext) ./memcmp.$(objext) ./memcpy.$(objext) \ ++ ./memmem.$(objext) ./memmove.$(objext) \ ++- ./mempcpy.$(objext) ./memset.$(objext) ./mkstemps.$(objext) \ +++ ./mempcpy.$(objext) ./memset.$(objext) \ ++ ./pex-djgpp.$(objext) ./pex-msdos.$(objext) \ ++ ./pex-unix.$(objext) ./pex-win32.$(objext) \ ++ ./putenv.$(objext) \ ++--- gdb-10.2/opcodes/i386-dis.c.orig +++++ gdb-10.2/opcodes/i386-dis.c ++@@ -9778,6 +9778,10 @@ print_insn (bfd_vma pc, disassemble_info *info) ++ threebyte = *codep; ++ dp = &dis386_twobyte[threebyte]; ++ need_modrm = twobyte_has_modrm[*codep]; +++ if (dp->name && ((strcmp(dp->name, "ud2a") == 0) || (strcmp(dp->name, "ud2") == 0))) { +++ extern int kernel_BUG_encoding_bytes(void); +++ codep += kernel_BUG_encoding_bytes(); +++ } ++ codep++; ++ } ++ else ++--- gdb-10.2/readline/readline/misc.c.orig +++++ gdb-10.2/readline/readline/misc.c ++@@ -403,7 +403,7 @@ _rl_history_set_point (void) ++ ++ #if defined (VI_MODE) ++ if (rl_editing_mode == vi_mode && _rl_keymap != vi_insertion_keymap) ++- rl_point = 0; +++ rl_point = rl_end; ++ #endif /* VI_MODE */ ++ ++ if (rl_editing_mode == emacs_mode) ++--- gdb-10.2/readline/readline/readline.h.orig +++++ gdb-10.2/readline/readline/readline.h ++@@ -395,7 +395,7 @@ extern int rl_crlf PARAMS((void)); ++ #if defined (USE_VARARGS) && defined (PREFER_STDARG) ++ extern int rl_message (const char *, ...) __attribute__((__format__ (printf, 1, 2))); ++ #else ++-extern int rl_message (); +++extern int rl_message (void); ++ #endif ++ ++ extern int rl_show_char PARAMS((int)); ++--- gdb-10.2/readline/readline/rltypedefs.h.orig +++++ gdb-10.2/readline/readline/rltypedefs.h ++@@ -32,10 +32,10 @@ extern "C" { ++ # define _FUNCTION_DEF ++ ++ #if defined(__GNUC__) || defined(__clang__) ++-typedef int Function () __attribute__ ((deprecated)); ++-typedef void VFunction () __attribute__ ((deprecated)); ++-typedef char *CPFunction () __attribute__ ((deprecated)); ++-typedef char **CPPFunction () __attribute__ ((deprecated)); +++typedef int Function (void) __attribute__ ((deprecated)); +++typedef void VFunction (void) __attribute__ ((deprecated)); +++typedef char *CPFunction (void) __attribute__ ((deprecated)); +++typedef char **CPPFunction (void) __attribute__ ((deprecated)); ++ #else ++ typedef int Function (); ++ typedef void VFunction (); ++--- gdb-10.2/readline/readline/util.c.orig +++++ gdb-10.2/readline/readline/util.c ++@@ -487,10 +487,13 @@ _rl_trace (va_alist) ++ ++ if (_rl_tracefp == 0) ++ _rl_tropen (); +++ if (!_rl_tracefp) +++ goto out; ++ vfprintf (_rl_tracefp, format, args); ++ fprintf (_rl_tracefp, "\n"); ++ fflush (_rl_tracefp); ++ +++out: ++ va_end (args); ++ } ++ ++@@ -513,16 +516,17 @@ _rl_tropen (void) ++ sprintf (fnbuf, "/var/tmp/rltrace.%ld", (long) getpid ()); ++ #endif ++ unlink (fnbuf); ++- _rl_tracefp = fopen (fnbuf, "w+"); +++ _rl_tracefp = fopen (fnbuf, "w+xe"); ++ return _rl_tracefp != 0; ++ } ++ ++ int ++ _rl_trclose (void) ++ { ++- int r; +++ int r = 0; ++ ++- r = fclose (_rl_tracefp); +++ if (_rl_tracefp) +++ r = fclose (_rl_tracefp); ++ _rl_tracefp = 0; ++ return r; ++ } ++--- gdb-10.2/gdb/completer.c.orig +++++ gdb-10.2/gdb/completer.c ++@@ -2949,6 +2949,8 @@ ++ ++ /* How many items of MAX length can we fit in the screen window? */ ++ cols = gdb_complete_get_screenwidth (displayer); +++ rl_reset_screen_size(); +++ rl_get_screen_size(NULL, &cols); ++ max += 2; ++ limit = cols / max; ++ if (limit != 1 && (limit * max == cols)) +diff -Nur crash-7.3.0-orig/gdb-7.6.patch crash-7.3.0/gdb-7.6.patch +--- crash-7.3.0-orig/gdb-7.6.patch 2023-07-07 14:06:14.176365967 +0800 ++++ crash-7.3.0/gdb-7.6.patch 1970-01-01 08:00:00.000000000 +0800 +@@ -1,2619 +0,0 @@ +- +-# When this file is updated in an existing source tree, it gets re-applied +-# during the next build using "patch -N --fuzz=0", which ignores patches +-# that have already been applied. However, if a gdb file has been modified +-# multiple times, the subsequent patching may fail to recognize that a +-# given patch has been previously applied, and will attempt to re-apply it. +-# To prevent any uninintended consequences, this file also acts as a +-# shell script that can restore any gdb file to its original state prior +-# to all subsequent patch applications. +- +-# The gdb-7.6-ppc64le-support.patch will have modified both files below +-# during the initial build, so continue previous behavior. +- +-if [ "$1" = "PPC64" ] +-then +- exit 0 +-fi +- +-tar xvzmf gdb-7.6.tar.gz \ +- gdb-7.6/gdb/symtab.c \ +- gdb-7.6/gdb/printcmd.c +- +-exit 0 +- +---- gdb-7.6/bfd/bfd-in2.h +-+++ gdb-7.6/bfd/bfd-in2.h +-@@ -1242,6 +1242,8 @@ long bfd_get_mtime (bfd *abfd); +- +- file_ptr bfd_get_size (bfd *abfd); +- +-+file_ptr bfd_get_file_size (bfd *abfd); +-+ +- void *bfd_mmap (bfd *abfd, void *addr, bfd_size_type len, +- int prot, int flags, file_ptr offset, +- void **map_addr, bfd_size_type *map_len); +---- gdb-7.6/bfd/bfdio.c +-+++ gdb-7.6/bfd/bfdio.c +-@@ -434,6 +434,29 @@ bfd_get_size (bfd *abfd) +- return buf.st_size; +- } +- +-+/* +-+FUNCTION +-+ bfd_get_file_size +-+ +-+SYNOPSIS +-+ file_ptr bfd_get_file_size (bfd *abfd); +-+ +-+DESCRIPTION +-+ Return the file size (as read from file system) for the file +-+ associated with BFD @var{abfd}. It supports both normal files +-+ and archive elements. +-+ +-+*/ +-+ +-+file_ptr +-+bfd_get_file_size (bfd *abfd) +-+{ +-+ if (abfd->my_archive != NULL +-+ && !bfd_is_thin_archive (abfd->my_archive)) +-+ return arelt_size (abfd); +-+ +-+ return bfd_get_size (abfd); +-+} +- +- /* +- FUNCTION +---- gdb-7.6/gdb/dwarf2read.c +-+++ gdb-7.6/gdb/dwarf2read.c +-@@ -1822,6 +1822,15 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *vnames) +- if ((aflag & SEC_HAS_CONTENTS) == 0) +- { +- } +-+ else if (elf_section_data (sectp)->this_hdr.sh_size +-+ > bfd_get_file_size (abfd)) +-+ { +-+ bfd_size_type size = elf_section_data (sectp)->this_hdr.sh_size; +-+ warning (_("Discarding section %s which has a section size (%s" +-+ ") larger than the file size [in module %s]"), +-+ sectp->name, phex_nz (size, sizeof (size)), +-+ abfd->filename); +-+ } +- else if (section_is_p (sectp->name, &names->info)) +- { +- dwarf2_per_objfile->info.asection = sectp; +---- gdb-7.6/libiberty/Makefile.in.orig +-+++ gdb-7.6/libiberty/Makefile.in +-@@ -175,6 +175,7 @@ REQUIRED_OFILES = \ +- ./getruntime.$(objext) ./hashtab.$(objext) ./hex.$(objext) \ +- ./lbasename.$(objext) ./lrealpath.$(objext) \ +- ./make-relative-prefix.$(objext) ./make-temp-file.$(objext) \ +-+ ./mkstemps.$(objext) \ +- ./objalloc.$(objext) \ +- ./obstack.$(objext) \ +- ./partition.$(objext) ./pexecute.$(objext) ./physmem.$(objext) \ +-@@ -206,7 +207,7 @@ CONFIGURED_OFILES = ./asprintf.$(objext) +- ./index.$(objext) ./insque.$(objext) \ +- ./memchr.$(objext) ./memcmp.$(objext) ./memcpy.$(objext) \ +- ./memmem.$(objext) ./memmove.$(objext) \ +-- ./mempcpy.$(objext) ./memset.$(objext) ./mkstemps.$(objext) \ +-+ ./mempcpy.$(objext) ./memset.$(objext) \ +- ./pex-djgpp.$(objext) ./pex-msdos.$(objext) \ +- ./pex-unix.$(objext) ./pex-win32.$(objext) \ +- ./putenv.$(objext) \ +---- gdb-7.6/opcodes/i386-dis.c.orig +-+++ gdb-7.6/opcodes/i386-dis.c +-@@ -11510,6 +11510,10 @@ print_insn (bfd_vma pc, disassemble_info +- threebyte = *++codep; +- dp = &dis386_twobyte[threebyte]; +- need_modrm = twobyte_has_modrm[*codep]; +-+ if (dp->name && ((strcmp(dp->name, "ud2a") == 0) || (strcmp(dp->name, "ud2") == 0))) { +-+ extern int kernel_BUG_encoding_bytes(void); +-+ codep += kernel_BUG_encoding_bytes(); +-+ } +- codep++; +- } +- else +---- gdb-7.6/gdb/dwarf2read.c.orig +-+++ gdb-7.6/gdb/dwarf2read.c +-@@ -2670,7 +2670,11 @@ read_index_from_section (struct objfile +- indices. */ +- if (version < 4) +- { +-+#ifdef CRASH_MERGE +-+ static int warning_printed = 1; +-+#else +- static int warning_printed = 0; +-+#endif +- if (!warning_printed) +- { +- warning (_("Skipping obsolete .gdb_index section in %s."), +-@@ -2689,7 +2693,11 @@ read_index_from_section (struct objfile +- "set use-deprecated-index-sections on". */ +- if (version < 6 && !deprecated_ok) +- { +-+#ifdef CRASH_MERGE +-+ static int warning_printed = 1; +-+#else +- static int warning_printed = 0; +-+#endif +- if (!warning_printed) +- { +- warning (_("\ +---- gdb-7.6/gdb/amd64-linux-nat.c.orig +-+++ gdb-7.6/gdb/amd64-linux-nat.c +-@@ -45,6 +45,17 @@ +- /* ezannoni-2003-07-09: I think this is fixed. The extraneous defs have +- been removed from ptrace.h in the kernel. However, better safe than +- sorry. */ +-+#ifdef CRASH_MERGE +-+/* +-+ * When compiling within a 2.6.25-based Fedora build environment with +-+ * gcc 4.3, four new "typedef unsigned int u32;" declarations were +-+ * required due to a new ptrace_bts_config structure declaration in +-+ * "asm-x86/ptrace-abi.h" that used u32 members, but u32 is defined in +-+ * "asm-x86/types.h" within a __KERNEL__ section. They've been changed +-+ * to __u32, but this patch remains for building in that environment. +-+ */ +-+typedef unsigned int u32; +-+#endif +- #include +- #include +- #include "gdb_proc_service.h" +---- gdb-7.6/gdb/symfile.c.orig +-+++ gdb-7.6/gdb/symfile.c +-@@ -693,7 +693,26 @@ default_symfile_offsets (struct objfile +- for (cur_sec = abfd->sections; cur_sec != NULL; cur_sec = cur_sec->next) +- /* We do not expect this to happen; just skip this step if the +- relocatable file has a section with an assigned VMA. */ +-- if (bfd_section_vma (abfd, cur_sec) != 0) +-+ if (bfd_section_vma (abfd, cur_sec) != 0 +-+ /* +-+ * Kernel modules may have some non-zero VMAs, i.e., like the +-+ * __ksymtab and __ksymtab_gpl sections in this example: +-+ * +-+ * Section Headers: +-+ * [Nr] Name Type Address Offset +-+ * Size EntSize Flags Link Info Align +-+ * ... +-+ * [ 8] __ksymtab PROGBITS 0000000000000060 0000ad90 +-+ * 0000000000000010 0000000000000000 A 0 0 16 +-+ * [ 9] .rela__ksymtab RELA 0000000000000000 0000ada0 +-+ * 0000000000000030 0000000000000018 43 8 8 +-+ * [10] __ksymtab_gpl PROGBITS 0000000000000070 0000add0 +-+ * 00000000000001a0 0000000000000000 A 0 0 16 +-+ * ... +-+ * +-+ * but they should be treated as if they are NULL. +-+ */ +-+ && strncmp (bfd_get_section_name (abfd, cur_sec), "__k", 3) != 0) +- break; +- +- if (cur_sec == NULL) +-@@ -1122,6 +1141,12 @@ symbol_file_add_with_addrs_or_offsets (b +- error (_("Not confirmed.")); +- +- objfile = allocate_objfile (abfd, flags | (mainline ? OBJF_MAINLINE : 0)); +-+#ifdef CRASH_MERGE +-+ if (add_flags & SYMFILE_MAINLINE) { +-+ extern struct objfile *gdb_kernel_objfile; +-+ gdb_kernel_objfile = objfile; +-+ } +-+#endif +- +- if (parent) +- add_separate_debug_objfile (objfile, parent); +-@@ -1484,6 +1509,9 @@ find_separate_debug_file (const char *di +- VEC (char_ptr) *debugdir_vec; +- struct cleanup *back_to; +- int ix; +-+#ifdef CRASH_MERGE +-+ extern int check_specified_module_tree(char *, char *); +-+#endif +- +- /* Set I to max (strlen (canon_dir), strlen (dir)). */ +- i = strlen (dir); +-@@ -1513,6 +1541,15 @@ find_separate_debug_file (const char *di +- if (separate_debug_file_exists (debugfile, crc32, objfile)) +- return debugfile; +- +-+#ifdef CRASH_MERGE +-+{ +-+ if (check_specified_module_tree(objfile->name, debugfile) && +-+ separate_debug_file_exists(debugfile, crc32, objfile)) { +-+ return debugfile; +-+ } +-+} +-+#endif +-+ +- /* Then try in the global debugfile directories. +- +- Keep backward compatibility so that DEBUG_FILE_DIRECTORY being "" will +-@@ -1583,6 +1620,10 @@ find_separate_debug_file_by_debuglink (s +- char *debugfile; +- unsigned long crc32; +- struct cleanup *cleanups; +-+#ifdef CRASH_MERGE +-+ char *name_copy; +-+ extern char *check_specified_kernel_debug_file(); +-+#endif +- +- debuglink = get_debug_link_info (objfile, &crc32); +- +-@@ -1635,6 +1676,12 @@ find_separate_debug_file_by_debuglink (s +- } +- +- do_cleanups (cleanups); +-+#ifdef CRASH_MERGE +-+ if (debugfile == NULL) { +-+ name_copy = check_specified_kernel_debug_file(); +-+ return (name_copy ? xstrdup(name_copy) : NULL); +-+ } +-+#endif +- return debugfile; +- } +- +-@@ -2409,8 +2456,10 @@ add_symbol_file_command (char *args, int +- so we can't determine what section names are valid. */ +- } +- +-+#ifndef CRASH_MERGE +- if (from_tty && (!query ("%s", ""))) +- error (_("Not confirmed.")); +-+#endif +- +- symbol_file_add (filename, from_tty ? SYMFILE_VERBOSE : 0, +- section_addrs, flags); +-@@ -3690,6 +3739,15 @@ bfd_byte * +- symfile_relocate_debug_section (struct objfile *objfile, +- asection *sectp, bfd_byte *buf) +- { +-+#ifdef CRASH_MERGE +-+ /* Executable files have all the relocations already resolved. +-+ * Handle files linked with --emit-relocs. +-+ * http://sources.redhat.com/ml/gdb/2006-08/msg00137.html +-+ */ +-+ bfd *abfd = objfile->obfd; +-+ if ((abfd->flags & EXEC_P) != 0) +-+ return NULL; +-+#endif +- gdb_assert (objfile->sf->sym_relocate); +- +- return (*objfile->sf->sym_relocate) (objfile, sectp, buf); +---- gdb-7.6/gdb/cli/cli-cmds.c.orig +-+++ gdb-7.6/gdb/cli/cli-cmds.c +-@@ -466,6 +466,10 @@ show_script_ext_mode (struct ui_file *fi +- If SEARCH_PATH is non-zero, and the file isn't found in cwd, +- search for it in the source search path. */ +- +-+#ifdef CRASH_MERGE +-+static int crash_from_tty = 0; +-+#endif +-+ +- int +- find_and_open_script (const char *script_file, int search_path, +- FILE **streamp, char **full_pathp) +-@@ -508,6 +512,32 @@ find_and_open_script (const char *script +- return 0; +- } +- +-+#ifdef CRASH_MERGE +-+ /* +-+ * Only allow trusted versions of .gdbinit files to be +-+ * sourced during session initialization. +-+ */ +-+ if (crash_from_tty == -1) +-+ { +-+ struct stat statbuf; +-+ FILE *stream = *streamp; +-+ int fd = fileno (stream); +-+ if (fstat (fd, &statbuf) < 0) +-+ { +-+ perror_with_name (*full_pathp); +-+ fclose (stream); +-+ return 0; +-+ } +-+ if (statbuf.st_uid != getuid () || (statbuf.st_mode & S_IWOTH)) +-+ { +-+ extern void untrusted_file(FILE *, char *); +-+ untrusted_file(NULL, *full_pathp); +-+ fclose (stream); +-+ return 0; +-+ } +-+ } +-+#endif +-+ +- return 1; +- } +- +-@@ -566,7 +596,11 @@ source_script_with_search (const char *f +- If the source command was invoked interactively, throw an +- error. Otherwise (e.g. if it was invoked by a script), +- silently ignore the error. */ +-+#ifdef CRASH_MERGE +-+ if (from_tty > 0) +-+#else +- if (from_tty) +-+#endif +- perror_with_name (file); +- else +- return; +-@@ -589,7 +623,14 @@ source_script_with_search (const char *f +- void +- source_script (char *file, int from_tty) +- { +-+#ifdef CRASH_MERGE +-+ crash_from_tty = from_tty; +-+#endif +- source_script_with_search (file, from_tty, 0); +-+#ifdef CRASH_MERGE +-+ crash_from_tty = 0; +-+#endif +-+ +- } +- +- /* Return the source_verbose global variable to its previous state +---- gdb-7.6/gdb/psymtab.c.orig +-+++ gdb-7.6/gdb/psymtab.c +-@@ -305,10 +305,14 @@ find_pc_sect_psymtab (struct objfile *ob +- struct minimal_symbol *msymbol) +- { +- struct partial_symtab *pst; +-+#ifdef CRASH_MERGE +-+ extern int gdb_line_number_callback(unsigned long, unsigned long, unsigned long); +-+#endif +- +- /* Try just the PSYMTABS_ADDRMAP mapping first as it has better granularity +- than the later used TEXTLOW/TEXTHIGH one. */ +- +-+#ifndef __i386__ +- if (objfile->psymtabs_addrmap != NULL) +- { +- pst = addrmap_find (objfile->psymtabs_addrmap, pc); +-@@ -343,6 +347,7 @@ find_pc_sect_psymtab (struct objfile *ob +- } +- +- next: +-+#endif +- +- /* Existing PSYMTABS_ADDRMAP mapping is present even for PARTIAL_SYMTABs +- which still have no corresponding full SYMTABs read. But it is not +-@@ -361,7 +366,12 @@ find_pc_sect_psymtab (struct objfile *ob +- +- best_pst = find_pc_sect_psymtab_closer (objfile, pc, section, pst, +- msymbol); +-+#ifdef CRASH_MERGE +-+ if ((best_pst != NULL) && +-+ gdb_line_number_callback(pc, pst->textlow, pst->texthigh)) +-+#else +- if (best_pst != NULL) +-+#endif +- return best_pst; +- } +- +---- gdb-7.6/gdb/symtab.c.orig +-+++ gdb-7.6/gdb/symtab.c +-@@ -1198,7 +1198,9 @@ demangle_for_lookup (const char *name, e +- doesn't affect these calls since they are looking for a known +- variable and thus can probably assume it will never hit the C++ +- code). */ +-- +-+#ifdef CRASH_MERGE +-+static void gdb_bait_and_switch(char *, struct symbol *); +-+#endif +- struct symbol * +- lookup_symbol_in_language (const char *name, const struct block *block, +- const domain_enum domain, enum language lang, +-@@ -1212,17 +1214,30 @@ lookup_symbol_in_language (const char *n +- is_a_field_of_this); +- do_cleanups (cleanup); +- +-+#ifdef CRASH_MERGE +-+ if (returnval && (domain == VAR_DOMAIN)) +-+ gdb_bait_and_switch((char *)modified_name, returnval); +-+#endif +-+ +- return returnval; +- } +- +- /* Behave like lookup_symbol_in_language, but performed with the +- current language. */ +- +-+#ifdef CRASH_MERGE +-+static struct block *gdb_get_crash_block(void); +-+#endif +-+ +- struct symbol * +- lookup_symbol (const char *name, const struct block *block, +- domain_enum domain, +- struct field_of_this_result *is_a_field_of_this) +- { +-+#ifdef CRASH_MERGE +-+ if (!block) +-+ block = gdb_get_crash_block(); +-+#endif +- return lookup_symbol_in_language (name, block, domain, +- current_language->la_language, +- is_a_field_of_this); +-@@ -5100,3 +5115,662 @@ When enabled, debugging messages are pri +- +- observer_attach_executable_changed (symtab_observer_executable_changed); +- } +-+ +-+#ifdef CRASH_MERGE +-+#include "gdb-stabs.h" +-+#include "version.h" +-+#define GDB_COMMON +-+#include "../../defs.h" +-+ +-+static void get_member_data(struct gnu_request *, struct type *); +-+static void dump_enum(struct type *, struct gnu_request *); +-+static void eval_enum(struct type *, struct gnu_request *); +-+static void gdb_get_line_number(struct gnu_request *); +-+static void gdb_get_datatype(struct gnu_request *); +-+static void gdb_get_symbol_type(struct gnu_request *); +-+static void gdb_command_exists(struct gnu_request *); +-+static void gdb_debug_command(struct gnu_request *); +-+static void gdb_function_numargs(struct gnu_request *); +-+static void gdb_add_symbol_file(struct gnu_request *); +-+static void gdb_delete_symbol_file(struct gnu_request *); +-+static void gdb_patch_symbol_values(struct gnu_request *); +-+extern void replace_ui_file_FILE(struct ui_file *, FILE *); +-+static void get_user_print_option_address(struct gnu_request *); +-+extern int get_frame_offset(CORE_ADDR); +-+static void gdb_set_crash_block(struct gnu_request *); +-+void gdb_command_funnel(struct gnu_request *); +-+ +-+struct objfile *gdb_kernel_objfile = { 0 }; +-+ +-+static ulong gdb_merge_flags = 0; +-+#define KERNEL_SYMBOLS_PATCHED (0x1) +-+ +-+#undef STREQ +-+#define STREQ(A, B) (A && B && (strcmp(A, B) == 0)) +-+ +-+/* +-+ * All commands from above come through here. +-+ */ +-+void +-+gdb_command_funnel(struct gnu_request *req) +-+{ +-+ struct symbol *sym; +-+ +-+ if (req->command != GNU_VERSION) { +-+ replace_ui_file_FILE(gdb_stdout, req->fp); +-+ replace_ui_file_FILE(gdb_stderr, req->fp); +-+ do_cleanups(all_cleanups()); +-+ } +-+ +-+ switch (req->command) +-+ { +-+ case GNU_VERSION: +-+ req->buf = (char *)version; +-+ break; +-+ +-+ case GNU_PASS_THROUGH: +-+ execute_command(req->buf, +-+ req->flags & GNU_FROM_TTY_OFF ? FALSE : TRUE); +-+ break; +-+ +-+ case GNU_USER_PRINT_OPTION: +-+ get_user_print_option_address(req); +-+ break; +-+ +-+ case GNU_RESOLVE_TEXT_ADDR: +-+ sym = find_pc_function(req->addr); +-+ if (!sym || TYPE_CODE(sym->type) != TYPE_CODE_FUNC) +-+ req->flags |= GNU_COMMAND_FAILED; +-+ break; +-+ +-+ case GNU_DISASSEMBLE: +-+ if (req->addr2) +-+ sprintf(req->buf, "disassemble 0x%lx 0x%lx", +-+ req->addr, req->addr2); +-+ else +-+ sprintf(req->buf, "disassemble 0x%lx", req->addr); +-+ execute_command(req->buf, TRUE); +-+ break; +-+ +-+ case GNU_ADD_SYMBOL_FILE: +-+ gdb_add_symbol_file(req); +-+ break; +-+ +-+ case GNU_DELETE_SYMBOL_FILE: +-+ gdb_delete_symbol_file(req); +-+ break; +-+ +-+ case GNU_GET_LINE_NUMBER: +-+ gdb_get_line_number(req); +-+ break; +-+ +-+ case GNU_GET_DATATYPE: +-+ gdb_get_datatype(req); +-+ break; +-+ +-+ case GNU_GET_SYMBOL_TYPE: +-+ gdb_get_symbol_type(req); +-+ break; +-+ +-+ case GNU_COMMAND_EXISTS: +-+ gdb_command_exists(req); +-+ break; +-+ +-+ case GNU_ALPHA_FRAME_OFFSET: +-+ req->value = 0; +-+ break; +-+ +-+ case GNU_FUNCTION_NUMARGS: +-+ gdb_function_numargs(req); +-+ break; +-+ +-+ case GNU_DEBUG_COMMAND: +-+ gdb_debug_command(req); +-+ break; +-+ +-+ case GNU_PATCH_SYMBOL_VALUES: +-+ gdb_patch_symbol_values(req); +-+ break; +-+ +-+ case GNU_SET_CRASH_BLOCK: +-+ gdb_set_crash_block(req); +-+ break; +-+ +-+ default: +-+ req->flags |= GNU_COMMAND_FAILED; +-+ break; +-+ } +-+} +-+ +-+/* +-+ * Given a PC value, return the file and line number. +-+ */ +-+static void +-+gdb_get_line_number(struct gnu_request *req) +-+{ +-+ struct symtab_and_line sal; +-+ struct symbol *sym; +-+ CORE_ADDR pc; +-+ +-+#define LASTCHAR(s) (s[strlen(s)-1]) +-+ +-+ /* +-+ * Prime the addrmap pump. +-+ */ +-+ if (req->name) +-+ sym = lookup_symbol(req->name, 0, VAR_DOMAIN, 0); +-+ +-+ pc = req->addr; +-+ +-+ sal = find_pc_line(pc, 0); +-+ +-+ if (!sal.symtab) { +-+ req->buf[0] = '\0'; +-+ return; +-+ } +-+ +-+ if (sal.symtab->filename && sal.symtab->dirname) { +-+ if (sal.symtab->filename[0] == '/') +-+ sprintf(req->buf, "%s: %d", +-+ sal.symtab->filename, sal.line); +-+ else +-+ sprintf(req->buf, "%s%s%s: %d", +-+ sal.symtab->dirname, +-+ LASTCHAR(sal.symtab->dirname) == '/' ? "" : "/", +-+ sal.symtab->filename, sal.line); +-+ } +-+} +-+ +-+ +-+/* +-+ * General purpose routine for determining datatypes. +-+ */ +-+ +-+static void +-+gdb_get_datatype(struct gnu_request *req) +-+{ +-+ register struct cleanup *old_chain = NULL; +-+ register struct type *type; +-+ register struct type *typedef_type; +-+ struct expression *expr; +-+ struct symbol *sym; +-+ register int i; +-+ struct field *nextfield; +-+ struct value *val; +-+ +-+ if (gdb_CRASHDEBUG(2)) +-+ console("gdb_get_datatype [%s] (a)\n", req->name); +-+ +-+ req->typecode = TYPE_CODE_UNDEF; +-+ +-+ /* +-+ * lookup_symbol() will pick up struct and union names. +-+ */ +-+ sym = lookup_symbol(req->name, 0, STRUCT_DOMAIN, 0); +-+ if (sym) { +-+ req->typecode = TYPE_CODE(sym->type); +-+ req->length = TYPE_LENGTH(sym->type); +-+ if (req->member) +-+ get_member_data(req, sym->type); +-+ +-+ if (TYPE_CODE(sym->type) == TYPE_CODE_ENUM) { +-+ if (req->flags & GNU_PRINT_ENUMERATORS) +-+ dump_enum(sym->type, req); +-+ } +-+ +-+ return; +-+ } +-+ +-+ /* +-+ * Otherwise parse the expression. +-+ */ +-+ if (gdb_CRASHDEBUG(2)) +-+ console("gdb_get_datatype [%s] (b)\n", req->name); +-+ +-+ expr = parse_expression(req->name); +-+ +-+ old_chain = make_cleanup(free_current_contents, &expr); +-+ +-+ +-+ switch (expr->elts[0].opcode) +-+ { +-+ case OP_VAR_VALUE: +-+ if (gdb_CRASHDEBUG(2)) +-+ console("expr->elts[0].opcode: OP_VAR_VALUE\n"); +-+ type = expr->elts[2].symbol->type; +-+ if (req->flags & GNU_VAR_LENGTH_TYPECODE) { +-+ req->typecode = TYPE_CODE(type); +-+ req->length = TYPE_LENGTH(type); +-+ } +-+ if (TYPE_CODE(type) == TYPE_CODE_ENUM) { +-+ req->typecode = TYPE_CODE(type); +-+ req->value = SYMBOL_VALUE(expr->elts[2].symbol); +-+ req->tagname = (char *)TYPE_TAG_NAME(type); +-+ if (!req->tagname) { +-+ val = evaluate_type(expr); +-+ eval_enum(value_type(val), req); +-+ } +-+ } +-+ break; +-+ +-+ case OP_TYPE: +-+ if (gdb_CRASHDEBUG(2)) +-+ console("expr->elts[0].opcode: OP_TYPE\n"); +-+ type = expr->elts[1].type; +-+ +-+ req->typecode = TYPE_CODE(type); +-+ req->length = TYPE_LENGTH(type); +-+ +-+ if (TYPE_CODE(type) == TYPE_CODE_TYPEDEF) { +-+ req->is_typedef = TYPE_CODE_TYPEDEF; +-+ if ((typedef_type = check_typedef(type))) { +-+ req->typecode = TYPE_CODE(typedef_type); +-+ req->length = TYPE_LENGTH(typedef_type); +-+ type = typedef_type; +-+ } +-+ } +-+ +-+ if (TYPE_CODE(type) == TYPE_CODE_ENUM) { +-+ if (req->is_typedef) +-+ if (req->flags & GNU_PRINT_ENUMERATORS) { +-+ if (req->is_typedef) +-+ fprintf_filtered(gdb_stdout, +-+ "typedef "); +-+ dump_enum(type, req); +-+ } +-+ } +-+ +-+ if (req->member) +-+ get_member_data(req, type); +-+ +-+ break; +-+ +-+ default: +-+ if (gdb_CRASHDEBUG(2)) +-+ console("expr->elts[0].opcode: %d (?)\n", +-+ expr->elts[0].opcode); +-+ break; +-+ +-+ } +-+ +-+ do_cleanups(old_chain); +-+} +-+ +-+/* +-+ * More robust enum list dump that gdb's, showing the value of each +-+ * identifier, each on its own line. +-+ */ +-+static void +-+dump_enum(struct type *type, struct gnu_request *req) +-+{ +-+ register int i; +-+ int len; +-+ int lastval; +-+ +-+ len = TYPE_NFIELDS (type); +-+ lastval = 0; +-+ if (TYPE_TAG_NAME(type)) +-+ fprintf_filtered(gdb_stdout, +-+ "enum %s {\n", TYPE_TAG_NAME (type)); +-+ else +-+ fprintf_filtered(gdb_stdout, "enum {\n"); +-+ +-+ for (i = 0; i < len; i++) { +-+ fprintf_filtered(gdb_stdout, " %s", +-+ TYPE_FIELD_NAME (type, i)); +-+ if (lastval != TYPE_FIELD_BITPOS (type, i)) { +-+ fprintf_filtered (gdb_stdout, " = %d", +-+ TYPE_FIELD_BITPOS (type, i)); +-+ lastval = TYPE_FIELD_BITPOS (type, i); +-+ } else +-+ fprintf_filtered(gdb_stdout, " = %d", lastval); +-+ fprintf_filtered(gdb_stdout, "\n"); +-+ lastval++; +-+ } +-+ if (TYPE_TAG_NAME(type)) +-+ fprintf_filtered(gdb_stdout, "};\n"); +-+ else +-+ fprintf_filtered(gdb_stdout, "} %s;\n", req->name); +-+} +-+ +-+/* +-+ * Given an enum type with no tagname, determine its value. +-+ */ +-+static void +-+eval_enum(struct type *type, struct gnu_request *req) +-+{ +-+ register int i; +-+ int len; +-+ int lastval; +-+ +-+ len = TYPE_NFIELDS (type); +-+ lastval = 0; +-+ +-+ for (i = 0; i < len; i++) { +-+ if (lastval != TYPE_FIELD_BITPOS (type, i)) { +-+ lastval = TYPE_FIELD_BITPOS (type, i); +-+ } +-+ if (STREQ(TYPE_FIELD_NAME(type, i), req->name)) { +-+ req->tagname = "(unknown)"; +-+ req->value = lastval; +-+ return; +-+ } +-+ lastval++; +-+ } +-+} +-+ +-+/* +-+ * Walk through a struct type's list of fields looking for the desired +-+ * member field, and when found, return its relevant data. +-+ */ +-+static void +-+get_member_data(struct gnu_request *req, struct type *type) +-+{ +-+ register short i; +-+ struct field *nextfield; +-+ short nfields; +-+ struct type *typedef_type; +-+ +-+ req->member_offset = -1; +-+ +-+ nfields = TYPE_MAIN_TYPE(type)->nfields; +-+ nextfield = TYPE_MAIN_TYPE(type)->flds_bnds.fields; +-+ +-+ if (nfields == 0) { +-+ struct type *newtype; +-+ newtype = lookup_transparent_type(req->name); +-+ if (newtype) { +-+ console("get_member_data(%s.%s): switching type from %lx to %lx\n", +-+ req->name, req->member, type, newtype); +-+ nfields = TYPE_MAIN_TYPE(newtype)->nfields; +-+ nextfield = TYPE_MAIN_TYPE(newtype)->flds_bnds.fields; +-+ } +-+ } +-+ +-+ for (i = 0; i < nfields; i++) { +-+ if (STREQ(req->member, nextfield->name)) { +-+ req->member_offset = nextfield->loc.bitpos; +-+ req->member_length = TYPE_LENGTH(nextfield->type); +-+ req->member_typecode = TYPE_CODE(nextfield->type); +-+ if ((req->member_typecode == TYPE_CODE_TYPEDEF) && +-+ (typedef_type = check_typedef(nextfield->type))) +-+ req->member_length = TYPE_LENGTH(typedef_type); +-+ return; +-+ } +-+ nextfield++; +-+ } +-+} +-+ +-+/* +-+ * Check whether a command exists. If it doesn't, the command will be +-+ * returned indirectly via the error_hook. +-+ */ +-+static void +-+gdb_command_exists(struct gnu_request *req) +-+{ +-+ extern struct cmd_list_element *cmdlist; +-+ register struct cmd_list_element *c; +-+ +-+ req->value = FALSE; +-+ c = lookup_cmd(&req->name, cmdlist, "", 0, 1); +-+ req->value = TRUE; +-+} +-+ +-+static void +-+gdb_function_numargs(struct gnu_request *req) +-+{ +-+ struct symbol *sym; +-+ +-+ sym = find_pc_function(req->pc); +-+ +-+ if (!sym || TYPE_CODE(sym->type) != TYPE_CODE_FUNC) { +-+ req->flags |= GNU_COMMAND_FAILED; +-+ return; +-+ } +-+ +-+ req->value = (ulong)TYPE_NFIELDS(sym->type); +-+} +-+ +-+struct load_module *gdb_current_load_module = NULL; +-+ +-+static void +-+gdb_add_symbol_file(struct gnu_request *req) +-+{ +-+ register struct objfile *loaded_objfile = NULL; +-+ register struct objfile *objfile; +-+ register struct minimal_symbol *m; +-+ struct load_module *lm; +-+ int external, subsequent, found; +-+ off_t offset; +-+ ulong value, adjusted; +-+ struct symbol *sym; +-+ struct expression *expr; +-+ struct cleanup *old_chain; +-+ int i; +-+ int allsect = 0; +-+ char *secname; +-+ char buf[80]; +-+ +-+ gdb_current_load_module = lm = (struct load_module *)req->addr; +-+ +-+ req->name = lm->mod_namelist; +-+ gdb_delete_symbol_file(req); +-+ +-+ if ((lm->mod_flags & MOD_NOPATCH) == 0) { +-+ for (i = 0 ; i < lm->mod_sections; i++) { +-+ if (STREQ(lm->mod_section_data[i].name, ".text") && +-+ (lm->mod_section_data[i].flags & SEC_FOUND)) +-+ allsect = 1; +-+ } +-+ +-+ if (!allsect) { +-+ sprintf(req->buf, "add-symbol-file %s 0x%lx %s", lm->mod_namelist, +-+ lm->mod_text_start ? lm->mod_text_start : lm->mod_base, +-+ lm->mod_flags & MOD_DO_READNOW ? "-readnow" : ""); +-+ if (lm->mod_data_start) { +-+ sprintf(buf, " -s .data 0x%lx", lm->mod_data_start); +-+ strcat(req->buf, buf); +-+ } +-+ if (lm->mod_bss_start) { +-+ sprintf(buf, " -s .bss 0x%lx", lm->mod_bss_start); +-+ strcat(req->buf, buf); +-+ } +-+ if (lm->mod_rodata_start) { +-+ sprintf(buf, " -s .rodata 0x%lx", lm->mod_rodata_start); +-+ strcat(req->buf, buf); +-+ } +-+ } else { +-+ sprintf(req->buf, "add-symbol-file %s 0x%lx %s", lm->mod_namelist, +-+ lm->mod_text_start, lm->mod_flags & MOD_DO_READNOW ? +-+ "-readnow" : ""); +-+ for (i = 0; i < lm->mod_sections; i++) { +-+ secname = lm->mod_section_data[i].name; +-+ if ((lm->mod_section_data[i].flags & SEC_FOUND) && +-+ !STREQ(secname, ".text")) { +-+ sprintf(buf, " -s %s 0x%lx", secname, +-+ lm->mod_section_data[i].offset + lm->mod_base); +-+ strcat(req->buf, buf); +-+ } +-+ } +-+ } +-+ } +-+ +-+ if (gdb_CRASHDEBUG(1)) +-+ fprintf_filtered(gdb_stdout, "%s\n", req->buf); +-+ +-+ execute_command(req->buf, FALSE); +-+ +-+ ALL_OBJFILES(objfile) { +-+ if (same_file(objfile->name, lm->mod_namelist)) { +-+ loaded_objfile = objfile; +-+ break; +-+ } +-+ } +-+ +-+ if (!loaded_objfile) +-+ req->flags |= GNU_COMMAND_FAILED; +-+} +-+ +-+static void +-+gdb_delete_symbol_file(struct gnu_request *req) +-+{ +-+ register struct objfile *objfile; +-+ +-+ ALL_OBJFILES(objfile) { +-+ if (STREQ(objfile->name, req->name) || +-+ same_file(objfile->name, req->name)) { +-+ free_objfile(objfile); +-+ break; +-+ } +-+ } +-+ +-+ if (gdb_CRASHDEBUG(2)) { +-+ fprintf_filtered(gdb_stdout, "current object files:\n"); +-+ ALL_OBJFILES(objfile) +-+ fprintf_filtered(gdb_stdout, " %s\n", objfile->name); +-+ } +-+} +-+ +-+/* +-+ * Walk through all minimal_symbols, patching their values with the +-+ * correct addresses. +-+ */ +-+static void +-+gdb_patch_symbol_values(struct gnu_request *req) +-+{ +-+ struct minimal_symbol *msymbol; +-+ struct objfile *objfile; +-+ +-+ req->name = PATCH_KERNEL_SYMBOLS_START; +-+ patch_kernel_symbol(req); +-+ +-+ ALL_MSYMBOLS (objfile, msymbol) +-+ { +-+ req->name = (char *)msymbol->ginfo.name; +-+ req->addr = (ulong)(&SYMBOL_VALUE_ADDRESS(msymbol)); +-+ if (!patch_kernel_symbol(req)) { +-+ req->flags |= GNU_COMMAND_FAILED; +-+ break; +-+ } +-+ } +-+ +-+ req->name = PATCH_KERNEL_SYMBOLS_STOP; +-+ patch_kernel_symbol(req); +-+ +-+ clear_symtab_users(0); +-+ gdb_merge_flags |= KERNEL_SYMBOLS_PATCHED; +-+} +-+ +-+static void +-+gdb_get_symbol_type(struct gnu_request *req) +-+{ +-+ struct expression *expr; +-+ struct value *val; +-+ struct cleanup *old_chain = NULL; +-+ struct type *type; +-+ struct type *target_type; +-+ +-+ req->typecode = TYPE_CODE_UNDEF; +-+ +-+ expr = parse_expression (req->name); +-+ old_chain = make_cleanup (free_current_contents, &expr); +-+ val = evaluate_type (expr); +-+ +-+ type = value_type(val); +-+ +-+ req->type_name = (char *)TYPE_MAIN_TYPE(type)->name; +-+ req->typecode = TYPE_MAIN_TYPE(type)->code; +-+ req->length = type->length; +-+ target_type = TYPE_MAIN_TYPE(type)->target_type; +-+ +-+ if (target_type) { +-+ req->target_typename = (char *)TYPE_MAIN_TYPE(target_type)->name; +-+ req->target_typecode = TYPE_MAIN_TYPE(target_type)->code; +-+ req->target_length = target_type->length; +-+ } +-+ +-+ if (req->member) +-+ get_member_data(req, type); +-+ +-+ do_cleanups (old_chain); +-+} +-+ +-+static void +-+gdb_debug_command(struct gnu_request *req) +-+{ +-+ +-+} +-+ +-+/* +-+ * Only necessary on "patched" kernel symbol sessions, and called only by +-+ * lookup_symbol(), pull a symbol value bait-and-switch operation by altering +-+ * either a data symbol's address value or a text symbol's block start address. +-+ */ +-+static void +-+gdb_bait_and_switch(char *name, struct symbol *sym) +-+{ +-+ struct minimal_symbol *msym; +-+ struct block *block; +-+ +-+ if ((gdb_merge_flags & KERNEL_SYMBOLS_PATCHED) && +-+ (msym = lookup_minimal_symbol(name, NULL, gdb_kernel_objfile))) { +-+ if (sym->aclass == LOC_BLOCK) { +-+ block = (struct block *)SYMBOL_BLOCK_VALUE(sym); +-+ BLOCK_START(block) = SYMBOL_VALUE_ADDRESS(msym); +-+ } else +-+ SYMBOL_VALUE_ADDRESS(sym) = SYMBOL_VALUE_ADDRESS(msym); +-+ } +-+} +-+ +-+#include "valprint.h" +-+ +-+void +-+get_user_print_option_address(struct gnu_request *req) +-+{ +-+ extern struct value_print_options user_print_options; +-+ +-+ req->addr = 0; +-+ +-+ if (strcmp(req->name, "output_format") == 0) +-+ req->addr = (ulong)&user_print_options.output_format; +-+ if (strcmp(req->name, "print_max") == 0) +-+ req->addr = (ulong)&user_print_options.print_max; +-+ if (strcmp(req->name, "prettyprint_structs") == 0) +-+ req->addr = (ulong)&user_print_options.prettyprint_structs; +-+ if (strcmp(req->name, "prettyprint_arrays") == 0) +-+ req->addr = (ulong)&user_print_options.prettyprint_arrays; +-+ if (strcmp(req->name, "repeat_count_threshold") == 0) +-+ req->addr = (ulong)&user_print_options.repeat_count_threshold; +-+ if (strcmp(req->name, "stop_print_at_null") == 0) +-+ req->addr = (ulong)&user_print_options.stop_print_at_null; +-+ if (strcmp(req->name, "output_radix") == 0) +-+ req->addr = (ulong)&output_radix; +-+} +-+ +-+CORE_ADDR crash_text_scope; +-+ +-+static void +-+gdb_set_crash_block(struct gnu_request *req) +-+{ +-+ if (!req->addr) { /* debug */ +-+ crash_text_scope = 0; +-+ return; +-+ } +-+ +-+ if ((req->addr2 = (ulong)block_for_pc(req->addr))) +-+ crash_text_scope = req->addr; +-+ else { +-+ crash_text_scope = 0; +-+ req->flags |= GNU_COMMAND_FAILED; +-+ } +-+} +-+ +-+static struct block * +-+gdb_get_crash_block(void) +-+{ +-+ if (crash_text_scope) +-+ return block_for_pc(crash_text_scope); +-+ else +-+ return NULL; +-+} +-+#endif +---- gdb-7.6/gdb/c-typeprint.c.orig +-+++ gdb-7.6/gdb/c-typeprint.c +-@@ -1097,7 +1097,8 @@ c_type_print_base (struct type *type, st +- fprintf_filtered (stream, "static "); +- c_print_type (TYPE_FIELD_TYPE (type, i), +- TYPE_FIELD_NAME (type, i), +-- stream, show - 1, level + 4, +-+ stream, strlen(TYPE_FIELD_NAME (type, i)) ? +-+ show - 1 : show, level + 4, +- &local_flags); +- if (!field_is_static (&TYPE_FIELD (type, i)) +- && TYPE_FIELD_PACKED (type, i)) +---- gdb-7.6/gdb/xml-syscall.c.orig +-+++ gdb-7.6/gdb/xml-syscall.c +-@@ -38,7 +38,11 @@ +- static void +- syscall_warn_user (void) +- { +-+#ifdef CRASH_MERGE +-+ static int have_warned = 1; +-+#else +- static int have_warned = 0; +-+#endif +- if (!have_warned) +- { +- have_warned = 1; +---- gdb-7.6/gdb/exceptions.c.orig +-+++ gdb-7.6/gdb/exceptions.c +-@@ -218,6 +218,10 @@ exceptions_state_mc_action_iter_1 (void) +- +- /* Return EXCEPTION to the nearest containing catch_errors(). */ +- +-+#ifdef CRASH_MERGE +-+void (*error_hook) (void) ATTRIBUTE_NORETURN; +-+#endif +-+ +- void +- throw_exception (struct gdb_exception exception) +- { +-@@ -225,6 +229,13 @@ throw_exception (struct gdb_exception ex +- immediate_quit = 0; +- +- do_cleanups (all_cleanups ()); +-+#ifdef CRASH_MERGE +-+ if (error_hook) { +-+ fprintf_filtered(gdb_stderr, "%s\n", exception.message); +-+ (*error_hook)(); +-+ } else +-+ fprintf_filtered(gdb_stderr, "gdb called without error_hook: %s\n", exception.message); +-+#endif +- +- /* Jump to the containing catch_errors() call, communicating REASON +- to that call via setjmp's return value. Note that REASON can't +---- gdb-7.6/gdb/valprint.h.orig +-+++ gdb-7.6/gdb/valprint.h +-@@ -152,11 +152,17 @@ extern void print_function_pointer_addre +- struct gdbarch *gdbarch, +- CORE_ADDR address, +- struct ui_file *stream); +-- +-+#ifdef CRASH_MERGE +-+extern int valprint_read_string (CORE_ADDR addr, int len, int width, +-+ unsigned int fetchlimit, +-+ enum bfd_endian byte_order, gdb_byte **buffer, +-+ int *bytes_read); +-+#else +- extern int read_string (CORE_ADDR addr, int len, int width, +- unsigned int fetchlimit, +- enum bfd_endian byte_order, gdb_byte **buffer, +- int *bytes_read); +-+#endif +- +- extern void val_print_optimized_out (struct ui_file *stream); +- +---- gdb-7.6/gdb/target.c.orig +-+++ gdb-7.6/gdb/target.c +-@@ -1779,6 +1779,13 @@ target_xfer_partial (struct target_ops * +- int +- target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) +- { +-+#ifdef CRASH_MERGE +-+ extern int gdb_readmem_callback(unsigned long, void *, int, int); +-+ if (gdb_readmem_callback(memaddr, (void *)myaddr, len, 0)) +-+ return 0; +-+ else +-+ return EIO; +-+#endif +- /* Dispatch to the topmost target, not the flattened current_target. +- Memory accesses check target->to_has_(all_)memory, and the +- flattened target doesn't inherit those. */ +-@@ -1814,6 +1821,13 @@ target_read_stack (CORE_ADDR memaddr, gd +- int +- target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, ssize_t len) +- { +-+#ifdef CRASH_MERGE +-+ extern int gdb_readmem_callback(unsigned long, void *, int, int); +-+ if (gdb_readmem_callback(memaddr, (void *)myaddr, len, 1)) +-+ return 0; +-+ else +-+ return EIO; +-+#endif +- /* Dispatch to the topmost target, not the flattened current_target. +- Memory accesses check target->to_has_(all_)memory, and the +- flattened target doesn't inherit those. */ +---- gdb-7.6/gdb/printcmd.c.orig +-+++ gdb-7.6/gdb/printcmd.c +-@@ -1001,11 +1001,62 @@ print_command_1 (char *exp, int voidprin +- } +- +- static void +-+print_command_2 (char *exp, int inspect, int voidprint) +-+{ +-+ struct expression *expr; +-+ struct cleanup *old_chain = 0; +-+ char format = 0; +-+ struct value *val; +-+ struct format_data fmt; +-+ int cleanup = 0; +-+ +-+ if (exp && *exp == '/') +-+ { +-+ exp++; +-+ fmt = decode_format (&exp, last_format, 0); +-+ validate_format (fmt, "print"); +-+ last_format = format = fmt.format; +-+ } +-+ else +-+ { +-+ fmt.count = 1; +-+ fmt.format = 0; +-+ fmt.size = 0; +-+ fmt.raw = 0; +-+ } +-+ +-+ if (exp && *exp) +-+ { +-+ expr = parse_expression (exp); +-+ old_chain = make_cleanup (free_current_contents, &expr); +-+ cleanup = 1; +-+ val = evaluate_expression (expr); +-+ } +-+ else +-+ val = access_value_history (0); +-+ +-+ printf_filtered ("%d %d %d %d %d %d\n", +-+ TYPE_CODE (check_typedef(value_type (val))), +-+ TYPE_UNSIGNED (check_typedef(value_type (val))), +-+ TYPE_LENGTH (check_typedef(value_type(val))), +-+ value_offset (val), value_bitpos (val), value_bitsize(val)); +-+ +-+ if (cleanup) +-+ do_cleanups (old_chain); +-+} +-+ +-+static void +- print_command (char *exp, int from_tty) +- { +- print_command_1 (exp, 1); +- } +- +-+static void +-+printm_command (char *exp, int from_tty) +-+{ +-+ print_command_2 (exp, 0, 1); +-+} +-+ +- /* Same as print, except it doesn't print void results. */ +- static void +- call_command (char *exp, int from_tty) +-@@ -2593,6 +2644,12 @@ EXP may be preceded with /FMT, where FMT +- but no count or size letter (see \"x\" command).")); +- set_cmd_completer (c, expression_completer); +- add_com_alias ("p", "print", class_vars, 1); +-+ +-+ c = add_com ("printm", class_vars, printm_command, _("\ +-+Similar to \"print\" command, but it used to print the type, size, offset,\n\ +-+bitpos and bitsize of the expression EXP.")); +-+ set_cmd_completer (c, expression_completer); +-+ +- add_com_alias ("inspect", "print", class_vars, 1); +- +- add_setshow_uinteger_cmd ("max-symbolic-offset", no_class, +---- gdb-7.6/gdb/ui-file.c.orig +-+++ gdb-7.6/gdb/ui-file.c +-@@ -671,6 +671,17 @@ gdb_fopen (char *name, char *mode) +- return stdio_file_new (f, 1); +- } +- +-+#ifdef CRASH_MERGE +-+void +-+replace_ui_file_FILE(struct ui_file *file, FILE *fp) +-+{ +-+ struct stdio_file *stdio_file; +-+ +-+ stdio_file = (struct stdio_file *)ui_file_data(file); +-+ stdio_file->file = fp; +-+} +-+#endif +-+ +- /* ``struct ui_file'' implementation that maps onto two ui-file objects. */ +- +- static ui_file_write_ftype tee_file_write; +---- gdb-7.6/gdb/main.c.orig +-+++ gdb-7.6/gdb/main.c +-@@ -806,7 +806,7 @@ captured_main (void *data) +- { +- print_gdb_version (gdb_stdout); +- wrap_here (""); +-- printf_filtered ("\n"); +-+ printf_filtered ("\n\n"); +- exit (0); +- } +- +-@@ -853,6 +853,13 @@ captured_main (void *data) +- } +- } +- +-+#ifdef CRASH_MERGE +-+{ +-+ extern void update_gdb_hooks(void); +-+ update_gdb_hooks(); +-+} +-+#endif +-+ +- /* FIXME: cagney/2003-02-03: The big hack (part 2 of 2) that lets +- GDB retain the old MI1 interpreter startup behavior. Output the +- copyright message after the interpreter is installed when it is +-@@ -880,7 +887,11 @@ captured_main (void *data) +- processed; it sets global parameters, which are independent of +- what file you are debugging or what directory you are in. */ +- if (system_gdbinit && !inhibit_gdbinit) +-+#ifdef CRASH_MERGE +-+ catch_command_errors (source_script, system_gdbinit, -1, RETURN_MASK_ALL); +-+#else +- catch_command_errors (source_script, system_gdbinit, 0, RETURN_MASK_ALL); +-+#endif +- +- /* Read and execute $HOME/.gdbinit file, if it exists. This is done +- *before* all the command line arguments are processed; it sets +-@@ -888,7 +899,11 @@ captured_main (void *data) +- debugging or what directory you are in. */ +- +- if (home_gdbinit && !inhibit_gdbinit && !inhibit_home_gdbinit) +-+#ifdef CRASH_MERGE +-+ catch_command_errors (source_script, home_gdbinit, -1, RETURN_MASK_ALL); +-+#else +- catch_command_errors (source_script, home_gdbinit, 0, RETURN_MASK_ALL); +-+#endif +- +- /* Process '-ix' and '-iex' options early. */ +- for (i = 0; VEC_iterate (cmdarg_s, cmdarg_vec, i, cmdarg_p); i++) +-@@ -929,8 +944,12 @@ captured_main (void *data) +- catch_command_errors returns non-zero on success! */ +- if (catch_command_errors (exec_file_attach, execarg, +- !batch_flag, RETURN_MASK_ALL)) +-+#ifdef CRASH_MERGE +-+ catch_command_errors (symbol_file_add_main, symarg, 0, RETURN_MASK_ALL); +-+#else +- catch_command_errors (symbol_file_add_main, symarg, +- !batch_flag, RETURN_MASK_ALL); +-+#endif +- } +- else +- { +-@@ -992,8 +1011,12 @@ captured_main (void *data) +- { +- auto_load_local_gdbinit_loaded = 1; +- +-+#ifdef CRASH_MERGE +-+ catch_command_errors (source_script, local_gdbinit, -1, RETURN_MASK_ALL); +-+#else +- catch_command_errors (source_script, local_gdbinit, 0, +- RETURN_MASK_ALL); +-+#endif +- } +- } +- +-@@ -1039,6 +1062,12 @@ captured_main (void *data) +- while (1) +- { +- catch_errors (captured_command_loop, 0, "", RETURN_MASK_ALL); +-+#ifdef CRASH_MERGE +-+ { +-+ int console(char *, ...); +-+ console("\n"); +-+ } +-+#endif +- } +- /* No exit -- exit is through quit_command. */ +- } +-@@ -1053,6 +1082,23 @@ gdb_main (struct captured_main_args *arg +- return 1; +- } +- +-+#ifdef CRASH_MERGE +-+/* +-+ * NOTE: adapted from gdb.c, which is no longer built in; changed name of +-+ * original main() to gdb_main_entry() for use as crash entry point +-+ */ +-+int +-+gdb_main_entry (int argc, char **argv) +-+{ +-+ struct captured_main_args args; +-+ memset (&args, 0, sizeof args); +-+ args.argc = argc; +-+ args.argv = argv; +-+ args.use_windows = 0; +-+ args.interpreter_p = INTERP_CONSOLE; +-+ return gdb_main (&args); +-+} +-+#endif +- +- /* Don't use *_filtered for printing help. We don't want to prompt +- for continue no matter how small the screen or how much we're going +---- gdb-7.6/gdb/valprint.c.orig +-+++ gdb-7.6/gdb/valprint.c +-@@ -1768,8 +1768,13 @@ partial_memory_read (CORE_ADDR memaddr, +- this function instead? */ +- +- int +-+#ifdef CRASH_MERGE +-+valprint_read_string (CORE_ADDR addr, int len, int width, unsigned int fetchlimit, +-+ enum bfd_endian byte_order, gdb_byte **buffer, int *bytes_read) +-+#else +- read_string (CORE_ADDR addr, int len, int width, unsigned int fetchlimit, +- enum bfd_endian byte_order, gdb_byte **buffer, int *bytes_read) +-+#endif +- { +- int found_nul; /* Non-zero if we found the nul char. */ +- int errcode; /* Errno returned from bad reads. */ +-@@ -2472,8 +2477,13 @@ val_print_string (struct type *elttype, +- fetchlimit = (len == -1 ? options->print_max : min (len, +- options->print_max)); +- +-+#ifdef CRASH_MERGE +-+ errcode = valprint_read_string (addr, len, width, fetchlimit, byte_order, +-+ &buffer, &bytes_read); +-+#else +- errcode = read_string (addr, len, width, fetchlimit, byte_order, +- &buffer, &bytes_read); +-+#endif +- old_chain = make_cleanup (xfree, buffer); +- +- addr += bytes_read; +---- gdb-7.6/gdb/Makefile.in.orig +-+++ gdb-7.6/gdb/Makefile.in +-@@ -422,7 +422,7 @@ CONFIG_UNINSTALL = @CONFIG_UNINSTALL@ +- # It is also possible that you will need to add -I/usr/include/sys if +- # your system doesn't have fcntl.h in /usr/include (which is where it +- # should be according to Posix). +--DEFS = @DEFS@ +-+DEFS = -DCRASH_MERGE @DEFS@ +- GDB_CFLAGS = -I. -I$(srcdir) -I$(srcdir)/common -I$(srcdir)/config \ +- -DLOCALEDIR="\"$(localedir)\"" $(DEFS) +- +-@@ -934,7 +934,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $ +- +- TSOBS = inflow.o +- +--SUBDIRS = doc @subdirs@ data-directory $(GNULIB_BUILDDIR) +-+SUBDIRS = build_no_subdirs +- CLEANDIRS = $(SUBDIRS) +- +- # List of subdirectories in the build tree that must exist. +-@@ -969,8 +969,8 @@ generated_files = config.h observer.h ob +- $(COMPILE) $< +- $(POSTCOMPILE) +- +--all: gdb$(EXEEXT) $(CONFIG_ALL) +-- @$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do +-+all: gdb$(EXEEXT) +-+ @$(MAKE) -s $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do +- +- installcheck: +- +-@@ -1172,15 +1172,16 @@ libgdb.a: $(LIBGDB_OBS) +- +- # Removing the old gdb first works better if it is running, at least on SunOS. +- gdb$(EXEEXT): gdb.o $(LIBGDB_OBS) $(ADD_DEPS) $(CDEPS) $(TDEPLIBS) +-- rm -f gdb$(EXEEXT) +-+ @rm -f gdb$(EXEEXT) +-+ @(cd ../..; make --no-print-directory GDB_FLAGS=-DGDB_7_6 library) +- $(CC_LD) $(INTERNAL_LDFLAGS) $(WIN32LDAPP) \ +-- -o gdb$(EXEEXT) gdb.o $(LIBGDB_OBS) \ +-- $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES) +-+ -o $(shell /bin/cat mergeobj) $(LIBGDB_OBS) \ +-+ $(TDEPLIBS) $(TUI_LIBRARY) $(CLIBS) $(LOADLIBES) $(shell /bin/cat mergelibs) +- +- # Convenience rule to handle recursion. +- $(LIBGNU) $(GNULIB_H): all-lib +- all-lib: $(GNULIB_BUILDDIR)/Makefile +-- @$(MAKE) $(FLAGS_TO_PASS) DO=all DODIRS=$(GNULIB_BUILDDIR) subdir_do +-+ @$(MAKE) $(FLAGS_TO_PASS) DO=all DODIRS=$(GNULIB_BUILDDIR) subdir_do -s +- .PHONY: all-lib +- +- # Convenience rule to handle recursion. +-@@ -1389,12 +1390,12 @@ $(srcdir)/copying.c: @MAINTAINER_MODE_TR +- mv $(srcdir)/copying.tmp $(srcdir)/copying.c +- +- version.c: Makefile version.in +-- rm -f version.c-tmp version.c +-- echo '#include "version.h"' >> version.c-tmp +-- echo 'const char version[] = "'"`sed q ${srcdir}/version.in`"'";' >> version.c-tmp +-- echo 'const char host_name[] = "$(host_alias)";' >> version.c-tmp +-- echo 'const char target_name[] = "$(target_alias)";' >> version.c-tmp +-- mv version.c-tmp version.c +-+ @rm -f version.c-tmp version.c +-+ @echo '#include "version.h"' >> version.c-tmp +-+ @echo 'const char version[] = "'"`sed q ${srcdir}/version.in`"'";' >> version.c-tmp +-+ @echo 'const char host_name[] = "$(host_alias)";' >> version.c-tmp +-+ @echo 'const char target_name[] = "$(target_alias)";' >> version.c-tmp +-+ @mv version.c-tmp version.c +- +- observer.h: observer.sh doc/observer.texi +- ${srcdir}/observer.sh h ${srcdir}/doc/observer.texi observer.h +---- gdb-7.6/gdb/c-lang.c.orig +-+++ gdb-7.6/gdb/c-lang.c +-@@ -307,7 +307,11 @@ c_get_string (struct value *value, gdb_b +- { +- CORE_ADDR addr = value_as_address (value); +- +-+#ifdef CRASH_MERGE +-+ err = valprint_read_string (addr, *length, width, fetchlimit, +-+#else +- err = read_string (addr, *length, width, fetchlimit, +-+#endif +- byte_order, buffer, length); +- if (err) +- { +---- gdb-7.6/readline/rltypedefs.h.orig +-+++ gdb-7.6/readline/rltypedefs.h +-@@ -31,10 +31,10 @@ extern "C" { +- #if !defined (_FUNCTION_DEF) +- # define _FUNCTION_DEF +- +--typedef int Function (); +--typedef void VFunction (); +--typedef char *CPFunction (); +--typedef char **CPPFunction (); +-+typedef int Function (void); +-+typedef void VFunction (void); +-+typedef char *CPFunction (void); +-+typedef char **CPPFunction (void); +- +- #endif /* _FUNCTION_DEF */ +- +---- gdb-7.6/readline/readline.h.orig +-+++ gdb-7.6/readline/readline.h +-@@ -378,7 +378,7 @@ extern int rl_crlf PARAMS((void)); +- #if defined (USE_VARARGS) && defined (PREFER_STDARG) +- extern int rl_message (const char *, ...) __attribute__((__format__ (printf, 1, 2))); +- #else +--extern int rl_message (); +-+extern int rl_message (void); +- #endif +- +- extern int rl_show_char PARAMS((int)); +---- gdb-7.6/readline/misc.c.orig +-+++ gdb-7.6/readline/misc.c +-@@ -405,7 +405,7 @@ _rl_history_set_point () +- +- #if defined (VI_MODE) +- if (rl_editing_mode == vi_mode && _rl_keymap != vi_insertion_keymap) +-- rl_point = 0; +-+ rl_point = rl_end; +- #endif /* VI_MODE */ +- +- if (rl_editing_mode == emacs_mode) +---- gdb-7.6/Makefile.in.orig +-+++ gdb-7.6/Makefile.in +-@@ -342,6 +342,9 @@ AR_FOR_BUILD = @AR_FOR_BUILD@ +- AS_FOR_BUILD = @AS_FOR_BUILD@ +- CC_FOR_BUILD = @CC_FOR_BUILD@ +- CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +-+ifeq (${CRASH_TARGET}, PPC64) +-+CFLAGS_FOR_BUILD += -m64 -fPIC +-+endif +- CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +- CXX_FOR_BUILD = @CXX_FOR_BUILD@ +- DLLTOOL_FOR_BUILD = @DLLTOOL_FOR_BUILD@ +-@@ -407,6 +410,9 @@ GNATBIND = @GNATBIND@ +- GNATMAKE = @GNATMAKE@ +- +- CFLAGS = @CFLAGS@ +-+ifeq (${CRASH_TARGET}, PPC64) +-+CFLAGS += -m64 -fPIC +-+endif +- LDFLAGS = @LDFLAGS@ +- LIBCFLAGS = $(CFLAGS) +- CXXFLAGS = @CXXFLAGS@ +---- gdb-7.6/gdb/defs.h.orig +-+++ gdb-7.6/gdb/defs.h +-@@ -802,4 +802,8 @@ enum block_enum +- +- #include "utils.h" +- +-+#ifdef CRASH_MERGE +-+extern int gdb_main_entry(int, char **); +-+extern void replace_ui_file_FILE(struct ui_file *, FILE *); +-+#endif +- #endif /* #ifndef DEFS_H */ +---- gdb-7.6/bfd/elflink.c.orig +-+++ gdb-7.6/bfd/elflink.c +-@@ -4730,7 +4730,7 @@ error_free_dyn: +- struct elf_link_hash_entry *hlook; +- asection *slook; +- bfd_vma vlook; +-- size_t i, j, idx; +-+ size_t i, j, idx = 0; +- +- hlook = weaks; +- weaks = hlook->u.weakdef; +---- gdb-7.6/gdb/s390-nat.c.orig +-+++ gdb-7.6/gdb/s390-nat.c +-@@ -37,6 +37,8 @@ +- #include +- #include +- +-+#include +-+ +- #ifndef HWCAP_S390_HIGH_GPRS +- #define HWCAP_S390_HIGH_GPRS 512 +- #endif +---- gdb-7.6/gdb/printcmd.c.orig +-+++ gdb-7.6/gdb/printcmd.c +-@@ -573,11 +573,21 @@ print_address_symbolic (struct gdbarch * +- int unmapped = 0; +- int offset = 0; +- int line = 0; +-+#ifdef CRASH_MERGE +-+ extern int gdb_print_callback(unsigned long); +-+#endif +- +- /* Throw away both name and filename. */ +- struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &name); +- make_cleanup (free_current_contents, &filename); +- +-+#ifdef CRASH_MERGE +-+ if (!gdb_print_callback(addr)) { +-+ do_cleanups (cleanup_chain); +-+ return 0; +-+ } +-+#endif +-+ +- if (build_address_symbolic (gdbarch, addr, do_demangle, &name, &offset, +- &filename, &line, &unmapped)) +- { +---- gdb-7.6/bfd/bfd-in.h.orig +-+++ gdb-7.6/bfd/bfd-in.h +-@@ -294,9 +294,6 @@ typedef struct bfd_section *sec_ptr; +- +- #define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) +- +--#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma = (val)), ((ptr)->user_set_vma = TRUE), TRUE) +--#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),TRUE) +--#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),TRUE) +- /* Find the address one past the end of SEC. */ +- #define bfd_get_section_limit(bfd, sec) \ +- (((bfd)->direction != write_direction && (sec)->rawsize != 0 \ +-@@ -519,7 +516,6 @@ extern void warn_deprecated (const char +- +- #define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) +- +--#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = bool), TRUE) +- +- extern bfd_boolean bfd_cache_close +- (bfd *abfd); +---- gdb-7.6/bfd/bfd-in2.h.orig +-+++ gdb-7.6/bfd/bfd-in2.h +-@@ -301,9 +301,6 @@ typedef struct bfd_section *sec_ptr; +- +- #define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) +- +--#define bfd_set_section_vma(bfd, ptr, val) (((ptr)->vma = (ptr)->lma = (val)), ((ptr)->user_set_vma = TRUE), TRUE) +--#define bfd_set_section_alignment(bfd, ptr, val) (((ptr)->alignment_power = (val)),TRUE) +--#define bfd_set_section_userdata(bfd, ptr, val) (((ptr)->userdata = (val)),TRUE) +- /* Find the address one past the end of SEC. */ +- #define bfd_get_section_limit(bfd, sec) \ +- (((bfd)->direction != write_direction && (sec)->rawsize != 0 \ +-@@ -526,7 +523,6 @@ extern void warn_deprecated (const char +- +- #define bfd_get_symbol_leading_char(abfd) ((abfd)->xvec->symbol_leading_char) +- +--#define bfd_set_cacheable(abfd,bool) (((abfd)->cacheable = bool), TRUE) +- +- extern bfd_boolean bfd_cache_close +- (bfd *abfd); +-@@ -1572,6 +1568,32 @@ struct relax_table { +- int size; +- }; +- +-+/* Note: the following are provided as inline functions rather than macros +-+ because not all callers use the return value. A macro implementation +-+ would use a comma expression, eg: "((ptr)->foo = val, TRUE)" and some +-+ compilers will complain about comma expressions that have no effect. */ +-+static inline bfd_boolean +-+bfd_set_section_userdata (bfd * abfd ATTRIBUTE_UNUSED, asection * ptr, void * val) +-+{ +-+ ptr->userdata = val; +-+ return TRUE; +-+} +-+ +-+static inline bfd_boolean +-+bfd_set_section_vma (bfd * abfd ATTRIBUTE_UNUSED, asection * ptr, bfd_vma val) +-+{ +-+ ptr->vma = ptr->lma = val; +-+ ptr->user_set_vma = TRUE; +-+ return TRUE; +-+} +-+ +-+static inline bfd_boolean +-+bfd_set_section_alignment (bfd * abfd ATTRIBUTE_UNUSED, asection * ptr, unsigned int val) +-+{ +-+ ptr->alignment_power = val; +-+ return TRUE; +-+} +-+ +- /* These sections are global, and are managed by BFD. The application +- and target back end are not permitted to change the values in +- these sections. */ +-@@ -6095,6 +6117,14 @@ struct bfd +- unsigned int selective_search : 1; +- }; +- +-+/* See note beside bfd_set_section_userdata. */ +-+static inline bfd_boolean +-+bfd_set_cacheable (bfd * abfd, bfd_boolean val) +-+{ +-+ abfd->cacheable = val; +-+ return TRUE; +-+} +-+ +- typedef enum bfd_error +- { +- bfd_error_no_error = 0, +---- gdb-7.6/gdb/symtab.c.orig +-+++ gdb-7.6/gdb/symtab.c +-@@ -5405,7 +5405,7 @@ dump_enum(struct type *type, struct gnu_ +- { +- register int i; +- int len; +-- int lastval; +-+ long long lastval; +- +- len = TYPE_NFIELDS (type); +- lastval = 0; +-@@ -5418,12 +5418,12 @@ dump_enum(struct type *type, struct gnu_ +- for (i = 0; i < len; i++) { +- fprintf_filtered(gdb_stdout, " %s", +- TYPE_FIELD_NAME (type, i)); +-- if (lastval != TYPE_FIELD_BITPOS (type, i)) { +-- fprintf_filtered (gdb_stdout, " = %d", +-- TYPE_FIELD_BITPOS (type, i)); +-- lastval = TYPE_FIELD_BITPOS (type, i); +-+ if (lastval != TYPE_FIELD_ENUMVAL (type, i)) { +-+ fprintf_filtered (gdb_stdout, " = %s", +-+ plongest(TYPE_FIELD_ENUMVAL (type, i))); +-+ lastval = TYPE_FIELD_ENUMVAL (type, i); +- } else +-- fprintf_filtered(gdb_stdout, " = %d", lastval); +-+ fprintf_filtered(gdb_stdout, " = %s", plongest(lastval)); +- fprintf_filtered(gdb_stdout, "\n"); +- lastval++; +- } +---- gdb-7.6/gdb/aarch64-linux-nat.c.orig +-+++ gdb-7.6/gdb/aarch64-linux-nat.c +-@@ -32,6 +32,7 @@ +- #include "elf/common.h" +- +- #include +-+#include +- #include +- +- #include "gregset.h" +---- gdb-7.6/sim/igen/Makefile.in.orig +-+++ gdb-7.6/sim/igen/Makefile.in +-@@ -117,7 +117,7 @@ IGEN_OBJS=\ +- gen.o +- +- igen: igen.o $(IGEN_OBJS) +-- $(CC_FOR_BUILD) $(BUILD_LDFLAGS) -o igen igen.o $(IGEN_OBJS) $(LIBIBERTY_LIB) +-+ $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o igen igen.o $(IGEN_OBJS) $(LIBIBERTY_LIB) +- +- igen.o: igen.c misc.h filter_host.h lf.h table.h ld-decode.h ld-cache.h ld-insn.h filter.h gen-model.h gen-itable.h gen-icache.h gen-idecode.h gen-engine.h gen-semantics.h gen-support.h gen.h igen.h +- $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/igen.c +---- gdb-7.6/sim/mips/cp1.c.orig +-+++ gdb-7.6/sim/mips/cp1.c +-@@ -1359,7 +1359,7 @@ fp_rsqrt2(sim_cpu *cpu, +- /* Conversion operations. */ +- +- uword64 +--convert (sim_cpu *cpu, +-+sim_mips_convert (sim_cpu *cpu, +- address_word cia, +- int rm, +- uword64 op, +---- gdb-7.6/sim/mips/sim-main.h.orig +-+++ gdb-7.6/sim/mips/sim-main.h +-@@ -770,8 +770,8 @@ unsigned64 fp_nmadd (SIM_STATE, unsigned64 op1, unsigned64 op2, +- unsigned64 fp_nmsub (SIM_STATE, unsigned64 op1, unsigned64 op2, +- unsigned64 op3, FP_formats fmt); +- #define NegMultiplySub(op1,op2,op3,fmt) fp_nmsub(SIM_ARGS, op1, op2, op3, fmt) +--unsigned64 convert (SIM_STATE, int rm, unsigned64 op, FP_formats from, FP_formats to); +--#define Convert(rm,op,from,to) convert (SIM_ARGS, rm, op, from, to) +-+unsigned64 sim_mips_convert (SIM_STATE, int rm, unsigned64 op, FP_formats from, FP_formats to); +-+#define Convert(rm,op,from,to) sim_mips_convert (SIM_ARGS, rm, op, from, to) +- unsigned64 convert_ps (SIM_STATE, int rm, unsigned64 op, FP_formats from, +- FP_formats to); +- #define ConvertPS(rm,op,from,to) convert_ps (SIM_ARGS, rm, op, from, to) +- +---- gdb-7.6/readline/util.c +-+++ gdb-7.6/readline/util.c +-@@ -493,10 +493,13 @@ _rl_trace (va_alist) +- +- if (_rl_tracefp == 0) +- _rl_tropen (); +-+ if (!_rl_tracefp) +-+ goto out; +- vfprintf (_rl_tracefp, format, args); +- fprintf (_rl_tracefp, "\n"); +- fflush (_rl_tracefp); +- +-+out: +- va_end (args); +- } +- +-@@ -509,16 +512,17 @@ _rl_tropen () +- fclose (_rl_tracefp); +- sprintf (fnbuf, "/var/tmp/rltrace.%ld", getpid()); +- unlink(fnbuf); +-- _rl_tracefp = fopen (fnbuf, "w+"); +-+ _rl_tracefp = fopen (fnbuf, "w+xe"); +- return _rl_tracefp != 0; +- } +- +- int +- _rl_trclose () +- { +-- int r; +-+ int r = 0; +- +-- r = fclose (_rl_tracefp); +-+ if (_rl_tracefp) +-+ r = fclose (_rl_tracefp); +- _rl_tracefp = 0; +- return r; +- } +---- gdb-7.6/gdb/symtab.c.orig +-+++ gdb-7.6/gdb/symtab.c +-@@ -5447,9 +5447,9 @@ eval_enum(struct type *type, struct gnu_ +- lastval = 0; +- +- for (i = 0; i < len; i++) { +-- if (lastval != TYPE_FIELD_BITPOS (type, i)) { +-- lastval = TYPE_FIELD_BITPOS (type, i); +-- } +-+ if (lastval != TYPE_FIELD_ENUMVAL (type, i)) +-+ lastval = TYPE_FIELD_ENUMVAL (type, i); +-+ +- if (STREQ(TYPE_FIELD_NAME(type, i), req->name)) { +- req->tagname = "(unknown)"; +- req->value = lastval; +---- gdb-7.6/gdb/symtab.c.orig +-+++ gdb-7.6/gdb/symtab.c +-@@ -5236,6 +5236,12 @@ gdb_command_funnel(struct gnu_request *r +- gdb_set_crash_block(req); +- break; +- +-+ case GNU_GET_FUNCTION_RANGE: +-+ sym = lookup_symbol(req->name, 0, VAR_DOMAIN, 0); +-+ if (!find_pc_partial_function(req->pc, NULL, &req->addr, &req->addr2)) +-+ req->flags |= GNU_COMMAND_FAILED; +-+ break; +-+ +- default: +- req->flags |= GNU_COMMAND_FAILED; +- break; +---- gdb-7.6/opcodes/i386-dis.c.orig +-+++ gdb-7.6/opcodes/i386-dis.c +-@@ -11300,6 +11300,29 @@ get_sib (disassemble_info *info) +- } +- } +- +-+static char * +-+check_for_extensions(struct dis_private *priv) +-+{ +-+ unsigned char ModRM; +-+ +-+ if ((priv->the_buffer[0] == 0x66) && +-+ (priv->the_buffer[1] == 0x0f) && +-+ (priv->the_buffer[2] == 0xae)) { +-+ ModRM = priv->the_buffer[3]; +-+ if (ModRM == 0xf8) +-+ return "pcommit"; +-+ +-+ switch ((ModRM >> 3)) +-+ { +-+ case 0x6: +-+ return "clwb"; +-+ case 0x7: +-+ return "clflushopt"; +-+ } +-+ } +-+ return NULL; +-+} +-+ +- static int +- print_insn (bfd_vma pc, disassemble_info *info) +- { +-@@ -11312,6 +11335,7 @@ print_insn (bfd_vma pc, disassemble_info +- struct dis_private priv; +- int prefix_length; +- int default_prefixes; +-+ char *extension; +- +- priv.orig_sizeflag = AFLAG | DFLAG; +- if ((info->mach & bfd_mach_i386_i386) != 0) +-@@ -11575,6 +11599,7 @@ print_insn (bfd_vma pc, disassemble_info +- need_vex = 0; +- need_vex_reg = 0; +- vex_w_done = 0; +-+ extension = NULL; +- +- if (dp->name == NULL && dp->op[0].bytemode == FLOATCODE) +- { +-@@ -11610,9 +11635,14 @@ print_insn (bfd_vma pc, disassemble_info +- name = prefix_name (all_prefixes[i], priv.orig_sizeflag); +- if (name == NULL) +- name = INTERNAL_DISASSEMBLER_ERROR; +-- (*info->fprintf_func) (info->stream, "%s", name); +-- return 1; +-- } +-+ if ((extension = check_for_extensions(&priv))) { +-+ strcpy(obuf, extension); +-+ obufp = &obuf[strlen(obuf)]; +-+ } else { +-+ (*info->fprintf_func) (info->stream, "%s", name); +-+ return 1; +-+ } +-+ } +- } +- +- /* Check if the REX prefix is used. */ +-@@ -11637,7 +11667,7 @@ print_insn (bfd_vma pc, disassemble_info +- all_prefixes[last_data_prefix] = 0; +- +- prefix_length = 0; +-- for (i = 0; i < (int) ARRAY_SIZE (all_prefixes); i++) +-+ for (i = 0; !extension && i < (int) ARRAY_SIZE (all_prefixes); i++) +- if (all_prefixes[i]) +- { +- const char *name; +-@@ -11655,7 +11685,8 @@ print_insn (bfd_vma pc, disassemble_info +- return MAX_CODE_LENGTH; +- } +- +-- obufp = mnemonicendp; +-+ if (!extension) +-+ obufp = mnemonicendp; +- for (i = strlen (obuf) + prefix_length; i < 6; i++) +- oappend (" "); +- oappend (" "); +---- gdb-7.6/bfd/coff-i386.c.orig +-+++ gdb-7.6/bfd/coff-i386.c +-@@ -141,7 +141,7 @@ coff_i386_reloc (bfd *abfd, +- #define DOIT(x) \ +- x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) +- +-- if (diff != 0) +-+ if (diff != 0) +- { +- reloc_howto_type *howto = reloc_entry->howto; +- unsigned char *addr = (unsigned char *) data + reloc_entry->address; +---- gdb-7.6/bfd/coff-x86_64.c.orig +-+++ gdb-7.6/bfd/coff-x86_64.c +-@@ -139,7 +139,7 @@ coff_amd64_reloc (bfd *abfd, +- #define DOIT(x) \ +- x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) +- +-- if (diff != 0) +-+ if (diff != 0) +- { +- reloc_howto_type *howto = reloc_entry->howto; +- unsigned char *addr = (unsigned char *) data + reloc_entry->address; +---- gdb-7.6/opcodes/arm-dis.c.orig +-+++ gdb-7.6/opcodes/arm-dis.c +-@@ -2103,7 +2103,7 @@ print_insn_coprocessor (bfd_vma pc, +- +- /* Is ``imm'' a negative number? */ +- if (imm & 0x40) +-- imm |= (-1 << 7); +-+ imm -= 0x80; +- +- func (stream, "%d", imm); +- } +-diff -up gdb-7.6/bfd/elf64-ppc.c.orig gdb-7.6/bfd/elf64-ppc.c +---- gdb-7.6/bfd/elf64-ppc.c.orig 2016-02-02 11:04:25.436527347 -0500 +-+++ gdb-7.6/bfd/elf64-ppc.c 2016-02-02 11:11:51.926468454 -0500 +-@@ -11743,7 +11743,7 @@ ppc64_elf_size_stubs (struct bfd_link_in +- stub_sec = stub_sec->next) +- if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) +- stub_sec->size = ((stub_sec->size + (1 << htab->plt_stub_align) - 1) +-- & (-1 << htab->plt_stub_align)); +-+ & -(1 << htab->plt_stub_align)); +- +- for (stub_sec = htab->stub_bfd->sections; +- stub_sec != NULL; +-@@ -12093,7 +12093,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_ +- stub_sec = stub_sec->next) +- if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) +- stub_sec->size = ((stub_sec->size + (1 << htab->plt_stub_align) - 1) +-- & (-1 << htab->plt_stub_align)); +-+ & -(1 << htab->plt_stub_align)); +- +- for (stub_sec = htab->stub_bfd->sections; +- stub_sec != NULL; +---- gdb-7.6/include/opcode/ppc.h.orig +-+++ gdb-7.6/include/opcode/ppc.h +-@@ -278,7 +278,7 @@ extern const unsigned int num_powerpc_op +- /* Use with the shift field of a struct powerpc_operand to indicate +- that BITM and SHIFT cannot be used to determine where the operand +- goes in the insn. */ +--#define PPC_OPSHIFT_INV (-1 << 31) +-+#define PPC_OPSHIFT_INV (-1U << 31) +- +- /* Values defined for the flags field of a struct powerpc_operand. */ +- +---- gdb-7.6/opcodes/mips-dis.c.orig +-+++ gdb-7.6/opcodes/mips-dis.c +-@@ -245,18 +245,6 @@ static const char * const mips_cp0_names +- "c0_taglo", "c0_taghi", "c0_errorepc", "$31" +- }; +- +--static const struct mips_cp0sel_name mips_cp0sel_names_mipsr5900[] = +--{ +-- { 24, 2, "c0_iab" }, +-- { 24, 3, "c0_iabm" }, +-- { 24, 4, "c0_dab" }, +-- { 24, 5, "c0_dabm" }, +-- { 24, 6, "c0_dvb" }, +-- { 24, 7, "c0_dvbm" }, +-- { 25, 1, "c0_perfcnt,1" }, +-- { 25, 2, "c0_perfcnt,2" } +--}; +-- +- static const char * const mips_cp0_names_mips3264[32] = +- { +- "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1", +---- gdb-7.6/gdb/ada-lang.c.orig +-+++ gdb-7.6/gdb/ada-lang.c +-@@ -10503,7 +10503,7 @@ ada_evaluate_subexp (struct type *expect +- } +- else +- arg1 = ada_value_struct_elt (arg1, &exp->elts[pc + 2].string, 0); +-- arg1 = unwrap_value (arg1); +-+ arg1 = unwrap_value (arg1); +- return ada_to_fixed_value (arg1); +- +- case OP_TYPE: +---- gdb-7.6/gdb/linux-record.c.orig +-+++ gdb-7.6/gdb/linux-record.c +-@@ -112,7 +112,7 @@ record_linux_sockaddr (struct regcache * +- "memory at addr = 0x%s len = %d.\n", +- phex_nz (len, tdep->size_pointer), +- tdep->size_int); +-- return -1; +-+ return -1; +- } +- addrlen = (int) extract_unsigned_integer (a, tdep->size_int, byte_order); +- if (addrlen <= 0 || addrlen > tdep->size_sockaddr) +-@@ -150,7 +150,7 @@ record_linux_msghdr (struct regcache *re +- "len = %d.\n", +- phex_nz (addr, tdep->size_pointer), +- tdep->size_msghdr); +-- return -1; +-+ return -1; +- } +- +- /* msg_name msg_namelen */ +-@@ -186,7 +186,7 @@ record_linux_msghdr (struct regcache *re +- "len = %d.\n", +- phex_nz (addr,tdep->size_pointer), +- tdep->size_iovec); +-- return -1; +-+ return -1; +- } +- tmpaddr = (CORE_ADDR) extract_unsigned_integer (iov, +- tdep->size_pointer, +-@@ -948,7 +948,7 @@ Do you want to stop the program?"), +- "memory at addr = 0x%s len = %d.\n", +- OUTPUT_REG (tmpulongest, tdep->arg2), +- tdep->size_ulong); +-- return -1; +-+ return -1; +- } +- tmpulongest = extract_unsigned_integer (a, tdep->size_ulong, +- byte_order); +---- gdb-7.6/gdb/inflow.c.orig +-+++ gdb-7.6/gdb/inflow.c +-@@ -391,7 +391,7 @@ terminal_ours_1 (int output_only) +- if (tinfo->run_terminal != NULL || gdb_has_a_terminal () == 0) +- return; +- +-- { +-+ { +- #ifdef SIGTTOU +- /* Ignore this signal since it will happen when we try to set the +- pgrp. */ +---- gdb-7.6/gdb/printcmd.c.orig +-+++ gdb-7.6/gdb/printcmd.c +-@@ -1045,7 +1045,7 @@ print_command_2 (char *exp, int inspect, +- else +- val = access_value_history (0); +- +-- printf_filtered ("%d %d %d %d %d %d\n", +-+ printf_filtered ("%d %d %d %d %d %d\n", +- TYPE_CODE (check_typedef(value_type (val))), +- TYPE_UNSIGNED (check_typedef(value_type (val))), +- TYPE_LENGTH (check_typedef(value_type(val))), +---- gdb-7.6/gdb/c-typeprint.c.orig +-+++ gdb-7.6/gdb/c-typeprint.c +-@@ -1293,7 +1293,7 @@ c_type_print_base (struct type *type, st +- if (TYPE_NFIELDS (type) != 0 || TYPE_NFN_FIELDS (type) != 0) +- fprintf_filtered (stream, "\n"); +- +-- for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); i++) +-+ for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); i++) +- { +- struct type *target = TYPE_TYPEDEF_FIELD_TYPE (type, i); +- +---- gdb-7.6/gdb/symtab.c.orig +-+++ gdb-7.6/gdb/symtab.c +-@@ -5139,6 +5139,8 @@ static void get_user_print_option_addres +- extern int get_frame_offset(CORE_ADDR); +- static void gdb_set_crash_block(struct gnu_request *); +- void gdb_command_funnel(struct gnu_request *); +-+static long lookup_struct_contents(struct gnu_request *); +-+static void iterate_datatypes(struct gnu_request *); +- +- struct objfile *gdb_kernel_objfile = { 0 }; +- +-@@ -5242,6 +5244,14 @@ gdb_command_funnel(struct gnu_request *r +- req->flags |= GNU_COMMAND_FAILED; +- break; +- +-+ case GNU_LOOKUP_STRUCT_CONTENTS: +-+ req->value = lookup_struct_contents(req); +-+ break; +-+ +-+ case GNU_GET_NEXT_DATATYPE: +-+ iterate_datatypes(req); +-+ break; +-+ +- default: +- req->flags |= GNU_COMMAND_FAILED; +- break; +-@@ -5779,4 +5789,135 @@ gdb_get_crash_block(void) +- else +- return NULL; +- } +-+ +-+static long +-+lookup_struct_contents(struct gnu_request *req) +-+{ +-+ int i; +-+ long r; +-+ struct field *f; +-+ struct main_type *m; +-+ const char *n; +-+ struct main_type *top_m = (struct main_type *)req->addr; +-+ char *type_name = req->type_name; +-+ +-+ if (!top_m || !type_name) +-+ return 0; +-+ +-+ for (i = 0; i < top_m->nfields; i++) +-+ { +-+ f = top_m->flds_bnds.fields + i; +-+ if (!f->type) +-+ continue; +-+ m = f->type->main_type; +-+ +-+ // If the field is an array, check the target type - +-+ // it might be structure, or might not be. +-+ // - struct request_sock *syn_table[0]; +-+ // here m->target_type->main_type->code is expected +-+ // to be TYPE_CODE_PTR +-+ // - struct list_head vec[TVN_SIZE]; +-+ // here m->target_type->main_type->code should be +-+ // TYPE_CODE_STRUCT +-+ if (m->code == TYPE_CODE_ARRAY && m->target_type) +-+ m = m->target_type->main_type; +-+ +-+ /* Here is a recursion. +-+ * If we have struct variable (not pointer), +-+ * scan this inner structure +-+ */ +-+ if (m->code == TYPE_CODE_STRUCT) { +-+ req->addr = (ulong)m; +-+ r = lookup_struct_contents(req); +-+ req->addr = (ulong)top_m; +-+ if (r) +-+ return 1; +-+ } +-+ +-+ if (m->code == TYPE_CODE_PTR && m->target_type) +-+ m = m->target_type->main_type; +-+ if (m->name) +-+ n = m->name; +-+ else if (m->tag_name) +-+ n = m->tag_name; +-+ else +-+ continue; +-+ +-+ if (strstr(n, type_name)) +-+ return 1; +-+ } +-+ +-+ return 0; +-+} +-+ +-+static void +-+iterate_datatypes (struct gnu_request *req) +-+{ +-+ static struct block_iterator bi; // Keeping this static will simplify code +-+ struct block *b; +-+ int do_return = 0; +-+ struct global_iterator *gi = &req->global_iterator; +-+ +-+ if (gi->finished) +-+ return; +-+ +-+ if (gi->obj == NULL) +-+ { +-+ gi->obj = current_program_space->objfiles; +-+ gi->symtab = NULL; +-+ do_return = 1; // The initial case - we don't need to make next step. +-+ } +-+ +-+ for (; gi->obj; gi->obj = gi->obj->next, gi->symtab = NULL) +-+ { +-+ if (gi->symtab == NULL) +-+ { +-+ // Symtab `symtab` is nullified for every objfile +-+ if (gi->obj->sf) +-+ gi->obj->sf->qf->expand_all_symtabs(gi->obj); +-+ gi->symtab = gi->obj->symtabs; +-+ gi->sym = NULL; +-+ } +-+ +-+ for (; gi->symtab; gi->symtab = gi->symtab->next, gi->block_index = -1) +-+ { +-+ if (!gi->symtab->primary) +-+ continue; +-+ +-+ if (gi->block_index == -1) +-+ { +-+ gi->block_index = GLOBAL_BLOCK; +-+ gi->sym = NULL; +-+ } +-+ for (; gi->block_index <= STATIC_BLOCK; gi->block_index++, gi->sym = NULL) +-+ { +-+ if (!gi->sym) +-+ { +-+ b = BLOCKVECTOR_BLOCK(BLOCKVECTOR(gi->symtab), gi->block_index); +-+ gi->sym = block_iterator_first(b, &bi); +-+ } +-+ for (; gi->sym; gi->sym = block_iterator_next(&bi)) +-+ { +-+ QUIT; +-+ +-+ if (SYMBOL_CLASS (gi->sym) != LOC_TYPEDEF) +-+ continue; +-+ +-+ // Iteration 1 (do_return == 0): initialization +-+ // Iteration 2 (do_return == 1): iterate symbol +-+ if (do_return++ == 0) +-+ continue; +-+ +-+ // Yield the current symbol and its size +-+ req->addr = (ulong)(gi->sym->type->main_type); +-+ req->name = (char *)(gi->sym->ginfo.name); +-+ req->length = gi->sym->type->length; +-+ +-+ return; +-+ } +-+ } +-+ } +-+ } +-+ gi->finished = 1; +-+} +- #endif +---- gdb-7.6/bfd/elf64-s390.c.orig +-+++ gdb-7.6/bfd/elf64-s390.c +-@@ -323,10 +323,10 @@ elf_s390_reloc_name_lookup (bfd *abfd AT +- && strcasecmp (elf_howto_table[i].name, r_name) == 0) +- return &elf_howto_table[i]; +- +-- if (strcasecmp (elf64_s390_vtinherit_howto.name, r_name) == 0) +-- return &elf64_s390_vtinherit_howto; +-- if (strcasecmp (elf64_s390_vtentry_howto.name, r_name) == 0) +-- return &elf64_s390_vtentry_howto; +-+ if (strcasecmp (elf64_s390_vtinherit_howto.name, r_name) == 0) +-+ return &elf64_s390_vtinherit_howto; +-+ if (strcasecmp (elf64_s390_vtentry_howto.name, r_name) == 0) +-+ return &elf64_s390_vtentry_howto; +- +- return NULL; +- } +---- gdb-7.6/gdb/symtab.c.orig +-+++ gdb-7.6/gdb/symtab.c +-@@ -5122,7 +5122,7 @@ When enabled, debugging messages are pri +- #define GDB_COMMON +- #include "../../defs.h" +- +--static void get_member_data(struct gnu_request *, struct type *); +-+static void get_member_data(struct gnu_request *, struct type *, long, int); +- static void dump_enum(struct type *, struct gnu_request *); +- static void eval_enum(struct type *, struct gnu_request *); +- static void gdb_get_line_number(struct gnu_request *); +-@@ -5327,7 +5327,7 @@ gdb_get_datatype(struct gnu_request *req +- req->typecode = TYPE_CODE(sym->type); +- req->length = TYPE_LENGTH(sym->type); +- if (req->member) +-- get_member_data(req, sym->type); +-+ get_member_data(req, sym->type, 0, 1); +- +- if (TYPE_CODE(sym->type) == TYPE_CODE_ENUM) { +- if (req->flags & GNU_PRINT_ENUMERATORS) +-@@ -5397,7 +5397,7 @@ gdb_get_datatype(struct gnu_request *req +- } +- +- if (req->member) +-- get_member_data(req, type); +-+ get_member_data(req, type, 0, 1); +- +- break; +- +-@@ -5480,7 +5480,7 @@ eval_enum(struct type *type, struct gnu_ +- * member field, and when found, return its relevant data. +- */ +- static void +--get_member_data(struct gnu_request *req, struct type *type) +-+get_member_data(struct gnu_request *req, struct type *type, long offset, int is_first) +- { +- register short i; +- struct field *nextfield; +-@@ -5492,7 +5492,7 @@ get_member_data(struct gnu_request *req, +- nfields = TYPE_MAIN_TYPE(type)->nfields; +- nextfield = TYPE_MAIN_TYPE(type)->flds_bnds.fields; +- +-- if (nfields == 0) { +-+ if (nfields == 0 && is_first /* The first call */) { +- struct type *newtype; +- newtype = lookup_transparent_type(req->name); +- if (newtype) { +-@@ -5505,13 +5505,18 @@ get_member_data(struct gnu_request *req, +- +- for (i = 0; i < nfields; i++) { +- if (STREQ(req->member, nextfield->name)) { +-- req->member_offset = nextfield->loc.bitpos; +-+ req->member_offset = offset + nextfield->loc.bitpos; +- req->member_length = TYPE_LENGTH(nextfield->type); +- req->member_typecode = TYPE_CODE(nextfield->type); +- if ((req->member_typecode == TYPE_CODE_TYPEDEF) && +- (typedef_type = check_typedef(nextfield->type))) +- req->member_length = TYPE_LENGTH(typedef_type); +- return; +-+ } else if (*nextfield->name == 0) { /* Anonymous struct/union */ +-+ get_member_data(req, nextfield->type, +-+ offset + nextfield->loc.bitpos, 0); +-+ if (req->member_offset != -1) +-+ return; +- } +- nextfield++; +- } +-@@ -5706,7 +5711,7 @@ gdb_get_symbol_type(struct gnu_request * +- } +- +- if (req->member) +-- get_member_data(req, type); +-+ get_member_data(req, type, 0, 1); +- +- do_cleanups (old_chain); +- } +-diff -up gdb-7.6/bfd/configure.orig gdb-7.6/bfd/configure +---- gdb-7.6/bfd/configure.orig 2017-02-17 17:19:51.654898822 -0500 +-+++ gdb-7.6/bfd/configure 2017-02-17 17:19:57.922038757 -0500 +-@@ -12193,7 +12193,7 @@ fi +- +- NO_WERROR= +- if test "${ERROR_ON_WARNING}" = yes ; then +-- GCC_WARN_CFLAGS="$GCC_WARN_CFLAGS -Werror" +-+ GCC_WARN_CFLAGS="$GCC_WARN_CFLAGS" +- NO_WERROR="-Wno-error" +- fi +- +-diff -up gdb-7.6/opcodes/configure.orig gdb-7.6/opcodes/configure +---- gdb-7.6/opcodes/configure.orig 2017-02-17 17:19:08.849943016 -0500 +-+++ gdb-7.6/opcodes/configure 2017-02-17 17:19:23.256264699 -0500 +-@@ -11539,7 +11539,7 @@ fi +- +- NO_WERROR= +- if test "${ERROR_ON_WARNING}" = yes ; then +-- GCC_WARN_CFLAGS="$GCC_WARN_CFLAGS -Werror" +-+ GCC_WARN_CFLAGS="$GCC_WARN_CFLAGS" +- NO_WERROR="-Wno-error" +- fi +- +---- gdb-7.6/gdb/symtab.c.orig +-+++ gdb-7.6/gdb/symtab.c +-@@ -5266,6 +5266,7 @@ gdb_get_line_number(struct gnu_request * +- { +- struct symtab_and_line sal; +- struct symbol *sym; +-+ struct objfile *objfile; +- CORE_ADDR pc; +- +- #define LASTCHAR(s) (s[strlen(s)-1]) +-@@ -5281,8 +5282,22 @@ gdb_get_line_number(struct gnu_request * +- sal = find_pc_line(pc, 0); +- +- if (!sal.symtab) { +-- req->buf[0] = '\0'; +-- return; +-+ /* +-+ * If a module address line number can't be found, it's typically +-+ * due to its addrmap still containing offset values because its +-+ * objfile doesn't have full symbols loaded. +-+ */ +-+ if (req->lm) { +-+ objfile = req->lm->loaded_objfile; +-+ if (!objfile_has_full_symbols(objfile) && objfile->sf) { +-+ objfile->sf->qf->expand_all_symtabs(objfile); +-+ sal = find_pc_line(pc, 0); +-+ } +-+ } +-+ if (!sal.symtab) { +-+ req->buf[0] = '\0'; +-+ return; +-+ } +- } +- +- if (sal.symtab->filename && sal.symtab->dirname) { +-@@ -5557,7 +5572,6 @@ struct load_module *gdb_current_load_mod +- static void +- gdb_add_symbol_file(struct gnu_request *req) +- { +-- register struct objfile *loaded_objfile = NULL; +- register struct objfile *objfile; +- register struct minimal_symbol *m; +- struct load_module *lm; +-@@ -5576,6 +5590,7 @@ gdb_add_symbol_file(struct gnu_request * +- +- req->name = lm->mod_namelist; +- gdb_delete_symbol_file(req); +-+ lm->loaded_objfile = NULL; +- +- if ((lm->mod_flags & MOD_NOPATCH) == 0) { +- for (i = 0 ; i < lm->mod_sections; i++) { +-@@ -5623,12 +5638,15 @@ gdb_add_symbol_file(struct gnu_request * +- +- ALL_OBJFILES(objfile) { +- if (same_file(objfile->name, lm->mod_namelist)) { +-- loaded_objfile = objfile; +-+ if (objfile->separate_debug_objfile) +-+ lm->loaded_objfile = objfile->separate_debug_objfile; +-+ else +-+ lm->loaded_objfile = objfile; +- break; +- } +- } +- +-- if (!loaded_objfile) +-+ if (!lm->loaded_objfile) +- req->flags |= GNU_COMMAND_FAILED; +- } +- +---- gdb-7.6/gdb/symtab.c.orig +-+++ gdb-7.6/gdb/symtab.c +-@@ -5500,7 +5500,7 @@ get_member_data(struct gnu_request *req, +- register short i; +- struct field *nextfield; +- short nfields; +-- struct type *typedef_type; +-+ struct type *typedef_type, *target_type; +- +- req->member_offset = -1; +- +-@@ -5523,6 +5523,13 @@ get_member_data(struct gnu_request *req, +- req->member_offset = offset + nextfield->loc.bitpos; +- req->member_length = TYPE_LENGTH(nextfield->type); +- req->member_typecode = TYPE_CODE(nextfield->type); +-+ req->member_main_type_name = (char *)TYPE_NAME(nextfield->type); +-+ req->member_main_type_tag_name = (char *)TYPE_TAG_NAME(nextfield->type); +-+ target_type = TYPE_TARGET_TYPE(nextfield->type); +-+ if (target_type) { +-+ req->member_target_type_name = (char *)TYPE_NAME(target_type); +-+ req->member_target_type_tag_name = (char *)TYPE_TAG_NAME(target_type); +-+ } +- if ((req->member_typecode == TYPE_CODE_TYPEDEF) && +- (typedef_type = check_typedef(nextfield->type))) +- req->member_length = TYPE_LENGTH(typedef_type); +- +---- gdb-7.6/gdb/symtab.c.orig +-+++ gdb-7.6/gdb/symtab.c +-@@ -5727,6 +5727,7 @@ gdb_get_symbol_type(struct gnu_request * +- req->type_name = (char *)TYPE_MAIN_TYPE(type)->name; +- req->typecode = TYPE_MAIN_TYPE(type)->code; +- req->length = type->length; +-+ req->type_tag_name = (char *)TYPE_TAG_NAME(type); +- target_type = TYPE_MAIN_TYPE(type)->target_type; +- +- if (target_type) { +---- gdb-7.6/gdb/common/linux-ptrace.c.orig +-+++ gdb-7.6/gdb/common/linux-ptrace.c +-@@ -108,14 +108,14 @@ linux_ptrace_test_ret_to_nx (void) +- ".globl linux_ptrace_test_ret_to_nx_instr;" +- "linux_ptrace_test_ret_to_nx_instr:" +- "ret" +-- : : "r" (return_address) : "%esp", "memory"); +-+ : : "r" (return_address) : "memory"); +- #elif defined __x86_64__ +- asm volatile ("pushq %0;" +- ".globl linux_ptrace_test_ret_to_nx_instr;" +- "linux_ptrace_test_ret_to_nx_instr:" +- "ret" +- : : "r" ((uint64_t) (uintptr_t) return_address) +-- : "%rsp", "memory"); +-+ : "memory"); +- #else +- # error "!__i386__ && !__x86_64__" +- #endif +---- gdb-7.6/gdb/features/aarch64.c.orig +-+++ gdb-7.6/gdb/features/aarch64.c +-@@ -5,7 +5,6 @@ +- #include "osabi.h" +- #include "target-descriptions.h" +- +--struct target_desc *tdesc_aarch64; +- static void +- initialize_tdesc_aarch64 (void) +- { +---- gdb-7.6/gdb/aarch64-linux-nat.c.orig +-+++ gdb-7.6/gdb/aarch64-linux-nat.c +-@@ -37,6 +37,7 @@ +- +- #include "gregset.h" +- +-+extern struct target_desc *tdesc_aarch64; +- #include "features/aarch64.c" +- +- /* Defines ps_err_e, struct ps_prochandle. */ +---- gdb-7.6/gdb/aarch64-tdep.c.orig +-+++ gdb-7.6/gdb/aarch64-tdep.c +-@@ -52,6 +52,7 @@ +- #include "gdb_assert.h" +- #include "vec.h" +- +-+struct target_desc *tdesc_aarch64; +- #include "features/aarch64.c" +- #include "features/aarch64-without-fpu.c" +- +---- gdb-7.6/gdb/symtab.c.orig +-+++ gdb-7.6/gdb/symtab.c +-@@ -2080,7 +2080,7 @@ find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section) +- struct symtab *s = NULL; +- struct symtab *best_s = NULL; +- struct objfile *objfile; +-- CORE_ADDR distance = 0; +-+ CORE_ADDR distance = 0, start, end; +- struct minimal_symbol *msymbol; +- +- /* If we know that this is not a text address, return failure. This is +-@@ -2117,10 +2117,20 @@ find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section) +- bv = BLOCKVECTOR (s); +- b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); +- +-- if (BLOCK_START (b) <= pc +-- && BLOCK_END (b) > pc +-- && (distance == 0 +-- || BLOCK_END (b) - BLOCK_START (b) < distance)) +-+ start = BLOCK_START (b); +-+ end = BLOCK_END (b); +-+ +-+ /* +-+ * If we have an addrmap mapping code addresses to blocks, and pc +-+ * is in the range [start, end), let's use it. +-+ */ +-+ if ((pc >= start && pc < end) && BLOCKVECTOR_MAP (bv)) { +-+ if (addrmap_find (BLOCKVECTOR_MAP (bv), pc)) +-+ return s; +-+ } +-+ +-+ if ((pc >= start && pc < end) && ((distance == 0) +-+ || (end - start < distance))) +- { +- /* For an objfile that has its functions reordered, +- find_pc_psymtab will find the proper partial symbol table +---- gdb-7.6/gdb/mips-tdep.c.orig +-+++ gdb-7.6/gdb/mips-tdep.c +-@@ -3261,6 +3261,16 @@ restart: +- /* Irix 6.2 N32 ABI uses sd instructions for saving $gp and $ra. */ +- set_reg_offset (gdbarch, this_cache, reg, sp + low_word); +- } +-+ else if (((inst & 0xFFE08020) == 0xeba00020) /* gssq reg,reg,offset($sp) */ +-+ && regsize_is_64_bits) +-+ { +-+ reg = (inst >> 16) & 0x1F; +-+ low_word = ((((inst >> 6) & 0x1FF) ^ 0x100) - 0x100) << 4; +-+ set_reg_offset (gdbarch, this_cache, reg, sp + low_word); +-+ reg = inst & 0x1F; +-+ low_word = (((((inst >> 6) & 0x1FF) ^ 0x100) - 0x100) << 4) + 8; +-+ set_reg_offset (gdbarch, this_cache, reg, sp + low_word); +-+ } +- else if (high_word == 0x27be) /* addiu $30,$sp,size */ +- { +- /* Old gcc frame, r30 is virtual frame pointer. */ +diff -Nur crash-7.3.0-orig/gdb-7.6-ppc64le-support.patch crash-7.3.0/gdb-7.6-ppc64le-support.patch +--- crash-7.3.0-orig/gdb-7.6-ppc64le-support.patch 2023-07-07 14:06:14.165365910 +0800 ++++ crash-7.3.0/gdb-7.6-ppc64le-support.patch 1970-01-01 08:00:00.000000000 +0800 +@@ -1,4950 +0,0 @@ +- +-# +-# gdb-7.6-ppc64_sysv_abi_push_float.patch +-# +- +-From: Tiago Daitx +-Date: Mon Apr 1 04:05:35 2013 +0000 +-Git-commit: d81e75c0756f21d2c3d45ce86d8b45c65f01ef67 +-References: ppc64le enablement +- +-gdb/ChangeLog +-2013-03-01 Tiago Stürmer Daitx +- +- * ppc-sysv-tdep.c (ppc64_sysv_abi_push_float): New function. +- (ppc64_sysv_abi_push_dummy_call): Handle complex arguments. +- +-Acked-by: Petr Tesarik +- +---- +- gdb/ChangeLog | 5 + +- gdb/ppc-sysv-tdep.c | 196 +++++++++++++++++++++++++++++++++------------------- +- 2 files changed, 131 insertions(+), 70 deletions(-) +- +---- a/gdb/ChangeLog +-+++ b/gdb/ChangeLog +-@@ -1,3 +1,8 @@ +-+2013-03-31 Tiago Stürmer Daitx +-+ +-+ * ppc-sysv-tdep.c (ppc64_sysv_abi_push_float): New function. +-+ (ppc64_sysv_abi_push_dummy_call): Handle complex arguments. +-+ +- 2013-04-26 Joel Brobecker +- +- * NEWS: Change "since GDB 7.5" into "in GDB 7.6". +---- a/gdb/ppc-sysv-tdep.c +-+++ b/gdb/ppc-sysv-tdep.c +-@@ -1101,6 +1101,83 @@ convert_code_addr_to_desc_addr (CORE_ADD +- return 1; +- } +- +-+/* Push a float in either registers, or in the stack. Using the ppc 64 bit +-+ SysV ABI. +-+ +-+ This implements a dumbed down version of the ABI. It always writes +-+ values to memory, GPR and FPR, even when not necessary. Doing this +-+ greatly simplifies the logic. */ +-+ +-+static void +-+ppc64_sysv_abi_push_float (struct gdbarch *gdbarch, struct regcache *regcache, +-+ struct gdbarch_tdep *tdep, struct type *type, +-+ const bfd_byte *val, int freg, int greg, +-+ CORE_ADDR gparam) +-+{ +-+ gdb_byte regval[MAX_REGISTER_SIZE]; +-+ const gdb_byte *p; +-+ +-+ if (TYPE_LENGTH (type) <= 8) +-+ { +-+ /* Version 1.7 of the 64-bit PowerPC ELF ABI says: +-+ +-+ "Single precision floating point values are mapped to +-+ the first word in a single doubleword." +-+ +-+ And version 1.9 says: +-+ +-+ "Single precision floating point values are mapped to +-+ the second word in a single doubleword." +-+ +-+ GDB then writes single precision floating point values +-+ at both words in a doubleword, to support both ABIs. */ +-+ if (TYPE_LENGTH (type) == 4) +-+ { +-+ memcpy (regval, val, 4); +-+ memcpy (regval + 4, val, 4); +-+ p = regval; +-+ } +-+ else +-+ p = val; +-+ +-+ /* Write value in the stack's parameter save area. */ +-+ write_memory (gparam, p, 8); +-+ +-+ /* Floats and Doubles go in f1 .. f13. They also consume a left aligned +-+ GREG, and can end up in memory. */ +-+ if (freg <= 13) +-+ { +-+ struct type *regtype; +-+ +-+ regtype = register_type (gdbarch, tdep->ppc_fp0_regnum + freg); +-+ convert_typed_floating (val, type, regval, regtype); +-+ regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg, regval); +-+ } +-+ if (greg <= 10) +-+ regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, regval); +-+ } +-+ else +-+ { +-+ /* IBM long double stored in two doublewords of the +-+ parameter save area and corresponding registers. */ +-+ if (!tdep->soft_float && freg <= 13) +-+ { +-+ regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg, val); +-+ if (freg <= 12) +-+ regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg + 1, +-+ val + 8); +-+ } +-+ if (greg <= 10) +-+ { +-+ regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, val); +-+ if (greg <= 9) +-+ regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg + 1, +-+ val + 8); +-+ } +-+ write_memory (gparam, val, TYPE_LENGTH (type)); +-+ } +-+} +-+ +- /* Pass the arguments in either registers, or in the stack. Using the +- ppc 64 bit SysV ABI. +- +-@@ -1218,53 +1295,9 @@ ppc64_sysv_abi_push_dummy_call (struct g +- +- if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) <= 8) +- { +-- /* Floats and Doubles go in f1 .. f13. They also +-- consume a left aligned GREG,, and can end up in +-- memory. */ +- if (write_pass) +-- { +-- gdb_byte regval[MAX_REGISTER_SIZE]; +-- const gdb_byte *p; +-- +-- /* Version 1.7 of the 64-bit PowerPC ELF ABI says: +-- +-- "Single precision floating point values are mapped to +-- the first word in a single doubleword." +-- +-- And version 1.9 says: +-- +-- "Single precision floating point values are mapped to +-- the second word in a single doubleword." +-- +-- GDB then writes single precision floating point values +-- at both words in a doubleword, to support both ABIs. */ +-- if (TYPE_LENGTH (type) == 4) +-- { +-- memcpy (regval, val, 4); +-- memcpy (regval + 4, val, 4); +-- p = regval; +-- } +-- else +-- p = val; +-- +-- /* Write value in the stack's parameter save area. */ +-- write_memory (gparam, p, 8); +-- +-- if (freg <= 13) +-- { +-- struct type *regtype +-- = register_type (gdbarch, tdep->ppc_fp0_regnum); +-- +-- convert_typed_floating (val, type, regval, regtype); +-- regcache_cooked_write (regcache, +-- tdep->ppc_fp0_regnum + freg, +-- regval); +-- } +-- if (greg <= 10) +-- regcache_cooked_write (regcache, +-- tdep->ppc_gp0_regnum + greg, +-- regval); +-- } +-+ ppc64_sysv_abi_push_float (gdbarch, regcache, tdep, type, +-+ val, freg, greg, gparam); +- +- freg++; +- greg++; +-@@ -1276,35 +1309,58 @@ ppc64_sysv_abi_push_dummy_call (struct g +- && (gdbarch_long_double_format (gdbarch) +- == floatformats_ibm_long_double)) +- { +-- /* IBM long double stored in two doublewords of the +-- parameter save area and corresponding registers. */ +- if (write_pass) +-+ ppc64_sysv_abi_push_float (gdbarch, regcache, tdep, type, +-+ val, freg, greg, gparam); +-+ freg += 2; +-+ greg += 2; +-+ gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize); +-+ } +-+ else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX +-+ && (TYPE_LENGTH (type) == 8 || TYPE_LENGTH (type) == 16)) +-+ { +-+ int i; +-+ +-+ for (i = 0; i < 2; i++) +- { +-- if (!tdep->soft_float && freg <= 13) +-- { +-- regcache_cooked_write (regcache, +-- tdep->ppc_fp0_regnum + freg, +-- val); +-- if (freg <= 12) +-- regcache_cooked_write (regcache, +-- tdep->ppc_fp0_regnum + freg + 1, +-- val + 8); +-- } +-- if (greg <= 10) +-+ if (write_pass) +- { +-- regcache_cooked_write (regcache, +-- tdep->ppc_gp0_regnum + greg, +-- val); +-- if (greg <= 9) +-- regcache_cooked_write (regcache, +-- tdep->ppc_gp0_regnum + greg + 1, +-- val + 8); +-+ struct type *target_type; +-+ +-+ target_type = check_typedef (TYPE_TARGET_TYPE (type)); +-+ ppc64_sysv_abi_push_float (gdbarch, regcache, tdep, +-+ target_type, val + i * +-+ TYPE_LENGTH (target_type), +-+ freg, greg, gparam); +- } +-- write_memory (gparam, val, TYPE_LENGTH (type)); +-+ freg++; +-+ greg++; +-+ /* Always consume parameter stack space. */ +-+ gparam = align_up (gparam + 8, tdep->wordsize); +-+ } +-+ } +-+ else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX +-+ && TYPE_LENGTH (type) == 32 +-+ && (gdbarch_long_double_format (gdbarch) +-+ == floatformats_ibm_long_double)) +-+ { +-+ int i; +-+ +-+ for (i = 0; i < 2; i++) +-+ { +-+ struct type *target_type; +-+ +-+ target_type = check_typedef (TYPE_TARGET_TYPE (type)); +-+ if (write_pass) +-+ ppc64_sysv_abi_push_float (gdbarch, regcache, tdep, +-+ target_type, val + i * +-+ TYPE_LENGTH (target_type), +-+ freg, greg, gparam); +-+ freg += 2; +-+ greg += 2; +-+ gparam = align_up (gparam + TYPE_LENGTH (target_type), +-+ tdep->wordsize); +- } +-- freg += 2; +-- greg += 2; +-- gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize); +- } +- else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT +- && TYPE_LENGTH (type) <= 8) +- +- +- +-# +-# gdb-7.6-bound_minimal_symbol.patch +-# +- +-From: Tom Tromey +-Date: Mon Apr 8 19:59:09 2013 +0000 +-Git-commit: 7cbd4a934e9cf3808e1199c62e65b4c25b24b4e5 +-References: ppc64le enablement +- +- * minsyms.h (struct bound_minimal_symbol): New. +- (lookup_minimal_symbol_and_objfile): Return bound_minimal_symbol. +- Remove objfile argument. +- (lookup_minimal_symbol_by_pc_section, lookup_minimal_symbol_by_pc): +- Return bound_minimal_symbol. +- * minsyms.c (lookup_minimal_symbol_by_pc_1) +- (lookup_minimal_symbol_by_pc_section, lookup_minimal_symbol_by_pc): +- Return bound_minimal_symbol. +- (in_gnu_ifunc_stub): Update. +- (lookup_minimal_symbol_and_objfile): Return bound_minimal_symbol. +- Remove 'objfile_p' argument. +- (lookup_solib_trampoline_symbol_by_pc): Update. +- * ada-tasks.c, amd64-windows-tdep.c, arm-tdep.c, +- arm-wince-tdep.c, block.c, blockframe.c, breakpoint.c, btrace.c, +- c-valprint.c, dwarf2loc.c, elfread.c, frame.c, frv-tdep.c, +- glibc-tdep.c, gnu-v2-abi.c, gnu-v3-abi.c, hppa-hpux-tdep.c, +- i386-tdep.c, ia64-tdep.c, infcall.c, infcmd.c, jit.c, +- linux-fork.c, m32c-tdep.c, m68hc11-tdep.c, maint.c, +- mips-tdep.c, p-valprint.c, parse.c, ppc-linux-tdep.c, +- ppc-sysv-tdep.c, printcmd.c, rs6000-tdep.c, sh64-tdep.c, +- stack.c, symtab.c, tui/tui-disasm.c: Update. +- +-Acked-by: Petr Tesarik +- +---- +- gdb/ChangeLog | 24 +++++++++++++++++++ +- gdb/ada-tasks.c | 6 ++-- +- gdb/amd64-windows-tdep.c | 12 +++++---- +- gdb/arm-tdep.c | 23 +++++++++--------- +- gdb/arm-wince-tdep.c | 14 +++++------ +- gdb/block.c | 5 ++-- +- gdb/blockframe.c | 8 +++--- +- gdb/breakpoint.c | 6 ++-- +- gdb/btrace.c | 8 +++--- +- gdb/c-valprint.c | 14 +++++------ +- gdb/coff-pe-read.c | 19 ++++++--------- +- gdb/dwarf2loc.c | 51 ++++++++++++++++++++++++------------------ +- gdb/elfread.c | 10 ++++---- +- gdb/frame.c | 2 - +- gdb/frv-tdep.c | 8 +++--- +- gdb/glibc-tdep.c | 11 ++++----- +- gdb/gnu-v2-abi.c | 6 ++-- +- gdb/gnu-v3-abi.c | 4 +-- +- gdb/hppa-hpux-tdep.c | 37 +++++++++++++++++------------- +- gdb/i386-tdep.c | 10 ++++---- +- gdb/ia64-tdep.c | 4 +-- +- gdb/infcall.c | 6 ++-- +- gdb/infcmd.c | 6 ++-- +- gdb/jit.c | 18 ++++++++------ +- gdb/linux-fork.c | 6 ++-- +- gdb/m32c-tdep.c | 15 ++++++------ +- gdb/m68hc11-tdep.c | 8 +++--- +- gdb/maint.c | 10 ++++---- +- gdb/minsyms.c | 57 ++++++++++++++++++++++++++++++++--------------- +- gdb/minsyms.h | 32 ++++++++++++++++++-------- +- gdb/mips-tdep.c | 48 +++++++++++++++++++-------------------- +- gdb/p-valprint.c | 13 +++++----- +- gdb/parse.c | 7 +++-- +- gdb/ppc-linux-tdep.c | 9 ++++--- +- gdb/ppc-sysv-tdep.c | 7 +++-- +- gdb/printcmd.c | 5 ++-- +- gdb/rs6000-tdep.c | 16 ++++++------- +- gdb/sh64-tdep.c | 6 ++-- +- gdb/stack.c | 28 ++++++++++++----------- +- gdb/symtab.c | 23 +++++++++--------- +- gdb/tui/tui-disasm.c | 2 - +- 41 files changed, 345 insertions(+), 259 deletions(-) +- +---- a/gdb/ChangeLog +-+++ b/gdb/ChangeLog +-@@ -1,3 +1,27 @@ +-+2013-04-08 Tom Tromey +-+ +-+ * minsyms.h (struct bound_minimal_symbol): New. +-+ (lookup_minimal_symbol_and_objfile): Return bound_minimal_symbol. +-+ Remove objfile argument. +-+ (lookup_minimal_symbol_by_pc_section, lookup_minimal_symbol_by_pc): +-+ Return bound_minimal_symbol. +-+ * minsyms.c (lookup_minimal_symbol_by_pc_1) +-+ (lookup_minimal_symbol_by_pc_section, lookup_minimal_symbol_by_pc): +-+ Return bound_minimal_symbol. +-+ (in_gnu_ifunc_stub): Update. +-+ (lookup_minimal_symbol_and_objfile): Return bound_minimal_symbol. +-+ Remove 'objfile_p' argument. +-+ (lookup_solib_trampoline_symbol_by_pc): Update. +-+ * ada-tasks.c, amd64-windows-tdep.c, arm-tdep.c, +-+ arm-wince-tdep.c, block.c, blockframe.c, breakpoint.c, btrace.c, +-+ c-valprint.c, dwarf2loc.c, elfread.c, frame.c, frv-tdep.c, +-+ glibc-tdep.c, gnu-v2-abi.c, gnu-v3-abi.c, hppa-hpux-tdep.c, +-+ i386-tdep.c, ia64-tdep.c, infcall.c, infcmd.c, jit.c, +-+ linux-fork.c, m32c-tdep.c, m68hc11-tdep.c, maint.c, +-+ mips-tdep.c, p-valprint.c, parse.c, ppc-linux-tdep.c, +-+ ppc-sysv-tdep.c, printcmd.c, rs6000-tdep.c, sh64-tdep.c, +-+ stack.c, symtab.c, tui/tui-disasm.c: Update. +-+ +- 2013-03-31 Tiago Stürmer Daitx +- +- * ppc-sysv-tdep.c (ppc64_sysv_abi_push_float): New function. +---- a/gdb/ada-tasks.c +-+++ b/gdb/ada-tasks.c +-@@ -635,12 +635,12 @@ read_atcb (CORE_ADDR task_id, struct ada +- sizeof (task_info->name) - 1); +- else +- { +-- struct minimal_symbol *msym; +-+ struct bound_minimal_symbol msym; +- +- msym = lookup_minimal_symbol_by_pc (task_id); +-- if (msym) +-+ if (msym.minsym) +- { +-- const char *full_name = SYMBOL_LINKAGE_NAME (msym); +-+ const char *full_name = SYMBOL_LINKAGE_NAME (msym.minsym); +- const char *task_name = full_name; +- const char *p; +- +---- a/gdb/amd64-windows-tdep.c +-+++ b/gdb/amd64-windows-tdep.c +-@@ -140,14 +140,14 @@ amd64_skip_main_prologue (struct gdbarch +- +- if (target_read_memory (pc + 1, buf, sizeof buf) == 0) +- { +-- struct minimal_symbol *s; +-+ struct bound_minimal_symbol s; +- CORE_ADDR call_dest; +- +- call_dest = pc + 5 + extract_signed_integer (buf, 4, byte_order); +- s = lookup_minimal_symbol_by_pc (call_dest); +-- if (s != NULL +-- && SYMBOL_LINKAGE_NAME (s) != NULL +-- && strcmp (SYMBOL_LINKAGE_NAME (s), "__main") == 0) +-+ if (s.minsym != NULL +-+ && SYMBOL_LINKAGE_NAME (s.minsym) != NULL +-+ && strcmp (SYMBOL_LINKAGE_NAME (s.minsym), "__main") == 0) +- pc += 5; +- } +- } +-@@ -175,7 +175,9 @@ amd64_windows_skip_trampoline_code (stru +- CORE_ADDR indirect_addr = pc + offset + 6; +- +- struct minimal_symbol *indsym +-- = indirect_addr ? lookup_minimal_symbol_by_pc (indirect_addr) : NULL; +-+ = (indirect_addr +-+ ? lookup_minimal_symbol_by_pc (indirect_addr).minsym +-+ : NULL); +- const char *symname = indsym ? SYMBOL_LINKAGE_NAME (indsym) : NULL; +- +- if (symname) +---- a/gdb/arm-tdep.c +-+++ b/gdb/arm-tdep.c +-@@ -381,7 +381,7 @@ arm_find_mapping_symbol (CORE_ADDR memad +- int +- arm_pc_is_thumb (struct gdbarch *gdbarch, CORE_ADDR memaddr) +- { +-- struct minimal_symbol *sym; +-+ struct bound_minimal_symbol sym; +- char type; +- struct displaced_step_closure* dsc +- = get_displaced_step_closure_by_addr(memaddr); +-@@ -423,8 +423,8 @@ arm_pc_is_thumb (struct gdbarch *gdbarch +- +- /* Thumb functions have a "special" bit set in minimal symbols. */ +- sym = lookup_minimal_symbol_by_pc (memaddr); +-- if (sym) +-- return (MSYMBOL_IS_SPECIAL (sym)); +-+ if (sym.minsym) +-+ return (MSYMBOL_IS_SPECIAL (sym.minsym)); +- +- /* If the user wants to override the fallback mode, let them. */ +- if (strcmp (arm_fallback_mode_string, "arm") == 0) +-@@ -468,14 +468,14 @@ static int +- skip_prologue_function (struct gdbarch *gdbarch, CORE_ADDR pc, int is_thumb) +- { +- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); +-- struct minimal_symbol *msym; +-+ struct bound_minimal_symbol msym; +- +- msym = lookup_minimal_symbol_by_pc (pc); +-- if (msym != NULL +-- && SYMBOL_VALUE_ADDRESS (msym) == pc +-- && SYMBOL_LINKAGE_NAME (msym) != NULL) +-+ if (msym.minsym != NULL +-+ && SYMBOL_VALUE_ADDRESS (msym.minsym) == pc +-+ && SYMBOL_LINKAGE_NAME (msym.minsym) != NULL) +- { +-- const char *name = SYMBOL_LINKAGE_NAME (msym); +-+ const char *name = SYMBOL_LINKAGE_NAME (msym.minsym); +- +- /* The GNU linker's Thumb call stub to foo is named +- __foo_from_thumb. */ +-@@ -1284,7 +1284,7 @@ arm_skip_stack_protector(CORE_ADDR pc, s +- { +- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); +- unsigned int basereg; +-- struct minimal_symbol *stack_chk_guard; +-+ struct bound_minimal_symbol stack_chk_guard; +- int offset; +- int is_thumb = arm_pc_is_thumb (gdbarch, pc); +- CORE_ADDR addr; +-@@ -1299,8 +1299,9 @@ arm_skip_stack_protector(CORE_ADDR pc, s +- /* If name of symbol doesn't start with '__stack_chk_guard', this +- instruction sequence is not for stack protector. If symbol is +- removed, we conservatively think this sequence is for stack protector. */ +-- if (stack_chk_guard +-- && strncmp (SYMBOL_LINKAGE_NAME (stack_chk_guard), "__stack_chk_guard", +-+ if (stack_chk_guard.minsym +-+ && strncmp (SYMBOL_LINKAGE_NAME (stack_chk_guard.minsym), +-+ "__stack_chk_guard", +- strlen ("__stack_chk_guard")) != 0) +- return pc; +- +---- a/gdb/arm-wince-tdep.c +-+++ b/gdb/arm-wince-tdep.c +-@@ -43,7 +43,7 @@ arm_pe_skip_trampoline_code (struct fram +- struct gdbarch *gdbarch = get_frame_arch (frame); +- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); +- ULONGEST indirect; +-- struct minimal_symbol *indsym; +-+ struct bound_minimal_symbol indsym; +- const char *symname; +- CORE_ADDR next_pc; +- +-@@ -62,10 +62,10 @@ arm_pe_skip_trampoline_code (struct fram +- return 0; +- +- indsym = lookup_minimal_symbol_by_pc (indirect); +-- if (indsym == NULL) +-+ if (indsym.minsym == NULL) +- return 0; +- +-- symname = SYMBOL_LINKAGE_NAME (indsym); +-+ symname = SYMBOL_LINKAGE_NAME (indsym.minsym); +- if (symname == NULL || strncmp (symname, "__imp_", 6) != 0) +- return 0; +- +-@@ -100,11 +100,11 @@ arm_wince_skip_main_prologue (struct gdb +- +- long offset = sign_extend (this_instr & 0x000fffff, 23) << 2; +- CORE_ADDR call_dest = (pc + 8 + offset) & 0xffffffffU; +-- struct minimal_symbol *s = lookup_minimal_symbol_by_pc (call_dest); +-+ struct bound_minimal_symbol s = lookup_minimal_symbol_by_pc (call_dest); +- +-- if (s != NULL +-- && SYMBOL_LINKAGE_NAME (s) != NULL +-- && strcmp (SYMBOL_LINKAGE_NAME (s), "__gccmain") == 0) +-+ if (s.minsym != NULL +-+ && SYMBOL_LINKAGE_NAME (s.minsym) != NULL +-+ && strcmp (SYMBOL_LINKAGE_NAME (s.minsym), "__gccmain") == 0) +- pc += 4; +- } +- +---- a/gdb/block.c +-+++ b/gdb/block.c +-@@ -208,7 +208,7 @@ call_site_for_pc (struct gdbarch *gdbarc +- +- if (slot == NULL) +- { +-- struct minimal_symbol *msym = lookup_minimal_symbol_by_pc (pc); +-+ struct bound_minimal_symbol msym = lookup_minimal_symbol_by_pc (pc); +- +- /* DW_TAG_gnu_call_site will be missing just if GCC could not determine +- the call target. */ +-@@ -216,7 +216,8 @@ call_site_for_pc (struct gdbarch *gdbarc +- _("DW_OP_GNU_entry_value resolving cannot find " +- "DW_TAG_GNU_call_site %s in %s"), +- paddress (gdbarch, pc), +-- msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym)); +-+ (msym.minsym == NULL ? "???" +-+ : SYMBOL_PRINT_NAME (msym.minsym))); +- } +- +- return *slot; +---- a/gdb/blockframe.c +-+++ b/gdb/blockframe.c +-@@ -88,7 +88,7 @@ CORE_ADDR +- get_pc_function_start (CORE_ADDR pc) +- { +- struct block *bl; +-- struct minimal_symbol *msymbol; +-+ struct bound_minimal_symbol msymbol; +- +- bl = block_for_pc (pc); +- if (bl) +-@@ -103,9 +103,9 @@ get_pc_function_start (CORE_ADDR pc) +- } +- +- msymbol = lookup_minimal_symbol_by_pc (pc); +-- if (msymbol) +-+ if (msymbol.minsym) +- { +-- CORE_ADDR fstart = SYMBOL_VALUE_ADDRESS (msymbol); +-+ CORE_ADDR fstart = SYMBOL_VALUE_ADDRESS (msymbol.minsym); +- +- if (find_pc_section (fstart)) +- return fstart; +-@@ -218,7 +218,7 @@ find_pc_partial_function_gnu_ifunc (CORE +- && section == cache_pc_function_section) +- goto return_cached_value; +- +-- msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section); +-+ msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section).minsym; +- ALL_OBJFILES (objfile) +- { +- if (objfile->sf) +---- a/gdb/breakpoint.c +-+++ b/gdb/breakpoint.c +-@@ -9824,14 +9824,14 @@ resolve_sal_pc (struct symtab_and_line * +- if we have line numbers but no functions (as can +- happen in assembly source). */ +- +-- struct minimal_symbol *msym; +-+ struct bound_minimal_symbol msym; +- struct cleanup *old_chain = save_current_space_and_thread (); +- +- switch_to_program_space_and_thread (sal->pspace); +- +- msym = lookup_minimal_symbol_by_pc (sal->pc); +-- if (msym) +-- sal->section = SYMBOL_OBJ_SECTION (msym); +-+ if (msym.minsym) +-+ sal->section = SYMBOL_OBJ_SECTION (msym.minsym); +- +- do_cleanups (old_chain); +- } +---- a/gdb/btrace.c +-+++ b/gdb/btrace.c +-@@ -272,7 +272,7 @@ compute_ftrace (VEC (btrace_inst_s) *itr +- for (idx = 0; VEC_iterate (btrace_inst_s, itrace, idx, binst); ++idx) +- { +- struct symtab_and_line sal; +-- struct minimal_symbol *mfun; +-+ struct bound_minimal_symbol mfun; +- struct symbol *fun; +- const char *filename; +- CORE_ADDR pc; +-@@ -285,7 +285,7 @@ compute_ftrace (VEC (btrace_inst_s) *itr +- fun = find_pc_function (pc); +- mfun = lookup_minimal_symbol_by_pc (pc); +- +-- if (fun == NULL && mfun == NULL) +-+ if (fun == NULL && mfun.minsym == NULL) +- { +- DEBUG_FTRACE ("no symbol at %u, pc=%s", idx, +- core_addr_to_string_nz (pc)); +-@@ -293,11 +293,11 @@ compute_ftrace (VEC (btrace_inst_s) *itr +- } +- +- /* If we're switching functions, we start over. */ +-- if (ftrace_function_switched (bfun, mfun, fun)) +-+ if (ftrace_function_switched (bfun, mfun.minsym, fun)) +- { +- bfun = VEC_safe_push (btrace_func_s, ftrace, NULL); +- +-- ftrace_init_func (bfun, mfun, fun, idx); +-+ ftrace_init_func (bfun, mfun.minsym, fun, idx); +- ftrace_debug (bfun, "init"); +- } +- +---- a/gdb/c-valprint.c +-+++ b/gdb/c-valprint.c +-@@ -310,18 +310,18 @@ c_val_print (struct type *type, const gd +- CORE_ADDR vt_address = unpack_pointer (type, +- valaddr +- + embedded_offset); +-- struct minimal_symbol *msymbol = +-- lookup_minimal_symbol_by_pc (vt_address); +-+ struct bound_minimal_symbol msymbol = +-+ lookup_minimal_symbol_by_pc (vt_address); +- +- /* If 'symbol_print' is set, we did the work above. */ +- if (!options->symbol_print +-- && (msymbol != NULL) +-- && (vt_address == SYMBOL_VALUE_ADDRESS (msymbol))) +-+ && (msymbol.minsym != NULL) +-+ && (vt_address == SYMBOL_VALUE_ADDRESS (msymbol.minsym))) +- { +- if (want_space) +- fputs_filtered (" ", stream); +- fputs_filtered (" <", stream); +-- fputs_filtered (SYMBOL_PRINT_NAME (msymbol), stream); +-+ fputs_filtered (SYMBOL_PRINT_NAME (msymbol.minsym), stream); +- fputs_filtered (">", stream); +- want_space = 1; +- } +-@@ -337,8 +337,8 @@ c_val_print (struct type *type, const gd +- if (want_space) +- fputs_filtered (" ", stream); +- +-- if (msymbol != NULL) +-- wsym = lookup_symbol (SYMBOL_LINKAGE_NAME (msymbol), +-+ if (msymbol.minsym != NULL) +-+ wsym = lookup_symbol (SYMBOL_LINKAGE_NAME (msymbol.minsym), +- block, VAR_DOMAIN, +- &is_this_fld); +- +---- a/gdb/coff-pe-read.c +-+++ b/gdb/coff-pe-read.c +-@@ -203,8 +203,7 @@ add_pe_forwarded_sym (const char *sym_na +- const char *dll_name, struct objfile *objfile) +- { +- CORE_ADDR vma; +-- struct objfile *forward_objfile; +-- struct minimal_symbol *msymbol; +-+ struct bound_minimal_symbol msymbol; +- short section; +- enum minimal_symbol_type msymtype; +- int dll_name_len = strlen (dll_name); +-@@ -218,20 +217,18 @@ add_pe_forwarded_sym (const char *sym_na +- forward_func_name); +- +- +-- msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name, +-- &forward_objfile); +-+ msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name); +- +-- if (!msymbol) +-+ if (!msymbol.minsym) +- { +- int i; +- +- for (i = 0; i < forward_dll_name_len; i++) +- forward_qualified_name[i] = tolower (forward_qualified_name[i]); +-- msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name, +-- &forward_objfile); +-+ msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name); +- } +- +-- if (!msymbol) +-+ if (!msymbol.minsym) +- { +- if (debug_coff_pe_read) +- fprintf_unfiltered (gdb_stdlog, _("Unable to find function \"%s\" in" +-@@ -246,9 +243,9 @@ add_pe_forwarded_sym (const char *sym_na +- " \"%s\" in dll \"%s\", pointing to \"%s\"\n"), +- sym_name, dll_name, forward_qualified_name); +- +-- vma = SYMBOL_VALUE_ADDRESS (msymbol); +-- section = SYMBOL_SECTION (msymbol); +-- msymtype = MSYMBOL_TYPE (msymbol); +-+ vma = SYMBOL_VALUE_ADDRESS (msymbol.minsym); +-+ section = SYMBOL_SECTION (msymbol.minsym); +-+ msymtype = MSYMBOL_TYPE (msymbol.minsym); +- +- /* Generate a (hopefully unique) qualified name using the first part +- of the dll name, e.g. KERNEL32!AddAtomA. This matches the style +---- a/gdb/dwarf2loc.c +-+++ b/gdb/dwarf2loc.c +-@@ -500,19 +500,20 @@ call_site_to_target_addr (struct gdbarch +- dwarf_block = FIELD_DWARF_BLOCK (call_site->target); +- if (dwarf_block == NULL) +- { +-- struct minimal_symbol *msym; +-+ struct bound_minimal_symbol msym; +- +- msym = lookup_minimal_symbol_by_pc (call_site->pc - 1); +- throw_error (NO_ENTRY_VALUE_ERROR, +- _("DW_AT_GNU_call_site_target is not specified " +- "at %s in %s"), +- paddress (call_site_gdbarch, call_site->pc), +-- msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym)); +-+ (msym.minsym == NULL ? "???" +-+ : SYMBOL_PRINT_NAME (msym.minsym))); +- +- } +- if (caller_frame == NULL) +- { +-- struct minimal_symbol *msym; +-+ struct bound_minimal_symbol msym; +- +- msym = lookup_minimal_symbol_by_pc (call_site->pc - 1); +- throw_error (NO_ENTRY_VALUE_ERROR, +-@@ -520,7 +521,8 @@ call_site_to_target_addr (struct gdbarch +- "requires known frame which is currently not " +- "available at %s in %s"), +- paddress (call_site_gdbarch, call_site->pc), +-- msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym)); +-+ (msym.minsym == NULL ? "???" +-+ : SYMBOL_PRINT_NAME (msym.minsym))); +- +- } +- caller_arch = get_frame_arch (caller_frame); +-@@ -547,7 +549,7 @@ call_site_to_target_addr (struct gdbarch +- msym = lookup_minimal_symbol (physname, NULL, NULL); +- if (msym == NULL) +- { +-- msym = lookup_minimal_symbol_by_pc (call_site->pc - 1); +-+ msym = lookup_minimal_symbol_by_pc (call_site->pc - 1).minsym; +- throw_error (NO_ENTRY_VALUE_ERROR, +- _("Cannot find function \"%s\" for a call site target " +- "at %s in %s"), +-@@ -643,14 +645,15 @@ func_verify_no_selftailcall (struct gdba +- +- if (target_addr == verify_addr) +- { +-- struct minimal_symbol *msym; +-+ struct bound_minimal_symbol msym; +- +- msym = lookup_minimal_symbol_by_pc (verify_addr); +- throw_error (NO_ENTRY_VALUE_ERROR, +- _("DW_OP_GNU_entry_value resolving has found " +- "function \"%s\" at %s can call itself via tail " +- "calls"), +-- msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym), +-+ (msym.minsym == NULL ? "???" +-+ : SYMBOL_PRINT_NAME (msym.minsym)), +- paddress (gdbarch, verify_addr)); +- } +- +-@@ -674,10 +677,11 @@ static void +- tailcall_dump (struct gdbarch *gdbarch, const struct call_site *call_site) +- { +- CORE_ADDR addr = call_site->pc; +-- struct minimal_symbol *msym = lookup_minimal_symbol_by_pc (addr - 1); +-+ struct bound_minimal_symbol msym = lookup_minimal_symbol_by_pc (addr - 1); +- +- fprintf_unfiltered (gdb_stdlog, " %s(%s)", paddress (gdbarch, addr), +-- msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym)); +-+ (msym.minsym == NULL ? "???" +-+ : SYMBOL_PRINT_NAME (msym.minsym))); +- +- } +- +-@@ -907,7 +911,7 @@ call_site_find_chain_1 (struct gdbarch * +- +- if (retval == NULL) +- { +-- struct minimal_symbol *msym_caller, *msym_callee; +-+ struct bound_minimal_symbol msym_caller, msym_callee; +- +- msym_caller = lookup_minimal_symbol_by_pc (caller_pc); +- msym_callee = lookup_minimal_symbol_by_pc (callee_pc); +-@@ -915,11 +919,11 @@ call_site_find_chain_1 (struct gdbarch * +- _("There are no unambiguously determinable intermediate " +- "callers or callees between caller function \"%s\" at %s " +- "and callee function \"%s\" at %s"), +-- (msym_caller == NULL +-- ? "???" : SYMBOL_PRINT_NAME (msym_caller)), +-+ (msym_caller.minsym == NULL +-+ ? "???" : SYMBOL_PRINT_NAME (msym_caller.minsym)), +- paddress (gdbarch, caller_pc), +-- (msym_callee == NULL +-- ? "???" : SYMBOL_PRINT_NAME (msym_callee)), +-+ (msym_callee.minsym == NULL +-+ ? "???" : SYMBOL_PRINT_NAME (msym_callee.minsym)), +- paddress (gdbarch, callee_pc)); +- } +- +-@@ -1011,7 +1015,8 @@ dwarf_expr_reg_to_entry_parameter (struc +- caller_frame = get_prev_frame (frame); +- if (gdbarch != frame_unwind_arch (frame)) +- { +-- struct minimal_symbol *msym = lookup_minimal_symbol_by_pc (func_addr); +-+ struct bound_minimal_symbol msym +-+ = lookup_minimal_symbol_by_pc (func_addr); +- struct gdbarch *caller_gdbarch = frame_unwind_arch (frame); +- +- throw_error (NO_ENTRY_VALUE_ERROR, +-@@ -1019,18 +1024,21 @@ dwarf_expr_reg_to_entry_parameter (struc +- "(of %s (%s)) does not match caller gdbarch %s"), +- gdbarch_bfd_arch_info (gdbarch)->printable_name, +- paddress (gdbarch, func_addr), +-- msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym), +-+ (msym.minsym == NULL ? "???" +-+ : SYMBOL_PRINT_NAME (msym.minsym)), +- gdbarch_bfd_arch_info (caller_gdbarch)->printable_name); +- } +- +- if (caller_frame == NULL) +- { +-- struct minimal_symbol *msym = lookup_minimal_symbol_by_pc (func_addr); +-+ struct bound_minimal_symbol msym +-+ = lookup_minimal_symbol_by_pc (func_addr); +- +- throw_error (NO_ENTRY_VALUE_ERROR, _("DW_OP_GNU_entry_value resolving " +- "requires caller of %s (%s)"), +- paddress (gdbarch, func_addr), +-- msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym)); +-+ (msym.minsym == NULL ? "???" +-+ : SYMBOL_PRINT_NAME (msym.minsym))); +- } +- caller_pc = get_frame_pc (caller_frame); +- call_site = call_site_for_pc (gdbarch, caller_pc); +-@@ -1040,8 +1048,8 @@ dwarf_expr_reg_to_entry_parameter (struc +- { +- struct minimal_symbol *target_msym, *func_msym; +- +-- target_msym = lookup_minimal_symbol_by_pc (target_addr); +-- func_msym = lookup_minimal_symbol_by_pc (func_addr); +-+ target_msym = lookup_minimal_symbol_by_pc (target_addr).minsym; +-+ func_msym = lookup_minimal_symbol_by_pc (func_addr).minsym; +- throw_error (NO_ENTRY_VALUE_ERROR, +- _("DW_OP_GNU_entry_value resolving expects callee %s at %s " +- "but the called frame is for %s at %s"), +-@@ -1064,7 +1072,8 @@ dwarf_expr_reg_to_entry_parameter (struc +- } +- if (iparams == call_site->parameter_count) +- { +-- struct minimal_symbol *msym = lookup_minimal_symbol_by_pc (caller_pc); +-+ struct minimal_symbol *msym +-+ = lookup_minimal_symbol_by_pc (caller_pc).minsym; +- +- /* DW_TAG_GNU_call_site_parameter will be missing just if GCC could not +- determine its value. */ +---- a/gdb/elfread.c +-+++ b/gdb/elfread.c +-@@ -735,7 +735,7 @@ elf_gnu_ifunc_cache_eq (const void *a_vo +- static int +- elf_gnu_ifunc_record_cache (const char *name, CORE_ADDR addr) +- { +-- struct minimal_symbol *msym; +-+ struct bound_minimal_symbol msym; +- asection *sect; +- struct objfile *objfile; +- htab_t htab; +-@@ -743,13 +743,13 @@ elf_gnu_ifunc_record_cache (const char * +- void **slot; +- +- msym = lookup_minimal_symbol_by_pc (addr); +-- if (msym == NULL) +-+ if (msym.minsym == NULL) +- return 0; +-- if (SYMBOL_VALUE_ADDRESS (msym) != addr) +-+ if (SYMBOL_VALUE_ADDRESS (msym.minsym) != addr) +- return 0; +- /* minimal symbols have always SYMBOL_OBJ_SECTION non-NULL. */ +-- sect = SYMBOL_OBJ_SECTION (msym)->the_bfd_section; +-- objfile = SYMBOL_OBJ_SECTION (msym)->objfile; +-+ sect = SYMBOL_OBJ_SECTION (msym.minsym)->the_bfd_section; +-+ objfile = SYMBOL_OBJ_SECTION (msym.minsym)->objfile; +- +- /* If .plt jumps back to .plt the symbol is still deferred for later +- resolution and it has no use for GDB. Besides ".text" this symbol can +---- a/gdb/frame.c +-+++ b/gdb/frame.c +-@@ -1678,7 +1678,7 @@ get_prev_frame_1 (struct frame_info *thi +- +- /* gcc -fsplit-stack __morestack can continue the stack anywhere. */ +- this_pc_in_block = get_frame_address_in_block (this_frame); +-- morestack_msym = lookup_minimal_symbol_by_pc (this_pc_in_block); +-+ morestack_msym = lookup_minimal_symbol_by_pc (this_pc_in_block).minsym; +- if (morestack_msym) +- morestack_name = SYMBOL_LINKAGE_NAME (morestack_msym); +- if (!morestack_name || strcmp (morestack_name, "__morestack") != 0) +---- a/gdb/frv-tdep.c +-+++ b/gdb/frv-tdep.c +-@@ -1072,7 +1072,7 @@ frv_skip_main_prologue (struct gdbarch * +- { +- LONGEST displ; +- CORE_ADDR call_dest; +-- struct minimal_symbol *s; +-+ struct bound_minimal_symbol s; +- +- displ = ((op & 0xfe000000) >> 7) | (op & 0x0003ffff); +- if ((displ & 0x00800000) != 0) +-@@ -1081,9 +1081,9 @@ frv_skip_main_prologue (struct gdbarch * +- call_dest = pc + 4 * displ; +- s = lookup_minimal_symbol_by_pc (call_dest); +- +-- if (s != NULL +-- && SYMBOL_LINKAGE_NAME (s) != NULL +-- && strcmp (SYMBOL_LINKAGE_NAME (s), "__main") == 0) +-+ if (s.minsym != NULL +-+ && SYMBOL_LINKAGE_NAME (s.minsym) != NULL +-+ && strcmp (SYMBOL_LINKAGE_NAME (s.minsym), "__main") == 0) +- { +- pc += 4; +- return pc; +---- a/gdb/glibc-tdep.c +-+++ b/gdb/glibc-tdep.c +-@@ -53,19 +53,18 @@ glibc_skip_solib_resolver (struct gdbarc +- of GNU/Linux will provide a portable, efficient interface for +- debugging programs that use shared libraries. */ +- +-- struct objfile *objfile; +-- struct minimal_symbol *resolver +-- = lookup_minimal_symbol_and_objfile ("_dl_runtime_resolve", &objfile); +-+ struct bound_minimal_symbol resolver +-+ = lookup_minimal_symbol_and_objfile ("_dl_runtime_resolve"); +- +-- if (resolver) +-+ if (resolver.minsym) +- { +- /* The dynamic linker began using this name in early 2005. */ +- struct minimal_symbol *fixup +-- = lookup_minimal_symbol ("_dl_fixup", NULL, objfile); +-+ = lookup_minimal_symbol ("_dl_fixup", NULL, resolver.objfile); +- +- /* This is the name used in older versions. */ +- if (! fixup) +-- fixup = lookup_minimal_symbol ("fixup", NULL, objfile); +-+ fixup = lookup_minimal_symbol ("fixup", NULL, resolver.objfile); +- +- if (fixup && SYMBOL_VALUE_ADDRESS (fixup) == pc) +- return frame_unwind_caller_pc (get_current_frame ()); +---- a/gdb/gnu-v2-abi.c +-+++ b/gdb/gnu-v2-abi.c +-@@ -191,7 +191,7 @@ gnuv2_value_rtti_type (struct value *v, +- struct type *known_type; +- struct type *rtti_type; +- CORE_ADDR vtbl; +-- struct minimal_symbol *minsym; +-+ struct bound_minimal_symbol minsym; +- char *demangled_name, *p; +- const char *linkage_name; +- struct type *btype; +-@@ -245,8 +245,8 @@ gnuv2_value_rtti_type (struct value *v, +- +- /* Try to find a symbol that is the vtable. */ +- minsym=lookup_minimal_symbol_by_pc(vtbl); +-- if (minsym==NULL +-- || (linkage_name=SYMBOL_LINKAGE_NAME (minsym))==NULL +-+ if (minsym.minsym==NULL +-+ || (linkage_name=SYMBOL_LINKAGE_NAME (minsym.minsym))==NULL +- || !is_vtable_name (linkage_name)) +- return NULL; +- +---- a/gdb/gnu-v3-abi.c +-+++ b/gdb/gnu-v3-abi.c +-@@ -306,7 +306,7 @@ gnuv3_rtti_type (struct value *value, +- /* Find the linker symbol for this vtable. */ +- vtable_symbol +- = lookup_minimal_symbol_by_pc (value_address (vtable) +-- + value_embedded_offset (vtable)); +-+ + value_embedded_offset (vtable)).minsym; +- if (! vtable_symbol) +- return NULL; +- +-@@ -988,7 +988,7 @@ gnuv3_skip_trampoline (struct frame_info +- real_stop_pc = stop_pc; +- +- /* Find the linker symbol for this potential thunk. */ +-- thunk_sym = lookup_minimal_symbol_by_pc (real_stop_pc); +-+ thunk_sym = lookup_minimal_symbol_by_pc (real_stop_pc).minsym; +- section = find_pc_section (real_stop_pc); +- if (thunk_sym == NULL || section == NULL) +- return 0; +---- a/gdb/hppa-hpux-tdep.c +-+++ b/gdb/hppa-hpux-tdep.c +-@@ -89,7 +89,7 @@ hppa32_hpux_in_solib_call_trampoline (st +- CORE_ADDR pc, char *name) +- { +- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); +-- struct minimal_symbol *minsym; +-+ struct bound_minimal_symbol minsym; +- struct unwind_table_entry *u; +- +- /* First see if PC is in one of the two C-library trampolines. */ +-@@ -98,7 +98,8 @@ hppa32_hpux_in_solib_call_trampoline (st +- return 1; +- +- minsym = lookup_minimal_symbol_by_pc (pc); +-- if (minsym && strcmp (SYMBOL_LINKAGE_NAME (minsym), ".stub") == 0) +-+ if (minsym.minsym +-+ && strcmp (SYMBOL_LINKAGE_NAME (minsym.minsym), ".stub") == 0) +- return 1; +- +- /* Get the unwind descriptor corresponding to PC, return zero +-@@ -174,16 +175,16 @@ hppa64_hpux_in_solib_call_trampoline (st +- step. If it does, then assume we are not in a stub and return. +- +- Finally peek at the instructions to see if they look like a stub. */ +-- struct minimal_symbol *minsym; +-+ struct bound_minimal_symbol minsym; +- asection *sec; +- CORE_ADDR addr; +- int insn; +- +- minsym = lookup_minimal_symbol_by_pc (pc); +-- if (! minsym) +-+ if (! minsym.minsym) +- return 0; +- +-- sec = SYMBOL_OBJ_SECTION (minsym)->the_bfd_section; +-+ sec = SYMBOL_OBJ_SECTION (minsym.minsym)->the_bfd_section; +- +- if (bfd_get_section_vma (sec->owner, sec) <= pc +- && pc < (bfd_get_section_vma (sec->owner, sec) +-@@ -311,7 +312,7 @@ hppa_hpux_skip_trampoline_code (struct f +- int word_size = gdbarch_ptr_bit (gdbarch) / 8; +- long orig_pc = pc; +- long prev_inst, curr_inst, loc; +-- struct minimal_symbol *msym; +-+ struct bound_minimal_symbol msym; +- struct unwind_table_entry *u; +- +- /* Addresses passed to dyncall may *NOT* be the actual address +-@@ -366,10 +367,12 @@ hppa_hpux_skip_trampoline_code (struct f +- /*--------------------------------------------------------------------------*/ +- msym = lookup_minimal_symbol_by_pc (pc); +- +-- if (msym == NULL || MSYMBOL_TYPE (msym) != mst_solib_trampoline) +-+ if (msym.minsym == NULL +-+ || MSYMBOL_TYPE (msym.minsym) != mst_solib_trampoline) +- return orig_pc == pc ? 0 : pc & ~0x3; +- +-- else if (msym != NULL && MSYMBOL_TYPE (msym) == mst_solib_trampoline) +-+ else if (msym.minsym != NULL +-+ && MSYMBOL_TYPE (msym.minsym) == mst_solib_trampoline) +- { +- struct objfile *objfile; +- struct minimal_symbol *msymbol; +-@@ -384,7 +387,7 @@ hppa_hpux_skip_trampoline_code (struct f +- { +- if (MSYMBOL_TYPE (msymbol) == mst_text +- && strcmp (SYMBOL_LINKAGE_NAME (msymbol), +-- SYMBOL_LINKAGE_NAME (msym)) == 0) +-+ SYMBOL_LINKAGE_NAME (msym.minsym)) == 0) +- { +- function_found = 1; +- break; +-@@ -401,7 +404,7 @@ hppa_hpux_skip_trampoline_code (struct f +- should be mst_text. So we need to fix the msym, and also +- get out of this function. */ +- { +-- MSYMBOL_TYPE (msym) = mst_text; +-+ MSYMBOL_TYPE (msym.minsym) = mst_text; +- return orig_pc == pc ? 0 : pc & ~0x3; +- } +- } +-@@ -472,21 +475,22 @@ hppa_hpux_skip_trampoline_code (struct f +- (curr_inst == 0xeaa0d000) || +- (curr_inst == 0xeaa0d002)) +- { +-- struct minimal_symbol *stubsym, *libsym; +-+ struct bound_minimal_symbol stubsym; +-+ struct minimal_symbol *libsym; +- +- stubsym = lookup_minimal_symbol_by_pc (loc); +-- if (stubsym == NULL) +-+ if (stubsym.minsym == NULL) +- { +- warning (_("Unable to find symbol for 0x%lx"), loc); +- return orig_pc == pc ? 0 : pc & ~0x3; +- } +- +-- libsym = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (stubsym), +-+ libsym = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (stubsym.minsym), +- NULL, NULL); +- if (libsym == NULL) +- { +- warning (_("Unable to find library symbol for %s."), +-- SYMBOL_PRINT_NAME (stubsym)); +-+ SYMBOL_PRINT_NAME (stubsym.minsym)); +- return orig_pc == pc ? 0 : pc & ~0x3; +- } +- +-@@ -1025,7 +1029,8 @@ static CORE_ADDR +- hppa_hpux_find_import_stub_for_addr (CORE_ADDR funcaddr) +- { +- struct objfile *objfile; +-- struct minimal_symbol *funsym, *stubsym; +-+ struct bound_minimal_symbol funsym; +-+ struct minimal_symbol *stubsym; +- CORE_ADDR stubaddr; +- +- funsym = lookup_minimal_symbol_by_pc (funcaddr); +-@@ -1034,7 +1039,7 @@ hppa_hpux_find_import_stub_for_addr (COR +- ALL_OBJFILES (objfile) +- { +- stubsym = lookup_minimal_symbol_solib_trampoline +-- (SYMBOL_LINKAGE_NAME (funsym), objfile); +-+ (SYMBOL_LINKAGE_NAME (funsym.minsym), objfile); +- +- if (stubsym) +- { +---- a/gdb/i386-tdep.c +-+++ b/gdb/i386-tdep.c +-@@ -1687,15 +1687,15 @@ i386_skip_main_prologue (struct gdbarch +- { +- /* Make sure address is computed correctly as a 32bit +- integer even if CORE_ADDR is 64 bit wide. */ +-- struct minimal_symbol *s; +-+ struct bound_minimal_symbol s; +- CORE_ADDR call_dest; +- +- call_dest = pc + 5 + extract_signed_integer (buf, 4, byte_order); +- call_dest = call_dest & 0xffffffffU; +- s = lookup_minimal_symbol_by_pc (call_dest); +-- if (s != NULL +-- && SYMBOL_LINKAGE_NAME (s) != NULL +-- && strcmp (SYMBOL_LINKAGE_NAME (s), "__main") == 0) +-+ if (s.minsym != NULL +-+ && SYMBOL_LINKAGE_NAME (s.minsym) != NULL +-+ && strcmp (SYMBOL_LINKAGE_NAME (s.minsym), "__main") == 0) +- pc += 5; +- } +- } +-@@ -3352,7 +3352,7 @@ i386_pe_skip_trampoline_code (struct fra +- unsigned long indirect = +- read_memory_unsigned_integer (pc + 2, 4, byte_order); +- struct minimal_symbol *indsym = +-- indirect ? lookup_minimal_symbol_by_pc (indirect) : 0; +-+ indirect ? lookup_minimal_symbol_by_pc (indirect).minsym : 0; +- const char *symname = indsym ? SYMBOL_LINKAGE_NAME (indsym) : 0; +- +- if (symname) +---- a/gdb/ia64-tdep.c +-+++ b/gdb/ia64-tdep.c +-@@ -3651,11 +3651,11 @@ ia64_convert_from_func_ptr_addr (struct +- /* There are also descriptors embedded in vtables. */ +- if (s) +- { +-- struct minimal_symbol *minsym; +-+ struct bound_minimal_symbol minsym; +- +- minsym = lookup_minimal_symbol_by_pc (addr); +- +-- if (minsym && is_vtable_name (SYMBOL_LINKAGE_NAME (minsym))) +-+ if (minsym.minsym && is_vtable_name (SYMBOL_LINKAGE_NAME (minsym.minsym))) +- return read_memory_unsigned_integer (addr, 8, byte_order); +- } +- +---- a/gdb/infcall.c +-+++ b/gdb/infcall.c +-@@ -355,10 +355,10 @@ get_function_name (CORE_ADDR funaddr, ch +- +- { +- /* Try the minimal symbols. */ +-- struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (funaddr); +-+ struct bound_minimal_symbol msymbol = lookup_minimal_symbol_by_pc (funaddr); +- +-- if (msymbol) +-- return SYMBOL_PRINT_NAME (msymbol); +-+ if (msymbol.minsym) +-+ return SYMBOL_PRINT_NAME (msymbol.minsym); +- } +- +- { +---- a/gdb/infcmd.c +-+++ b/gdb/infcmd.c +-@@ -1332,12 +1332,12 @@ until_next_command (int from_tty) +- +- if (!func) +- { +-- struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc); +-+ struct bound_minimal_symbol msymbol = lookup_minimal_symbol_by_pc (pc); +- +-- if (msymbol == NULL) +-+ if (msymbol.minsym == NULL) +- error (_("Execution is not within a known function.")); +- +-- tp->control.step_range_start = SYMBOL_VALUE_ADDRESS (msymbol); +-+ tp->control.step_range_start = SYMBOL_VALUE_ADDRESS (msymbol.minsym); +- tp->control.step_range_end = pc; +- } +- else +---- a/gdb/jit.c +-+++ b/gdb/jit.c +-@@ -1016,8 +1016,8 @@ static int +- jit_breakpoint_re_set_internal (struct gdbarch *gdbarch, +- struct jit_program_space_data *ps_data) +- { +-- struct minimal_symbol *reg_symbol, *desc_symbol; +-- struct objfile *objf; +-+ struct bound_minimal_symbol reg_symbol; +-+ struct minimal_symbol *desc_symbol; +- struct jit_objfile_data *objf_data; +- CORE_ADDR addr; +- +-@@ -1025,19 +1025,21 @@ jit_breakpoint_re_set_internal (struct g +- { +- /* Lookup the registration symbol. If it is missing, then we +- assume we are not attached to a JIT. */ +-- reg_symbol = lookup_minimal_symbol_and_objfile (jit_break_name, &objf); +-- if (reg_symbol == NULL || SYMBOL_VALUE_ADDRESS (reg_symbol) == 0) +-+ reg_symbol = lookup_minimal_symbol_and_objfile (jit_break_name); +-+ if (reg_symbol.minsym == NULL +-+ || SYMBOL_VALUE_ADDRESS (reg_symbol.minsym) == 0) +- return 1; +- +-- desc_symbol = lookup_minimal_symbol (jit_descriptor_name, NULL, objf); +-+ desc_symbol = lookup_minimal_symbol (jit_descriptor_name, NULL, +-+ reg_symbol.objfile); +- if (desc_symbol == NULL || SYMBOL_VALUE_ADDRESS (desc_symbol) == 0) +- return 1; +- +-- objf_data = get_jit_objfile_data (objf); +-- objf_data->register_code = reg_symbol; +-+ objf_data = get_jit_objfile_data (reg_symbol.objfile); +-+ objf_data->register_code = reg_symbol.minsym; +- objf_data->descriptor = desc_symbol; +- +-- ps_data->objfile = objf; +-+ ps_data->objfile = reg_symbol.objfile; +- } +- else +- objf_data = get_jit_objfile_data (ps_data->objfile); +---- a/gdb/linux-fork.c +-+++ b/gdb/linux-fork.c +-@@ -592,11 +592,11 @@ info_checkpoints_command (char *arg, int +- printf_filtered (_(", line %d"), sal.line); +- if (!sal.symtab && !sal.line) +- { +-- struct minimal_symbol *msym; +-+ struct bound_minimal_symbol msym; +- +- msym = lookup_minimal_symbol_by_pc (pc); +-- if (msym) +-- printf_filtered (", <%s>", SYMBOL_LINKAGE_NAME (msym)); +-+ if (msym.minsym) +-+ printf_filtered (", <%s>", SYMBOL_LINKAGE_NAME (msym.minsym)); +- } +- +- putchar_filtered ('\n'); +---- a/gdb/m32c-tdep.c +-+++ b/gdb/m32c-tdep.c +-@@ -2457,14 +2457,15 @@ m32c_m16c_address_to_pointer (struct gdb +- struct minimal_symbol *tramp_msym; +- +- /* Try to find a linker symbol at this address. */ +-- struct minimal_symbol *func_msym = lookup_minimal_symbol_by_pc (addr); +-+ struct bound_minimal_symbol func_msym +-+ = lookup_minimal_symbol_by_pc (addr); +- +-- if (! func_msym) +-+ if (! func_msym.minsym) +- error (_("Cannot convert code address %s to function pointer:\n" +- "couldn't find a symbol at that address, to find trampoline."), +- paddress (gdbarch, addr)); +- +-- func_name = SYMBOL_LINKAGE_NAME (func_msym); +-+ func_name = SYMBOL_LINKAGE_NAME (func_msym.minsym); +- tramp_name = xmalloc (strlen (func_name) + 5); +- strcpy (tramp_name, func_name); +- strcat (tramp_name, ".plt"); +-@@ -2535,11 +2536,11 @@ m32c_m16c_pointer_to_address (struct gdb +- { +- /* See if there is a minimal symbol at that address whose name is +- "NAME.plt". */ +-- struct minimal_symbol *ptr_msym = lookup_minimal_symbol_by_pc (ptr); +-+ struct bound_minimal_symbol ptr_msym = lookup_minimal_symbol_by_pc (ptr); +- +-- if (ptr_msym) +-+ if (ptr_msym.minsym) +- { +-- const char *ptr_msym_name = SYMBOL_LINKAGE_NAME (ptr_msym); +-+ const char *ptr_msym_name = SYMBOL_LINKAGE_NAME (ptr_msym.minsym); +- int len = strlen (ptr_msym_name); +- +- if (len > 4 +-@@ -2572,7 +2573,7 @@ m32c_m16c_pointer_to_address (struct gdb +- { +- ptr_msym = lookup_minimal_symbol_by_pc ((aspace << 16) | ptr); +- +-- if (ptr_msym) +-+ if (ptr_msym.minsym) +- ptr |= aspace << 16; +- } +- } +---- a/gdb/m68hc11-tdep.c +-+++ b/gdb/m68hc11-tdep.c +-@@ -587,18 +587,18 @@ m68hc11_analyze_instruction (struct gdba +- static enum insn_return_kind +- m68hc11_get_return_insn (CORE_ADDR pc) +- { +-- struct minimal_symbol *sym; +-+ struct bound_minimal_symbol sym; +- +- /* A flag indicating that this is a STO_M68HC12_FAR or STO_M68HC12_INTERRUPT +- function is stored by elfread.c in the high bit of the info field. +- Use this to decide which instruction the function uses to return. */ +- sym = lookup_minimal_symbol_by_pc (pc); +-- if (sym == 0) +-+ if (sym.minsym == 0) +- return RETURN_RTS; +- +-- if (MSYMBOL_IS_RTC (sym)) +-+ if (MSYMBOL_IS_RTC (sym.minsym)) +- return RETURN_RTC; +-- else if (MSYMBOL_IS_RTI (sym)) +-+ else if (MSYMBOL_IS_RTI (sym.minsym)) +- return RETURN_RTI; +- else +- return RETURN_RTS; +---- a/gdb/maint.c +-+++ b/gdb/maint.c +-@@ -445,7 +445,7 @@ maintenance_translate_address (char *arg +- CORE_ADDR address; +- struct obj_section *sect; +- char *p; +-- struct minimal_symbol *sym; +-+ struct bound_minimal_symbol sym; +- struct objfile *objfile; +- +- if (arg == NULL || *arg == 0) +-@@ -480,13 +480,13 @@ maintenance_translate_address (char *arg +- else +- sym = lookup_minimal_symbol_by_pc (address); +- +-- if (sym) +-+ if (sym.minsym) +- { +-- const char *symbol_name = SYMBOL_PRINT_NAME (sym); +-+ const char *symbol_name = SYMBOL_PRINT_NAME (sym.minsym); +- const char *symbol_offset +-- = pulongest (address - SYMBOL_VALUE_ADDRESS (sym)); +-+ = pulongest (address - SYMBOL_VALUE_ADDRESS (sym.minsym)); +- +-- sect = SYMBOL_OBJ_SECTION(sym); +-+ sect = SYMBOL_OBJ_SECTION(sym.minsym); +- if (sect != NULL) +- { +- const char *section_name; +---- a/gdb/minsyms.c +-+++ b/gdb/minsyms.c +-@@ -474,7 +474,7 @@ lookup_minimal_symbol_solib_trampoline ( +- there are text and trampoline symbols at the same address. +- Otherwise prefer mst_text symbols. */ +- +--static struct minimal_symbol * +-+static struct bound_minimal_symbol +- lookup_minimal_symbol_by_pc_section_1 (CORE_ADDR pc, +- struct obj_section *section, +- int want_trampoline) +-@@ -485,6 +485,8 @@ lookup_minimal_symbol_by_pc_section_1 (C +- struct objfile *objfile; +- struct minimal_symbol *msymbol; +- struct minimal_symbol *best_symbol = NULL; +-+ struct objfile *best_objfile = NULL; +-+ struct bound_minimal_symbol result; +- enum minimal_symbol_type want_type, other_type; +- +- want_type = want_trampoline ? mst_solib_trampoline : mst_text; +-@@ -690,14 +692,18 @@ lookup_minimal_symbol_by_pc_section_1 (C +- SYMBOL_VALUE_ADDRESS (&msymbol[hi])))) +- { +- best_symbol = &msymbol[hi]; +-+ best_objfile = objfile; +- } +- } +- } +- } +-- return (best_symbol); +-+ +-+ result.minsym = best_symbol; +-+ result.objfile = best_objfile; +-+ return result; +- } +- +--struct minimal_symbol * +-+struct bound_minimal_symbol +- lookup_minimal_symbol_by_pc_section (CORE_ADDR pc, struct obj_section *section) +- { +- if (section == NULL) +-@@ -707,17 +713,31 @@ lookup_minimal_symbol_by_pc_section (COR +- debugging) always returns NULL making the call somewhat useless. */ +- section = find_pc_section (pc); +- if (section == NULL) +-- return NULL; +-+ { +-+ struct bound_minimal_symbol result; +-+ +-+ memset (&result, 0, sizeof (result)); +-+ return result; +-+ } +- } +- return lookup_minimal_symbol_by_pc_section_1 (pc, section, 0); +- } +- +- /* See minsyms.h. */ +- +--struct minimal_symbol * +-+struct bound_minimal_symbol +- lookup_minimal_symbol_by_pc (CORE_ADDR pc) +- { +-- return lookup_minimal_symbol_by_pc_section (pc, NULL); +-+ struct obj_section *section = find_pc_section (pc); +-+ +-+ if (section == NULL) +-+ { +-+ struct bound_minimal_symbol result; +-+ +-+ memset (&result, 0, sizeof (result)); +-+ return result; +-+ } +-+ return lookup_minimal_symbol_by_pc_section_1 (pc, section, 0); +- } +- +- /* Return non-zero iff PC is in an STT_GNU_IFUNC function resolver. */ +-@@ -725,9 +745,9 @@ lookup_minimal_symbol_by_pc (CORE_ADDR p +- int +- in_gnu_ifunc_stub (CORE_ADDR pc) +- { +-- struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc); +-+ struct bound_minimal_symbol msymbol = lookup_minimal_symbol_by_pc (pc); +- +-- return msymbol && MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc; +-+ return msymbol.minsym && MSYMBOL_TYPE (msymbol.minsym) == mst_text_gnu_ifunc; +- } +- +- /* See elf_gnu_ifunc_resolve_addr for its real implementation. */ +-@@ -785,10 +805,10 @@ const struct gnu_ifunc_fns *gnu_ifunc_fn +- +- /* See minsyms.h. */ +- +--struct minimal_symbol * +--lookup_minimal_symbol_and_objfile (const char *name, +-- struct objfile **objfile_p) +-+struct bound_minimal_symbol +-+lookup_minimal_symbol_and_objfile (const char *name) +- { +-+ struct bound_minimal_symbol result; +- struct objfile *objfile; +- unsigned int hash = msymbol_hash (name) % MINIMAL_SYMBOL_HASH_SIZE; +- +-@@ -802,13 +822,15 @@ lookup_minimal_symbol_and_objfile (const +- { +- if (strcmp (SYMBOL_LINKAGE_NAME (msym), name) == 0) +- { +-- *objfile_p = objfile; +-- return msym; +-+ result.minsym = msym; +-+ result.objfile = objfile; +-+ return result; +- } +- } +- } +- +-- return 0; +-+ memset (&result, 0, sizeof (result)); +-+ return result; +- } +- +- +-@@ -1287,14 +1309,15 @@ static struct minimal_symbol * +- lookup_solib_trampoline_symbol_by_pc (CORE_ADDR pc) +- { +- struct obj_section *section = find_pc_section (pc); +-- struct minimal_symbol *msymbol; +-+ struct bound_minimal_symbol msymbol; +- +- if (section == NULL) +- return NULL; +- msymbol = lookup_minimal_symbol_by_pc_section_1 (pc, section, 1); +- +-- if (msymbol != NULL && MSYMBOL_TYPE (msymbol) == mst_solib_trampoline) +-- return msymbol; +-+ if (msymbol.minsym != NULL +-+ && MSYMBOL_TYPE (msymbol.minsym) == mst_solib_trampoline) +-+ return msymbol.minsym; +- return NULL; +- } +- +---- a/gdb/minsyms.h +-+++ b/gdb/minsyms.h +-@@ -20,6 +20,23 @@ +- #ifndef MINSYMS_H +- #define MINSYMS_H +- +-+/* Several lookup functions return both a minimal symbol and the +-+ objfile in which it is found. This structure is used in these +-+ cases. */ +-+ +-+struct bound_minimal_symbol +-+{ +-+ /* The minimal symbol that was found, or NULL if no minimal symbol +-+ was found. */ +-+ +-+ struct minimal_symbol *minsym; +-+ +-+ /* If MINSYM is not NULL, then this is the objfile in which the +-+ symbol is defined. */ +-+ +-+ struct objfile *objfile; +-+}; +-+ +- /* This header declares most of the API for dealing with minimal +- symbols and minimal symbol tables. A few things are declared +- elsewhere; see below. +-@@ -169,12 +186,9 @@ struct minimal_symbol *lookup_minimal_sy +- struct objfile *); +- +- /* Find the minimal symbol named NAME, and return both the minsym +-- struct and its objfile. This only checks the linkage name. Sets +-- *OBJFILE_P and returns the minimal symbol, if it is found. If it +-- is not found, returns NULL. */ +-+ struct and its objfile. This only checks the linkage name. */ +- +--struct minimal_symbol *lookup_minimal_symbol_and_objfile (const char *, +-- struct objfile **); +-+struct bound_minimal_symbol lookup_minimal_symbol_and_objfile (const char *); +- +- /* Look through all the current minimal symbol tables and find the +- first minimal symbol that matches NAME and has text type. If OBJF +-@@ -213,10 +227,10 @@ struct minimal_symbol *lookup_minimal_sy +- If SECTION is NULL, this uses the result of find_pc_section +- instead. +- +-- Returns a pointer to the minimal symbol if such a symbol is found, +-- or NULL if PC is not in a suitable range. */ +-+ The result has a non-NULL 'minsym' member if such a symbol is +-+ found, or NULL if PC is not in a suitable range. */ +- +--struct minimal_symbol *lookup_minimal_symbol_by_pc_section +-+struct bound_minimal_symbol lookup_minimal_symbol_by_pc_section +- (CORE_ADDR, +- struct obj_section *); +- +-@@ -226,7 +240,7 @@ struct minimal_symbol *lookup_minimal_sy +- This is a wrapper that calls lookup_minimal_symbol_by_pc_section +- with a NULL section argument. */ +- +--struct minimal_symbol *lookup_minimal_symbol_by_pc (CORE_ADDR); +-+struct bound_minimal_symbol lookup_minimal_symbol_by_pc (CORE_ADDR); +- +- /* Iterate over all the minimal symbols in the objfile OBJF which +- match NAME. Both the ordinary and demangled names of each symbol +---- a/gdb/mips-tdep.c +-+++ b/gdb/mips-tdep.c +-@@ -1115,15 +1115,15 @@ show_mask_address (struct ui_file *file, +- int +- mips_pc_is_mips (CORE_ADDR memaddr) +- { +-- struct minimal_symbol *sym; +-+ struct bound_minimal_symbol sym; +- +- /* Flags indicating that this is a MIPS16 or microMIPS function is +- stored by elfread.c in the high bit of the info field. Use this +- to decide if the function is standard MIPS. Otherwise if bit 0 +- of the address is clear, then this is a standard MIPS function. */ +- sym = lookup_minimal_symbol_by_pc (memaddr); +-- if (sym) +-- return msymbol_is_mips (sym); +-+ if (sym.minsym) +-+ return msymbol_is_mips (sym.minsym); +- else +- return is_mips_addr (memaddr); +- } +-@@ -1133,15 +1133,15 @@ mips_pc_is_mips (CORE_ADDR memaddr) +- int +- mips_pc_is_mips16 (struct gdbarch *gdbarch, CORE_ADDR memaddr) +- { +-- struct minimal_symbol *sym; +-+ struct bound_minimal_symbol sym; +- +- /* A flag indicating that this is a MIPS16 function is stored by +- elfread.c in the high bit of the info field. Use this to decide +- if the function is MIPS16. Otherwise if bit 0 of the address is +- set, then ELF file flags will tell if this is a MIPS16 function. */ +- sym = lookup_minimal_symbol_by_pc (memaddr); +-- if (sym) +-- return msymbol_is_mips16 (sym); +-+ if (sym.minsym) +-+ return msymbol_is_mips16 (sym.minsym); +- else +- return is_mips16_addr (gdbarch, memaddr); +- } +-@@ -1151,7 +1151,7 @@ mips_pc_is_mips16 (struct gdbarch *gdbar +- int +- mips_pc_is_micromips (struct gdbarch *gdbarch, CORE_ADDR memaddr) +- { +-- struct minimal_symbol *sym; +-+ struct bound_minimal_symbol sym; +- +- /* A flag indicating that this is a microMIPS function is stored by +- elfread.c in the high bit of the info field. Use this to decide +-@@ -1159,8 +1159,8 @@ mips_pc_is_micromips (struct gdbarch *gd +- is set, then ELF file flags will tell if this is a microMIPS +- function. */ +- sym = lookup_minimal_symbol_by_pc (memaddr); +-- if (sym) +-- return msymbol_is_micromips (sym); +-+ if (sym.minsym) +-+ return msymbol_is_micromips (sym.minsym); +- else +- return is_micromips_addr (gdbarch, memaddr); +- } +-@@ -1171,7 +1171,7 @@ mips_pc_is_micromips (struct gdbarch *gd +- static enum mips_isa +- mips_pc_isa (struct gdbarch *gdbarch, CORE_ADDR memaddr) +- { +-- struct minimal_symbol *sym; +-+ struct bound_minimal_symbol sym; +- +- /* A flag indicating that this is a MIPS16 or a microMIPS function +- is stored by elfread.c in the high bit of the info field. Use +-@@ -1179,11 +1179,11 @@ mips_pc_isa (struct gdbarch *gdbarch, CO +- MIPS. Otherwise if bit 0 of the address is set, then ELF file +- flags will tell if this is a MIPS16 or a microMIPS function. */ +- sym = lookup_minimal_symbol_by_pc (memaddr); +-- if (sym) +-+ if (sym.minsym) +- { +-- if (msymbol_is_micromips (sym)) +-+ if (msymbol_is_micromips (sym.minsym)) +- return ISA_MICROMIPS; +-- else if (msymbol_is_mips16 (sym)) +-+ else if (msymbol_is_mips16 (sym.minsym)) +- return ISA_MIPS16; +- else +- return ISA_MIPS; +-@@ -3582,7 +3582,7 @@ mips_stub_frame_sniffer (const struct fr +- gdb_byte dummy[4]; +- struct obj_section *s; +- CORE_ADDR pc = get_frame_address_in_block (this_frame); +-- struct minimal_symbol *msym; +-+ struct bound_minimal_symbol msym; +- +- /* Use the stub unwinder for unreadable code. */ +- if (target_read_memory (get_frame_pc (this_frame), dummy, 4) != 0) +-@@ -3602,9 +3602,9 @@ mips_stub_frame_sniffer (const struct fr +- /* Calling a PIC function from a non-PIC function passes through a +- stub. The stub for foo is named ".pic.foo". */ +- msym = lookup_minimal_symbol_by_pc (pc); +-- if (msym != NULL +-- && SYMBOL_LINKAGE_NAME (msym) != NULL +-- && strncmp (SYMBOL_LINKAGE_NAME (msym), ".pic.", 5) == 0) +-+ if (msym.minsym != NULL +-+ && SYMBOL_LINKAGE_NAME (msym.minsym) != NULL +-+ && strncmp (SYMBOL_LINKAGE_NAME (msym.minsym), ".pic.", 5) == 0) +- return 1; +- +- return 0; +-@@ -7626,7 +7626,7 @@ mips_skip_pic_trampoline_code (struct fr +- { +- struct gdbarch *gdbarch = get_frame_arch (frame); +- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); +-- struct minimal_symbol *msym; +-+ struct bound_minimal_symbol msym; +- int i; +- gdb_byte stub_code[16]; +- int32_t stub_words[4]; +-@@ -7635,18 +7635,18 @@ mips_skip_pic_trampoline_code (struct fr +- instructions inserted before foo or a three instruction sequence +- which jumps to foo. */ +- msym = lookup_minimal_symbol_by_pc (pc); +-- if (msym == NULL +-- || SYMBOL_VALUE_ADDRESS (msym) != pc +-- || SYMBOL_LINKAGE_NAME (msym) == NULL +-- || strncmp (SYMBOL_LINKAGE_NAME (msym), ".pic.", 5) != 0) +-+ if (msym.minsym == NULL +-+ || SYMBOL_VALUE_ADDRESS (msym.minsym) != pc +-+ || SYMBOL_LINKAGE_NAME (msym.minsym) == NULL +-+ || strncmp (SYMBOL_LINKAGE_NAME (msym.minsym), ".pic.", 5) != 0) +- return 0; +- +- /* A two-instruction header. */ +-- if (MSYMBOL_SIZE (msym) == 8) +-+ if (MSYMBOL_SIZE (msym.minsym) == 8) +- return pc + 8; +- +- /* A three-instruction (plus delay slot) trampoline. */ +-- if (MSYMBOL_SIZE (msym) == 16) +-+ if (MSYMBOL_SIZE (msym.minsym) == 16) +- { +- if (target_read_memory (pc, stub_code, 16) != 0) +- return 0; +---- a/gdb/p-valprint.c +-+++ b/gdb/p-valprint.c +-@@ -221,18 +221,18 @@ pascal_val_print (struct type *type, con +- /* Print vtbl's nicely. */ +- CORE_ADDR vt_address = unpack_pointer (type, +- valaddr + embedded_offset); +-- struct minimal_symbol *msymbol = +-+ struct bound_minimal_symbol msymbol = +- lookup_minimal_symbol_by_pc (vt_address); +- +- /* If 'symbol_print' is set, we did the work above. */ +- if (!options->symbol_print +-- && (msymbol != NULL) +-- && (vt_address == SYMBOL_VALUE_ADDRESS (msymbol))) +-+ && (msymbol.minsym != NULL) +-+ && (vt_address == SYMBOL_VALUE_ADDRESS (msymbol.minsym))) +- { +- if (want_space) +- fputs_filtered (" ", stream); +- fputs_filtered ("<", stream); +-- fputs_filtered (SYMBOL_PRINT_NAME (msymbol), stream); +-+ fputs_filtered (SYMBOL_PRINT_NAME (msymbol.minsym), stream); +- fputs_filtered (">", stream); +- want_space = 1; +- } +-@@ -247,8 +247,9 @@ pascal_val_print (struct type *type, con +- if (want_space) +- fputs_filtered (" ", stream); +- +-- if (msymbol != NULL) +-- wsym = lookup_symbol (SYMBOL_LINKAGE_NAME (msymbol), block, +-+ if (msymbol.minsym != NULL) +-+ wsym = lookup_symbol (SYMBOL_LINKAGE_NAME (msymbol.minsym), +-+ block, +- VAR_DOMAIN, &is_this_fld); +- +- if (wsym) +---- a/gdb/parse.c +-+++ b/gdb/parse.c +-@@ -508,13 +508,14 @@ write_exp_msymbol (struct minimal_symbol +- pc = gdbarch_convert_from_func_ptr_addr (gdbarch, addr, ¤t_target); +- if (pc != addr) +- { +-- struct minimal_symbol *ifunc_msym = lookup_minimal_symbol_by_pc (pc); +-+ struct bound_minimal_symbol ifunc_msym = lookup_minimal_symbol_by_pc (pc); +- +- /* In this case, assume we have a code symbol instead of +- a data symbol. */ +- +-- if (ifunc_msym != NULL && MSYMBOL_TYPE (ifunc_msym) == mst_text_gnu_ifunc +-- && SYMBOL_VALUE_ADDRESS (ifunc_msym) == pc) +-+ if (ifunc_msym.minsym != NULL +-+ && MSYMBOL_TYPE (ifunc_msym.minsym) == mst_text_gnu_ifunc +-+ && SYMBOL_VALUE_ADDRESS (ifunc_msym.minsym) == pc) +- { +- /* A function descriptor has been resolved but PC is still in the +- STT_GNU_IFUNC resolver body (such as because inferior does not +---- a/gdb/ppc-linux-tdep.c +-+++ b/gdb/ppc-linux-tdep.c +-@@ -332,7 +332,7 @@ static struct ppc_insn_pattern powerpc32 +- static int +- powerpc_linux_in_dynsym_resolve_code (CORE_ADDR pc) +- { +-- struct minimal_symbol *sym; +-+ struct bound_minimal_symbol sym; +- +- /* Check whether PC is in the dynamic linker. This also checks +- whether it is in the .plt section, used by non-PIC executables. */ +-@@ -341,9 +341,10 @@ powerpc_linux_in_dynsym_resolve_code (CO +- +- /* Check if we are in the resolver. */ +- sym = lookup_minimal_symbol_by_pc (pc); +-- if (sym != NULL +-- && (strcmp (SYMBOL_LINKAGE_NAME (sym), "__glink") == 0 +-- || strcmp (SYMBOL_LINKAGE_NAME (sym), "__glink_PLTresolve") == 0)) +-+ if (sym.minsym != NULL +-+ && (strcmp (SYMBOL_LINKAGE_NAME (sym.minsym), "__glink") == 0 +-+ || strcmp (SYMBOL_LINKAGE_NAME (sym.minsym), +-+ "__glink_PLTresolve") == 0)) +- return 1; +- +- return 0; +---- a/gdb/ppc-sysv-tdep.c +-+++ b/gdb/ppc-sysv-tdep.c +-@@ -1076,12 +1076,13 @@ static int +- convert_code_addr_to_desc_addr (CORE_ADDR code_addr, CORE_ADDR *desc_addr) +- { +- struct obj_section *dot_fn_section; +-- struct minimal_symbol *dot_fn; +-+ struct bound_minimal_symbol dot_fn; +- struct minimal_symbol *fn; +-+ +- /* Find the minimal symbol that corresponds to CODE_ADDR (should +- have a name of the form ".FN"). */ +- dot_fn = lookup_minimal_symbol_by_pc (code_addr); +-- if (dot_fn == NULL || SYMBOL_LINKAGE_NAME (dot_fn)[0] != '.') +-+ if (dot_fn.minsym == NULL || SYMBOL_LINKAGE_NAME (dot_fn.minsym)[0] != '.') +- return 0; +- /* Get the section that contains CODE_ADDR. Need this for the +- "objfile" that it contains. */ +-@@ -1092,7 +1093,7 @@ convert_code_addr_to_desc_addr (CORE_ADD +- address. Only look for the minimal symbol in ".FN"'s object file +- - avoids problems when two object files (i.e., shared libraries) +- contain a minimal symbol with the same name. */ +-- fn = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (dot_fn) + 1, NULL, +-+ fn = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (dot_fn.minsym) + 1, NULL, +- dot_fn_section->objfile); +- if (fn == NULL) +- return 0; +---- a/gdb/printcmd.c +-+++ b/gdb/printcmd.c +-@@ -668,7 +668,7 @@ build_address_symbolic (struct gdbarch * +- save some memory, but for many debug format--ELF/DWARF or +- anything/stabs--it would be inconvenient to eliminate those minimal +- symbols anyway). */ +-- msymbol = lookup_minimal_symbol_by_pc_section (addr, section); +-+ msymbol = lookup_minimal_symbol_by_pc_section (addr, section).minsym; +- symbol = find_pc_sect_function (addr, section); +- +- if (symbol) +-@@ -1166,7 +1166,8 @@ sym_info (char *arg, int from_tty) +- +- if (obj_section_addr (osect) <= sect_addr +- && sect_addr < obj_section_endaddr (osect) +-- && (msymbol = lookup_minimal_symbol_by_pc_section (sect_addr, osect))) +-+ && (msymbol +-+ = lookup_minimal_symbol_by_pc_section (sect_addr, osect).minsym)) +- { +- const char *obj_name, *mapped, *sec_name, *msym_name; +- char *loc_string; +---- a/gdb/rs6000-tdep.c +-+++ b/gdb/rs6000-tdep.c +-@@ -2152,15 +2152,15 @@ rs6000_skip_main_prologue (struct gdbarc +- { +- CORE_ADDR displ = op & BL_DISPLACEMENT_MASK; +- CORE_ADDR call_dest = pc + 4 + displ; +-- struct minimal_symbol *s = lookup_minimal_symbol_by_pc (call_dest); +-+ struct bound_minimal_symbol s = lookup_minimal_symbol_by_pc (call_dest); +- +- /* We check for ___eabi (three leading underscores) in addition +- to __eabi in case the GCC option "-fleading-underscore" was +- used to compile the program. */ +-- if (s != NULL +-- && SYMBOL_LINKAGE_NAME (s) != NULL +-- && (strcmp (SYMBOL_LINKAGE_NAME (s), "__eabi") == 0 +-- || strcmp (SYMBOL_LINKAGE_NAME (s), "___eabi") == 0)) +-+ if (s.minsym != NULL +-+ && SYMBOL_LINKAGE_NAME (s.minsym) != NULL +-+ && (strcmp (SYMBOL_LINKAGE_NAME (s.minsym), "__eabi") == 0 +-+ || strcmp (SYMBOL_LINKAGE_NAME (s.minsym), "___eabi") == 0)) +- pc += 4; +- } +- return pc; +-@@ -2226,7 +2226,7 @@ rs6000_skip_trampoline_code (struct fram +- unsigned int ii, op; +- int rel; +- CORE_ADDR solib_target_pc; +-- struct minimal_symbol *msymbol; +-+ struct bound_minimal_symbol msymbol; +- +- static unsigned trampoline_code[] = +- { +-@@ -2242,9 +2242,9 @@ rs6000_skip_trampoline_code (struct fram +- +- /* Check for bigtoc fixup code. */ +- msymbol = lookup_minimal_symbol_by_pc (pc); +-- if (msymbol +-+ if (msymbol.minsym +- && rs6000_in_solib_return_trampoline (gdbarch, pc, +-- SYMBOL_LINKAGE_NAME (msymbol))) +-+ SYMBOL_LINKAGE_NAME (msymbol.minsym))) +- { +- /* Double-check that the third instruction from PC is relative "b". */ +- op = read_memory_integer (pc + 8, 4, byte_order); +---- a/gdb/sh64-tdep.c +-+++ b/gdb/sh64-tdep.c +-@@ -237,7 +237,7 @@ sh64_elf_make_msymbol_special (asymbol * +- static int +- pc_is_isa32 (bfd_vma memaddr) +- { +-- struct minimal_symbol *sym; +-+ struct bound_minimal_symbol sym; +- +- /* If bit 0 of the address is set, assume this is a +- ISA32 (shmedia) address. */ +-@@ -248,8 +248,8 @@ pc_is_isa32 (bfd_vma memaddr) +- the high bit of the info field. Use this to decide if the function is +- ISA16 or ISA32. */ +- sym = lookup_minimal_symbol_by_pc (memaddr); +-- if (sym) +-- return MSYMBOL_IS_SPECIAL (sym); +-+ if (sym.minsym) +-+ return MSYMBOL_IS_SPECIAL (sym.minsym); +- else +- return 0; +- } +---- a/gdb/stack.c +-+++ b/gdb/stack.c +-@@ -1036,23 +1036,25 @@ find_frame_funname (struct frame_info *f +- changed (and we'll create a find_pc_minimal_function or some +- such). */ +- +-- struct minimal_symbol *msymbol = NULL; +-+ struct bound_minimal_symbol msymbol; +- +- /* Don't attempt to do this for inlined functions, which do not +- have a corresponding minimal symbol. */ +- if (!block_inlined_p (SYMBOL_BLOCK_VALUE (func))) +- msymbol +- = lookup_minimal_symbol_by_pc (get_frame_address_in_block (frame)); +-+ else +-+ memset (&msymbol, 0, sizeof (msymbol)); +- +-- if (msymbol != NULL +-- && (SYMBOL_VALUE_ADDRESS (msymbol) +-+ if (msymbol.minsym != NULL +-+ && (SYMBOL_VALUE_ADDRESS (msymbol.minsym) +- > BLOCK_START (SYMBOL_BLOCK_VALUE (func)))) +- { +- /* We also don't know anything about the function besides +- its address and name. */ +- func = 0; +-- *funname = SYMBOL_PRINT_NAME (msymbol); +-- *funlang = SYMBOL_LANGUAGE (msymbol); +-+ *funname = SYMBOL_PRINT_NAME (msymbol.minsym); +-+ *funlang = SYMBOL_LANGUAGE (msymbol.minsym); +- } +- else +- { +-@@ -1079,17 +1081,17 @@ find_frame_funname (struct frame_info *f +- } +- else +- { +-- struct minimal_symbol *msymbol; +-+ struct bound_minimal_symbol msymbol; +- CORE_ADDR pc; +- +- if (!get_frame_address_in_block_if_available (frame, &pc)) +- return; +- +- msymbol = lookup_minimal_symbol_by_pc (pc); +-- if (msymbol != NULL) +-+ if (msymbol.minsym != NULL) +- { +-- *funname = SYMBOL_PRINT_NAME (msymbol); +-- *funlang = SYMBOL_LANGUAGE (msymbol); +-+ *funname = SYMBOL_PRINT_NAME (msymbol.minsym); +-+ *funlang = SYMBOL_LANGUAGE (msymbol.minsym); +- } +- } +- } +-@@ -1423,13 +1425,13 @@ frame_info (char *addr_exp, int from_tty +- } +- else if (frame_pc_p) +- { +-- struct minimal_symbol *msymbol; +-+ struct bound_minimal_symbol msymbol; +- +- msymbol = lookup_minimal_symbol_by_pc (frame_pc); +-- if (msymbol != NULL) +-+ if (msymbol.minsym != NULL) +- { +-- funname = SYMBOL_PRINT_NAME (msymbol); +-- funlang = SYMBOL_LANGUAGE (msymbol); +-+ funname = SYMBOL_PRINT_NAME (msymbol.minsym); +-+ funlang = SYMBOL_LANGUAGE (msymbol.minsym); +- } +- } +- calling_frame_info = get_prev_frame (fi); +---- a/gdb/symtab.c +-+++ b/gdb/symtab.c +-@@ -956,7 +956,7 @@ find_pc_sect_symtab_via_partial (CORE_AD +- /* If we know that this is not a text address, return failure. This is +- necessary because we loop based on texthigh and textlow, which do +- not include the data ranges. */ +-- msymbol = lookup_minimal_symbol_by_pc_section (pc, section); +-+ msymbol = lookup_minimal_symbol_by_pc_section (pc, section).minsym; +- if (msymbol +- && (MSYMBOL_TYPE (msymbol) == mst_data +- || MSYMBOL_TYPE (msymbol) == mst_bss +-@@ -2088,7 +2088,7 @@ find_pc_sect_symtab (CORE_ADDR pc, struc +- addresses, which do not include the data ranges, and because +- we call find_pc_sect_psymtab which has a similar restriction based +- on the partial_symtab's texthigh and textlow. */ +-- msymbol = lookup_minimal_symbol_by_pc_section (pc, section); +-+ msymbol = lookup_minimal_symbol_by_pc_section (pc, section).minsym; +- if (msymbol +- && (MSYMBOL_TYPE (msymbol) == mst_data +- || MSYMBOL_TYPE (msymbol) == mst_bss +-@@ -2219,7 +2219,7 @@ find_pc_sect_line (CORE_ADDR pc, struct +- struct linetable_entry *item; +- struct symtab_and_line val; +- struct blockvector *bv; +-- struct minimal_symbol *msymbol; +-+ struct bound_minimal_symbol msymbol; +- struct minimal_symbol *mfunsym; +- struct objfile *objfile; +- +-@@ -2305,11 +2305,12 @@ find_pc_sect_line (CORE_ADDR pc, struct +- * infinite recursion. +- */ +- msymbol = lookup_minimal_symbol_by_pc (pc); +-- if (msymbol != NULL) +-- if (MSYMBOL_TYPE (msymbol) == mst_solib_trampoline) +-+ if (msymbol.minsym != NULL) +-+ if (MSYMBOL_TYPE (msymbol.minsym) == mst_solib_trampoline) +- { +-- mfunsym = lookup_minimal_symbol_text (SYMBOL_LINKAGE_NAME (msymbol), +-- NULL); +-+ mfunsym +-+ = lookup_minimal_symbol_text (SYMBOL_LINKAGE_NAME (msymbol.minsym), +-+ NULL); +- if (mfunsym == NULL) +- /* I eliminated this warning since it is coming out +- * in the following situation: +-@@ -2325,7 +2326,7 @@ find_pc_sect_line (CORE_ADDR pc, struct +- ; +- /* fall through */ +- else if (SYMBOL_VALUE_ADDRESS (mfunsym) +-- == SYMBOL_VALUE_ADDRESS (msymbol)) +-+ == SYMBOL_VALUE_ADDRESS (msymbol.minsym)) +- /* Avoid infinite recursion */ +- /* See above comment about why warning is commented out. */ +- /* warning ("In stub for %s; unable to find real function/line info", +-@@ -2838,7 +2839,7 @@ skip_prologue_sal (struct symtab_and_lin +- else +- { +- struct minimal_symbol *msymbol +-- = lookup_minimal_symbol_by_pc_section (sal->pc, sal->section); +-+ = lookup_minimal_symbol_by_pc_section (sal->pc, sal->section).minsym; +- +- if (msymbol == NULL) +- { +-@@ -2894,8 +2895,8 @@ skip_prologue_sal (struct symtab_and_lin +- if (skip && start_sal.pc != pc +- && (sym ? (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) <= start_sal.end +- && start_sal.end < BLOCK_END (SYMBOL_BLOCK_VALUE (sym))) +-- : (lookup_minimal_symbol_by_pc_section (start_sal.end, section) +-- == lookup_minimal_symbol_by_pc_section (pc, section)))) +-+ : (lookup_minimal_symbol_by_pc_section (start_sal.end, section).minsym +-+ == lookup_minimal_symbol_by_pc_section (pc, section).minsym))) +- { +- /* First pc of next line */ +- pc = start_sal.end; +---- a/gdb/tui/tui-disasm.c +-+++ b/gdb/tui/tui-disasm.c +-@@ -121,7 +121,7 @@ tui_find_disassembly_address (struct gdb +- pos = max_lines - 1; +- do { +- new_low -= 1 * max_lines; +-- msymbol = lookup_minimal_symbol_by_pc_section (new_low, 0); +-+ msymbol = lookup_minimal_symbol_by_pc_section (new_low, 0).minsym; +- +- if (msymbol) +- new_low = SYMBOL_VALUE_ADDRESS (msymbol); +- +- +-# +-# gdb-7.6-add-powerpc64le-linux.patch +-# +- +-From: Alan Modra +-Date: Thu Apr 25 13:22:52 2013 +0000 +-Git-commit: 49926cd0c84887c581110fb2a471b21ff19048d2 +-References: ppc64le enablement +- +-bfd/ +- * config.bfd: Add powerpc64le-linux. +- +-Acked-by: Petr Tesarik +- +---- +- bfd/ChangeLog | 4 ++++ +- bfd/config.bfd | 3 ++- +- 2 files changed, 6 insertions(+), 1 deletion(-) +- +---- a/bfd/ChangeLog +-+++ b/bfd/ChangeLog +-@@ -1,3 +1,7 @@ +-+2013-04-25 Alan Modra +-+ +-+ * config.bfd: Add powerpc64le-linux. +-+ +- 2013-03-08 Venkataramanan Kumar +- +- * elf64-aarch64.c (elf_backend_can_gc_sections): Enable gc-section +---- a/bfd/config.bfd +-+++ b/bfd/config.bfd +-@@ -1242,7 +1242,8 @@ case "${targ}" in +- targ_selvecs="bfd_elf64_powerpcle_vec bfd_elf32_powerpc_vec bfd_elf32_powerpcle_vec rs6000coff_vec rs6000coff64_vec aix5coff64_vec" +- want64=true +- ;; +-- powerpc64le-*-elf* | powerpcle-*-elf64*) +-+ powerpc64le-*-elf* | powerpcle-*-elf64* | powerpc64le-*-linux* | \ +-+ powerpc64le-*-*bsd*) +- targ_defvec=bfd_elf64_powerpcle_vec +- targ_selvecs="bfd_elf64_powerpc_vec bfd_elf32_powerpcle_vec bfd_elf32_powerpc_vec rs6000coff_vec rs6000coff64_vec aix5coff64_vec" +- want64=true +- +- +-# +-# gdb-7.6-update-autoconf-2013-04-24.patch +-# +- +-From: Jan-Benedict Glaw +-Date: Mon Apr 29 15:13:53 2013 +0000 +-Git-commit: 5dad867ccace0a74c90b729372c9c01392756875 +-References: ppc64le enablement +- +- * config.guess: Update from config repo. +- * config.sub: Ditto. +- +-Acked-by: Petr Tesarik +- +---- +- ChangeLog | 5 +++++ +- config.guess | 25 +++++++++++++++++-------- +- config.sub | 23 +++++++++++------------ +- 3 files changed, 33 insertions(+), 20 deletions(-) +- +---- a/ChangeLog +-+++ b/ChangeLog +-@@ -1,3 +1,8 @@ +-+2013-04-29 Jan-Benedict Glaw +-+ +-+ * config.guess: Update from config repo. +-+ * config.sub: Ditto. +-+ +- 2013-02-15 Yufeng Zhang +- +- * configure.ac: Sync with GCC repo. +---- a/config.guess +-+++ b/config.guess +-@@ -1,10 +1,8 @@ +- #! /bin/sh +- # Attempt to guess a canonical system name. +--# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +--# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +--# 2011, 2012, 2013 Free Software Foundation, Inc. +-+# Copyright 1992-2013 Free Software Foundation, Inc. +- +--timestamp='2012-12-30' +-+timestamp='2013-04-24' +- +- # This file is free software; you can redistribute it and/or modify it +- # under the terms of the GNU General Public License as published by +-@@ -52,9 +50,7 @@ version="\ +- GNU config.guess ($timestamp) +- +- Originally written by Per Bothner. +--Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +--2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, +--2012, 2013 Free Software Foundation, Inc. +-+Copyright 1992-2013 Free Software Foundation, Inc. +- +- This is free software; see the source for copying conditions. There is NO +- warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." +-@@ -887,6 +883,9 @@ EOF +- if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi +- echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} +- exit ;; +-+ arc:Linux:*:* | arceb:Linux:*:*) +-+ echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ exit ;; +- arm*:Linux:*:*) +- eval $set_cc_for_build +- if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ +-@@ -925,6 +924,11 @@ EOF +- #ifdef __dietlibc__ +- LIBC=dietlibc +- #endif +-+ #else +-+ #include +-+ #ifdef __UCLIBC__ +-+ LIBC=uclibc +-+ #endif +- EOF +- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` +- echo "${UNAME_MACHINE}-pc-linux-${LIBC}" +-@@ -957,6 +961,9 @@ EOF +- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` +- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } +- ;; +-+ or1k:Linux:*:*) +-+ echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ exit ;; +- or32:Linux:*:*) +- echo ${UNAME_MACHINE}-unknown-linux-gnu +- exit ;; +-@@ -999,7 +1006,9 @@ EOF +- echo ${UNAME_MACHINE}-dec-linux-gnu +- exit ;; +- x86_64:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ LIBC=gnu +-+ test -r /lib/libc.so && od -An -S13 /lib/libc.so | grep -q __uClibc_main && LIBC=uclibc +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- xtensa*:Linux:*:*) +- echo ${UNAME_MACHINE}-unknown-linux-gnu +---- a/config.sub +-+++ b/config.sub +-@@ -1,10 +1,8 @@ +- #! /bin/sh +- # Configuration validation subroutine script. +--# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +--# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +--# 2011, 2012, 2013 Free Software Foundation, Inc. +-+# Copyright 1992-2013 Free Software Foundation, Inc. +- +--timestamp='2013-01-11' +-+timestamp='2013-04-24' +- +- # This file is free software; you can redistribute it and/or modify it +- # under the terms of the GNU General Public License as published by +-@@ -70,9 +68,7 @@ Report bugs and patches to +-Date: Tue Jun 4 02:44:35 2013 +0000 +-Git-commit: 845d47080b7d7e068e4ec3d11fe6e27b403ac6e3 +-References: ppc64le enablement +- +- * ppc-tdep.h (ppc_insns_match_pattern): Update prototype. +- * rs6000-tdep.c (read_insn): Add frame param, don't assume big-endian. +- (ppc_insns_match_pattern): Add frame param. Avoid multiple +- target mem reads on optional insns. +- * ppc-linux-tdep.c (ppc_skip_trampoline_code): Update +- ppc_insns_match_pattern calls. +- * ppc64-tdep.c (ppc64_standard_linkage2, ppc64_standard_linkage3): +- Add match for power7 thread safety insns, and new order of +- std 2,40(1) insn. Correct code shown for _dl_runtime_resolve +- invocation in comment, and update rest of comment. +- (PPC64_STANDARD_LINKAGE1_LEN, PPC64_STANDARD_LINKAGE2_LEN, +- PPC64_STANDARD_LINKAGE3_LEN): Delete. +- (ppc64_standard_linkage2_target): Update insn offsets. +- (ppc64_skip_trampoline_code): Use a single insn buffer. Match newer +- stubs first. Update calls. +- +-Acked-by: Petr Tesarik +- +---- +- gdb/ChangeLog | 18 ++++++ +- gdb/ppc-linux-tdep.c | 4 - +- gdb/ppc-tdep.h | 4 - +- gdb/ppc64-tdep.c | 140 ++++++++++++++++++++++++++++++--------------------- +- gdb/rs6000-tdep.c | 35 +++++++----- +- 5 files changed, 128 insertions(+), 73 deletions(-) +- +---- a/gdb/ChangeLog +-+++ b/gdb/ChangeLog +-@@ -1,3 +1,21 @@ +-+2013-06-04 Alan Modra +-+ +-+ * ppc-tdep.h (ppc_insns_match_pattern): Update prototype. +-+ * rs6000-tdep.c (read_insn): Add frame param, don't assume big-endian. +-+ (ppc_insns_match_pattern): Add frame param. Avoid multiple +-+ target mem reads on optional insns. +-+ * ppc-linux-tdep.c (ppc_skip_trampoline_code): Update +-+ ppc_insns_match_pattern calls. +-+ * ppc64-tdep.c (ppc64_standard_linkage2, ppc64_standard_linkage3): +-+ Add match for power7 thread safety insns, and new order of +-+ std 2,40(1) insn. Correct code shown for _dl_runtime_resolve +-+ invocation in comment, and update rest of comment. +-+ (PPC64_STANDARD_LINKAGE1_LEN, PPC64_STANDARD_LINKAGE2_LEN, +-+ PPC64_STANDARD_LINKAGE3_LEN): Delete. +-+ (ppc64_standard_linkage2_target): Update insn offsets. +-+ (ppc64_skip_trampoline_code): Use a single insn buffer. Match newer +-+ stubs first. Update calls. +-+ +- 2013-04-08 Tom Tromey +- +- * minsyms.h (struct bound_minimal_symbol): New. +---- a/gdb/ppc-linux-tdep.c +-+++ b/gdb/ppc-linux-tdep.c +-@@ -361,7 +361,7 @@ ppc_skip_trampoline_code (struct frame_i +- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); +- CORE_ADDR target = 0; +- +-- if (ppc_insns_match_pattern (pc, powerpc32_plt_stub, insnbuf)) +-+ if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub, insnbuf)) +- { +- /* Insn pattern is +- lis r11, xxxx +-@@ -373,7 +373,7 @@ ppc_skip_trampoline_code (struct frame_i +- target = read_memory_unsigned_integer (target, 4, byte_order); +- } +- +-- if (ppc_insns_match_pattern (pc, powerpc32_plt_stub_so, insnbuf)) +-+ if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub_so, insnbuf)) +- { +- /* Insn pattern is +- lwz r11, xxxx(r30) +---- a/gdb/ppc-tdep.h +-+++ b/gdb/ppc-tdep.h +-@@ -300,9 +300,9 @@ struct ppc_insn_pattern +- int optional; /* If non-zero, this insn may be absent. */ +- }; +- +--extern int ppc_insns_match_pattern (CORE_ADDR pc, +-+extern int ppc_insns_match_pattern (struct frame_info *frame, CORE_ADDR pc, +- struct ppc_insn_pattern *pattern, +-- unsigned int *insn); +-+ unsigned int *insns); +- extern CORE_ADDR ppc_insn_d_field (unsigned int insn); +- +- extern CORE_ADDR ppc_insn_ds_field (unsigned int insn); +---- a/gdb/ppc64-tdep.c +-+++ b/gdb/ppc64-tdep.c +-@@ -59,9 +59,10 @@ ppc64_desc_entry_point (struct gdbarch * +- return (CORE_ADDR) read_memory_unsigned_integer (desc, 8, byte_order); +- } +- +--/* Pattern for the standard linkage function. These are built by +-- build_plt_stub in elf64-ppc.c, whose GLINK argument is always +-- zero. */ +-+/* Patterns for the standard linkage functions. These are built by +-+ build_plt_stub in bfd/elf64-ppc.c. */ +-+ +-+/* Old PLT call stub. */ +- +- static struct ppc_insn_pattern ppc64_standard_linkage1[] = +- { +-@@ -95,15 +96,23 @@ static struct ppc_insn_pattern ppc64_sta +- { 0, 0, 0 } +- }; +- +--#define PPC64_STANDARD_LINKAGE1_LEN ARRAY_SIZE (ppc64_standard_linkage1) +-+/* Current PLT call stub to access PLT entries more than +/- 32k from r2. +-+ Also supports older stub with different placement of std 2,40(1), +-+ a stub that omits the std 2,40(1), and both versions of power7 +-+ thread safety read barriers. Note that there are actually two more +-+ instructions following "cmpldi r2, 0", "bnectr+" and "b ", +-+ but there isn't any need to match them. */ +- +- static struct ppc_insn_pattern ppc64_standard_linkage2[] = +- { +-+ /* std r2, 40(r1) */ +-+ { -1, insn_ds (62, 2, 1, 40, 0), 1 }, +-+ +- /* addis r12, r2, */ +- { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 }, +- +-- /* std r2, 40(r1) */ +-- { -1, insn_ds (62, 2, 1, 40, 0), 0 }, +-+ /* std r2, 40(r1) */ +-+ { -1, insn_ds (62, 2, 1, 40, 0), 1 }, +- +- /* ld r11, (r12) */ +- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 }, +-@@ -114,24 +123,33 @@ static struct ppc_insn_pattern ppc64_sta +- /* mtctr r11 */ +- { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, +- +-+ /* xor r11, r11, r11 */ +-+ { -1, 0x7d6b5a78, 1 }, +-+ +-+ /* add r12, r12, r11 */ +-+ { -1, 0x7d8c5a14, 1 }, +-+ +- /* ld r2, (r12) */ +- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 }, +- +- /* ld r11, (r12) */ +- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 }, +- +-- /* bctr */ +-- { -1, 0x4e800420, 0 }, +-+ /* bctr */ +-+ { -1, 0x4e800420, 1 }, +-+ +-+ /* cmpldi r2, 0 */ +-+ { -1, 0x28220000, 1 }, +- +- { 0, 0, 0 } +- }; +- +--#define PPC64_STANDARD_LINKAGE2_LEN ARRAY_SIZE (ppc64_standard_linkage2) +-+/* Current PLT call stub to access PLT entries within +/- 32k of r2. */ +- +- static struct ppc_insn_pattern ppc64_standard_linkage3[] = +- { +-- /* std r2, 40(r1) */ +-- { -1, insn_ds (62, 2, 1, 40, 0), 0 }, +-+ /* std r2, 40(r1) */ +-+ { -1, insn_ds (62, 2, 1, 40, 0), 1 }, +- +- /* ld r11, (r2) */ +- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 }, +-@@ -142,56 +160,71 @@ static struct ppc_insn_pattern ppc64_sta +- /* mtctr r11 */ +- { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, +- +-+ /* xor r11, r11, r11 */ +-+ { -1, 0x7d6b5a78, 1 }, +-+ +-+ /* add r2, r2, r11 */ +-+ { -1, 0x7c425a14, 1 }, +-+ +- /* ld r11, (r2) */ +- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 1 }, +- +- /* ld r2, (r2) */ +- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 2, 0, 0), 0 }, +- +-- /* bctr */ +-- { -1, 0x4e800420, 0 }, +-+ /* bctr */ +-+ { -1, 0x4e800420, 1 }, +-+ +-+ /* cmpldi r2, 0 */ +-+ { -1, 0x28220000, 1 }, +- +- { 0, 0, 0 } +- }; +- +--#define PPC64_STANDARD_LINKAGE3_LEN ARRAY_SIZE (ppc64_standard_linkage3) +-- +- /* When the dynamic linker is doing lazy symbol resolution, the first +- call to a function in another object will go like this: +- +- - The user's function calls the linkage function: +- +-- 100007c4: 4b ff fc d5 bl 10000498 +-- 100007c8: e8 41 00 28 ld r2,40(r1) +-+ 100003d4: 4b ff ff ad bl 10000380 +-+ 100003d8: e8 41 00 28 ld r2,40(r1) +- +-- - The linkage function loads the entry point (and other stuff) from +-- the function descriptor in the PLT, and jumps to it: +-+ - The linkage function loads the entry point and toc pointer from +-+ the function descriptor in the PLT, and jumps to it: +- +-- 10000498: 3d 82 00 00 addis r12,r2,0 +-- 1000049c: f8 41 00 28 std r2,40(r1) +-- 100004a0: e9 6c 80 98 ld r11,-32616(r12) +-- 100004a4: e8 4c 80 a0 ld r2,-32608(r12) +-- 100004a8: 7d 69 03 a6 mtctr r11 +-- 100004ac: e9 6c 80 a8 ld r11,-32600(r12) +-- 100004b0: 4e 80 04 20 bctr +-+ : +-+ 10000380: f8 41 00 28 std r2,40(r1) +-+ 10000384: e9 62 80 78 ld r11,-32648(r2) +-+ 10000388: 7d 69 03 a6 mtctr r11 +-+ 1000038c: e8 42 80 80 ld r2,-32640(r2) +-+ 10000390: 28 22 00 00 cmpldi r2,0 +-+ 10000394: 4c e2 04 20 bnectr+ +-+ 10000398: 48 00 03 a0 b 10000738 +- +- - But since this is the first time that PLT entry has been used, it +-- sends control to its glink entry. That loads the number of the +-- PLT entry and jumps to the common glink0 code: +-+ sends control to its glink entry. That loads the number of the +-+ PLT entry and jumps to the common glink0 code: +- +-- 10000c98: 38 00 00 00 li r0,0 +-- 10000c9c: 4b ff ff dc b 10000c78 +-+ : +-+ 10000738: 38 00 00 01 li r0,1 +-+ 1000073c: 4b ff ff bc b 100006f8 <__glink_PLTresolve> +- +- - The common glink0 code then transfers control to the dynamic +-- linker's fixup code: +-+ linker's fixup code: +- +-- 10000c78: e8 41 00 28 ld r2,40(r1) +-- 10000c7c: 3d 82 00 00 addis r12,r2,0 +-- 10000c80: e9 6c 80 80 ld r11,-32640(r12) +-- 10000c84: e8 4c 80 88 ld r2,-32632(r12) +-- 10000c88: 7d 69 03 a6 mtctr r11 +-- 10000c8c: e9 6c 80 90 ld r11,-32624(r12) +-- 10000c90: 4e 80 04 20 bctr +-+ 100006f0: 0000000000010440 .quad plt0 - (. + 16) +-+ <__glink_PLTresolve>: +-+ 100006f8: 7d 88 02 a6 mflr r12 +-+ 100006fc: 42 9f 00 05 bcl 20,4*cr7+so,10000700 +-+ 10000700: 7d 68 02 a6 mflr r11 +-+ 10000704: e8 4b ff f0 ld r2,-16(r11) +-+ 10000708: 7d 88 03 a6 mtlr r12 +-+ 1000070c: 7d 82 5a 14 add r12,r2,r11 +-+ 10000710: e9 6c 00 00 ld r11,0(r12) +-+ 10000714: e8 4c 00 08 ld r2,8(r12) +-+ 10000718: 7d 69 03 a6 mtctr r11 +-+ 1000071c: e9 6c 00 10 ld r11,16(r12) +-+ 10000720: 4e 80 04 20 bctr +- +- Eventually, this code will figure out how to skip all of this, +- including the dynamic linker. At the moment, we just get through +-@@ -234,8 +267,8 @@ ppc64_standard_linkage2_target (struct f +- CORE_ADDR desc +- = ((CORE_ADDR) get_frame_register_unsigned (frame, +- tdep->ppc_gp0_regnum + 2) +-- + (ppc_insn_d_field (insn[0]) << 16) +-- + ppc_insn_ds_field (insn[2])); +-+ + (ppc_insn_d_field (insn[1]) << 16) +-+ + ppc_insn_ds_field (insn[3])); +- +- /* The first word of the descriptor is the entry point. Return that. */ +- return ppc64_desc_entry_point (gdbarch, desc); +-@@ -266,23 +299,20 @@ ppc64_standard_linkage3_target (struct f +- CORE_ADDR +- ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) +- { +-- unsigned int ppc64_standard_linkage1_insn[PPC64_STANDARD_LINKAGE1_LEN]; +-- unsigned int ppc64_standard_linkage2_insn[PPC64_STANDARD_LINKAGE2_LEN]; +-- unsigned int ppc64_standard_linkage3_insn[PPC64_STANDARD_LINKAGE3_LEN]; +-+#define MAX(a,b) ((a) > (b) ? (a) : (b)) +-+ unsigned int insns[MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage1), +-+ ARRAY_SIZE (ppc64_standard_linkage2)), +-+ ARRAY_SIZE (ppc64_standard_linkage3)) - 1]; +- CORE_ADDR target; +- +-- if (ppc_insns_match_pattern (pc, ppc64_standard_linkage1, +-- ppc64_standard_linkage1_insn)) +-- pc = ppc64_standard_linkage1_target (frame, pc, +-- ppc64_standard_linkage1_insn); +-- else if (ppc_insns_match_pattern (pc, ppc64_standard_linkage2, +-- ppc64_standard_linkage2_insn)) +-- pc = ppc64_standard_linkage2_target (frame, pc, +-- ppc64_standard_linkage2_insn); +-- else if (ppc_insns_match_pattern (pc, ppc64_standard_linkage3, +-- ppc64_standard_linkage3_insn)) +-- pc = ppc64_standard_linkage3_target (frame, pc, +-- ppc64_standard_linkage3_insn); +-+ if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage3, insns) +-+ && (insns[8] != 0 || insns[9] != 0)) +-+ pc = ppc64_standard_linkage3_target (frame, pc, insns); +-+ else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage2, insns) +-+ && (insns[10] != 0 || insns[11] != 0)) +-+ pc = ppc64_standard_linkage2_target (frame, pc, insns); +-+ else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage1, insns)) +-+ pc = ppc64_standard_linkage1_target (frame, pc, insns); +- else +- return 0; +- +---- a/gdb/rs6000-tdep.c +-+++ b/gdb/rs6000-tdep.c +-@@ -4238,14 +4238,15 @@ show_powerpc_exact_watchpoints (struct u +- fprintf_filtered (file, _("Use of exact watchpoints is %s.\n"), value); +- } +- +--/* Read a PPC instruction from memory. PPC instructions are always +-- big-endian, no matter what endianness the program is running in, so +-- we can hardcode BFD_ENDIAN_BIG for read_memory_unsigned_integer. */ +-+/* Read a PPC instruction from memory. */ +- +- static unsigned int +--read_insn (CORE_ADDR pc) +-+read_insn (struct frame_info *frame, CORE_ADDR pc) +- { +-- return read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG); +-+ struct gdbarch *gdbarch = get_frame_arch (frame); +-+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); +-+ +-+ return read_memory_unsigned_integer (pc, 4, byte_order); +- } +- +- /* Return non-zero if the instructions at PC match the series +-@@ -4262,19 +4263,25 @@ read_insn (CORE_ADDR pc) +- i'th instruction in memory. */ +- +- int +--ppc_insns_match_pattern (CORE_ADDR pc, struct ppc_insn_pattern *pattern, +-- unsigned int *insn) +-+ppc_insns_match_pattern (struct frame_info *frame, CORE_ADDR pc, +-+ struct ppc_insn_pattern *pattern, +-+ unsigned int *insns) +- { +- int i; +-+ unsigned int insn; +- +-- for (i = 0; pattern[i].mask; i++) +-+ for (i = 0, insn = 0; pattern[i].mask; i++) +- { +-- insn[i] = read_insn (pc); +-- if ((insn[i] & pattern[i].mask) == pattern[i].data) +-- pc += 4; +-- else if (pattern[i].optional) +-- insn[i] = 0; +-- else +-+ if (insn == 0) +-+ insn = read_insn (frame, pc); +-+ insns[i] = 0; +-+ if ((insn & pattern[i].mask) == pattern[i].data) +-+ { +-+ insns[i] = insn; +-+ pc += 4; +-+ insn = 0; +-+ } +-+ else if (!pattern[i].optional) +- return 0; +- } +- +- +-# +-# gdb-7.6-floatformat.patch +-# +- +-From: DJ Delorie +-Date: Tue Aug 20 06:02:53 2013 +0000 +-Git-commit: 21290977cbdd41c6f4e7b297e63901ad491acadd +-References: ppc64le enablement +- +-merge from gcc +- +-Acked-by: Petr Tesarik +- +---- +- include/ChangeLog | 10 ++++++++++ +- include/dwarf2.def | 3 +++ +- include/floatformat.h | 3 ++- +- libiberty/ChangeLog | 6 ++++++ +- libiberty/floatformat.c | 13 +++++++++++-- +- 5 files changed, 32 insertions(+), 3 deletions(-) +- +---- a/include/ChangeLog +-+++ b/include/ChangeLog +-@@ -1,3 +1,13 @@ +-+2013-08-20 Alan Modra +-+ +-+ * floatformat.h (floatformat_ibm_long_double): Delete. +-+ (floatformat_ibm_long_double_big): Declare. +-+ (floatformat_ibm_long_double_little): Declare. +-+ +-+2013-08-19 Dehao Chen +-+ +-+ * dwarf2.def (DW_AT_GNU_discriminator): New attribute. +-+ +- 2013-03-12 Sebastian Huber +- +- * opcode/nios2.h: Edit comment. +---- a/include/dwarf2.def +-+++ b/include/dwarf2.def +-@@ -390,6 +390,9 @@ DW_AT (DW_AT_GNU_ranges_base, 0x2132) +- DW_AT (DW_AT_GNU_addr_base, 0x2133) +- DW_AT (DW_AT_GNU_pubnames, 0x2134) +- DW_AT (DW_AT_GNU_pubtypes, 0x2135) +-+/* Attribute for discriminator. +-+ See http://gcc.gnu.org/wiki/Discriminator */ +-+DW_AT (DW_AT_GNU_discriminator, 0x2136) +- /* VMS extensions. */ +- DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201) +- /* GNAT extensions. */ +---- a/include/floatformat.h +-+++ b/include/floatformat.h +-@@ -128,7 +128,8 @@ extern const struct floatformat floatfor +- extern const struct floatformat floatformat_ia64_quad_big; +- extern const struct floatformat floatformat_ia64_quad_little; +- /* IBM long double (double+double). */ +--extern const struct floatformat floatformat_ibm_long_double; +-+extern const struct floatformat floatformat_ibm_long_double_big; +-+extern const struct floatformat floatformat_ibm_long_double_little; +- +- /* Convert from FMT to a double. +- FROM is the address of the extended float. +---- a/libiberty/ChangeLog +-+++ b/libiberty/ChangeLog +-@@ -1,3 +1,9 @@ +-+2013-08-20 Alan Modra +-+ +-+ * floatformat.c (floatformat_ibm_long_double): Rename to.. +-+ (floatformat_ibm_long_double_big): ..this. +-+ (floatformat_ibm_long_double_little): New. +-+ +- 2013-03-01 Andreas Schwab +- +- * obstacks.texi (Obstacks): Trim @node to only contain the +---- a/libiberty/floatformat.c +-+++ b/libiberty/floatformat.c +-@@ -371,14 +371,23 @@ floatformat_ibm_long_double_is_valid (co +- } +- } +- +--const struct floatformat floatformat_ibm_long_double = +-+const struct floatformat floatformat_ibm_long_double_big = +- { +- floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52, +- floatformat_intbit_no, +-- "floatformat_ibm_long_double", +-+ "floatformat_ibm_long_double_big", +- floatformat_ibm_long_double_is_valid, +- &floatformat_ieee_double_big +- }; +-+ +-+const struct floatformat floatformat_ibm_long_double_little = +-+{ +-+ floatformat_little, 128, 0, 1, 11, 1023, 2047, 12, 52, +-+ floatformat_intbit_no, +-+ "floatformat_ibm_long_double_little", +-+ floatformat_ibm_long_double_is_valid, +-+ &floatformat_ieee_double_little +-+}; +- +- +- #ifndef min +- +-# +-# gdb-7.6-ppc64-ELFv2-trampoline-match.patch +-# +- +-From: Alan Modra +-Date: Mon Nov 11 14:14:40 2013 +1030 +-Git-commit: ef1bc9e72fd2f0310ac3113acc41e1c115e3ac79 +-References: ppc64le enablement +- +-PowerPC64 ELFv2 trampoline match +- +-ELFv2 needs different plt call stubs to ELFv1, register usage differs +-too. When I added these to ld I changed register usage in the ELFv1 +-stubs as well, simplifying the linker code and (perhaps) future +-maintenance. All well and good, but this means gdb needs to cope with +-more stub variants. This patch also handles skipping over addis/addi +-setting up r2 in ELFv2 global entry code. We want breakpoints to be +-set past this point to catch calls via the local entry point. +- +- * ppc64-tdep.c (ppc64_plt_entry_point): Renamed from.. +- (ppc64_desc_entry_point): ..this. Update comments here and at +- call points. +- (ppc64_standard_linkage1, ppc64_standard_linkage2, +- ppc64_standard_linkage3): Update comments. +- (ppc64_standard_linkage4, ppc64_standard_linkage5, +- (ppc64_standard_linkage6, ppc64_standard_linkage7): New insn +- patterns. +- (ppc64_standard_linkage4_target): New function. +- (ppc64_skip_trampoline_code): Skip ELFv2 patterns too. +- * rs6000-tdep.c (skip_prologue): Skip ELFv2 r2 setup. Correct +- nop match. Fix comment wrap. +- +-Acked-by: Petr Tesarik +- +---- +- gdb/ChangeLog | 15 ++++ +- gdb/ppc64-tdep.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++-------- +- gdb/rs6000-tdep.c | 20 ++++- +- 3 files changed, 203 insertions(+), 33 deletions(-) +- +---- a/gdb/ChangeLog +-+++ b/gdb/ChangeLog +-@@ -1,3 +1,18 @@ +-+2013-11-15 Alan Modra +-+ +-+ * ppc64-tdep.c (ppc64_plt_entry_point): Renamed from.. +-+ (ppc64_desc_entry_point): ..this. Update comments here and at +-+ call points. +-+ (ppc64_standard_linkage1, ppc64_standard_linkage2, +-+ ppc64_standard_linkage3): Update comments. +-+ (ppc64_standard_linkage4, ppc64_standard_linkage5, +-+ (ppc64_standard_linkage6, ppc64_standard_linkage7): New insn +-+ patterns. +-+ (ppc64_standard_linkage4_target): New function. +-+ (ppc64_skip_trampoline_code): Skip ELFv2 patterns too. +-+ * rs6000-tdep.c (skip_prologue): Skip ELFv2 r2 setup. Correct +-+ nop match. Fix comment wrap. +-+ +- 2013-06-04 Alan Modra +- +- * ppc-tdep.h (ppc_insns_match_pattern): Update prototype. +---- a/gdb/ppc64-tdep.c +-+++ b/gdb/ppc64-tdep.c +-@@ -48,21 +48,21 @@ +- | (((spr) & 0x3e0) << 6) \ +- | (((xo) & 0x3ff) << 1)) +- +--/* If DESC is the address of a 64-bit PowerPC FreeBSD function +-- descriptor, return the descriptor's entry point. */ +-+/* If PLT is the address of a 64-bit PowerPC PLT entry, +-+ return the function's entry point. */ +- +- static CORE_ADDR +--ppc64_desc_entry_point (struct gdbarch *gdbarch, CORE_ADDR desc) +-+ppc64_plt_entry_point (struct gdbarch *gdbarch, CORE_ADDR plt) +- { +- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); +-- /* The first word of the descriptor is the entry point. */ +-- return (CORE_ADDR) read_memory_unsigned_integer (desc, 8, byte_order); +-+ /* The first word of the PLT entry is the function entry point. */ +-+ return (CORE_ADDR) read_memory_unsigned_integer (plt, 8, byte_order); +- } +- +- /* Patterns for the standard linkage functions. These are built by +- build_plt_stub in bfd/elf64-ppc.c. */ +- +--/* Old PLT call stub. */ +-+/* Old ELFv1 PLT call stub. */ +- +- static struct ppc_insn_pattern ppc64_standard_linkage1[] = +- { +-@@ -96,7 +96,7 @@ static struct ppc_insn_pattern ppc64_sta +- { 0, 0, 0 } +- }; +- +--/* Current PLT call stub to access PLT entries more than +/- 32k from r2. +-+/* ELFv1 PLT call stub to access PLT entries more than +/- 32k from r2. +- Also supports older stub with different placement of std 2,40(1), +- a stub that omits the std 2,40(1), and both versions of power7 +- thread safety read barriers. Note that there are actually two more +-@@ -144,7 +144,7 @@ static struct ppc_insn_pattern ppc64_sta +- { 0, 0, 0 } +- }; +- +--/* Current PLT call stub to access PLT entries within +/- 32k of r2. */ +-+/* ELFv1 PLT call stub to access PLT entries within +/- 32k of r2. */ +- +- static struct ppc_insn_pattern ppc64_standard_linkage3[] = +- { +-@@ -181,6 +181,128 @@ static struct ppc_insn_pattern ppc64_sta +- { 0, 0, 0 } +- }; +- +-+/* ELFv1 PLT call stub to access PLT entries more than +/- 32k from r2. +-+ A more modern variant of ppc64_standard_linkage2 differing in +-+ register usage. */ +-+ +-+static struct ppc_insn_pattern ppc64_standard_linkage4[] = +-+ { +-+ /* std r2, 40(r1) */ +-+ { -1, insn_ds (62, 2, 1, 40, 0), 1 }, +-+ +-+ /* addis r11, r2, */ +-+ { insn_d (-1, -1, -1, 0), insn_d (15, 11, 2, 0), 0 }, +-+ +-+ /* ld r12, (r11) */ +-+ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 11, 0, 0), 0 }, +-+ +-+ /* addi r11, r11, */ +-+ { insn_d (-1, -1, -1, 0), insn_d (14, 11, 11, 0), 1 }, +-+ +-+ /* mtctr r12 */ +-+ { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 }, +-+ +-+ /* xor r2, r12, r12 */ +-+ { -1, 0x7d826278, 1 }, +-+ +-+ /* add r11, r11, r2 */ +-+ { -1, 0x7d6b1214, 1 }, +-+ +-+ /* ld r2, (r11) */ +-+ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 11, 0, 0), 0 }, +-+ +-+ /* ld r11, (r11) */ +-+ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 11, 0, 0), 1 }, +-+ +-+ /* bctr */ +-+ { -1, 0x4e800420, 1 }, +-+ +-+ /* cmpldi r2, 0 */ +-+ { -1, 0x28220000, 1 }, +-+ +-+ { 0, 0, 0 } +-+ }; +-+ +-+/* ELFv1 PLT call stub to access PLT entries within +/- 32k of r2. +-+ A more modern variant of ppc64_standard_linkage3 differing in +-+ register usage. */ +-+ +-+static struct ppc_insn_pattern ppc64_standard_linkage5[] = +-+ { +-+ /* std r2, 40(r1) */ +-+ { -1, insn_ds (62, 2, 1, 40, 0), 1 }, +-+ +-+ /* ld r12, (r2) */ +-+ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 2, 0, 0), 0 }, +-+ +-+ /* addi r2, r2, */ +-+ { insn_d (-1, -1, -1, 0), insn_d (14, 2, 2, 0), 1 }, +-+ +-+ /* mtctr r12 */ +-+ { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 }, +-+ +-+ /* xor r11, r12, r12 */ +-+ { -1, 0x7d8b6278, 1 }, +-+ +-+ /* add r2, r2, r11 */ +-+ { -1, 0x7c425a14, 1 }, +-+ +-+ /* ld r11, (r2) */ +-+ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 1 }, +-+ +-+ /* ld r2, (r2) */ +-+ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 2, 0, 0), 0 }, +-+ +-+ /* bctr */ +-+ { -1, 0x4e800420, 1 }, +-+ +-+ /* cmpldi r2, 0 */ +-+ { -1, 0x28220000, 1 }, +-+ +-+ { 0, 0, 0 } +-+ }; +-+ +-+/* ELFv2 PLT call stub to access PLT entries more than +/- 32k from r2. */ +-+ +-+static struct ppc_insn_pattern ppc64_standard_linkage6[] = +-+ { +-+ /* std r2, 24(r1) */ +-+ { -1, insn_ds (62, 2, 1, 24, 0), 1 }, +-+ +-+ /* addis r11, r2, */ +-+ { insn_d (-1, -1, -1, 0), insn_d (15, 11, 2, 0), 0 }, +-+ +-+ /* ld r12, (r11) */ +-+ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 11, 0, 0), 0 }, +-+ +-+ /* mtctr r12 */ +-+ { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 }, +-+ +-+ /* bctr */ +-+ { -1, 0x4e800420, 0 }, +-+ +-+ { 0, 0, 0 } +-+ }; +-+ +-+/* ELFv2 PLT call stub to access PLT entries within +/- 32k of r2. */ +-+ +-+static struct ppc_insn_pattern ppc64_standard_linkage7[] = +-+ { +-+ /* std r2, 24(r1) */ +-+ { -1, insn_ds (62, 2, 1, 40, 0), 1 }, +-+ +-+ /* ld r12, (r2) */ +-+ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 2, 0, 0), 0 }, +-+ +-+ /* mtctr r12 */ +-+ { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 }, +-+ +-+ /* bctr */ +-+ { -1, 0x4e800420, 0 }, +-+ +-+ { 0, 0, 0 } +-+ }; +-+ +- /* When the dynamic linker is doing lazy symbol resolution, the first +- call to a function in another object will go like this: +- +-@@ -243,16 +365,14 @@ ppc64_standard_linkage1_target (struct f +- struct gdbarch *gdbarch = get_frame_arch (frame); +- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +- +-- /* The address of the function descriptor this linkage function +-- references. */ +-- CORE_ADDR desc +-+ /* The address of the PLT entry this linkage function references. */ +-+ CORE_ADDR plt +- = ((CORE_ADDR) get_frame_register_unsigned (frame, +- tdep->ppc_gp0_regnum + 2) +- + (ppc_insn_d_field (insn[0]) << 16) +- + ppc_insn_ds_field (insn[2])); +- +-- /* The first word of the descriptor is the entry point. Return that. */ +-- return ppc64_desc_entry_point (gdbarch, desc); +-+ return ppc64_plt_entry_point (gdbarch, plt); +- } +- +- static CORE_ADDR +-@@ -262,16 +382,14 @@ ppc64_standard_linkage2_target (struct f +- struct gdbarch *gdbarch = get_frame_arch (frame); +- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +- +-- /* The address of the function descriptor this linkage function +-- references. */ +-- CORE_ADDR desc +-+ /* The address of the PLT entry this linkage function references. */ +-+ CORE_ADDR plt +- = ((CORE_ADDR) get_frame_register_unsigned (frame, +- tdep->ppc_gp0_regnum + 2) +- + (ppc_insn_d_field (insn[1]) << 16) +- + ppc_insn_ds_field (insn[3])); +- +-- /* The first word of the descriptor is the entry point. Return that. */ +-- return ppc64_desc_entry_point (gdbarch, desc); +-+ return ppc64_plt_entry_point (gdbarch, plt); +- } +- +- static CORE_ADDR +-@@ -281,15 +399,28 @@ ppc64_standard_linkage3_target (struct f +- struct gdbarch *gdbarch = get_frame_arch (frame); +- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +- +-- /* The address of the function descriptor this linkage function +-- references. */ +-- CORE_ADDR desc +-+ /* The address of the PLT entry this linkage function references. */ +-+ CORE_ADDR plt +- = ((CORE_ADDR) get_frame_register_unsigned (frame, +- tdep->ppc_gp0_regnum + 2) +- + ppc_insn_ds_field (insn[1])); +- +-- /* The first word of the descriptor is the entry point. Return that. */ +-- return ppc64_desc_entry_point (gdbarch, desc); +-+ return ppc64_plt_entry_point (gdbarch, plt); +-+} +-+ +-+static CORE_ADDR +-+ppc64_standard_linkage4_target (struct frame_info *frame, +-+ CORE_ADDR pc, unsigned int *insn) +-+{ +-+ struct gdbarch *gdbarch = get_frame_arch (frame); +-+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +-+ +-+ CORE_ADDR plt +-+ = ((CORE_ADDR) get_frame_register_unsigned (frame, tdep->ppc_gp0_regnum + 2) +-+ + (ppc_insn_d_field (insn[1]) << 16) +-+ + ppc_insn_ds_field (insn[2])); +-+ +-+ return ppc64_plt_entry_point (gdbarch, plt); +- } +- +- +-@@ -300,13 +431,27 @@ CORE_ADDR +- ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) +- { +- #define MAX(a,b) ((a) > (b) ? (a) : (b)) +-- unsigned int insns[MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage1), +-- ARRAY_SIZE (ppc64_standard_linkage2)), +-- ARRAY_SIZE (ppc64_standard_linkage3)) - 1]; +-+ unsigned int insns[MAX (MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage1), +-+ ARRAY_SIZE (ppc64_standard_linkage2)), +-+ MAX (ARRAY_SIZE (ppc64_standard_linkage3), +-+ ARRAY_SIZE (ppc64_standard_linkage4))), +-+ MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage5), +-+ ARRAY_SIZE (ppc64_standard_linkage6)), +-+ ARRAY_SIZE (ppc64_standard_linkage7))) - 1]; +- CORE_ADDR target; +- +-- if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage3, insns) +-- && (insns[8] != 0 || insns[9] != 0)) +-+ if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage7, insns)) +-+ pc = ppc64_standard_linkage3_target (frame, pc, insns); +-+ else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage6, insns)) +-+ pc = ppc64_standard_linkage4_target (frame, pc, insns); +-+ else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage5, insns) +-+ && (insns[8] != 0 || insns[9] != 0)) +-+ pc = ppc64_standard_linkage3_target (frame, pc, insns); +-+ else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage4, insns) +-+ && (insns[9] != 0 || insns[10] != 0)) +-+ pc = ppc64_standard_linkage4_target (frame, pc, insns); +-+ else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage3, insns) +-+ && (insns[8] != 0 || insns[9] != 0)) +- pc = ppc64_standard_linkage3_target (frame, pc, insns); +- else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage2, insns) +- && (insns[10] != 0 || insns[11] != 0)) +---- a/gdb/rs6000-tdep.c +-+++ b/gdb/rs6000-tdep.c +-@@ -1616,7 +1616,19 @@ skip_prologue (struct gdbarch *gdbarch, +- continue; +- +- } +-- else if ((op & 0xffff0000) == 0x60000000) +-+ else if ((op & 0xffff0000) == 0x3c4c0000 +-+ || (op & 0xffff0000) == 0x3c400000 +-+ || (op & 0xffff0000) == 0x38420000) +-+ { +-+ /* . 0: addis 2,12,.TOC.-0b@ha +-+ . addi 2,2,.TOC.-0b@l +-+ or +-+ . lis 2,.TOC.@ha +-+ . addi 2,2,.TOC.@l +-+ used by ELFv2 global entry points to set up r2. */ +-+ continue; +-+ } +-+ else if (op == 0x60000000) +- { +- /* nop */ +- /* Allow nops in the prologue, but do not consider them to +-@@ -1627,8 +1639,7 @@ skip_prologue (struct gdbarch *gdbarch, +- +- } +- else if ((op & 0xffff0000) == 0x3c000000) +-- { /* addis 0,0,NUM, used +-- for >= 32k frames */ +-+ { /* addis 0,0,NUM, used for >= 32k frames */ +- fdata->offset = (op & 0x0000ffff) << 16; +- fdata->frameless = 0; +- r0_contains_arg = 0; +-@@ -1636,8 +1647,7 @@ skip_prologue (struct gdbarch *gdbarch, +- +- } +- else if ((op & 0xffff0000) == 0x60000000) +-- { /* ori 0,0,NUM, 2nd ha +-- lf of >= 32k frames */ +-+ { /* ori 0,0,NUM, 2nd half of >= 32k frames */ +- fdata->offset |= (op & 0x0000ffff); +- fdata->frameless = 0; +- r0_contains_arg = 0; +- +-# +-# gdb-7.6-update-autoconf-2013-06-10.patch +-# +- +-From: Alan Modra +-Date: Sat Nov 23 08:55:31 2013 +1030 +-Git-commit: f3f51a69187bd04f61373f54afd359e595d18011 +-References: ppc64le enablement +- +-Import config.sub and config.guess from upstream. +- +-Acked-by: Petr Tesarik +- +---- +- ChangeLog | 4 + +- config.guess | 144 ++++++++++++++++++++++++++++++++--------------------------- +- config.sub | 17 ++++-- +- 3 files changed, 94 insertions(+), 71 deletions(-) +- +---- a/ChangeLog +-+++ b/ChangeLog +-@@ -1,3 +1,7 @@ +-+2013-11-23 Alan Modra +-+ +-+ * config.sub, config.guess: Import from upstream. +-+ +- 2013-04-29 Jan-Benedict Glaw +- +- * config.guess: Update from config repo. +---- a/config.guess +-+++ b/config.guess +-@@ -2,7 +2,7 @@ +- # Attempt to guess a canonical system name. +- # Copyright 1992-2013 Free Software Foundation, Inc. +- +--timestamp='2013-04-24' +-+timestamp='2013-06-10' +- +- # This file is free software; you can redistribute it and/or modify it +- # under the terms of the GNU General Public License as published by +-@@ -132,6 +132,27 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` | +- UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +- UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown +- +-+case "${UNAME_SYSTEM}" in +-+Linux|GNU|GNU/*) +-+ # If the system lacks a compiler, then just pick glibc. +-+ # We could probably try harder. +-+ LIBC=gnu +-+ +-+ eval $set_cc_for_build +-+ cat <<-EOF > $dummy.c +-+ #include +-+ #if defined(__UCLIBC__) +-+ LIBC=uclibc +-+ #elif defined(__dietlibc__) +-+ LIBC=dietlibc +-+ #else +-+ LIBC=gnu +-+ #endif +-+ EOF +-+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` +-+ ;; +-+esac +-+ +- # Note: order is significant - the case branches are not exclusive. +- +- case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in +-@@ -853,21 +874,21 @@ EOF +- exit ;; +- *:GNU:*:*) +- # the GNU system +-- echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` +-+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` +- exit ;; +- *:GNU/*:*:*) +- # other systems with GNU libc and userland +-- echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu +-+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} +- exit ;; +- i*86:Minix:*:*) +- echo ${UNAME_MACHINE}-pc-minix +- exit ;; +- aarch64:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- aarch64_be:Linux:*:*) +- UNAME_MACHINE=aarch64_be +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- alpha:Linux:*:*) +- case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in +-@@ -880,67 +901,54 @@ EOF +- EV68*) UNAME_MACHINE=alphaev68 ;; +- esac +- objdump --private-headers /bin/sh | grep -q ld.so.1 +-- if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi +-- echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} +-+ if test "$?" = 0 ; then LIBC="gnulibc1" ; fi +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- arc:Linux:*:* | arceb:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- arm*:Linux:*:*) +- eval $set_cc_for_build +- if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ +- | grep -q __ARM_EABI__ +- then +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- else +- if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ +- | grep -q __ARM_PCS_VFP +- then +-- echo ${UNAME_MACHINE}-unknown-linux-gnueabi +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi +- else +-- echo ${UNAME_MACHINE}-unknown-linux-gnueabihf +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf +- fi +- fi +- exit ;; +- avr32*:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- cris:Linux:*:*) +-- echo ${UNAME_MACHINE}-axis-linux-gnu +-+ echo ${UNAME_MACHINE}-axis-linux-${LIBC} +- exit ;; +- crisv32:Linux:*:*) +-- echo ${UNAME_MACHINE}-axis-linux-gnu +-+ echo ${UNAME_MACHINE}-axis-linux-${LIBC} +- exit ;; +- frv:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- hexagon:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- i*86:Linux:*:*) +-- LIBC=gnu +-- eval $set_cc_for_build +-- sed 's/^ //' << EOF >$dummy.c +-- #ifdef __dietlibc__ +-- LIBC=dietlibc +-- #endif +-- #else +-- #include +-- #ifdef __UCLIBC__ +-- LIBC=uclibc +-- #endif +--EOF +-- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` +-- echo "${UNAME_MACHINE}-pc-linux-${LIBC}" +-+ echo ${UNAME_MACHINE}-pc-linux-${LIBC} +- exit ;; +- ia64:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- m32r*:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- m68*:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- mips:Linux:*:* | mips64:Linux:*:*) +- eval $set_cc_for_build +-@@ -959,59 +967,63 @@ EOF +- #endif +- EOF +- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` +-- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } +-+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } +- ;; +- or1k:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- or32:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- padre:Linux:*:*) +-- echo sparc-unknown-linux-gnu +-+ echo sparc-unknown-linux-${LIBC} +- exit ;; +- parisc64:Linux:*:* | hppa64:Linux:*:*) +-- echo hppa64-unknown-linux-gnu +-+ echo hppa64-unknown-linux-${LIBC} +- exit ;; +- parisc:Linux:*:* | hppa:Linux:*:*) +- # Look for CPU level +- case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in +-- PA7*) echo hppa1.1-unknown-linux-gnu ;; +-- PA8*) echo hppa2.0-unknown-linux-gnu ;; +-- *) echo hppa-unknown-linux-gnu ;; +-+ PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; +-+ PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; +-+ *) echo hppa-unknown-linux-${LIBC} ;; +- esac +- exit ;; +- ppc64:Linux:*:*) +-- echo powerpc64-unknown-linux-gnu +-+ echo powerpc64-unknown-linux-${LIBC} +- exit ;; +- ppc:Linux:*:*) +-- echo powerpc-unknown-linux-gnu +-+ echo powerpc-unknown-linux-${LIBC} +-+ exit ;; +-+ ppc64le:Linux:*:*) +-+ echo powerpc64le-unknown-linux-${LIBC} +-+ exit ;; +-+ ppcle:Linux:*:*) +-+ echo powerpcle-unknown-linux-${LIBC} +- exit ;; +- s390:Linux:*:* | s390x:Linux:*:*) +-- echo ${UNAME_MACHINE}-ibm-linux +-+ echo ${UNAME_MACHINE}-ibm-linux-${LIBC} +- exit ;; +- sh64*:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- sh*:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- sparc:Linux:*:* | sparc64:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- tile*:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- vax:Linux:*:*) +-- echo ${UNAME_MACHINE}-dec-linux-gnu +-+ echo ${UNAME_MACHINE}-dec-linux-${LIBC} +- exit ;; +- x86_64:Linux:*:*) +-- LIBC=gnu +-- test -r /lib/libc.so && od -An -S13 /lib/libc.so | grep -q __uClibc_main && LIBC=uclibc +- echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- xtensa*:Linux:*:*) +-- echo ${UNAME_MACHINE}-unknown-linux-gnu +-+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} +- exit ;; +- i*86:DYNIX/ptx:4*:*) +- # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. +-@@ -1244,19 +1256,21 @@ EOF +- exit ;; +- *:Darwin:*:*) +- UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown +-- case $UNAME_PROCESSOR in +-- i386) +-- eval $set_cc_for_build +-- if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then +-- if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ +-- (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ +-- grep IS_64BIT_ARCH >/dev/null +-- then +-- UNAME_PROCESSOR="x86_64" +-- fi +-- fi ;; +-- unknown) UNAME_PROCESSOR=powerpc ;; +-- esac +-+ eval $set_cc_for_build +-+ if test "$UNAME_PROCESSOR" = unknown ; then +-+ UNAME_PROCESSOR=powerpc +-+ fi +-+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then +-+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ +-+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ +-+ grep IS_64BIT_ARCH >/dev/null +-+ then +-+ case $UNAME_PROCESSOR in +-+ i386) UNAME_PROCESSOR=x86_64 ;; +-+ powerpc) UNAME_PROCESSOR=powerpc64 ;; +-+ esac +-+ fi +-+ fi +- echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} +- exit ;; +- *:procnto*:*:* | *:QNX:[0123456789]*:*) +---- a/config.sub +-+++ b/config.sub +-@@ -2,7 +2,7 @@ +- # Configuration validation subroutine script. +- # Copyright 1992-2013 Free Software Foundation, Inc. +- +--timestamp='2013-04-24' +-+timestamp='2013-10-01' +- +- # This file is free software; you can redistribute it and/or modify it +- # under the terms of the GNU General Public License as published by +-@@ -257,7 +257,7 @@ case $basic_machine in +- | avr | avr32 \ +- | be32 | be64 \ +- | bfin \ +-- | c4x | clipper \ +-+ | c4x | c8051 | clipper \ +- | d10v | d30v | dlx | dsp16xx \ +- | epiphany \ +- | fido | fr30 | frv \ +-@@ -265,6 +265,7 @@ case $basic_machine in +- | hexagon \ +- | i370 | i860 | i960 | ia64 \ +- | ip2k | iq2000 \ +-+ | k1om \ +- | le32 | le64 \ +- | lm32 \ +- | m32c | m32r | m32rle | m68000 | m68k | m88k \ +-@@ -324,7 +325,7 @@ case $basic_machine in +- c6x) +- basic_machine=tic6x-unknown +- ;; +-- m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) +-+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) +- basic_machine=$basic_machine-unknown +- os=-none +- ;; +-@@ -372,7 +373,7 @@ case $basic_machine in +- | be32-* | be64-* \ +- | bfin-* | bs2000-* \ +- | c[123]* | c30-* | [cjt]90-* | c4x-* \ +-- | clipper-* | craynv-* | cydra-* \ +-+ | c8051-* | clipper-* | craynv-* | cydra-* \ +- | d10v-* | d30v-* | dlx-* \ +- | elxsi-* \ +- | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ +-@@ -381,6 +382,7 @@ case $basic_machine in +- | hexagon-* \ +- | i*86-* | i860-* | i960-* | ia64-* \ +- | ip2k-* | iq2000-* \ +-+ | k1om-* \ +- | le32-* | le64-* \ +- | lm32-* \ +- | m32c-* | m32r-* | m32rle-* \ +-@@ -794,7 +796,7 @@ case $basic_machine in +- os=-mingw64 +- ;; +- mingw32) +-- basic_machine=i386-pc +-+ basic_machine=i686-pc +- os=-mingw32 +- ;; +- mingw32ce) +-@@ -830,7 +832,7 @@ case $basic_machine in +- basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` +- ;; +- msys) +-- basic_machine=i386-pc +-+ basic_machine=i686-pc +- os=-msys +- ;; +- mvs) +-@@ -1546,6 +1548,9 @@ case $basic_machine in +- c4x-* | tic4x-*) +- os=-coff +- ;; +-+ c8051-*) +-+ os=-elf +-+ ;; +- hexagon-*) +- os=-elf +- ;; +- +-# +-# gdb-7.6-ppc64le.patch +-# +- +-From: Ulrich Weigand +-References: ppc64le enablement +-Patch-mainline: not yet +- +-Signed-off-by: Ulrich Weigand +-Signed-off-by: Petr Tesarik +- +---- +- gdb/auxv.c | 1 +- gdb/configure.host | 4 +- gdb/configure.tgt | 2 +- gdb/doublest.c | 49 +- +- gdb/gdbarch.c | 33 + +- gdb/gdbarch.h | 6 +- gdb/gdbarch.sh | 1 +- gdb/gdbtypes.c | 4 +- gdb/infrun.c | 4 +- gdb/ppc-linux-tdep.c | 60 ++- +- gdb/ppc-sysv-tdep.c | 534 ++++++++++++++++++++++++--- +- gdb/ppc-tdep.h | 11 +- gdb/ppc64-tdep.c | 2 +- gdb/rs6000-tdep.c | 43 +- +- gdb/symtab.c | 2 +- gdb/testsuite/gdb.arch/altivec-regs.exp | 2 +- gdb/testsuite/gdb.arch/powerpc-d128-regs.exp | 2 +- gdb/testsuite/gdb.arch/vsx-regs.exp | 39 + +- gdb/testsuite/gdb.base/sigbpt.exp | 2 +- gdb/testsuite/gdb.base/step-bt.exp | 2 +- include/elf/common.h | 1 +- include/elf/ppc64.h | 54 ++ +- 22 files changed, 752 insertions(+), 106 deletions(-) +- +---- a/gdb/ppc64-tdep.c +-+++ b/gdb/ppc64-tdep.c +-@@ -289,7 +289,7 @@ static struct ppc_insn_pattern ppc64_sta +- static struct ppc_insn_pattern ppc64_standard_linkage7[] = +- { +- /* std r2, 24(r1) */ +-- { -1, insn_ds (62, 2, 1, 40, 0), 1 }, +-+ { -1, insn_ds (62, 2, 1, 24, 0), 1 }, +- +- /* ld r12, (r2) */ +- { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 2, 0, 0), 0 }, +---- a/gdb/rs6000-tdep.c +-+++ b/gdb/rs6000-tdep.c +-@@ -48,6 +48,7 @@ +- +- #include "elf-bfd.h" +- #include "elf/ppc.h" +-+#include "elf/ppc64.h" +- +- #include "solib-svr4.h" +- #include "ppc-tdep.h" +-@@ -2672,10 +2673,10 @@ dfp_pseudo_register_read (struct gdbarch +- else +- { +- status = regcache_raw_read (regcache, tdep->ppc_fp0_regnum + +-- 2 * reg_index + 1, buffer + 8); +-+ 2 * reg_index + 1, buffer); +- if (status == REG_VALID) +- status = regcache_raw_read (regcache, tdep->ppc_fp0_regnum + +-- 2 * reg_index, buffer); +-+ 2 * reg_index, buffer + 8); +- } +- +- return status; +-@@ -2701,9 +2702,9 @@ dfp_pseudo_register_write (struct gdbarc +- else +- { +- regcache_raw_write (regcache, tdep->ppc_fp0_regnum + +-- 2 * reg_index + 1, buffer + 8); +-+ 2 * reg_index + 1, buffer); +- regcache_raw_write (regcache, tdep->ppc_fp0_regnum + +-- 2 * reg_index, buffer); +-+ 2 * reg_index, buffer + 8); +- } +- } +- +-@@ -2781,7 +2782,8 @@ efpr_pseudo_register_read (struct gdbarc +- int reg_index = reg_nr - tdep->ppc_efpr0_regnum; +- +- /* Read the portion that overlaps the VMX register. */ +-- return regcache_raw_read_part (regcache, tdep->ppc_vr0_regnum + reg_index, 0, +-+ int offset = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 0 : 8; +-+ return regcache_raw_read_part (regcache, tdep->ppc_vr0_regnum + reg_index, offset, +- register_size (gdbarch, reg_nr), buffer); +- } +- +-@@ -2794,7 +2796,8 @@ efpr_pseudo_register_write (struct gdbar +- int reg_index = reg_nr - tdep->ppc_efpr0_regnum; +- +- /* Write the portion that overlaps the VMX register. */ +-- regcache_raw_write_part (regcache, tdep->ppc_vr0_regnum + reg_index, 0, +-+ int offset = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 0 : 8; +-+ regcache_raw_write_part (regcache, tdep->ppc_vr0_regnum + reg_index, offset, +- register_size (gdbarch, reg_nr), buffer); +- } +- +-@@ -3550,6 +3553,7 @@ rs6000_gdbarch_init (struct gdbarch_info +- enum auto_boolean soft_float_flag = powerpc_soft_float_global; +- int soft_float; +- enum powerpc_vector_abi vector_abi = powerpc_vector_abi_global; +-+ enum powerpc_elf_abi elf_abi = POWERPC_ELF_AUTO; +- int have_fpu = 1, have_spe = 0, have_mq = 0, have_altivec = 0, have_dfp = 0, +- have_vsx = 0; +- int tdesc_wordsize = -1; +-@@ -3856,6 +3860,21 @@ rs6000_gdbarch_init (struct gdbarch_info +- } +- +- #ifdef HAVE_ELF +-+ if (from_elf_exec) +-+ { +-+ switch (elf_elfheader (info.abfd)->e_flags & EF_PPC64_ABI) +-+ { +-+ case 1: +-+ elf_abi = POWERPC_ELF_V1; +-+ break; +-+ case 2: +-+ elf_abi = POWERPC_ELF_V2; +-+ break; +-+ default: +-+ break; +-+ } +-+ } +-+ +- if (soft_float_flag == AUTO_BOOLEAN_AUTO && from_elf_exec) +- { +- switch (bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_GNU, +-@@ -3892,6 +3911,15 @@ rs6000_gdbarch_init (struct gdbarch_info +- } +- #endif +- +-+ /* Default to ELFv2 ABI on 64-bit little-endian, and ELFv1 otherwise. */ +-+ if (elf_abi == POWERPC_ELF_AUTO) +-+ { +-+ if (wordsize == 8 && info.byte_order == BFD_ENDIAN_LITTLE) +-+ elf_abi = POWERPC_ELF_V2; +-+ else +-+ elf_abi = POWERPC_ELF_V1; +-+ } +-+ +- if (soft_float_flag == AUTO_BOOLEAN_TRUE) +- soft_float = 1; +- else if (soft_float_flag == AUTO_BOOLEAN_FALSE) +-@@ -3934,6 +3962,8 @@ rs6000_gdbarch_init (struct gdbarch_info +- meaningful, because 64-bit CPUs can run in 32-bit mode. So, perform +- separate word size check. */ +- tdep = gdbarch_tdep (arches->gdbarch); +-+ if (tdep && tdep->elf_abi != elf_abi) +-+ continue; +- if (tdep && tdep->soft_float != soft_float) +- continue; +- if (tdep && tdep->vector_abi != vector_abi) +-@@ -3956,6 +3986,7 @@ rs6000_gdbarch_init (struct gdbarch_info +- +- tdep = XCALLOC (1, struct gdbarch_tdep); +- tdep->wordsize = wordsize; +-+ tdep->elf_abi = elf_abi; +- tdep->soft_float = soft_float; +- tdep->vector_abi = vector_abi; +- +---- a/gdb/auxv.c +-+++ b/gdb/auxv.c +-@@ -441,6 +441,7 @@ fprint_target_auxv (struct ui_file *file +- TAG (AT_IGNOREPPC, _("Entry should be ignored"), dec); +- TAG (AT_BASE_PLATFORM, _("String identifying base platform"), str); +- TAG (AT_RANDOM, _("Address of 16 random bytes"), hex); +-+ TAG (AT_HWCAP2, _("Extension of AT_HWCAP"), hex); +- TAG (AT_EXECFN, _("File name of executable"), str); +- TAG (AT_SECURE, _("Boolean, was exec setuid-like?"), dec); +- TAG (AT_SYSINFO, _("Special system info/entry points"), hex); +---- a/gdb/configure.host +-+++ b/gdb/configure.host +-@@ -129,18 +129,18 @@ mips64*-*-openbsd*) gdb_host=obsd64 ;; +- powerpc-*-aix* | rs6000-*-*) +- gdb_host=aix ;; +- powerpc*-*-freebsd*) gdb_host=fbsd ;; +--powerpc-*-linux*) gdb_host=linux ;; +- powerpc-*-netbsd* | powerpc-*-knetbsd*-gnu) +- gdb_host=nbsd ;; +- powerpc-*-openbsd*) gdb_host=obsd ;; +- +--powerpc64-*-linux*) gdb_host=ppc64-linux +-+powerpc64*-*-linux*) gdb_host=ppc64-linux +- # Support 'pseudo-native' debugging on the Cell BE +- if test "${target_cpu}" = "spu"; then +- gdb_host=spu-linux +- gdb_native=yes +- fi +- ;; +-+powerpc*-*-linux*) gdb_host=linux ;; +- +- s390*-*-*) gdb_host=s390 ;; +- +---- a/gdb/configure.tgt +-+++ b/gdb/configure.tgt +-@@ -421,7 +421,7 @@ powerpc-*-aix* | rs6000-*-*) +- ppc-sysv-tdep.o solib-svr4.o \ +- ravenscar-thread.o ppc-ravenscar-thread.o" +- ;; +--powerpc-*-linux* | powerpc64-*-linux*) +-+powerpc*-*-linux*) +- # Target: PowerPC running Linux +- gdb_target_obs="rs6000-tdep.o ppc-linux-tdep.o ppc-sysv-tdep.o \ +- ppc64-tdep.o solib-svr4.o solib-spu.o \ +---- a/gdb/doublest.c +-+++ b/gdb/doublest.c +-@@ -190,7 +190,8 @@ convert_floatformat_to_doublest (const s +- { +- double dto; +- +-- floatformat_to_double (fmt, from, &dto); +-+ floatformat_to_double (fmt->split_half ? fmt->split_half : fmt, +-+ from, &dto); +- *to = (DOUBLEST) dto; +- return; +- } +-@@ -561,6 +562,11 @@ floatformat_is_negative (const struct fl +- gdb_assert (fmt->totalsize +- <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT); +- +-+ /* An IBM long double (a two element array of double) always takes the +-+ sign of the first double. */ +-+ if (fmt->split_half) +-+ fmt = fmt->split_half; +-+ +- order = floatformat_normalize_byteorder (fmt, uval, newfrom); +- +- if (order != fmt->byteorder) +-@@ -587,6 +593,13 @@ floatformat_classify (const struct float +- gdb_assert (fmt->totalsize +- <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT); +- +-+ /* An IBM long double (a two element array of double) can be classified +-+ by looking at the first double. inf and nan are specified as +-+ ignoring the second double. zero and subnormal will always have +-+ the second double 0.0 if the long double is correctly rounded. */ +-+ if (fmt->split_half) +-+ fmt = fmt->split_half; +-+ +- order = floatformat_normalize_byteorder (fmt, uval, newfrom); +- +- if (order != fmt->byteorder) +-@@ -669,6 +682,16 @@ floatformat_mantissa (const struct float +- gdb_assert (fmt->totalsize +- <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT); +- +-+ /* For IBM long double (a two element array of double), return the +-+ mantissa of the first double. The problem with returning the +-+ actual mantissa from both doubles is that there can be an +-+ arbitrary number of implied 0's or 1's between the mantissas +-+ of the first and second double. In any case, this function +-+ is only used for dumping out nans, and a nan is specified to +-+ ignore the value in the second double. */ +-+ if (fmt->split_half) +-+ fmt = fmt->split_half; +-+ +- order = floatformat_normalize_byteorder (fmt, uval, newfrom); +- +- if (order != fmt->byteorder) +-@@ -926,27 +949,3 @@ convert_typed_floating (const void *from +- floatformat_from_doublest (to_fmt, &d, to); +- } +- } +-- +--const struct floatformat *floatformat_ieee_single[BFD_ENDIAN_UNKNOWN]; +--const struct floatformat *floatformat_ieee_double[BFD_ENDIAN_UNKNOWN]; +--const struct floatformat *floatformat_ieee_quad[BFD_ENDIAN_UNKNOWN]; +--const struct floatformat *floatformat_arm_ext[BFD_ENDIAN_UNKNOWN]; +--const struct floatformat *floatformat_ia64_spill[BFD_ENDIAN_UNKNOWN]; +-- +--extern void _initialize_doublest (void); +-- +--extern void +--_initialize_doublest (void) +--{ +-- floatformat_ieee_single[BFD_ENDIAN_LITTLE] = &floatformat_ieee_single_little; +-- floatformat_ieee_single[BFD_ENDIAN_BIG] = &floatformat_ieee_single_big; +-- floatformat_ieee_double[BFD_ENDIAN_LITTLE] = &floatformat_ieee_double_little; +-- floatformat_ieee_double[BFD_ENDIAN_BIG] = &floatformat_ieee_double_big; +-- floatformat_arm_ext[BFD_ENDIAN_LITTLE] +-- = &floatformat_arm_ext_littlebyte_bigword; +-- floatformat_arm_ext[BFD_ENDIAN_BIG] = &floatformat_arm_ext_big; +-- floatformat_ia64_spill[BFD_ENDIAN_LITTLE] = &floatformat_ia64_spill_little; +-- floatformat_ia64_spill[BFD_ENDIAN_BIG] = &floatformat_ia64_spill_big; +-- floatformat_ieee_quad[BFD_ENDIAN_LITTLE] = &floatformat_ia64_quad_little; +-- floatformat_ieee_quad[BFD_ENDIAN_BIG] = &floatformat_ia64_quad_big; +--} +---- a/gdb/gdbarch.c +-+++ b/gdb/gdbarch.c +-@@ -200,6 +200,7 @@ struct gdbarch +- gdbarch_return_in_first_hidden_param_p_ftype *return_in_first_hidden_param_p; +- gdbarch_skip_prologue_ftype *skip_prologue; +- gdbarch_skip_main_prologue_ftype *skip_main_prologue; +-+ gdbarch_skip_entrypoint_ftype *skip_entrypoint; +- gdbarch_inner_than_ftype *inner_than; +- gdbarch_breakpoint_from_pc_ftype *breakpoint_from_pc; +- gdbarch_remote_breakpoint_from_pc_ftype *remote_breakpoint_from_pc; +-@@ -371,6 +372,7 @@ struct gdbarch startup_gdbarch = +- default_return_in_first_hidden_param_p, /* return_in_first_hidden_param_p */ +- 0, /* skip_prologue */ +- 0, /* skip_main_prologue */ +-+ 0, /* skip_entrypoint */ +- 0, /* inner_than */ +- 0, /* breakpoint_from_pc */ +- default_remote_breakpoint_from_pc, /* remote_breakpoint_from_pc */ +-@@ -672,6 +674,7 @@ verify_gdbarch (struct gdbarch *gdbarch) +- if (gdbarch->skip_prologue == 0) +- fprintf_unfiltered (log, "\n\tskip_prologue"); +- /* Skip verify of skip_main_prologue, has predicate. */ +-+ /* Skip verify of skip_entrypoint, has predicate. */ +- if (gdbarch->inner_than == 0) +- fprintf_unfiltered (log, "\n\tinner_than"); +- if (gdbarch->breakpoint_from_pc == 0) +-@@ -1285,6 +1288,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s +- "gdbarch_dump: single_step_through_delay = <%s>\n", +- host_address_to_string (gdbarch->single_step_through_delay)); +- fprintf_unfiltered (file, +-+ "gdbarch_dump: gdbarch_skip_entrypoint_p() = %d\n", +-+ gdbarch_skip_entrypoint_p (gdbarch)); +-+ fprintf_unfiltered (file, +-+ "gdbarch_dump: skip_entrypoint = <%s>\n", +-+ host_address_to_string (gdbarch->skip_entrypoint)); +-+ fprintf_unfiltered (file, +- "gdbarch_dump: gdbarch_skip_main_prologue_p() = %d\n", +- gdbarch_skip_main_prologue_p (gdbarch)); +- fprintf_unfiltered (file, +-@@ -2635,6 +2644,30 @@ set_gdbarch_skip_main_prologue (struct g +- } +- +- int +-+gdbarch_skip_entrypoint_p (struct gdbarch *gdbarch) +-+{ +-+ gdb_assert (gdbarch != NULL); +-+ return gdbarch->skip_entrypoint != NULL; +-+} +-+ +-+CORE_ADDR +-+gdbarch_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR ip) +-+{ +-+ gdb_assert (gdbarch != NULL); +-+ gdb_assert (gdbarch->skip_entrypoint != NULL); +-+ if (gdbarch_debug >= 2) +-+ fprintf_unfiltered (gdb_stdlog, "gdbarch_skip_entrypoint called\n"); +-+ return gdbarch->skip_entrypoint (gdbarch, ip); +-+} +-+ +-+void +-+set_gdbarch_skip_entrypoint (struct gdbarch *gdbarch, +-+ gdbarch_skip_entrypoint_ftype skip_entrypoint) +-+{ +-+ gdbarch->skip_entrypoint = skip_entrypoint; +-+} +-+ +-+int +- gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs) +- { +- gdb_assert (gdbarch != NULL); +---- a/gdb/gdbarch.h +-+++ b/gdb/gdbarch.h +-@@ -487,6 +487,12 @@ typedef CORE_ADDR (gdbarch_skip_main_pro +- extern CORE_ADDR gdbarch_skip_main_prologue (struct gdbarch *gdbarch, CORE_ADDR ip); +- extern void set_gdbarch_skip_main_prologue (struct gdbarch *gdbarch, gdbarch_skip_main_prologue_ftype *skip_main_prologue); +- +-+extern int gdbarch_skip_entrypoint_p (struct gdbarch *gdbarch); +-+ +-+typedef CORE_ADDR (gdbarch_skip_entrypoint_ftype) (struct gdbarch *gdbarch, CORE_ADDR ip); +-+extern CORE_ADDR gdbarch_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR ip); +-+extern void set_gdbarch_skip_entrypoint (struct gdbarch *gdbarch, gdbarch_skip_entrypoint_ftype *skip_entrypoint); +-+ +- typedef int (gdbarch_inner_than_ftype) (CORE_ADDR lhs, CORE_ADDR rhs); +- extern int gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs); +- extern void set_gdbarch_inner_than (struct gdbarch *gdbarch, gdbarch_inner_than_ftype *inner_than); +---- a/gdb/gdbarch.sh +-+++ b/gdb/gdbarch.sh +-@@ -527,6 +527,7 @@ m:int:return_in_first_hidden_param_p:str +- +- m:CORE_ADDR:skip_prologue:CORE_ADDR ip:ip:0:0 +- M:CORE_ADDR:skip_main_prologue:CORE_ADDR ip:ip +-+M:CORE_ADDR:skip_entrypoint:CORE_ADDR ip:ip +- f:int:inner_than:CORE_ADDR lhs, CORE_ADDR rhs:lhs, rhs:0:0 +- m:const gdb_byte *:breakpoint_from_pc:CORE_ADDR *pcptr, int *lenptr:pcptr, lenptr::0: +- # Return the adjusted address and kind to use for Z0/Z1 packets. +---- a/gdb/gdbtypes.c +-+++ b/gdb/gdbtypes.c +-@@ -107,8 +107,8 @@ const struct floatformat *floatformats_v +- &floatformat_vax_d +- }; +- const struct floatformat *floatformats_ibm_long_double[BFD_ENDIAN_UNKNOWN] = { +-- &floatformat_ibm_long_double, +-- &floatformat_ibm_long_double +-+ &floatformat_ibm_long_double_big, +-+ &floatformat_ibm_long_double_little +- }; +- +- /* Should opaque types be resolved? */ +---- a/gdb/infrun.c +-+++ b/gdb/infrun.c +-@@ -3139,6 +3139,10 @@ fill_in_stop_func (struct gdbarch *gdbar +- ecs->stop_func_start +- += gdbarch_deprecated_function_start_offset (gdbarch); +- +-+ if (gdbarch_skip_entrypoint_p (gdbarch)) +-+ ecs->stop_func_start = gdbarch_skip_entrypoint (gdbarch, +-+ ecs->stop_func_start); +-+ +- ecs->stop_func_filled_in = 1; +- } +- } +---- a/gdb/ppc-linux-tdep.c +-+++ b/gdb/ppc-linux-tdep.c +-@@ -44,6 +44,7 @@ +- #include "observer.h" +- #include "auxv.h" +- #include "elf/common.h" +-+#include "elf/ppc64.h" +- #include "exceptions.h" +- #include "arch-utils.h" +- #include "spu-tdep.h" +-@@ -876,6 +877,43 @@ ppc_linux_core_read_description (struct +- } +- } +- +-+/* If the ELF symbol has a local entry point, use it as SYMBOL_VALUE_ADDRESS +-+ for the msymbol. This matches the DWARF function start if present. */ +-+ +-+static void +-+ppc_elfv2_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym) +-+{ +-+ elf_symbol_type *elf_sym = (elf_symbol_type *)sym; +-+ switch (PPC64_LOCAL_ENTRY_OFFSET (elf_sym->internal_elf_sym.st_other)) +-+ { +-+ default: +-+ break; +-+ case 8: +-+ MSYMBOL_TARGET_FLAG_1 (msym) = 1; +-+ break; +-+ } +-+} +-+ +-+static CORE_ADDR +-+ppc_elfv2_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR pc) +-+{ +-+ struct bound_minimal_symbol fun; +-+ int local_entry_offset = 0; +-+ +-+ fun = lookup_minimal_symbol_by_pc (pc); +-+ if (fun.minsym == NULL) +-+ return pc; +-+ +-+ if (MSYMBOL_TARGET_FLAG_1 (fun.minsym)) +-+ local_entry_offset = 8; +-+ +-+ if (SYMBOL_VALUE_ADDRESS (fun.minsym) <= pc +-+ && pc < SYMBOL_VALUE_ADDRESS (fun.minsym) + local_entry_offset) +-+ return SYMBOL_VALUE_ADDRESS (fun.minsym) + local_entry_offset; +-+ +-+ return pc; +-+} +-+ +- /* Implementation of `gdbarch_stap_is_single_operand', as defined in +- gdbarch.h. */ +- +-@@ -1332,13 +1370,23 @@ ppc_linux_init_abi (struct gdbarch_info +- +- if (tdep->wordsize == 8) +- { +-- /* Handle PPC GNU/Linux 64-bit function pointers (which are really +-- function descriptors). */ +-- set_gdbarch_convert_from_func_ptr_addr +-- (gdbarch, ppc64_convert_from_func_ptr_addr); +-+ if (tdep->elf_abi == POWERPC_ELF_V1) +-+ { +-+ /* Handle PPC GNU/Linux 64-bit function pointers (which are really +-+ function descriptors). */ +-+ set_gdbarch_convert_from_func_ptr_addr +-+ (gdbarch, ppc64_convert_from_func_ptr_addr); +- +-- set_gdbarch_elf_make_msymbol_special (gdbarch, +-- ppc64_elf_make_msymbol_special); +-+ set_gdbarch_elf_make_msymbol_special +-+ (gdbarch, ppc64_elf_make_msymbol_special); +-+ } +-+ else +-+ { +-+ set_gdbarch_elf_make_msymbol_special +-+ (gdbarch, ppc_elfv2_elf_make_msymbol_special); +-+ +-+ set_gdbarch_skip_entrypoint (gdbarch, ppc_elfv2_skip_entrypoint); +-+ } +- +- /* Shared library handling. */ +- set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code); +---- a/gdb/ppc-sysv-tdep.c +-+++ b/gdb/ppc-sysv-tdep.c +-@@ -610,42 +610,48 @@ ppc_sysv_abi_push_dummy_call (struct gdb +- } +- +- /* Handle the return-value conventions for Decimal Floating Point values +-- in both ppc32 and ppc64, which are the same. */ +--static int +-+ in both ppc32 and ppc64, which are the same. INDEX specifies which +-+ part of a multi-part return value is to be handled. */ +-+static void +- get_decimal_float_return_value (struct gdbarch *gdbarch, struct type *valtype, +- struct regcache *regcache, gdb_byte *readbuf, +-- const gdb_byte *writebuf) +-+ const gdb_byte *writebuf, int index) +- { +- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +-+ int offset = index * TYPE_LENGTH (valtype); +- +- gdb_assert (TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT); +- +- /* 32-bit and 64-bit decimal floats in f1. */ +- if (TYPE_LENGTH (valtype) <= 8) +- { +-+ int regnum = tdep->ppc_fp0_regnum + 1 + index; +-+ +- if (writebuf != NULL) +- { +- gdb_byte regval[MAX_REGISTER_SIZE]; +- const gdb_byte *p; +- +- /* 32-bit decimal float is right aligned in the doubleword. */ +-- if (TYPE_LENGTH (valtype) == 4) +-+ if (TYPE_LENGTH (valtype) == 4 +-+ && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) +- { +-- memcpy (regval + 4, writebuf, 4); +-+ memcpy (regval + 4, writebuf + offset, 4); +- p = regval; +- } +- else +-- p = writebuf; +-+ p = writebuf + offset; +- +-- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, p); +-+ regcache_cooked_write (regcache, regnum, p); +- } +- if (readbuf != NULL) +- { +-- regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, readbuf); +-+ regcache_cooked_read (regcache, regnum, readbuf); +- +- /* Left align 32-bit decimal float. */ +-- if (TYPE_LENGTH (valtype) == 4) +-- memcpy (readbuf, readbuf + 4, 4); +-+ if (TYPE_LENGTH (valtype) == 4 +-+ && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) +-+ memcpy (readbuf + offset, readbuf + offset + 4, 4); +- } +- } +- /* 128-bit decimal floats in f2,f3. */ +-@@ -653,24 +659,27 @@ get_decimal_float_return_value (struct g +- { +- if (writebuf != NULL || readbuf != NULL) +- { +-- int i; +-+ int i, regnum; +- +- for (i = 0; i < 2; i++) +- { +-+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) +-+ regnum = tdep->ppc_fp0_regnum + 2 + i + 2 * index; +-+ else +-+ regnum = tdep->ppc_fp0_regnum + 3 - i + 2 * index; +-+ +- if (writebuf != NULL) +-- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 2 + i, +-- writebuf + i * 8); +-+ regcache_cooked_write (regcache, regnum, +-+ writebuf + offset + i * 8); +- if (readbuf != NULL) +-- regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 2 + i, +-- readbuf + i * 8); +-+ regcache_cooked_read (regcache, regnum, +-+ readbuf + offset + i * 8); +- } +- } +- } +- else +- /* Can't happen. */ +- internal_error (__FILE__, __LINE__, _("Unknown decimal float size.")); +-- +-- return RETURN_VALUE_REGISTER_CONVENTION; +- } +- +- /* Handle the return-value conventions specified by the SysV 32-bit +-@@ -802,8 +811,11 @@ do_ppc_sysv_return_value (struct gdbarch +- return RETURN_VALUE_REGISTER_CONVENTION; +- } +- if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT && !tdep->soft_float) +-- return get_decimal_float_return_value (gdbarch, type, regcache, readbuf, +-- writebuf); +-+ { +-+ get_decimal_float_return_value (gdbarch, type, regcache, +-+ readbuf, writebuf, 0); +-+ return RETURN_VALUE_REGISTER_CONVENTION; +-+ } +- else if ((TYPE_CODE (type) == TYPE_CODE_INT +- || TYPE_CODE (type) == TYPE_CODE_CHAR +- || TYPE_CODE (type) == TYPE_CODE_BOOL +-@@ -1102,6 +1114,156 @@ convert_code_addr_to_desc_addr (CORE_ADD +- return 1; +- } +- +-+/* Walk down the type tree of TYPE counting consecutive base elements. +-+ If *FIELD_TYPE is NULL, then set it to the first valid floating point +-+ or vector type. If a non-floating point or vector type is found, or +-+ if a floating point or vector type that doesn't match a non-NULL +-+ *FIELD_TYPE is found, then return -1, otherwise return the count in the +-+ sub-tree. */ +-+ +-+static LONGEST +-+ppc64_aggregate_candidate (struct type *type, +-+ struct type **field_type) +-+{ +-+ type = check_typedef (type); +-+ +-+ switch (TYPE_CODE (type)) +-+ { +-+ case TYPE_CODE_FLT: +-+ case TYPE_CODE_DECFLOAT: +-+ if (!*field_type) +-+ *field_type = type; +-+ if (TYPE_CODE (*field_type) == TYPE_CODE (type) +-+ && TYPE_LENGTH (*field_type) == TYPE_LENGTH (type)) +-+ return 1; +-+ break; +-+ +-+ case TYPE_CODE_COMPLEX: +-+ type = TYPE_TARGET_TYPE (type); +-+ if (TYPE_CODE (type) == TYPE_CODE_FLT +-+ || TYPE_CODE (type) == TYPE_CODE_DECFLOAT) +-+ { +-+ if (!*field_type) +-+ *field_type = type; +-+ if (TYPE_CODE (*field_type) == TYPE_CODE (type) +-+ && TYPE_LENGTH (*field_type) == TYPE_LENGTH (type)) +-+ return 2; +-+ } +-+ break; +-+ +-+ case TYPE_CODE_ARRAY: +-+ if (TYPE_VECTOR (type)) +-+ { +-+ if (!*field_type) +-+ *field_type = type; +-+ if (TYPE_CODE (*field_type) == TYPE_CODE (type) +-+ && TYPE_LENGTH (*field_type) == TYPE_LENGTH (type)) +-+ return 1; +-+ } +-+ else +-+ { +-+ LONGEST count, low_bound, high_bound; +-+ +-+ count = ppc64_aggregate_candidate +-+ (TYPE_TARGET_TYPE (type), field_type); +-+ if (count == -1) +-+ return -1; +-+ +-+ if (!get_array_bounds (type, &low_bound, &high_bound)) +-+ return -1; +-+ count *= high_bound - low_bound; +-+ +-+ /* There must be no padding. */ +-+ if (count == 0) +-+ return TYPE_LENGTH (type) == 0 ? 0 : -1; +-+ else if (TYPE_LENGTH (type) != count * TYPE_LENGTH (*field_type)) +-+ return -1; +-+ +-+ return count; +-+ } +-+ break; +-+ +-+ case TYPE_CODE_STRUCT: +-+ case TYPE_CODE_UNION: +-+ { +-+ LONGEST count = 0; +-+ int i; +-+ +-+ for (i = 0; i < TYPE_NFIELDS (type); i++) +-+ { +-+ LONGEST sub_count; +-+ +-+ if (field_is_static (&TYPE_FIELD (type, i))) +-+ continue; +-+ +-+ sub_count = ppc64_aggregate_candidate +-+ (TYPE_FIELD_TYPE (type, i), field_type); +-+ if (sub_count == -1) +-+ return -1; +-+ +-+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT) +-+ count += sub_count; +-+ else +-+ count = max (count, sub_count); +-+ } +-+ +-+ /* There must be no padding. */ +-+ if (count == 0) +-+ return TYPE_LENGTH (type) == 0 ? 0 : -1; +-+ else if (TYPE_LENGTH (type) != count * TYPE_LENGTH (*field_type)) +-+ return -1; +-+ +-+ return count; +-+ } +-+ break; +-+ +-+ default: +-+ break; +-+ } +-+ +-+ return -1; +-+} +-+ +-+/* If an argument of type TYPE is a homogeneous float or vector aggregate +-+ that shall be passed in FP/vector registers according to the ELFv2 ABI, +-+ return the homogeneous element type in *ELT_TYPE and the number of +-+ elements in *N_ELTS, and return non-zero. Otherwise, return zero. */ +-+ +-+static int +-+ppc64_elfv2_abi_homogeneous_aggregate (struct type *type, +-+ struct type **elt_type, int *n_elts) +-+{ +-+ /* Complex types at the top level are treated separately. However, +-+ complex types can be elements of homogeneous aggregates. */ +-+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT +-+ || TYPE_CODE (type) == TYPE_CODE_UNION +-+ || (TYPE_CODE (type) == TYPE_CODE_ARRAY && !TYPE_VECTOR (type))) +-+ { +-+ struct type *field_type = NULL; +-+ LONGEST field_count = ppc64_aggregate_candidate (type, &field_type); +-+ +-+ if (field_count > 0) +-+ { +-+ int n_regs = ((TYPE_CODE (field_type) == TYPE_CODE_FLT +-+ || TYPE_CODE (field_type) == TYPE_CODE_DECFLOAT)? +-+ (TYPE_LENGTH (field_type) + 7) >> 3 : 1); +-+ +-+ /* The ELFv2 ABI allows homogeneous aggregates to occupy +-+ up to 8 registers. */ +-+ if (field_count * n_regs <= 8) +-+ { +-+ if (elt_type) +-+ *elt_type = field_type; +-+ if (n_elts) +-+ *n_elts = (int) field_count; +-+ return 1; +-+ } +-+ } +-+ } +-+ +-+ return 0; +-+} +-+ +- /* Push a float in either registers, or in the stack. Using the ppc 64 bit +- SysV ABI. +- +-@@ -1143,6 +1305,8 @@ ppc64_sysv_abi_push_float (struct gdbarc +- +- /* Write value in the stack's parameter save area. */ +- write_memory (gparam, p, 8); +-+ if (greg <= 10) +-+ regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, p); +- +- /* Floats and Doubles go in f1 .. f13. They also consume a left aligned +- GREG, and can end up in memory. */ +-@@ -1154,8 +1318,6 @@ ppc64_sysv_abi_push_float (struct gdbarc +- convert_typed_floating (val, type, regval, regtype); +- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg, regval); +- } +-- if (greg <= 10) +-- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, regval); +- } +- else +- { +-@@ -1268,9 +1430,13 @@ ppc64_sysv_abi_push_dummy_call (struct g +- to their corresponding regions. */ +- refparam = align_down (sp - refparam_size, 16); +- gparam = align_down (refparam - gparam_size, 16); +-- /* Add in space for the TOC, link editor double word, +-- compiler double word, LR save area, CR save area. */ +-- sp = align_down (gparam - 48, 16); +-+ /* Add in space for the TOC, link editor double word (v1 only), +-+ compiler double word (v1 only), LR save area, CR save area, +-+ and backchain. */ +-+ if (tdep->elf_abi == POWERPC_ELF_V1) +-+ sp = align_down (gparam - 48, 16); +-+ else +-+ sp = align_down (gparam - 32, 16); +- } +- +- /* If the function is returning a `struct', then there is an +-@@ -1375,7 +1541,8 @@ ppc64_sysv_abi_push_dummy_call (struct g +- +- /* 32-bit decimal floats are right aligned in the +- doubleword. */ +-- if (TYPE_LENGTH (type) == 4) +-+ if (TYPE_LENGTH (type) == 4 +-+ && byte_order == BFD_ENDIAN_BIG) +- { +- memcpy (regval + 4, val, 4); +- p = regval; +-@@ -1407,10 +1574,21 @@ ppc64_sysv_abi_push_dummy_call (struct g +- { +- /* Make sure freg is even. */ +- freg += freg & 1; +-- regcache_cooked_write (regcache, +-- tdep->ppc_fp0_regnum + freg, val); +-- regcache_cooked_write (regcache, +-- tdep->ppc_fp0_regnum + freg + 1, val + 8); +-+ +-+ if (byte_order == BFD_ENDIAN_BIG) +-+ { +-+ regcache_cooked_write (regcache, +-+ tdep->ppc_fp0_regnum + freg, val); +-+ regcache_cooked_write (regcache, +-+ tdep->ppc_fp0_regnum + freg + 1, val + 8); +-+ } +-+ else +-+ { +-+ regcache_cooked_write (regcache, +-+ tdep->ppc_fp0_regnum + freg + 1, val); +-+ regcache_cooked_write (regcache, +-+ tdep->ppc_fp0_regnum + freg, val + 8); +-+ } +- } +- +- write_memory (gparam, val, TYPE_LENGTH (type)); +-@@ -1587,8 +1765,9 @@ ppc64_sysv_abi_push_dummy_call (struct g +- ULONGEST word = unpack_long (type, val); +- /* Convert any function code addresses into +- descriptors. */ +-- if (TYPE_CODE (type) == TYPE_CODE_PTR +-- || TYPE_CODE (type) == TYPE_CODE_REF) +-+ if (tdep->elf_abi == POWERPC_ELF_V1 +-+ && (TYPE_CODE (type) == TYPE_CODE_PTR +-+ || TYPE_CODE (type) == TYPE_CODE_REF)) +- { +- struct type *target_type; +- target_type = check_typedef (TYPE_TARGET_TYPE (type)); +-@@ -1613,6 +1792,9 @@ ppc64_sysv_abi_push_dummy_call (struct g +- } +- else +- { +-+ struct type *elt_type; +-+ int n_elts; +-+ +- int byte; +- for (byte = 0; byte < TYPE_LENGTH (type); +- byte += tdep->wordsize) +-@@ -1630,7 +1812,7 @@ ppc64_sysv_abi_push_dummy_call (struct g +- versions before 3.4 implemented this +- incorrectly; see +- . */ +-- if (byte == 0) +-+ if (byte_order == BFD_ENDIAN_BIG && byte == 0) +- memcpy (regval + tdep->wordsize - len, +- val + byte, len); +- else +-@@ -1649,7 +1831,7 @@ ppc64_sysv_abi_push_dummy_call (struct g +- value to memory. Fortunately, doing this +- simplifies the code. */ +- int len = TYPE_LENGTH (type); +-- if (len < tdep->wordsize) +-+ if (byte_order == BFD_ENDIAN_BIG && len < tdep->wordsize) +- write_memory (gparam + tdep->wordsize - len, val, len); +- else +- write_memory (gparam, val, len); +-@@ -1705,6 +1887,132 @@ ppc64_sysv_abi_push_dummy_call (struct g +- } +- } +- } +-+ /* In the ELFv2 ABI, homogeneous floating-point or vector +-+ aggregates are passed in registers. */ +-+ if (tdep->elf_abi == POWERPC_ELF_V2 +-+ && ppc64_elfv2_abi_homogeneous_aggregate (type, +-+ &elt_type, &n_elts)) +-+ { +-+ int i; +-+ for (i = 0; i < n_elts; i++) +-+ { +-+ const gdb_byte *elt_val +-+ = val + i * TYPE_LENGTH (elt_type); +-+ +-+ switch (TYPE_CODE (elt_type)) +-+ { +-+ case TYPE_CODE_FLT: +-+ if (TYPE_LENGTH (elt_type) <= 8) +-+ { +-+ if (write_pass && freg <= 13) +-+ { +-+ int fregnum = tdep->ppc_fp0_regnum + freg; +-+ gdb_byte regval[MAX_REGISTER_SIZE]; +-+ struct type *regtype +-+ = register_type (gdbarch, fregnum); +-+ convert_typed_floating (elt_val, elt_type, +-+ regval, regtype); +-+ regcache_cooked_write (regcache, +-+ fregnum, regval); +-+ } +-+ freg++; +-+ } +-+ else if (TYPE_LENGTH (elt_type) == 16 +-+ && (gdbarch_long_double_format (gdbarch) +-+ == floatformats_ibm_long_double)) +-+ { +-+ if (write_pass && freg <= 13) +-+ { +-+ int fregnum = tdep->ppc_fp0_regnum + freg; +-+ regcache_cooked_write (regcache, +-+ fregnum, elt_val); +-+ if (freg <= 12) +-+ regcache_cooked_write (regcache, +-+ fregnum + 1, +-+ elt_val + 8); +-+ } +-+ freg += 2; +-+ } +-+ break; +-+ +-+ case TYPE_CODE_DECFLOAT: +-+ if (TYPE_LENGTH (elt_type) <= 8) +-+ { +-+ if (write_pass && freg <= 13) +-+ { +-+ int fregnum = tdep->ppc_fp0_regnum + freg; +-+ gdb_byte regval[MAX_REGISTER_SIZE]; +-+ const gdb_byte *p; +-+ +-+ /* 32-bit decimal floats are right aligned +-+ in the doubleword. */ +-+ if (TYPE_LENGTH (elt_type) == 4 +-+ && byte_order == BFD_ENDIAN_BIG) +-+ { +-+ memcpy (regval + 4, elt_val, 4); +-+ p = regval; +-+ } +-+ else +-+ p = elt_val; +-+ +-+ regcache_cooked_write (regcache, fregnum, p); +-+ } +-+ freg++; +-+ } +-+ else if (TYPE_LENGTH (elt_type) == 16) +-+ { +-+ /* Make sure freg is even. */ +-+ freg += freg & 1; +-+ +-+ if (write_pass && freg <= 12) +-+ { +-+ int fregnum = tdep->ppc_fp0_regnum + freg; +-+ if (byte_order == BFD_ENDIAN_BIG) +-+ { +-+ regcache_cooked_write (regcache, +-+ fregnum, +-+ elt_val); +-+ regcache_cooked_write (regcache, +-+ fregnum + 1, +-+ elt_val + 8); +-+ } +-+ else +-+ { +-+ regcache_cooked_write (regcache, +-+ fregnum + 1, +-+ elt_val); +-+ regcache_cooked_write (regcache, +-+ fregnum, +-+ elt_val + 8); +-+ } +-+ } +-+ freg += 2; +-+ } +-+ break; +-+ +-+ case TYPE_CODE_ARRAY: +-+ gdb_assert (TYPE_VECTOR (type)); +-+ +-+ if (tdep->vector_abi == POWERPC_VEC_ALTIVEC +-+ && TYPE_LENGTH (elt_type) == 16) +-+ { +-+ if (write_pass && vreg <= 13) +-+ { +-+ int vregnum = tdep->ppc_vr0_regnum + vreg; +-+ regcache_cooked_write (regcache, +-+ vregnum, elt_val); +-+ } +-+ vreg++; +-+ } +-+ break; +-+ +-+ default: +-+ internal_error (__FILE__, __LINE__, +-+ _("Unknown element type.")); +-+ break; +-+ } +-+ } +-+ } +- /* Always consume parameter stack space. */ +- gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize); +- } +-@@ -1733,24 +2041,31 @@ ppc64_sysv_abi_push_dummy_call (struct g +- breakpoint. */ +- regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr); +- +-- /* Use the func_addr to find the descriptor, and use that to find +-- the TOC. If we're calling via a function pointer, the pointer +-- itself identifies the descriptor. */ +-- { +-- struct type *ftype = check_typedef (value_type (function)); +-- CORE_ADDR desc_addr = value_as_address (function); +-- +-- if (TYPE_CODE (ftype) == TYPE_CODE_PTR +-- || convert_code_addr_to_desc_addr (func_addr, &desc_addr)) +-- { +-- /* The TOC is the second double word in the descriptor. */ +-- CORE_ADDR toc = +-- read_memory_unsigned_integer (desc_addr + tdep->wordsize, +-- tdep->wordsize, byte_order); +-- regcache_cooked_write_unsigned (regcache, +-- tdep->ppc_gp0_regnum + 2, toc); +-- } +-- } +-+ /* In the ELFv1 ABI, use the func_addr to find the descriptor, and use +-+ that to find the TOC. If we're calling via a function pointer, +-+ the pointer itself identifies the descriptor. */ +-+ if (tdep->elf_abi == POWERPC_ELF_V1) +-+ { +-+ struct type *ftype = check_typedef (value_type (function)); +-+ CORE_ADDR desc_addr = value_as_address (function); +-+ +-+ if (TYPE_CODE (ftype) == TYPE_CODE_PTR +-+ || convert_code_addr_to_desc_addr (func_addr, &desc_addr)) +-+ { +-+ /* The TOC is the second double word in the descriptor. */ +-+ CORE_ADDR toc = +-+ read_memory_unsigned_integer (desc_addr + tdep->wordsize, +-+ tdep->wordsize, byte_order); +-+ regcache_cooked_write_unsigned (regcache, +-+ tdep->ppc_gp0_regnum + 2, toc); +-+ } +-+ } +-+ +-+ /* In the ELFv2 ABI, we need to pass the target address in r12 since +-+ we may be calling a global entry point. */ +-+ if (tdep->elf_abi == POWERPC_ELF_V2) +-+ regcache_cooked_write_unsigned (regcache, +-+ tdep->ppc_gp0_regnum + 12, func_addr); +- +- return sp; +- } +-@@ -1775,6 +2090,8 @@ ppc64_sysv_abi_return_value (struct gdba +- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); +- struct type *func_type = function ? value_type (function) : NULL; +- int opencl_abi = func_type? ppc_sysv_use_opencl_abi (func_type) : 0; +-+ struct type *elt_type; +-+ int n_elts; +- +- /* This function exists to support a calling convention that +- requires floating-point registers. It shouldn't be used on +-@@ -1799,8 +2116,11 @@ ppc64_sysv_abi_return_value (struct gdba +- return RETURN_VALUE_REGISTER_CONVENTION; +- } +- if (TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT) +-- return get_decimal_float_return_value (gdbarch, valtype, regcache, readbuf, +-- writebuf); +-+ { +-+ get_decimal_float_return_value (gdbarch, valtype, regcache, +-+ readbuf, writebuf, 0); +-+ return RETURN_VALUE_REGISTER_CONVENTION; +-+ } +- /* Integers in r3. */ +- if ((TYPE_CODE (valtype) == TYPE_CODE_INT +- || TYPE_CODE (valtype) == TYPE_CODE_ENUM +-@@ -2019,6 +2339,114 @@ ppc64_sysv_abi_return_value (struct gdba +- } +- } +- return RETURN_VALUE_REGISTER_CONVENTION; +-+ } +-+ /* In the ELFv2 ABI, homogeneous floating-point or vector +-+ aggregates are returned in registers. */ +-+ if (tdep->elf_abi == POWERPC_ELF_V2 +-+ && ppc64_elfv2_abi_homogeneous_aggregate (valtype, &elt_type, &n_elts)) +-+ { +-+ int i; +-+ for (i = 0; i < n_elts; i++) +-+ { +-+ int offset = i * TYPE_LENGTH (elt_type); +-+ +-+ switch (TYPE_CODE (elt_type)) +-+ { +-+ case TYPE_CODE_FLT: +-+ if (TYPE_LENGTH (elt_type) <= 8) +-+ { +-+ int regnum = tdep->ppc_fp0_regnum + 1 + i; +-+ gdb_byte regval[MAX_REGISTER_SIZE]; +-+ struct type *regtype = register_type (gdbarch, regnum); +-+ if (writebuf != NULL) +-+ { +-+ convert_typed_floating (writebuf + offset, elt_type, +-+ regval, regtype); +-+ regcache_cooked_write (regcache, regnum, regval); +-+ } +-+ if (readbuf != NULL) +-+ { +-+ regcache_cooked_read (regcache, regnum, regval); +-+ convert_typed_floating (regval, regtype, +-+ readbuf + offset, elt_type); +-+ } +-+ } +-+ else +-+ { +-+ int j, nregs = (TYPE_LENGTH (elt_type) + 7) / 8; +-+ for (j = 0; j < nregs; j++) +-+ { +-+ int regnum = tdep->ppc_fp0_regnum + 1 + nregs * i + j; +-+ +-+ if (writebuf != NULL) +-+ regcache_cooked_write (regcache, regnum, +-+ writebuf + offset + j * 8); +-+ if (readbuf != NULL) +-+ regcache_cooked_read (regcache, regnum, +-+ readbuf + offset + j * 8); +-+ } +-+ } +-+ break; +-+ +-+ case TYPE_CODE_DECFLOAT: +-+ get_decimal_float_return_value (gdbarch, elt_type, regcache, +-+ readbuf, writebuf, i); +-+ break; +-+ +-+ case TYPE_CODE_ARRAY: +-+ { +-+ int regnum = tdep->ppc_vr0_regnum + 2 + i; +-+ gdb_assert (TYPE_VECTOR (elt_type)); +-+ +-+ if (writebuf != NULL) +-+ regcache_cooked_write (regcache, regnum, writebuf + offset); +-+ if (readbuf != NULL) +-+ regcache_cooked_read (regcache, regnum, readbuf + offset); +-+ } +-+ break; +-+ } +-+ } +-+ return RETURN_VALUE_REGISTER_CONVENTION; +-+ } +-+ /* In the ELFv2 ABI, aggregate types of up to 16 bytes are +-+ returned in registers r3:r4. */ +-+ if (tdep->elf_abi == POWERPC_ELF_V2 +-+ && TYPE_LENGTH (valtype) <= 16 +-+ && (TYPE_CODE (valtype) == TYPE_CODE_STRUCT +-+ || TYPE_CODE (valtype) == TYPE_CODE_UNION +-+ || (TYPE_CODE (valtype) == TYPE_CODE_ARRAY && !TYPE_VECTOR (valtype)))) +-+ { +-+ int n_regs = (TYPE_LENGTH (valtype) + tdep->wordsize - 1) / tdep->wordsize; +-+ int i; +-+ +-+ for (i = 0; i < n_regs; i++) +-+ { +-+ gdb_byte regval[MAX_REGISTER_SIZE]; +-+ int regnum = tdep->ppc_gp0_regnum + 3 + i; +-+ int offset = i * tdep->wordsize; +-+ int len = TYPE_LENGTH (valtype) - offset; +-+ if (len > tdep->wordsize) +-+ len = tdep->wordsize; +-+ +-+ if (writebuf != NULL) +-+ { +-+ memset (regval, 0, sizeof regval); +-+ if (byte_order == BFD_ENDIAN_BIG && offset == 0) +-+ memcpy (regval + tdep->wordsize - len, writebuf, len); +-+ else +-+ memcpy (regval, writebuf + offset, len); +-+ regcache_cooked_write (regcache, regnum, regval); +-+ } +-+ if (readbuf != NULL) +-+ { +-+ regcache_cooked_read (regcache, regnum, regval); +-+ if (byte_order == BFD_ENDIAN_BIG && offset == 0) +-+ memcpy (readbuf, regval + tdep->wordsize - len, len); +-+ else +-+ memcpy (readbuf + offset, regval, len); +-+ } +-+ } +-+ return RETURN_VALUE_REGISTER_CONVENTION; +- } +- return RETURN_VALUE_STRUCT_CONVENTION; +- } +---- a/gdb/ppc-tdep.h +-+++ b/gdb/ppc-tdep.h +-@@ -182,6 +182,15 @@ extern void ppc_collect_vsxregset (const +- +- /* Private data that this module attaches to struct gdbarch. */ +- +-+/* ELF ABI version used by the inferior. */ +-+enum powerpc_elf_abi +-+{ +-+ POWERPC_ELF_AUTO, +-+ POWERPC_ELF_V1, +-+ POWERPC_ELF_V2, +-+ POWERPC_ELF_LAST +-+}; +-+ +- /* Vector ABI used by the inferior. */ +- enum powerpc_vector_abi +- { +-@@ -197,6 +206,8 @@ struct gdbarch_tdep +- int wordsize; /* Size in bytes of fixed-point word. */ +- int soft_float; /* Avoid FP registers for arguments? */ +- +-+ enum powerpc_elf_abi elf_abi; /* ELF ABI version. */ +-+ +- /* How to pass vector arguments. Never set to AUTO or LAST. */ +- enum powerpc_vector_abi vector_abi; +- +---- a/gdb/symtab.c +-+++ b/gdb/symtab.c +-@@ -2881,6 +2881,8 @@ skip_prologue_sal (struct symtab_and_lin +- +- /* Skip "first line" of function (which is actually its prologue). */ +- pc += gdbarch_deprecated_function_start_offset (gdbarch); +-+ if (gdbarch_skip_entrypoint_p (gdbarch)) +-+ pc = gdbarch_skip_entrypoint (gdbarch, pc); +- if (skip) +- pc = gdbarch_skip_prologue (gdbarch, pc); +- +---- a/gdb/testsuite/gdb.arch/altivec-regs.exp +-+++ b/gdb/testsuite/gdb.arch/altivec-regs.exp +-@@ -118,7 +118,7 @@ gdb_test "info reg vscr" "vscr.*0x1\t1" +- if {$endianness == "big"} { +- set decimal_vector ".uint128 = 0x00000001000000010000000100000001, v4_float = .1.*e-45, 1.*e-45, 1.*e-45, 1.*e-45., v4_int32 = .1, 1, 1, 1., v8_int16 = .0, 1, 0, 1, 0, 1, 0, 1., v16_int8 = .0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1.." +- } else { +-- set decimal_vector ".uint128 = 0x00000001000000010000000100000001, v4_float = .1.*e-45, 1.*e-45, 1.*e-45, 1.*e-45., v4_int32 = .1, 1, 1, 1., v8_int16 = .1, 0, 1, 0, 1, 0, 1, 0., v16_int8 = .1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.." +-+ set decimal_vector ".uint128 = 0x00000001000000010000000100000001, v4_float = .1.*e-45, 1.*e-45, 1.*e-45, 1.*e-45., v4_int32 = .1, 1, 1, 1., v8_int16 = .1, 0, 1, 0, 1, 0, 1, 0., v16_int8 = .1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.." +- } +- +- for {set i 0} {$i < 32} {incr i 1} { +---- a/gdb/testsuite/gdb.arch/powerpc-d128-regs.exp +-+++ b/gdb/testsuite/gdb.arch/powerpc-d128-regs.exp +-@@ -20,7 +20,7 @@ +- +- # Testcase for ppc decimal128 pseudo-registers. +- +--if ![istarget "powerpc64-*"] then { +-+if ![istarget "powerpc64*-*"] then { +- verbose "Skipping powerpc Decimal128 pseudo-registers testcase." +- return +- } +---- a/gdb/testsuite/gdb.arch/vsx-regs.exp +-+++ b/gdb/testsuite/gdb.arch/vsx-regs.exp +-@@ -58,19 +58,46 @@ if ![runto_main] then { +- gdb_suppress_tests +- } +- +-+send_gdb "show endian\n" +-+set endianness "" +-+gdb_expect { +-+ -re "(The target endianness is set automatically .currently )(big|little)( endian.*)$gdb_prompt $" { +-+ pass "endianness" +-+ set endianness $expect_out(2,string) +-+ } +-+ -re ".*$gdb_prompt $" { +-+ fail "couldn't get endianness" +-+ } +-+ timeout { fail "(timeout) endianness" } +-+} +-+ +- # Data sets used throughout the test +- +--set vector_register1 ".uint128 = 0x3ff4cccccccccccc0000000000000000, v2_double = .0x1, 0x0., v4_float = .0x1, 0xf99999a0, 0x0, 0x0., v4_int32 = .0x3ff4cccc, 0xcccccccc, 0x0, 0x0., v8_int16 = .0x3ff4, 0xcccc, 0xcccc, 0xcccc, 0x0, 0x0, 0x0, 0x0., v16_int8 = .0x3f, 0xf4, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0.." +-+if {$endianness == "big"} { +-+ set vector_register1 ".uint128 = 0x3ff4cccccccccccc0000000000000000, v2_double = .0x1, 0x0., v4_float = .0x1, 0xf99999a0, 0x0, 0x0., v4_int32 = .0x3ff4cccc, 0xcccccccc, 0x0, 0x0., v8_int16 = .0x3ff4, 0xcccc, 0xcccc, 0xcccc, 0x0, 0x0, 0x0, 0x0., v16_int8 = .0x3f, 0xf4, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0.." +-+ +-+ set vector_register1_vr ".uint128 = 0x3ff4cccccccccccc0000000100000001, v4_float = .0x1, 0xf99999a0, 0x0, 0x0., v4_int32 = .0x3ff4cccc, 0xcccccccc, 0x1, 0x1., v8_int16 = .0x3ff4, 0xcccc, 0xcccc, 0xcccc, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x3f, 0xf4, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.." +-+ +-+ set vector_register2 "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v2_double = .0x1, 0x1., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef., v16_int8 = .0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef.." +- +--set vector_register1_vr ".uint128 = 0x3ff4cccccccccccc0000000100000001, v4_float = .0x1, 0xf99999a0, 0x0, 0x0., v4_int32 = .0x3ff4cccc, 0xcccccccc, 0x1, 0x1., v8_int16 = .0x3ff4, 0xcccc, 0xcccc, 0xcccc, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x3f, 0xf4, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.." +-+ set vector_register2_vr "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef., v16_int8 = .0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef.." +- +--set vector_register2 "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v2_double = .0x1, 0x1., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef., v16_int8 = .0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef.." +-+ set vector_register3 ".uint128 = 0x00000001000000010000000100000001, v2_double = .0x0, 0x0., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.." +- +--set vector_register2_vr "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef., v16_int8 = .0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef.." +-+ set vector_register3_vr ".uint128 = 0x00000001000000010000000100000001, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.." +-+} else { +-+ set vector_register1 ".uint128 = 0x3ff4cccccccccccc0000000000000000, v2_double = .0x0, 0x1., v4_float = .0x0, 0x0, 0xf99999a0, 0x1., v4_int32 = .0x0, 0x0, 0xcccccccc, 0x3ff4cccc., v8_int16 = .0x0, 0x0, 0x0, 0x0, 0xcccc, 0xcccc, 0xcccc, 0x3ff4., v16_int8 = .0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xf4, 0x3f.." +- +--set vector_register3 ".uint128 = 0x00000001000000010000000100000001, v2_double = .0x0, 0x0., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.." +-+ set vector_register1_vr ".uint128 = 0x3ff4cccccccccccc0000000100000001, v4_float = .0x0, 0x0, 0xf99999a0, 0x1., v4_int32 = .0x1, 0x1, 0xcccccccc, 0x3ff4cccc., v8_int16 = .0x1, 0x0, 0x1, 0x0, 0xcccc, 0xcccc, 0xcccc, 0x3ff4., v16_int8 = .0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xf4, 0x3f.." +- +--set vector_register3_vr ".uint128 = 0x00000001000000010000000100000001, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.." +-+ set vector_register2 "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v2_double = .0x1, 0x1., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead., v16_int8 = .0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde.." +-+ +-+ set vector_register2_vr "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead., v16_int8 = .0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde.." +-+ +-+ set vector_register3 ".uint128 = 0x00000001000000010000000100000001, v2_double = .0x0, 0x0., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0., v16_int8 = .0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0.." +-+ +-+ set vector_register3_vr ".uint128 = 0x00000001000000010000000100000001, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0., v16_int8 = .0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0.." +-+} +- +- set float_register ".raw 0xdeadbeefdeadbeef." +- +---- a/gdb/testsuite/gdb.base/sigbpt.exp +-+++ b/gdb/testsuite/gdb.base/sigbpt.exp +-@@ -82,7 +82,7 @@ gdb_test "break keeper" +- set bowler_addrs bowler +- set segv_addr none +- gdb_test {display/i $pc} +--gdb_test "advance *bowler" "bowler.*" "advance to the bowler" +-+gdb_test "advance bowler" "bowler.*" "advance to the bowler" +- set test "stepping to fault" +- set signame "SIGSEGV" +- gdb_test_multiple "stepi" "$test" { +---- a/gdb/testsuite/gdb.base/step-bt.exp +-+++ b/gdb/testsuite/gdb.base/step-bt.exp +-@@ -32,7 +32,7 @@ gdb_start +- gdb_reinitialize_dir $srcdir/$subdir +- gdb_load ${binfile} +- +--gdb_test "break *hello" \ +-+gdb_test "break hello" \ +- "Breakpoint.*at.* file .*$srcfile, line .*" \ +- "breakpoint at first instruction of hello()" +- +---- a/include/elf/common.h +-+++ b/include/elf/common.h +-@@ -954,6 +954,7 @@ +- #define AT_BASE_PLATFORM 24 /* String identifying real platform, +- may differ from AT_PLATFORM. */ +- #define AT_RANDOM 25 /* Address of 16 random bytes. */ +-+#define AT_HWCAP2 26 /* Extension of AT_HWCAP. */ +- #define AT_EXECFN 31 /* Filename of executable. */ +- /* Pointer to the global system page used for system calls and other +- nice things. */ +---- a/include/elf/ppc64.h +-+++ b/include/elf/ppc64.h +-@@ -164,6 +164,60 @@ END_RELOC_NUMBERS (R_PPC64_max) +- #define IS_PPC64_TLS_RELOC(R) \ +- ((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA) +- +-+ +-+/* e_flags bits specifying ABI. +-+ 1 for original function descriptor using ABI, +-+ 2 for revised ABI without function descriptors, +-+ 0 for unspecified or not using any features affected by the differences. */ +-+#define EF_PPC64_ABI 3 +-+ +-+/* The ELFv2 ABI uses three bits in the symbol st_other field of a +-+ function definition to specify the number of instructions between a +-+ function's global entry point and local entry point. +-+ The global entry point is used when it is necessary to set up the +-+ toc pointer (r2) for the function. Callers must enter the global +-+ entry point with r12 set to the global entry point address. On +-+ return from the function, r2 may have a different value to that +-+ which it had on entry. +-+ The local entry point is used when r2 is known to already be valid +-+ for the function. There is no requirement on r12 when using the +-+ local entry point, and on return r2 will contain the same value as +-+ at entry. +-+ A value of zero in these bits means that the function has a single +-+ entry point with no requirement on r12 or r2, and that on return r2 +-+ will contain the same value as at entry. +-+ Values of one and seven are reserved. */ +-+#define STO_PPC64_LOCAL_BIT 5 +-+#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT) +-+ +-+// 3 bit other field to bytes. +-+static inline unsigned int +-+ppc64_decode_local_entry(unsigned int other) +-+{ +-+ return ((1 << other) >> 2) << 2; +-+} +-+ +-+// bytes to field value. +-+static inline unsigned int +-+ppc64_encode_local_entry(unsigned int val) +-+{ +-+ return (val >= 4 * 4 +-+ ? (val >= 8 * 4 +-+ ? (val >= 16 * 4 ? 6 : 5) +-+ : 4) +-+ : (val >= 2 * 4 +-+ ? 3 +-+ : (val >= 1 * 4 ? 2 : 0))); +-+} +-+ +-+/* st_other to number of bytes. */ +-+#define PPC64_LOCAL_ENTRY_OFFSET(other) \ +-+ ppc64_decode_local_entry (((other) & STO_PPC64_LOCAL_MASK) \ +-+ >> STO_PPC64_LOCAL_BIT) +-+/* number of bytes to st_other. */ +-+#define PPC64_SET_LOCAL_ENTRY_OFFSET(val) \ +-+ ppc64_encode_local_entry (val) << STO_PPC64_LOCAL_BIT +-+ +- /* Specify the start of the .glink section. */ +- #define DT_PPC64_GLINK DT_LOPROC +- +diff -Nur crash-7.3.0-orig/gdb-7.6-proc_service.h.patch crash-7.3.0/gdb-7.6-proc_service.h.patch +--- crash-7.3.0-orig/gdb-7.6-proc_service.h.patch 2023-07-07 14:06:14.165365910 +0800 ++++ crash-7.3.0/gdb-7.6-proc_service.h.patch 1970-01-01 08:00:00.000000000 +0800 +@@ -1,67 +0,0 @@ +---- gdb-7.6/gdb/gdb_proc_service.h.orig +-+++ gdb-7.6/gdb/gdb_proc_service.h +-@@ -115,7 +115,7 @@ extern pid_t ps_getpid (struct ps_procha +- /* Fetch the special per-thread address associated with the given LWP. +- This call is only used on a few platforms (most use a normal register). +- The meaning of the `int' parameter is machine-dependent. */ +--extern ps_err_e ps_get_thread_area (const struct ps_prochandle *, +-+extern ps_err_e ps_get_thread_area (struct ps_prochandle *, +- lwpid_t, int, psaddr_t *); +- +- +---- gdb-7.6/gdb/amd64-linux-nat.c.orig +-+++ gdb-7.6/gdb/amd64-linux-nat.c +-@@ -493,7 +493,7 @@ amd64_linux_new_fork (struct lwp_info *p +- a request for a thread's local storage address. */ +- +- ps_err_e +--ps_get_thread_area (const struct ps_prochandle *ph, +-+ps_get_thread_area (struct ps_prochandle *ph, +- lwpid_t lwpid, int idx, void **base) +- { +- if (gdbarch_bfd_arch_info (target_gdbarch ())->bits_per_word == 32) +---- gdb-7.6/gdb/aarch64-linux-nat.c.orig +-+++ gdb-7.6/gdb/aarch64-linux-nat.c +-@@ -750,7 +750,7 @@ aarch64_linux_new_fork (struct lwp_info +- storage (or its descriptor). */ +- +- ps_err_e +--ps_get_thread_area (const struct ps_prochandle *ph, +-+ps_get_thread_area (struct ps_prochandle *ph, +- lwpid_t lwpid, int idx, void **base) +- { +- struct iovec iovec; +---- gdb-7.6/gdb/arm-linux-nat.c.orig +-+++ gdb-7.6/gdb/arm-linux-nat.c +-@@ -613,7 +613,7 @@ supply_fpregset (struct regcache *regcac +- /* Fetch the thread-local storage pointer for libthread_db. */ +- +- ps_err_e +--ps_get_thread_area (const struct ps_prochandle *ph, +-+ps_get_thread_area (struct ps_prochandle *ph, +- lwpid_t lwpid, int idx, void **base) +- { +- if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) +---- gdb-7.6/gdb/i386-linux-nat.c.orig +-+++ gdb-7.6/gdb/i386-linux-nat.c +-@@ -849,7 +849,7 @@ i386_linux_new_fork (struct lwp_info *pa +- storage (or its descriptor). */ +- +- ps_err_e +--ps_get_thread_area (const struct ps_prochandle *ph, +-+ps_get_thread_area (struct ps_prochandle *ph, +- lwpid_t lwpid, int idx, void **base) +- { +- /* NOTE: cagney/2003-08-26: The definition of this buffer is found +---- gdb-7.6/gdb/mips-linux-nat.c.orig +-+++ gdb-7.6/gdb/mips-linux-nat.c +-@@ -154,7 +154,7 @@ mips64_linux_register_addr (struct gdbarch *gdbarch, int regno, int store) +- /* Fetch the thread-local storage pointer for libthread_db. */ +- +- ps_err_e +--ps_get_thread_area (const struct ps_prochandle *ph, +-+ps_get_thread_area (struct ps_prochandle *ph, +- lwpid_t lwpid, int idx, void **base) +- { +- if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) +- +diff -Nur crash-7.3.0-orig/gdb_interface.c crash-7.3.0/gdb_interface.c +--- crash-7.3.0-orig/gdb_interface.c 2023-07-07 14:06:14.165365910 +0800 ++++ crash-7.3.0/gdb_interface.c 2023-07-07 14:08:31.282076300 +0800 +@@ -17,18 +17,21 @@ + + #include "defs.h" + ++#ifndef GDB_10_2 + static void exit_after_gdb_info(void); ++#endif + static int is_restricted_command(char *, ulong); + static void strip_redirection(char *); + int get_frame_offset(ulong); + + int *gdb_output_format; + unsigned int *gdb_print_max; +-int *gdb_prettyprint_structs; +-int *gdb_prettyprint_arrays; +-int *gdb_repeat_count_threshold; +-int *gdb_stop_print_at_null; ++unsigned char *gdb_prettyprint_structs; ++unsigned char *gdb_prettyprint_arrays; ++unsigned int *gdb_repeat_count_threshold; ++unsigned char *gdb_stop_print_at_null; + unsigned int *gdb_output_radix; ++static void gdb_error_debug(void); + + static ulong gdb_user_print_option_address(char *); + +@@ -68,11 +71,13 @@ + } + + optind = 0; ++#ifndef GDB_10_2 + #if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) + command_loop_hook = main_loop; + #else + deprecated_command_loop_hook = main_loop; + #endif ++#endif + gdb_main_entry(argc, argv); + } + +@@ -117,22 +122,26 @@ + display_gdb_banner(void) + { + optind = 0; ++#ifndef GDB_10_2 + #if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) + command_loop_hook = exit_after_gdb_info; + #else + deprecated_command_loop_hook = exit_after_gdb_info; + #endif ++#endif + args[0] = "gdb"; + args[1] = "-version"; + gdb_main_entry(2, args); + } + ++#ifndef GDB_10_2 + static void + exit_after_gdb_info(void) + { + fprintf(fp, "\n"); + clean_exit(0); + } ++#endif + + /* + * Stash a copy of the gdb version locally. This can be called before +@@ -186,13 +195,13 @@ + gdb_user_print_option_address("output_format"); + gdb_print_max = (unsigned int *) + gdb_user_print_option_address("print_max"); +- gdb_prettyprint_structs = (int *) ++ gdb_prettyprint_structs = (unsigned char *) + gdb_user_print_option_address("prettyprint_structs"); +- gdb_prettyprint_arrays = (int *) ++ gdb_prettyprint_arrays = (unsigned char *) + gdb_user_print_option_address("prettyprint_arrays"); +- gdb_repeat_count_threshold = (int *) ++ gdb_repeat_count_threshold = (unsigned int *) + gdb_user_print_option_address("repeat_count_threshold"); +- gdb_stop_print_at_null = (int *) ++ gdb_stop_print_at_null = (unsigned char *) + gdb_user_print_option_address("stop_print_at_null"); + gdb_output_radix = (unsigned int *) + gdb_user_print_option_address("output_radix"); +@@ -291,6 +300,19 @@ + sprintf(req->buf, "set width 0"); + gdb_interface(req); + ++#ifdef GDB_10_2 ++ req->command = GNU_PASS_THROUGH; ++ req->name = NULL, req->flags = 0; ++ sprintf(req->buf, "set max-value-size unlimited"); ++ gdb_interface(req); ++ ++ req->command = GNU_PASS_THROUGH; ++ req->name = NULL, req->flags = 0; ++ sprintf(req->buf, "set max-completions unlimited"); ++ gdb_interface(req); ++#endif ++ ++#if 0 + /* + * Patch gdb's symbol values with the correct values from either + * the System.map or non-debug vmlinux, whichever is in effect. +@@ -303,6 +325,9 @@ + if (req->flags & GNU_COMMAND_FAILED) + error(FATAL, "patching of gdb symbol values failed\n"); + } else if (!(pc->flags & SILENT)) ++#else ++ if (!(pc->flags & SILENT)) ++#endif + fprintf(fp, "\n"); + + +@@ -364,19 +389,6 @@ + pc->cur_req = req; + pc->cur_gdb_cmd = req->command; + +- if (req->flags & GNU_RETURN_ON_ERROR) { +- error_hook = gdb_error_hook; +- if (setjmp(pc->gdb_interface_env)) { +- pc->last_gdb_cmd = pc->cur_gdb_cmd; +- pc->cur_gdb_cmd = 0; +- pc->cur_req = NULL; +- req->flags |= GNU_COMMAND_FAILED; +- pc->flags &= ~IN_GDB; +- return; +- } +- } else +- error_hook = NULL; +- + if (CRASHDEBUG(2)) + dump_gnu_request(req, IN_GDB); + +@@ -400,10 +412,12 @@ + SIGACTION(SIGINT, restart, &pc->sigaction, NULL); + SIGACTION(SIGSEGV, SIG_DFL, &pc->sigaction, NULL); + ++ if (req->flags & GNU_COMMAND_FAILED) ++ gdb_error_debug(); ++ + if (CRASHDEBUG(2)) + dump_gnu_request(req, !IN_GDB); + +- error_hook = NULL; + pc->last_gdb_cmd = pc->cur_gdb_cmd; + pc->cur_gdb_cmd = 0; + pc->cur_req = NULL; +@@ -627,8 +641,6 @@ + *gdb_prettyprint_structs = 1; /* these may piss somebody off... */ + *gdb_repeat_count_threshold = 0x7fffffff; + +- error_hook = NULL; +- + if (st->flags & ADD_SYMBOL_FILE) { + error(INFO, + "%s\n gdb add-symbol-file command failed\n", +@@ -698,11 +710,10 @@ + "run", "r", "break", "b", "tbreak", "hbreak", "thbreak", "rbreak", + "watch", "rwatch", "awatch", "attach", "continue", "c", "fg", "detach", + "finish", "handle", "interrupt", "jump", "kill", "next", "nexti", +- "signal", "step", "s", "stepi", "target", "thread", "until", "delete", +- "clear", "disable", "enable", "condition", "ignore", "frame", +- "select-frame", "f", "up", "down", "catch", "tcatch", "return", +- "file", "exec-file", "core-file", "symbol-file", "load", "si", "ni", +- "shell", "sy", ++ "signal", "step", "s", "stepi", "target", "until", "delete", ++ "clear", "disable", "enable", "condition", "ignore", "frame", "catch", ++ "tcatch", "return", "file", "exec-file", "core-file", "symbol-file", ++ "load", "si", "ni", "shell", "sy", + NULL /* must be last */ + }; + +@@ -742,13 +753,6 @@ + } + } + +- if (kt->relocate && +- STRNEQ("disassemble", cmd) && STRNEQ(cmd, "disas")) +- error(FATAL, +- "the gdb \"disassemble\" command is prohibited because the kernel text\n" +- "%swas relocated%s; use the crash \"dis\" command instead.\n", +- space(strlen(pc->curcmd)+2), kt->flags2 & KASLR ? " by KASLR" : ""); +- + return FALSE; + } + +@@ -824,7 +828,6 @@ + gdb_readmem_callback(ulong addr, void *buf, int len, int write) + { + char locbuf[SIZEOF_32BIT], *p1; +- uint32_t *p2; + int memtype; + ulong readflags; + +@@ -881,19 +884,12 @@ + } + + p1 = (char *)buf; +- if ((memtype == KVADDR) && +- text_value_cache_byte(addr, (unsigned char *)p1)) +- return TRUE; + + if (!readmem(addr, memtype, locbuf, SIZEOF_32BIT, + "gdb_readmem_callback", readflags)) + return FALSE; + + *p1 = locbuf[0]; +- if (memtype == KVADDR) { +- p2 = (uint32_t *)locbuf; +- text_value_cache(addr, *p2, 0); +- } + return TRUE; + + case SIZEOF_32BIT: +@@ -903,16 +899,10 @@ + return TRUE; + } + +- if ((memtype == KVADDR) && text_value_cache(addr, 0, buf)) +- return TRUE; +- + if (!readmem(addr, memtype, buf, SIZEOF_32BIT, + "gdb_readmem callback", readflags)) + return FALSE; + +- if (memtype == KVADDR) +- text_value_cache(addr, +- (uint32_t)*((uint32_t *)buf), NULL); + return TRUE; + } + +@@ -948,8 +938,8 @@ + /* + * Used by gdb_interface() to catch gdb-related errors, if desired. + */ +-void +-gdb_error_hook(void) ++static void ++gdb_error_debug(void) + { + char buf1[BUFSIZE]; + char buf2[BUFSIZE]; +@@ -969,13 +959,6 @@ + gdb_command_string(pc->cur_gdb_cmd, buf1, TRUE), buf2); + } + +-#ifdef GDB_7_6 +- do_cleanups(all_cleanups()); +-#else +- do_cleanups(NULL); +-#endif +- +- longjmp(pc->gdb_interface_env, 1); + } + + +@@ -1028,14 +1011,14 @@ + return FALSE; + } + } +- } else if (kt->flags2 & KASLR) +- vaddr -= (kt->relocate * -1); ++ } + } + + req->command = GNU_SET_CRASH_BLOCK; + req->addr = vaddr; + req->flags = 0; + req->addr2 = 0; ++ req->fp = pc->nullfp; + gdb_command_funnel(req); + + if (CRASHDEBUG(1)) +@@ -1065,4 +1048,37 @@ + } + #endif /* !ALPHA */ + ++unsigned long crash_get_kaslr_offset(void); ++unsigned long crash_get_kaslr_offset(void) ++{ ++ return kt->relocate * -1; ++} ++ ++/* Callbacks for crash_target */ ++int crash_get_nr_cpus(void); ++int crash_get_cpu_reg (int cpu, int regno, const char *regname, ++ int regsize, void *val); ++ ++int crash_get_nr_cpus(void) ++{ ++ if (SADUMP_DUMPFILE()) ++ return sadump_get_nr_cpus(); ++ else if (DISKDUMP_DUMPFILE()) ++ return diskdump_get_nr_cpus(); ++ else if (KDUMP_DUMPFILE()) ++ return kdump_get_nr_cpus(); ++ else if (VMSS_DUMPFILE()) ++ return vmware_vmss_get_nr_cpus(); ++ ++ /* Just CPU #0 */ ++ return 1; ++} ++ ++int crash_get_cpu_reg (int cpu, int regno, const char *regname, ++ int regsize, void *value) ++{ ++ if (!machdep->get_cpu_reg) ++ return FALSE; ++ return machdep->get_cpu_reg(cpu, regno, regname, regsize, value); ++} + +diff -Nur crash-7.3.0-orig/.gitignore crash-7.3.0/.gitignore +--- crash-7.3.0-orig/.gitignore 2023-07-07 14:06:14.163365900 +0800 ++++ crash-7.3.0/.gitignore 2023-07-07 14:08:31.283076305 +0800 +@@ -11,6 +11,18 @@ + *.rpm + gdb.files + gdb-7.6/ ++gdb-10.2/ + extensions/defs.h + extensions/*.so + extensions/eppic ++ ++# cscope files ++cscope.* ++ncscope.* ++ ++# ctags files ++tags ++TAGS ++ ++# Clang's compilation database file ++/compile_commands.json +diff -Nur crash-7.3.0-orig/help.c crash-7.3.0/help.c +--- crash-7.3.0-orig/help.c 2023-07-07 14:06:14.165365910 +0800 ++++ crash-7.3.0/help.c 2023-07-07 14:08:31.290076341 +0800 +@@ -535,7 +535,7 @@ + oflag = 0; + + while ((c = getopt(argcnt, args, +- "efNDdmM:ngcaBbHhkKsvVoptTzLxOr")) != EOF) { ++ "efNDdmM:ngcaBbHhkKsvVoptTzLOr")) != EOF) { + switch(c) + { + case 'e': +@@ -551,10 +551,6 @@ + dumpfile_memory(DUMPFILE_MEM_DUMP); + return; + +- case 'x': +- dump_text_value_cache(VERBOSE); +- return; +- + case 'd': + dump_dev_table(); + return; +@@ -666,7 +662,6 @@ + fprintf(fp, " -T - task_table plus context_array\n"); + fprintf(fp, " -v - vm_table\n"); + fprintf(fp, " -V - vm_table (verbose)\n"); +- fprintf(fp, " -x - text cache\n"); + fprintf(fp, " -z - help options\n"); + return; + +@@ -1026,7 +1021,6 @@ + " -T - task_table plus context_array", + " -v - vm_table", + " -V - vm_table (verbose)", +-" -x - text cache", + " -z - help options", + NULL + }; +@@ -6571,7 +6565,7 @@ + "kmem", + "kernel memory", + "[-f|-F|-c|-C|-i|-v|-V|-n|-z|-o|-h] [-p | -m member[,member]]\n" +-" [[-s|-S|-r] [slab] [-I slab[,slab]]] [-g [flags]] [[-P] address]]", ++" [[-s|-S|-S=cpu[s]|-r] [slab] [-I slab[,slab]]] [-g [flags]] [[-P] address]]", + " This command displays information about the use of kernel memory.\n", + " -f displays the contents of the system free memory headers.", + " also verifies that the page count equals nr_free_pages.", +@@ -6616,6 +6610,9 @@ + " slab data for each per-cpu slab is displayed, along with the", + " address of each kmem_cache_node, its count of full and partial", + " slabs, and a list of all tracked slabs.", ++" Note: one can specify the per-cpu slab data to be displayed;", ++" the cpu[s] can be given as \"1,3,5\", \"1-3\", \"1,3,5-7,10\",", ++" \"all\", or \"a\" (shortcut for \"all\").", + " -r displays the accumulated basic kmalloc() slab data of each", + " root slab cache and its children. The kernel must contain the", + " \"slab_root_caches\" list_head. (currently only available if", +@@ -8266,6 +8263,7 @@ + "Copyright (C) 2005, 2011, 2020-2021 NEC Corporation", + "Copyright (C) 1999, 2002, 2007 Silicon Graphics, Inc.", + "Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.", ++"Copyright (C) 2015, 2021 VMware, Inc.", + "This program is free software, covered by the GNU General Public License,", + "and you are welcome to change it and/or distribute copies of it under", + "certain conditions. Enter \"help copying\" to see the conditions.", +@@ -9384,8 +9382,8 @@ + " Traditionally when vmcores are compressed via the makedumpfile(8) facility", + " the libz compression library is used, and by default the crash utility", + " only supports libz. Recently makedumpfile has been enhanced to optionally", +-" use either the LZO or snappy compression libraries. To build crash with", +-" either or both of those libraries, type \"make lzo\" or \"make snappy\".", ++" use the LZO, snappy or zstd compression libraries. To build crash with any", ++" or all of those libraries, type \"make lzo\", \"make snappy\" or \"make zstd\".", + "", + " crash supports valgrind Memcheck tool on the crash's custom memory allocator.", + " To build crash with this feature enabled, type \"make valgrind\" and then run", +diff -Nur crash-7.3.0-orig/help.c.orig crash-7.3.0/help.c.orig +--- crash-7.3.0-orig/help.c.orig 1970-01-01 08:00:00.000000000 +0800 ++++ crash-7.3.0/help.c.orig 2023-07-07 14:05:59.058287642 +0800 +@@ -0,0 +1,9607 @@ ++/* help.c - core analysis suite ++ * ++ * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. ++ * Copyright (C) 2002-2020 David Anderson ++ * Copyright (C) 2002-2020 Red Hat, Inc. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include "defs.h" ++ ++static void reshuffle_cmdlist(void); ++static int sort_command_name(const void *, const void *); ++static void display_commands(void); ++static void display_copying_info(void); ++static void display_warranty_info(void); ++static void display_output_info(void); ++static void display_input_info(void); ++static void display_README(void); ++static char *gnu_public_license[]; ++static char *gnu_public_license_v3[]; ++static char *version_info[]; ++static char *output_info[]; ++static char *input_info[]; ++static char *README[]; ++static void dump_registers(void); ++ ++#define GPLv2 2 ++#define GPLv3 3 ++ ++#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) ++static int GPL_version = GPLv2; ++#else ++static int GPL_version = GPLv3; ++#endif ++ ++static ++char *program_usage_info[] = { ++ "", ++ "USAGE:", ++ "", ++ " crash [OPTION]... NAMELIST MEMORY-IMAGE[@ADDRESS] (dumpfile form)", ++ " crash [OPTION]... [NAMELIST] (live system form)", ++ "", ++ "OPTIONS:", ++ "", ++ " NAMELIST", ++ " This is a pathname to an uncompressed kernel image (a vmlinux", ++ " file), or a Xen hypervisor image (a xen-syms file) which has", ++ " been compiled with the \"-g\" option. If using the dumpfile form,", ++ " a vmlinux file may be compressed in either gzip or bzip2 formats.", ++ "", ++ " MEMORY-IMAGE", ++ " A kernel core dump file created by the netdump, diskdump, LKCD", ++ " kdump, xendump or kvmdump facilities.", ++ "", ++ " If a MEMORY-IMAGE argument is not entered, the session will be", ++ " invoked on the live system, which typically requires root privileges", ++ " because of the device file used to access system RAM. By default, ", ++ " /dev/crash will be used if it exists. If it does not exist, then ", ++ " /dev/mem will be used; but if the kernel has been configured with ", ++ " CONFIG_STRICT_DEVMEM, then /proc/kcore will be used. It is permissible", ++ " to explicitly enter /dev/crash, /dev/mem or /proc/kcore.", ++ "", ++ " An @ADDRESS value must be appended to the MEMORY-IMAGE if the dumpfile", ++ " is a raw RAM dumpfile that has no header information describing the file", ++ " contents. Multiple MEMORY-IMAGE@ADDRESS ordered pairs may be entered,", ++ " with each dumpfile containing a contiguous block of RAM, where the ADDRESS", ++ " value is the physical start address of the block expressed in hexadecimal.", ++ " The physical address value(s) will be used to create a temporary ELF header", ++ " in /var/tmp, which will only exist during the crash session. If a raw RAM", ++ " dumpfile represents a live memory source, such as that specified by the QEMU", ++ " mem-path argument of a memory-backend-file object, then \"live:\" must be", ++ " prepended to the MEMORY-IMAGE name.", ++ "", ++ " mapfile", ++ " If the NAMELIST file is not the same kernel that is running", ++ " (live system form), or the kernel that was running when the system", ++ " crashed (dumpfile form), then the System.map file of the original ", ++ " kernel should be entered on the command line.", ++ "", ++ " -h [option]", ++ " --help [option]", ++ " Without an option argument, display a crash usage help message.", ++ " If the option argument is a crash command name, the help page", ++ " for that command is displayed. If it is the string \"input\", a", ++ " page describing the various crash command line input options is", ++ " displayed. If it is the string \"output\", a page describing command", ++ " line output options is displayed. If it is the string \"all\", then", ++ " all of the possible help messages are displayed. After the help", ++ " message is displayed, crash exits.", ++ "", ++ " -s ", ++ " Silently proceed directly to the \"crash>\" prompt without displaying", ++ " any version, GPL, or crash initialization data during startup, and by", ++ " default, runtime command output is not passed to any scrolling command.", ++ "", ++ " -i file", ++ " Execute the command(s) contained in \"file\" prior to displaying ", ++ " the \"crash>\" prompt for interactive user input.", ++ "", ++ " -d num ", ++ " Set the internal debug level. The higher the number, the more", ++ " debugging data will be printed when crash initializes and runs.", ++ "", ++ " -S ", ++ " Use /boot/System.map as the mapfile.", ++ "", ++ " -e vi | emacs", ++ " Set the readline(3) command line editing mode to \"vi\" or \"emacs\". ", ++ " The default editing mode is \"vi\".", ++ "", ++ " -f ", ++ " Force the usage of a compressed vmlinux file if its original", ++ " name does not start with \"vmlinux\".", ++ "", ++ " -k ", ++ " Indicate that the NAMELIST file is an LKCD \"Kerntypes\" debuginfo file.", ++ "", ++ " -g [namelist]", ++ " Determine if a vmlinux or xen-syms namelist file contains debugging data.", ++ "", ++ " -t ", ++ " Display the system-crash timestamp and exit.", ++ "", ++ " -L ", ++ " Attempt to lock all of its virtual address space into memory by", ++ " calling mlockall(MCL_CURRENT|MCL_FUTURE) during initialization.", ++ " If the system call fails, an error message will be displayed,", ++ " but the session continues.", ++ "", ++ " -c tty-device", ++ " Open the tty-device as the console used for debug messages.", ++ "", ++ " -p page-size", ++ " If a processor's page size cannot be determined by the dumpfile, ", ++ " and the processor default cannot be used, use page-size.", ++ "", ++ " -o filename", ++ " Only used with the MEMORY-IMAGE@ADDRESS format for raw RAM dumpfiles,", ++ " specifies a filename of a new ELF vmcore that will be created and used", ++ " as the dumpfile. It will be saved to allow future use as a standalone", ++ " vmcore, replacing the original raw RAM dumpfile.", ++ "", ++ " -m option=value", ++ " --machdep option=value", ++ " Pass an option and value pair to machine-dependent code. These", ++ " architecture-specific option/pairs should only be required in", ++ " very rare circumstances:", ++ "", ++ " X86_64:", ++ " phys_base=", ++ " irq_eframe_link=", ++ " irq_stack_gap=", ++ " max_physmem_bits=", ++ " kernel_image_size=", ++ " vm=orig (pre-2.6.11 virtual memory address ranges)", ++ " vm=2.6.11 (2.6.11 and later virtual memory address ranges)", ++ " vm=xen (Xen kernel virtual memory address ranges)", ++ " vm=xen-rhel4 (RHEL4 Xen kernel virtual address ranges)", ++ " vm=5level (5-level page tables)", ++ " page_offset=", ++ " PPC64:", ++ " vm=orig", ++ " vm=2.6.14 (4-level page tables)", ++ " IA64:", ++ " phys_start=", ++ " init_stack_size=", ++ " vm=4l (4-level page tables)", ++ " ARM:", ++ " phys_base=", ++ " ARM64:", ++ " phys_offset=", ++ " kimage_voffset=", ++ " max_physmem_bits=", ++ " vabits_actual=", ++ " X86:", ++ " page_offset=", ++ "", ++ " -x ", ++ " Automatically load extension modules from a particular directory.", ++ " The directory is determined by the following order of precedence:", ++ "", ++ " (1) the directory specified in the CRASH_EXTENSIONS shell ", ++ " environment variable", ++ " (2) /usr/lib64/crash/extensions (64-bit architectures)", ++ " (3) /usr/lib/crash/extensions (32-bit architectures)", ++ " (4) the ./extensions subdirectory of the current directory", ++ "", ++ " --active", ++ " Track only the active task on each cpu.", ++ "", ++ " --buildinfo", ++ " Display the crash binary's build date, the user ID of the builder,", ++ " the hostname of the machine where the build was done, the target", ++ " architecture, the version number, and the compiler version.", ++ "", ++ " --memory_module modname", ++ " Use the modname as an alternative kernel module to the crash.ko", ++ " module that creates the /dev/crash device.", ++ "", ++ " --memory_device device", ++ " Use device as an alternative device to the /dev/crash, /dev/mem", ++ " or /proc/kcore devices.", ++ "", ++ " --log dumpfile", ++ " Dump the contents of the kernel log buffer. A kernel namelist", ++ " argument is not necessary, but the dumpfile must contain the", ++ " VMCOREINFO data taken from the original /proc/vmcore ELF header.", ++ "", ++ " --no_kallsyms", ++ " Do not use kallsyms-generated symbol information contained within", ++ " kernel module object files.", ++ "", ++ " --no_modules", ++ " Do not access or display any kernel module related information.", ++ "", ++ " --no_ikconfig", ++ " Do not attempt to read configuration data that was built into", ++ " kernels configured with CONFIG_IKCONFIG.", ++ "", ++ " --no_data_debug", ++ " Do not verify the validity of all structure member offsets and", ++ " structure sizes that it uses.", ++ "", ++ " --no_kmem_cache", ++ " Do not initialize the kernel's slab cache infrastructure, and", ++ " commands that use kmem_cache-related data will not work.", ++ "", ++ " --no_elf_notes", ++ " Do not use the registers from the ELF NT_PRSTATUS notes saved", ++ " in a compressed kdump header for backtraces.", ++ "", ++ " --kmem_cache_delay", ++ " Delay the initialization of the kernel's slab cache infrastructure", ++ " until it is required by a run-time command.", ++ "", ++ " --readnow", ++ " Pass this flag to the embedded gdb module, which will override", ++ " the two-stage strategy that it uses for reading symbol tables", ++ " from the NAMELIST. If module symbol tables are loaded during", ++ " runtime with the \"mod\" command, the same override will occur.", ++ "", ++ " --smp ", ++ " Specify that the system being analyzed is an SMP kernel.", ++ "", ++ " -v", ++ " --version", ++ " Display the version of the crash utility, the version of the", ++ " embedded gdb module, GPL information, and copyright notices.", ++ "", ++ " --cpus number", ++ " Specify the number of cpus in the SMP system being analyzed.", ++ "", ++ " --osrelease dumpfile", ++ " Display the OSRELEASE vmcoreinfo string from a kdump dumpfile", ++ " header.", ++ "", ++ " --hyper", ++ " Force the session to be that of a Xen hypervisor.", ++ "", ++ " --p2m_mfn pfn", ++ " When a Xen Hypervisor or its dom0 kernel crashes, the dumpfile", ++ " is typically analyzed with either the Xen hypervisor or the dom0", ++ " kernel. It is also possible to analyze any of the guest domU", ++ " kernels if the pfn_to_mfn_list_list pfn value of the guest kernel", ++ " is passed on the command line along with its NAMELIST and the ", ++ " dumpfile.", ++ "", ++ " --xen_phys_start physical-address", ++ " Supply the base physical address of the Xen hypervisor's text", ++ " and static data for older xendump dumpfiles that did not pass", ++ " that information in the dumpfile header.", ++ "", ++ " --zero_excluded", ++ " If the makedumpfile(8) facility has filtered a compressed kdump", ++ " dumpfile to exclude various types of non-essential pages, or has", ++ " marked a compressed or ELF kdump dumpfile as incomplete due to", ++ " an ENOSPC or other error during its creation, any attempt to", ++ " read missing pages will fail. With this flag, reads from any", ++ " of those pages will return zero-filled memory.", ++ "", ++ " --no_panic", ++ " Do not attempt to find the task that was running when the kernel", ++ " crashed. Set the initial context to that of the \"swapper\" task", ++ " on cpu 0.", ++ "", ++ " --more ", ++ " Use /bin/more as the command output scroller, overriding the", ++ " default of /usr/bin/less and any settings in either ./.crashrc", ++ " or $HOME/.crashrc.", ++ "", ++ " --less ", ++ " Use /usr/bin/less as the command output scroller, overriding any", ++ " settings in either ./.crashrc or $HOME/.crashrc.", ++ "", ++ " --CRASHPAGER", ++ " Use the output paging command defined in the CRASHPAGER shell", ++ " environment variable, overriding any settings in either ./.crashrc ", ++ " or $HOME/.crashrc.", ++ "", ++ " --no_scroll", ++ " Do not pass run-time command output to any scrolling command.", ++ "", ++ " --no_strip", ++ " Do not strip cloned kernel text symbol names.", ++ "", ++ " --no_crashrc", ++ " Do not execute the commands in either $HOME/.crashrc or ./.crashrc.", ++ "", ++ " --mod directory", ++ " When loading the debuginfo data of kernel modules with the \"mod -S\"", ++ " command, search for their object files in directory instead of in ", ++ " the standard location.", ++ "", ++ " --src directory", ++ " Search for the kernel source code in directory instead of in the", ++ " standard location that is compiled into the debuginfo data.", ++ "", ++ " --reloc size", ++ " When analyzing live x86 kernels configured with a CONFIG_PHYSICAL_START ", ++ " value that is larger than its CONFIG_PHYSICAL_ALIGN value, then it will", ++ " be necessary to enter a relocation size equal to the difference between", ++ " the two values.", ++ "", ++ " --hash count", ++ " Set the number of internal hash queue heads used for list gathering", ++ " and verification. The default count is 32768.", ++ "", ++ " --kaslr offset | auto", ++ " If x86, x86_64 or s390x kernel was configured with CONFIG_RANDOMIZE_BASE,", ++ " the offset value is equal to the difference between the symbol values ", ++ " compiled into the vmlinux file and their relocated KASLR value. If", ++ " set to auto, the KASLR offset value will be automatically calculated.", ++ "", ++ " --minimal", ++ " Bring up a session that is restricted to the log, dis, rd, sym,", ++ " eval, set and exit commands. This option may provide a way to", ++ " extract some minimal/quick information from a corrupted or truncated", ++ " dumpfile, or in situations where one of the several kernel subsystem ", ++ " initialization routines would abort the crash session.", ++ "", ++ " --kvmhost [32|64]", ++ " When examining an x86 KVM guest dumpfile, this option specifies", ++ " that the KVM host that created the dumpfile was an x86 (32-bit)", ++ " or an x86_64 (64-bit) machine, overriding the automatically", ++ " determined value.", ++ "", ++ " --kvmio ", ++ " override the automatically-calculated KVM guest I/O hole size.", ++ "", ++ " --offline [show|hide]", ++ " Show or hide command output that is associated with offline cpus,", ++ " overriding any settings in either ./.crashrc or $HOME/.crashrc.", ++ "", ++ "FILES:", ++ "", ++ " .crashrc", ++ " Initialization commands. The file can be located in the user's", ++ " HOME directory and/or the current directory. Commands found in", ++ " the .crashrc file in the HOME directory are executed before", ++ " those in the current directory's .crashrc file.", ++ "", ++ "ENVIRONMENT VARIABLES:", ++ "", ++ " EDITOR ", ++ " Command input is read using readline(3). If EDITOR is set to", ++ " emacs or vi then suitable keybindings are used. If EDITOR is", ++ " not set, then vi is used. This can be overridden by \"set vi\" or", ++ " \"set emacs\" commands located in a .crashrc file, or by entering", ++ " \"-e emacs\" on the crash command line.", ++ "", ++ " CRASHPAGER", ++ " If CRASHPAGER is set, its value is used as the name of the program", ++ " to which command output will be sent. If not, then command output", ++ " output is sent to \"/usr/bin/less -E -X\" by default.", ++ "", ++ " CRASH_MODULE_PATH", ++ " Specifies an alternative directory tree to search for kernel", ++ " module object files.", ++ "", ++ " CRASH_EXTENSIONS", ++ " Specifies a directory containing extension modules that will be", ++ " loaded automatically if the -x command line option is used.", ++ "", ++ NULL ++}; ++ ++void ++program_usage(int form) ++{ ++ if (form == SHORT_FORM) { ++ fprintf(fp, "\nUsage:\n\n"); ++ fprintf(fp, "%s\n%s\n", program_usage_info[3], ++ program_usage_info[4]); ++ fprintf(fp, "\nEnter \"%s -h\" for details.\n", ++ pc->program_name); ++ clean_exit(1); ++ } else { ++ FILE *scroll; ++ char *scroll_command; ++ char **p; ++ ++ if ((scroll_command = setup_scroll_command()) && ++ (scroll = popen(scroll_command, "w"))) ++ fp = scroll; ++ else ++ scroll = NULL; ++ ++ for (p = program_usage_info; *p; p++) { ++ fprintf(fp, *p, pc->program_name); ++ fprintf(fp, "\n"); ++ } ++ fflush(fp); ++ ++ if (scroll) ++ pclose(scroll); ++ ++ clean_exit(0); ++ } ++} ++ ++ ++/* ++ * Get an updated count of commands for subsequent help menu display, ++ * reshuffling the deck if this is the first time or if something's changed. ++ */ ++void ++help_init(void) ++{ ++ struct command_table_entry *cp; ++ struct extension_table *ext; ++ ++ for (pc->ncmds = 0, cp = pc->cmd_table; cp->name; cp++) { ++ if (!(cp->flags & HIDDEN_COMMAND)) ++ pc->ncmds++; ++ } ++ ++ for (ext = extension_table; ext; ext = ext->next) { ++ for (cp = ext->command_table; cp->name; cp++) { ++ if (!(cp->flags & (CLEANUP|HIDDEN_COMMAND))) ++ pc->ncmds++; ++ } ++ } ++ ++ if (!pc->cmdlist) { ++ pc->cmdlistsz = pc->ncmds; ++ if ((pc->cmdlist = (char **) ++ malloc(sizeof(char *) * pc->cmdlistsz)) == NULL) ++ error(FATAL, ++ "cannot malloc command list space\n"); ++ } else if (pc->ncmds > pc->cmdlistsz) { ++ pc->cmdlistsz = pc->ncmds; ++ if ((pc->cmdlist = (char **)realloc(pc->cmdlist, ++ sizeof(char *) * pc->cmdlistsz)) == NULL) ++ error(FATAL, ++ "cannot realloc command list space\n"); ++ } ++ ++ reshuffle_cmdlist(); ++} ++ ++/* ++ * If the command list is modified during runtime, re-shuffle the list ++ * for proper help menu display. ++ */ ++static void ++reshuffle_cmdlist(void) ++{ ++ int i, cnt; ++ struct command_table_entry *cp; ++ struct extension_table *ext; ++ ++ for (i = 0; i < pc->cmdlistsz; i++) ++ pc->cmdlist[i] = NULL; ++ ++ for (cnt = 0, cp = pc->cmd_table; cp->name; cp++) { ++ if (!(cp->flags & HIDDEN_COMMAND)) ++ pc->cmdlist[cnt++] = cp->name; ++ } ++ ++ for (ext = extension_table; ext; ext = ext->next) { ++ for (cp = ext->command_table; cp->name; cp++) { ++ if (!(cp->flags & (CLEANUP|HIDDEN_COMMAND))) ++ pc->cmdlist[cnt++] = cp->name; ++ } ++ } ++ ++ if (cnt > pc->cmdlistsz) ++ error(FATAL, "help table malfunction!\n"); ++ ++ qsort((void *)pc->cmdlist, (size_t)cnt, ++ sizeof(char *), sort_command_name); ++} ++ ++ ++/* ++ * The help list is in alphabetical order, with exception of the "q" command, ++ * which has historically always been the last command in the list. ++ */ ++ ++static int ++sort_command_name(const void *name1, const void *name2) ++{ ++ char **s1, **s2; ++ ++ s1 = (char **)name1; ++ s2 = (char **)name2; ++ ++ if (STREQ(*s1, "q")) ++ return 1; ++ ++ return strcmp(*s1, *s2); ++} ++ ++ ++/* ++ * Get help for a command, to dump an internal table, or the GNU public ++ * license copying/warranty information. ++ */ ++void ++cmd_help(void) ++{ ++ int c; ++ int oflag; ++ ++ oflag = 0; ++ ++ while ((c = getopt(argcnt, args, ++ "efNDdmM:ngcaBbHhkKsvVoptTzLxOr")) != EOF) { ++ switch(c) ++ { ++ case 'e': ++ dump_extension_table(VERBOSE); ++ return; ++ ++ case 'f': ++ dump_filesys_table(VERBOSE); ++ return; ++ ++ case 'n': ++ case 'D': ++ dumpfile_memory(DUMPFILE_MEM_DUMP); ++ return; ++ ++ case 'x': ++ dump_text_value_cache(VERBOSE); ++ return; ++ ++ case 'd': ++ dump_dev_table(); ++ return; ++ ++ case 'M': ++ dump_machdep_table(stol(optarg, FAULT_ON_ERROR, NULL)); ++ return; ++ case 'm': ++ dump_machdep_table(0); ++ return; ++ ++ case 'g': ++ dump_gdb_data(); ++ return; ++ ++ case 'N': ++ dump_net_table(); ++ return; ++ ++ case 'a': ++ dump_alias_data(); ++ return; ++ ++ case 'b': ++ dump_shared_bufs(); ++ return; ++ ++ case 'B': ++ dump_build_data(); ++ return; ++ ++ case 'c': ++ dump_numargs_cache(); ++ return; ++ ++ case 'H': ++ dump_hash_table(VERBOSE); ++ return; ++ ++ case 'h': ++ dump_hash_table(!VERBOSE); ++ return; ++ ++ case 'k': ++ dump_kernel_table(!VERBOSE); ++ return; ++ ++ case 'K': ++ dump_kernel_table(VERBOSE); ++ return; ++ ++ case 's': ++ dump_symbol_table(); ++ return; ++ ++ case 'V': ++ dump_vm_table(VERBOSE); ++ return; ++ ++ case 'v': ++ dump_vm_table(!VERBOSE); ++ return; ++ ++ case 'O': ++ dump_offset_table(NULL, TRUE); ++ return; ++ ++ case 'o': ++ oflag = TRUE; ++ break; ++ ++ case 'T': ++ dump_task_table(VERBOSE); ++ return; ++ ++ case 't': ++ dump_task_table(!VERBOSE); ++ return; ++ ++ case 'p': ++ dump_program_context(); ++ return; ++ ++ case 'z': ++ fprintf(fp, "help options:\n"); ++ fprintf(fp, " -a - alias data\n"); ++ fprintf(fp, " -b - shared buffer data\n"); ++ fprintf(fp, " -B - build data\n"); ++ fprintf(fp, " -c - numargs cache\n"); ++ fprintf(fp, " -d - device table\n"); ++ fprintf(fp, " -D - dumpfile contents/statistics\n"); ++ fprintf(fp, " -e - extension table data\n"); ++ fprintf(fp, " -f - filesys table\n"); ++ fprintf(fp, " -g - gdb data\n"); ++ fprintf(fp, " -h - hash_table data\n"); ++ fprintf(fp, " -H - hash_table data (verbose)\n"); ++ fprintf(fp, " -k - kernel_table\n"); ++ fprintf(fp, " -K - kernel_table (verbose)\n"); ++ fprintf(fp, " -L - LKCD page cache environment\n"); ++ fprintf(fp, " -M machine specific\n"); ++ fprintf(fp, " -m - machdep_table\n"); ++ fprintf(fp, " -N - net_table\n"); ++ fprintf(fp, " -n - dumpfile contents/statistics\n"); ++ fprintf(fp, " -o - offset_table and size_table\n"); ++ fprintf(fp, " -p - program_context\n"); ++ fprintf(fp, " -r - dump registers from dumpfile header\n"); ++ fprintf(fp, " -s - symbol table data\n"); ++ fprintf(fp, " -t - task_table\n"); ++ fprintf(fp, " -T - task_table plus context_array\n"); ++ fprintf(fp, " -v - vm_table\n"); ++ fprintf(fp, " -V - vm_table (verbose)\n"); ++ fprintf(fp, " -x - text cache\n"); ++ fprintf(fp, " -z - help options\n"); ++ return; ++ ++ case 'L': ++ dumpfile_memory(DUMPFILE_ENVIRONMENT); ++ return; ++ ++ case 'r': ++ dump_registers(); ++ return; ++ ++ default: ++ argerrs++; ++ break; ++ } ++ } ++ ++ if (argerrs) ++ cmd_usage(pc->curcmd, COMPLETE_HELP); ++ ++ if (!args[optind]) { ++ if (oflag) ++ dump_offset_table(NULL, FALSE); ++ else ++ display_help_screen(""); ++ return; ++ } ++ ++ do { ++ if (oflag) ++ dump_offset_table(args[optind], FALSE); ++ else ++ cmd_usage(args[optind], COMPLETE_HELP|MUST_HELP); ++ optind++; ++ } while (args[optind]); ++} ++ ++static void ++dump_registers(void) ++{ ++ if (pc->flags2 & QEMU_MEM_DUMP_ELF) { ++ dump_registers_for_qemu_mem_dump(); ++ return; ++ } else if (DISKDUMP_DUMPFILE()) { ++ dump_registers_for_compressed_kdump(); ++ return; ++ } else if (NETDUMP_DUMPFILE() || KDUMP_DUMPFILE()) { ++ dump_registers_for_elf_dumpfiles(); ++ return; ++ } else if (VMSS_DUMPFILE()) { ++ dump_registers_for_vmss_dump(); ++ return; ++ } ++ ++ error(FATAL, "-r option not supported on %s\n", ++ ACTIVE() ? "a live system" : "this dumpfile type"); ++} ++ ++/* ++ * Format and display the help menu. ++ */ ++ ++void ++display_help_screen(char *indent) ++{ ++ int i, j, rows; ++ char **namep; ++ ++ help_init(); ++ ++ fprintf(fp, "\n%s", indent); ++ ++ rows = (pc->ncmds + (HELP_COLUMNS-1)) / HELP_COLUMNS; ++ ++ for (i = 0; i < rows; i++) { ++ namep = &pc->cmdlist[i]; ++ for (j = 0; j < HELP_COLUMNS; j++) { ++ fprintf(fp,"%-15s", *namep); ++ namep += rows; ++ if ((namep - pc->cmdlist) >= pc->ncmds) ++ break; ++ } ++ fprintf(fp,"\n%s", indent); ++ } ++ ++ fprintf(fp, "\n%s%s version: %-6s gdb version: %s\n", indent, ++ pc->program_name, pc->program_version, pc->gdb_version); ++ fprintf(fp, ++ "%sFor help on any command above, enter \"help \".\n", ++ indent); ++ fprintf(fp, "%sFor help on input options, enter \"help input\".\n", ++ indent); ++ fprintf(fp, "%sFor help on output options, enter \"help output\".\n", ++ indent); ++#ifdef NO_LONGER_TRUE ++ fprintf(fp, "%sFor the most recent version: " ++ "http://www.missioncriticallinux.com/download\n\n", indent); ++#else ++ fprintf(fp, "\n"); ++#endif ++} ++ ++/* ++ * Used for generating HTML pages, dump the commands in the order ++ * they would be seen on the help menu, i.e., from left-to-right, row-by-row. ++ * Line ends are signaled with a "BREAK" string. ++ */ ++static void ++display_commands(void) ++{ ++ int i, j, rows; ++ char **namep; ++ ++ help_init(); ++ rows = (pc->ncmds + (HELP_COLUMNS-1)) / HELP_COLUMNS; ++ ++ for (i = 0; i < rows; i++) { ++ namep = &pc->cmdlist[i]; ++ for (j = 0; j < HELP_COLUMNS; j++) { ++ fprintf(fp,"%s\n", *namep); ++ namep += rows; ++ if ((namep - pc->cmdlist) >= pc->ncmds) { ++ fprintf(fp, "BREAK\n"); ++ break; ++ } ++ } ++ } ++} ++ ++ ++/* ++ * Help data for a command must be formatted using the following template: ++ ++"command-name", ++"command description line", ++"argument-usage line", ++"description...", ++"description...", ++"description...", ++NULL, ++ ++ * The first line is concatenated with the second line, and will follow the ++ * help command's "NAME" header. ++ * The first and third lines will also be concatenated, and will follow the ++ * help command's "SYNOPSIS" header. If the command has no arguments, enter ++ * a string consisting of a space, i.e., " ". ++ * The fourth and subsequent lines will follow the help command's "DESCRIPTION" ++ * header. ++ * ++ * The program name can be referenced by using the %%s format. The final ++ * entry in each command's help data string list must be a NULL. ++ */ ++ ++ ++char *help_foreach[] = { ++"foreach", ++"display command data for multiple tasks in the system", ++"[[pid | taskp | name | state | [kernel | user | gleader]] ...]\n" ++" command [flag] [argument]", ++" This command allows for an examination of various kernel data associated", ++" with any, or all, tasks in the system, without having to set the context", ++" to each targeted task.\n", ++" pid perform the command(s) on this PID.", ++" taskp perform the command(s) on task referenced by this hexadecimal", ++" task_struct pointer.", ++" name perform the command(s) on all tasks with this name. If the", ++" task name can be confused with a foreach command name, then", ++" precede the name string with a \"\\\". If the name string is", ++" enclosed within \"'\" characters, then the encompassed string", ++" must be a POSIX extended regular expression that will be used", ++" to match task names.", ++" user perform the command(s) on all user (non-kernel) threads.", ++" gleader perform the command(s) on all user (non-kernel) thread group leaders.", ++" 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, 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", ++" selected, or on all tasks:\n", ++" bt run the \"bt\" command (optional flags: -r -t -l -e -R -f -F", ++" -o -s -x -d)", ++" vm run the \"vm\" command (optional flags: -p -v -m -R -d -x)", ++" task run the \"task\" command (optional flags: -R -d -x)", ++" files run the \"files\" command (optional flag: -c -R)", ++" net run the \"net\" command (optional flags: -s -S -R -d -x)", ++" set run the \"set\" command", ++" ps run the \"ps\" command (optional flags: -G -s -p -c -t -l -a", ++" -g -r -y)", ++" sig run the \"sig\" command (optional flag: -g)", ++" vtop run the \"vtop\" command (optional flags: -c -u -k)\n", ++" flag Pass this optional flag to the command selected.", ++" argument Pass this argument to the command selected.", ++" ", ++" A header containing the PID, task address, cpu and command name will be", ++" pre-pended before the command output for each selected task. Consult the", ++" help page of each of the command types above for details.", ++"\nEXAMPLES", ++" Display the stack traces for all tasks:\n", ++" %s> foreach bt", ++" PID: 4752 TASK: c7680000 CPU: 1 COMMAND: \"xterm\"", ++" #0 [c7681edc] schedule at c01135f6", ++" (void)", ++" #1 [c7681f34] schedule_timeout at c01131ff", ++" (24)", ++" #2 [c7681f64] do_select at c0132838", ++" (5, c7681fa4, c7681fa0)", ++" #3 [c7681fbc] sys_select at c0132dad", ++" (5, 8070300, 8070380, 0, 0)", ++" #4 [bffffb0c] system_call at c0109944", ++" EAX: 0000008e EBX: 00000005 ECX: 08070300 EDX: 08070380 ", ++" DS: 002b ESI: 00000000 ES: 002b EDI: 00000000 ", ++" SS: 002b ESP: bffffadc EBP: bffffb0c ", ++" CS: 0023 EIP: 402259ee ERR: 0000008e EFLAGS: 00000246 ", ++" ", ++" PID: 557 TASK: c5600000 CPU: 0 COMMAND: \"nfsd\"", ++" #0 [c5601f38] schedule at c01135f6", ++" (void)", ++" #1 [c5601f90] schedule_timeout at c01131ff", ++" (c5600000)", ++" #2 [c5601fb8] svc_recv at c805363a", ++" (c0096f40, c5602800, 7fffffff, 100, c65c9f1c)", ++" #3 [c5601fec] (nfsd module) at c806e303", ++" (c5602800, c5602800, c0096f40, 6c6e0002, 50)", ++" #4 [c65c9f24] kernel_thread at c010834f", ++" (0, 0, ext2_file_inode_operations)", ++" ", ++" PID: 824 TASK: c7c84000 CPU: 0 COMMAND: \"mingetty\"", ++" ...\n", ++" Display the task_struct structure for each \"bash\" command:\n", ++" %s> foreach bash task", ++" ...\n", ++" Display the open files for all tasks:\n", ++" %s> foreach files", ++" ...\n", ++" Display the state of tasks whose name contains a match to \"event.*\":\n", ++" %s> foreach 'event.*' task -R state", ++" PID: 99 TASK: ffff8804750d5500 CPU: 0 COMMAND: \"events/0\"", ++" state = 1,", ++" ", ++" PID: 100 TASK: ffff8804750d4ac0 CPU: 1 COMMAND: \"events/1\"", ++" state = 1,", ++" ", ++" PID: 101 TASK: ffff8804750d4080 CPU: 2 COMMAND: \"events/2\"", ++" state = 1,", ++" ...\n", ++" Display the stack traces for all blocked (TASK_UNINTERRUPTIBLE) tasks:\n", ++" %s> foreach UN bt", ++" PID: 428 TASK: ffff880036b6c560 CPU: 1 COMMAND: \"jbd2/dm-1-8\"", ++" #0 [ffff880035779a70] __schedule at ffffffff815df272", ++" #1 [ffff880035779b08] schedule at ffffffff815dfacf", ++" #2 [ffff880035779b18] io_schedule at ffffffff815dfb7f", ++" #3 [ffff880035779b38] sleep_on_page at ffffffff81119a4e", ++" #4 [ffff880035779b48] __wait_on_bit at ffffffff815e039f", ++" #5 [ffff880035779b98] wait_on_page_bit at ffffffff81119bb8", ++" #6 [ffff880035779be8] filemap_fdatawait_range at ffffffff81119ccc", ++" #7 [ffff880035779cd8] filemap_fdatawait at ffffffff81119d8b", ++" #8 [ffff880035779ce8] jbd2_journal_commit_transaction at ffffffff8123a99c", ++" #9 [ffff880035779e58] kjournald2 at ffffffff8123ee7b", ++" #10 [ffff880035779ee8] kthread at ffffffff8108fb9c", ++" #11 [ffff880035779f48] kernel_thread_helper at ffffffff815ebaf4", ++" ...\n", ++NULL ++}; ++ ++char *help_ascii[] = { ++"ascii", ++"translate a hexadecimal string to ASCII", ++"value ...", ++" Translates 32-bit or 64-bit hexadecimal values to ASCII. If no argument", ++" is entered, an ASCII chart is displayed.", ++"\nEXAMPLES", ++" Translate the hexadecimal value of 0x62696c2f7273752f to ASCII:", ++"\n %s> ascii 62696c2f7273752f", ++" 62696c2f7273752f: /usr/lib", ++"\n Display an ASCII chart:", ++"\n %s> ascii", ++" ", ++" 0 1 2 3 4 5 6 7", ++" +-------------------------------", ++" 0 | NUL DLE SP 0 @ P ' p", ++" 1 | SOH DC1 ! 1 A Q a q", ++" 2 | STX DC2 \" 2 B R b r", ++" 3 | ETX DC3 # 3 C S c s", ++" 4 | EOT DC4 $ 4 D T d t", ++" 5 | ENQ NAK \% 5 E U e u", ++" 6 | ACK SYN & 6 F V f v", ++" 7 | BEL ETB ` 7 G W g w", ++" 8 | BS CAN ( 8 H X h x", ++" 9 | HT EM ) 9 I Y i y", ++" A | LF SUB * : J Z j z", ++" B | VT ESC + ; K [ k {", ++" C | FF FS , < L \\ l |", ++" D | CR GS _ = M ] m }", ++" E | SO RS . > N ^ n ~", ++" F | SI US / ? O - o DEL", ++NULL ++}; ++ ++char *help_quit[] = { ++"quit", ++"exit this session", ++" ", ++" Bail out of the current %s session.", ++"\nNOTE", ++" This command is equivalent to the \"exit\" command.", ++NULL ++}; ++ ++char *help_exit[] = { ++"exit", ++"exit this session", ++" ", ++" Bail out of the current %s session.", ++"\nNOTE", ++" This command is equivalent to the \"q\" command.", ++NULL ++}; ++ ++char *help_help[] = { ++"help", ++"get help", ++"[command | all] [-