├── .github └── workflows │ ├── ci-build.yml │ ├── ci-test.yml │ └── pr-closer.yml ├── .gitignore ├── .rh_rpm_package ├── COPYING3 ├── Makefile ├── README ├── alpha.c ├── arm.c ├── arm64.c ├── bpf.c ├── ci-tests ├── .fmf │ └── version ├── local.fmf └── main.fmf ├── cmdline.c ├── configure.c ├── crash.8 ├── crash_target.c ├── defs.h ├── dev.c ├── diskdump.c ├── diskdump.h ├── extensions.c ├── extensions ├── Makefile ├── dminfo.c ├── echo.c ├── eppic.c ├── eppic.mk ├── snap.c └── snap.mk ├── filesys.c ├── gdb-16.2.patch ├── gdb_interface.c ├── global_data.c ├── help.c ├── ia64.c ├── ibm_common.h ├── ipcs.c ├── kaslr_helper.c ├── kernel.c ├── kvmdump.c ├── kvmdump.h ├── lkcd_common.c ├── lkcd_dump_v5.h ├── lkcd_dump_v7.h ├── lkcd_dump_v8.h ├── lkcd_fix_mem.c ├── lkcd_fix_mem.h ├── lkcd_v1.c ├── lkcd_v2_v3.c ├── lkcd_v5.c ├── lkcd_v7.c ├── lkcd_v8.c ├── lkcd_vmdump_v1.h ├── lkcd_vmdump_v2_v3.h ├── lkcd_x86_trace.c ├── lkcd_x86_trace.h ├── loongarch64.c ├── lzorle_decompress.c ├── lzorle_decompress.h ├── main.c ├── makedumpfile.c ├── makedumpfile.h ├── maple_tree.c ├── maple_tree.h ├── memory.c ├── memory_driver ├── Makefile ├── README └── crash.c ├── mips.c ├── mips64.c ├── net.c ├── netdump.c ├── netdump.h ├── ppc.c ├── ppc64.c ├── printk.c ├── qemu-load.c ├── qemu-load.h ├── qemu.c ├── ramdump.c ├── remote.c ├── riscv64.c ├── rse.h ├── s390.c ├── s390_dump.c ├── s390dbf.c ├── s390x.c ├── sadump.c ├── sadump.h ├── sbitmap.c ├── sparc64.c ├── symbols.c ├── task.c ├── test.c ├── tools.c ├── unwind.c ├── unwind.h ├── unwind_arm.c ├── unwind_decoder.c ├── unwind_i.h ├── unwind_x86.h ├── unwind_x86_32_64.c ├── unwind_x86_64.h ├── va_server.c ├── va_server.h ├── va_server_v1.c ├── vas_crash.h ├── vmcore.h ├── vmware_guestdump.c ├── vmware_vmss.c ├── vmware_vmss.h ├── x86.c ├── x86_64.c ├── xen_dom0.c ├── xen_dom0.h ├── xen_hyper.c ├── xen_hyper_command.c ├── xen_hyper_defs.h ├── xen_hyper_dump_tables.c ├── xen_hyper_global_data.c ├── xendump.c └── xendump.h /.github/workflows/ci-build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | 7 | jobs: 8 | build: 9 | name: Build 10 | runs-on: ubuntu-24.04 11 | strategy: 12 | matrix: 13 | arch: 14 | - x86_64 15 | - aarch64 16 | - s390x 17 | - powerpc64 18 | - x86 19 | - riscv64 20 | - mips 21 | - alpha 22 | - sparc64 23 | 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v4 27 | 28 | - name: Set Environment 29 | env: 30 | ARCH: ${{ matrix.arch }} 31 | run: | 32 | case $ARCH in 33 | x86) GNU_ARCH="i686-linux-gnu" ;; 34 | x86_64) CROSS_COMPILER_PKG="gcc-x86-64-linux-gnu" 35 | CROSS_COMPILER_PKG+=" g++-x86-64-linux-gnu" 36 | GNU_ARCH="$ARCH-linux-gnu" ;; 37 | *) GNU_ARCH="$ARCH-linux-gnu" ;; 38 | esac 39 | 40 | if [ -n "$GNU_ARCH" ]; then 41 | if [ -z "$CROSS_COMPILER_PKG" ]; then 42 | CROSS_COMPILER_PKG="gcc-$GNU_ARCH" 43 | CROSS_COMPILER_PKG+=" g++-$GNU_ARCH" 44 | fi 45 | EXTRA_PKGS+=" $CROSS_COMPILER_PKG" 46 | CROSS_COMPILE="$GNU_ARCH" 47 | fi 48 | 49 | echo "EXTRA_PKGS=$EXTRA_PKGS" >> $GITHUB_ENV 50 | echo "CROSS_COMPILE=$CROSS_COMPILE" >> $GITHUB_ENV 51 | 52 | - name: Install deps for crash-utility building 53 | run: | 54 | sudo apt-get update 55 | sudo apt-get install make gcc g++ bison flex texinfo wget patch tar build-essential libc-dev autoconf automake libncurses-dev 56 | 57 | - name: Install corss compile tool pkgs 58 | if: env.EXTRA_PKGS != '' 59 | run: | 60 | sudo apt-get update 61 | sudo apt-get -q=2 install ${{ env.EXTRA_PKGS }} 62 | 63 | - name: Cross compile gmp lib 64 | run: | 65 | mkdir $GITHUB_WORKSPACE/libtools 66 | wget https://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.2.1.tar.bz2 67 | tar -jxvf gmp-6.2.1.tar.bz2 68 | cd gmp-6.2.1 69 | ./configure --host=${{ env.CROSS_COMPILE }} --prefix=$GITHUB_WORKSPACE/libtools 70 | make -j`nproc` 71 | sudo make install 72 | cd .. 73 | - name: Cross compile mpfr lib 74 | run: | 75 | wget https://gcc.gnu.org/pub/gcc/infrastructure/mpfr-4.1.0.tar.bz2 76 | tar -jxvf mpfr-4.1.0.tar.bz2 77 | cd mpfr-4.1.0 78 | ./configure --host=${{ env.CROSS_COMPILE }} --prefix=$GITHUB_WORKSPACE/libtools --with-gmp=$GITHUB_WORKSPACE/libtools 79 | make -j`nproc` 80 | sudo make install 81 | cd .. 82 | - name: Cross compile crash-utility 83 | run: | 84 | sudo cp $GITHUB_WORKSPACE/libtools/include/* /usr/include/ 85 | sudo cp -r $GITHUB_WORKSPACE/libtools/lib/* /usr/lib/ 86 | make CROSS_COMPILE=${{ env.CROSS_COMPILE }}- -j`nproc` warn 87 | - name: Checking and Clean up 88 | run: | 89 | echo "Run command: file crash ..." 90 | file crash 91 | echo "Clean up for compiling ..." 92 | make CROSS_COMPILE=${{ env.CROSS_COMPILE }}- -j`nproc` clean 93 | -------------------------------------------------------------------------------- /.github/workflows/ci-test.yml: -------------------------------------------------------------------------------- 1 | name: Testing Farm CI 2 | 3 | on: 4 | schedule: 5 | - cron: '10 2 * * 1' 6 | 7 | jobs: 8 | cron_schedule: 9 | name: Testing Farm CI (${{ matrix.arch }} ${{ matrix.compose }}) 10 | runs-on: ubuntu-latest 11 | timeout-minutes: 90 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | arch: [x86_64] 16 | compose: [Fedora-Rawhide] 17 | 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@v4 21 | 22 | - name: Checking TF_API_KEY 23 | run: | 24 | if [ -z "${{ secrets.TF_API_KEY }}" ]; then 25 | echo "TF_API_KEY is empty!" 26 | exit 1 27 | else 28 | echo "TF_API_KEY is set!" 29 | fi 30 | 31 | - name: Schedule tests on Testing Farm 32 | id: testing-farm 33 | uses: sclorg/testing-farm-as-github-action@v4 34 | with: 35 | api_key: ${{ secrets.TF_API_KEY }} 36 | git_url: https://github.com/crash-utility/crash.git 37 | tf_scope: private 38 | git_ref: master 39 | tmt_path: ci-tests 40 | tmt_plan_regex: local$ 41 | compose: ${{ matrix.compose }} 42 | arch: ${{ matrix.arch }} 43 | -------------------------------------------------------------------------------- /.github/workflows/pr-closer.yml: -------------------------------------------------------------------------------- 1 | name: Close Pull Request 2 | 3 | on: 4 | pull_request_target: 5 | types: [opened, reopened] 6 | 7 | jobs: 8 | run: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: superbrothers/close-pull-request@v3 12 | with: 13 | comment: "The github repo does not accept PRs, please subscribe to mail list via https://lists.crash-utility.osci.io/admin/lists/devel.lists.crash-utility.osci.io/ for contribution and discussion. Or post your patch to mail list: devel@lists.crash-utility.osci.io" 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | configure 2 | build_data.c 3 | cscope.out 4 | crashlib.a 5 | *.o 6 | crash 7 | CFLAGS.extra 8 | LDFLAGS.extra 9 | crash.spec 10 | *.gz 11 | *.rpm 12 | gdb.files 13 | gdb-7.6/ 14 | gdb-10.2/ 15 | gdb-16.2/ 16 | extensions/defs.h 17 | extensions/*.so 18 | extensions/eppic 19 | 20 | # cscope files 21 | cscope.* 22 | ncscope.* 23 | 24 | # ctags files 25 | tags 26 | TAGS 27 | 28 | # Clang's compilation database file 29 | /compile_commands.json 30 | -------------------------------------------------------------------------------- /.rh_rpm_package: -------------------------------------------------------------------------------- 1 | 9.0.0++ 2 | -------------------------------------------------------------------------------- /ci-tests/.fmf/version: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /ci-tests/local.fmf: -------------------------------------------------------------------------------- 1 | summary: Generate vmcore and analyze it with crash tool 2 | environment: 3 | KDUMP_UTILS_RPM: kdump-utils 4 | discover+: 5 | test: 6 | - /kdump/default_crashkernel 7 | - /kdump/config-any 8 | - /kdump/crash-sysrq-c 9 | - /kdump/build-crash-utility 10 | - /kdump/analyse-crash-cmd/common_analyse 11 | 12 | -------------------------------------------------------------------------------- /ci-tests/main.fmf: -------------------------------------------------------------------------------- 1 | provision: 2 | - name: client 3 | hardware: 4 | memory: ">= 4 GiB" 5 | cpu: 6 | processors: ">= 4" 7 | 8 | prepare: 9 | # Set root password to log in as root in the console 10 | - name: Set root password 11 | how: shell 12 | script: 13 | - echo root:kdump | chpasswd 14 | 15 | - name: Use custom mirror 16 | how: shell 17 | script: 18 | - test -v CUSTOM_MIRROR && sed -e 's/^metalink=/#metalink=/g' -e "s|^#baseurl=http://download.example/pub/fedora/linux|baseurl=${CUSTOM_MIRROR}|g" -i.bak /etc/yum.repos.d/fedora{,-updates}.repo || true 19 | 20 | execute: 21 | how: tmt 22 | exit-first: true 23 | 24 | discover: 25 | how: fmf 26 | url: https://github.com/crash-utility/crash-test.git 27 | ref: main 28 | -------------------------------------------------------------------------------- /crash_target.c: -------------------------------------------------------------------------------- 1 | /* 2 | * crash_target.c 3 | * 4 | * Copyright (c) 2021 VMware, Inc. 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * Author: Alexey Makhalov 17 | */ 18 | 19 | #include 20 | #include "top.h" 21 | #include "target.h" 22 | #include "inferior.h" 23 | #include "regcache.h" 24 | #include "gdbarch.h" 25 | 26 | void crash_target_init (void); 27 | 28 | extern "C" int gdb_readmem_callback(unsigned long, void *, int, int); 29 | extern "C" int crash_get_current_task_reg (int regno, const char *regname, 30 | int regsize, void *val); 31 | extern "C" int gdb_change_thread_context (void); 32 | extern "C" void crash_get_current_task_info(unsigned long *pid, char **comm); 33 | 34 | /* The crash target. */ 35 | 36 | static const target_info crash_target_info = { 37 | "crash", 38 | N_("Local core dump file"), 39 | N_("Use a built-in crash instance as a target.") 40 | }; 41 | 42 | class crash_target final : public process_stratum_target 43 | { 44 | public: 45 | 46 | const target_info &info () const override 47 | { return crash_target_info; } 48 | 49 | void fetch_registers (struct regcache *, int) override; 50 | enum target_xfer_status xfer_partial (enum target_object object, 51 | const char *annex, 52 | gdb_byte *readbuf, 53 | const gdb_byte *writebuf, 54 | ULONGEST offset, ULONGEST len, 55 | ULONGEST *xfered_len) override; 56 | 57 | bool has_all_memory () override { return true; } 58 | bool has_memory () override { return true; } 59 | bool has_stack () override { return true; } 60 | bool has_registers () override { return true; } 61 | bool thread_alive (ptid_t ptid) override { return true; } 62 | std::string pid_to_str (ptid_t ptid) override 63 | { 64 | unsigned long pid; 65 | char *comm; 66 | crash_get_current_task_info(&pid, &comm); 67 | return string_printf ("%ld %s", pid, comm); 68 | } 69 | 70 | }; 71 | 72 | static void supply_registers(struct regcache *regcache, int regno) 73 | { 74 | gdb_byte regval[16]; 75 | struct gdbarch *arch = regcache->arch (); 76 | const char *regname = gdbarch_register_name(arch, regno); 77 | int regsize = register_size(arch, regno); 78 | 79 | if (regsize > sizeof (regval)) 80 | error (_("fatal error: buffer size is not enough to fit register value")); 81 | 82 | if (crash_get_current_task_reg (regno, regname, regsize, (void *)®val)) 83 | regcache->raw_supply (regno, regval); 84 | else 85 | regcache->raw_supply (regno, NULL); 86 | } 87 | 88 | void 89 | crash_target::fetch_registers (struct regcache *regcache, int regno) 90 | { 91 | if (regno >= 0) { 92 | supply_registers(regcache, regno); 93 | } else if (regno == -1) { 94 | for (int r = 0; r < gdbarch_num_regs (regcache->arch ()); r++) 95 | supply_registers(regcache, r); 96 | } 97 | } 98 | 99 | 100 | enum target_xfer_status 101 | crash_target::xfer_partial (enum target_object object, const char *annex, 102 | gdb_byte *readbuf, const gdb_byte *writebuf, 103 | ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) 104 | { 105 | if (object != TARGET_OBJECT_MEMORY && object != TARGET_OBJECT_STACK_MEMORY 106 | && object != TARGET_OBJECT_CODE_MEMORY) 107 | return TARGET_XFER_E_IO; 108 | 109 | if (gdb_readmem_callback(offset, (void *)(readbuf ? readbuf : writebuf), len, !readbuf)) 110 | { 111 | *xfered_len = len; 112 | return TARGET_XFER_OK; 113 | } 114 | 115 | return TARGET_XFER_E_IO; 116 | } 117 | 118 | #define CRASH_INFERIOR_PID 1 119 | 120 | void 121 | crash_target_init (void) 122 | { 123 | crash_target *target = new crash_target (); 124 | 125 | /* Own the target until it is successfully pushed. */ 126 | target_ops_up target_holder (target); 127 | 128 | current_inferior ()->push_target (std::move (target_holder)); 129 | 130 | inferior_appeared (current_inferior (), CRASH_INFERIOR_PID); 131 | 132 | /*Only create 1 gdb threads to view tasks' stack unwinding*/ 133 | thread_info *thread = add_thread_silent (target, 134 | ptid_t(CRASH_INFERIOR_PID, 0, 0)); 135 | switch_to_thread (thread); 136 | 137 | /* Fetch all registers from core file. */ 138 | target_fetch_registers (get_thread_regcache(thread), -1); 139 | 140 | /* Now, set up the frame cache. */ 141 | reinit_frame_cache (); 142 | } 143 | 144 | extern "C" int 145 | gdb_change_thread_context (void) 146 | { 147 | target_fetch_registers(get_thread_regcache(inferior_thread()), -1); 148 | reinit_frame_cache(); 149 | return TRUE; 150 | } 151 | -------------------------------------------------------------------------------- /diskdump.h: -------------------------------------------------------------------------------- 1 | /* 2 | * diskdump.h 3 | * 4 | * Copyright (C) 2004, 2005, 2006 David Anderson 5 | * Copyright (C) 2004, 2005, 2006 Red Hat, Inc. All rights reserved. 6 | * Copyright (C) 2005 FUJITSU LIMITED 7 | * Copyright (C) 2005 NEC Corporation 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | */ 19 | 20 | #include 21 | 22 | #define divideup(x, y) (((x) + ((y) - 1)) / (y)) 23 | #define round(x, y) (((x) / (y)) * (y)) 24 | 25 | #define DUMP_PARTITION_SIGNATURE "diskdump" 26 | #define SIG_LEN (sizeof(DUMP_PARTITION_SIGNATURE) - 1) 27 | #define DISK_DUMP_SIGNATURE "DISKDUMP" 28 | #define KDUMP_SIGNATURE "KDUMP " 29 | 30 | #define DUMP_HEADER_COMPLETED 0 31 | #define DUMP_HEADER_INCOMPLETED 1 32 | #define DUMP_HEADER_COMPRESSED 8 33 | 34 | struct disk_dump_header { 35 | char signature[SIG_LEN]; /* = "DISKDUMP" */ 36 | int header_version; /* Dump header version */ 37 | struct new_utsname utsname; /* copy of system_utsname */ 38 | struct timeval timestamp; /* Time stamp */ 39 | unsigned int status; /* Above flags */ 40 | int block_size; /* Size of a block in byte */ 41 | int sub_hdr_size; /* Size of arch dependent 42 | header in blocks */ 43 | unsigned int bitmap_blocks; /* Size of Memory bitmap in 44 | block */ 45 | unsigned int max_mapnr; /* = max_mapnr, OBSOLETE! 46 | 32bit only, full 64bit 47 | in sub header. */ 48 | unsigned int total_ram_blocks;/* Number of blocks should be 49 | written */ 50 | unsigned int device_blocks; /* Number of total blocks in 51 | * the dump device */ 52 | unsigned int written_blocks; /* Number of written blocks */ 53 | unsigned int current_cpu; /* CPU# which handles dump */ 54 | int nr_cpus; /* Number of CPUs */ 55 | struct task_struct *tasks[0]; 56 | }; 57 | 58 | struct disk_dump_sub_header { 59 | long elf_regs; 60 | }; 61 | 62 | struct kdump_sub_header { 63 | unsigned long phys_base; 64 | int dump_level; /* header_version 1 and later */ 65 | int split; /* header_version 2 and later */ 66 | unsigned long start_pfn; /* header_version 2 and later, 67 | OBSOLETE! 32bit only, full 64bit 68 | in start_pfn_64. */ 69 | unsigned long end_pfn; /* header_version 2 and later, 70 | OBSOLETE! 32bit only, full 64bit 71 | in end_pfn_64. */ 72 | off_t offset_vmcoreinfo; /* header_version 3 and later */ 73 | unsigned long size_vmcoreinfo; /* header_version 3 and later */ 74 | off_t offset_note; /* header_version 4 and later */ 75 | unsigned long size_note; /* header_version 4 and later */ 76 | off_t offset_eraseinfo; /* header_version 5 and later */ 77 | unsigned long size_eraseinfo; /* header_version 5 and later */ 78 | unsigned long long start_pfn_64; /* header_version 6 and later */ 79 | unsigned long long end_pfn_64; /* header_version 6 and later */ 80 | unsigned long long max_mapnr_64; /* header_version 6 and later */ 81 | }; 82 | 83 | /* page flags */ 84 | #define DUMP_DH_COMPRESSED_ZLIB 0x1 /* page is compressed with zlib */ 85 | #define DUMP_DH_COMPRESSED_LZO 0x2 /* page is compressed with lzo */ 86 | #define DUMP_DH_COMPRESSED_SNAPPY 0x4 /* page is compressed with snappy */ 87 | #define DUMP_DH_COMPRESSED_INCOMPLETE 0x8 /* dumpfile is incomplete */ 88 | #define DUMP_DH_EXCLUDED_VMEMMAP 0x10 /* unused vmemmap pages are excluded */ 89 | #define DUMP_DH_COMPRESSED_ZSTD 0x20 /* page is compressed with zstd */ 90 | 91 | /* descriptor of each page for vmcore */ 92 | typedef struct page_desc { 93 | off_t offset; /* the offset of the page data*/ 94 | unsigned int size; /* the size of this dump page */ 95 | unsigned int flags; /* flags */ 96 | unsigned long long page_flags; /* page flags */ 97 | } page_desc_t; 98 | 99 | #define DISKDUMP_CACHED_PAGES (16) 100 | #define PAGE_VALID (0x1) /* flags */ 101 | #define DISKDUMP_VALID_PAGE(flags) ((flags) & PAGE_VALID) 102 | 103 | -------------------------------------------------------------------------------- /extensions/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile for building crash shared object extensions 3 | # 4 | # Copyright (C) 2005, 2007, 2009, 2011, 2013 David Anderson 5 | # Copyright (C) 2005, 2007, 2009, 2011, 2013 Red Hat, Inc. All rights reserved. 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # To build the extension shared objects in this directory, run 18 | # "make extensions" from the top-level directory. 19 | # 20 | # To add a new extension object, simply copy your module's .c file 21 | # to this directory, and it will be built automatically using 22 | # the "standard" compile line. If that compile line does not 23 | # suffice, create a .mk file with the same prefix as the .c file, 24 | # and that makefile will be invoked. 25 | # 26 | 27 | CONTRIB_SO := $(patsubst %.c,%.so,$(wildcard *.c)) 28 | 29 | all: link_defs $(CONTRIB_SO) 30 | 31 | link_defs: 32 | @rm -f defs.h 33 | @ln ../defs.h 34 | 35 | $(CONTRIB_SO): %.so: %.c defs.h 36 | @if [ -f $*.mk ]; then \ 37 | $(MAKE) -f $*.mk; \ 38 | else \ 39 | grep -q '((constructor))' $*.c && { \ 40 | echo "gcc -Wall -g -shared -rdynamic -o $@ $*.c -fPIC -D$(TARGET) $(TARGET_CFLAGS) $(GDB_FLAGS)"; \ 41 | gcc -Wall -g -shared -rdynamic -o $@ $*.c -fPIC -D$(TARGET) $(TARGET_CFLAGS) $(GDB_FLAGS); \ 42 | } || { \ 43 | echo "gcc -Wall -g -nostartfiles -shared -rdynamic -o $@ $*.c -fPIC -D$(TARGET) $(TARGET_CFLAGS) $(GDB_FLAGS)"; \ 44 | gcc -Wall -g -nostartfiles -shared -rdynamic -o $@ $*.c -fPIC -D$(TARGET) $(TARGET_CFLAGS) $(GDB_FLAGS); \ 45 | }; \ 46 | fi 47 | 48 | clean: 49 | rm -f $(CONTRIB_SO) 50 | @for MAKEFILE in `grep -sl "^clean:" *.mk`; \ 51 | do $(MAKE) -f $$MAKEFILE clean; \ 52 | done 53 | -------------------------------------------------------------------------------- /extensions/echo.c: -------------------------------------------------------------------------------- 1 | /* echo.c - simple example of a crash extension 2 | * 3 | * Copyright (C) 2001, 2002 Mission Critical Linux, Inc. 4 | * Copyright (C) 2002-2005, 2007, 2013 David Anderson 5 | * Copyright (C) 2002-2005, 2007, 2013 Red Hat, Inc. All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #include "defs.h" /* From the crash source top-level directory */ 19 | 20 | static void echo_init(void); /* constructor function */ 21 | static void echo_fini(void); /* destructor function (optional) */ 22 | 23 | static void cmd_echo(void); /* Declare the commands and their help data. */ 24 | static char *help_echo[]; 25 | 26 | /* 27 | * Please making the functions and global variables static within your 28 | * extension if you don't want to make them visiable to subsequently 29 | * loaded extensions. Otherwise, non-static symbols within 2 extensions 30 | * that have the same name can cause confliction. 31 | */ 32 | static struct command_table_entry command_table[] = { 33 | { "echo", cmd_echo, help_echo, 0}, /* One or more commands, */ 34 | { NULL }, /* terminated by NULL, */ 35 | }; 36 | 37 | 38 | static void __attribute__((constructor)) 39 | echo_init(void) /* Register the command set. */ 40 | { 41 | register_extension(command_table); 42 | } 43 | 44 | /* 45 | * This function is called if the shared object is unloaded. 46 | * If desired, perform any cleanups here. 47 | */ 48 | static void __attribute__((destructor)) 49 | echo_fini(void) { } 50 | 51 | 52 | /* 53 | * Arguments are passed to the command functions in the global args[argcnt] 54 | * array. See getopt(3) for info on dash arguments. Check out defs.h and 55 | * other crash commands for usage of the myriad of utility routines available 56 | * to accomplish what your task. 57 | */ 58 | static void 59 | cmd_echo(void) 60 | { 61 | int c; 62 | 63 | while ((c = getopt(argcnt, args, "")) != EOF) { 64 | switch(c) 65 | { 66 | default: 67 | argerrs++; 68 | break; 69 | } 70 | } 71 | 72 | if (argerrs) 73 | cmd_usage(pc->curcmd, SYNOPSIS); 74 | 75 | while (args[optind]) 76 | fprintf(fp, "%s ", args[optind++]); 77 | 78 | fprintf(fp, "\n"); 79 | } 80 | 81 | /* 82 | * The optional help data is simply an array of strings in a defined format. 83 | * For example, the "help echo" command will use the help_echo[] string 84 | * array below to create a help page that looks like this: 85 | * 86 | * NAME 87 | * echo - echoes back its arguments 88 | * 89 | * SYNOPSIS 90 | * echo arg ... 91 | * 92 | * DESCRIPTION 93 | * This command simply echoes back its arguments. 94 | * 95 | * EXAMPLE 96 | * Echo back all command arguments: 97 | * 98 | * crash> echo hello, world 99 | * hello, world 100 | * 101 | */ 102 | 103 | static char *help_echo[] = { 104 | "echo", /* command name */ 105 | "echoes back its arguments", /* short description */ 106 | "arg ...", /* argument synopsis, or " " if none */ 107 | 108 | " This command simply echoes back its arguments.", 109 | "\nEXAMPLE", 110 | " Echo back all command arguments:\n", 111 | " crash> echo hello, world", 112 | " hello, world", 113 | NULL 114 | }; 115 | 116 | 117 | -------------------------------------------------------------------------------- /extensions/eppic.c: -------------------------------------------------------------------------------- 1 | /* 2 | Place holder for proper working of the extension Makefile. 3 | Eppic crash application file is in eppic/applications/crash/eppic.c 4 | */ 5 | -------------------------------------------------------------------------------- /extensions/eppic.mk: -------------------------------------------------------------------------------- 1 | # 2 | # This program is free software; you can redistribute it and/or modify 3 | # it under the terms of the GNU General Public License as published by 4 | # the Free Software Foundation; either version 2 of the License, or 5 | # (at your option) any later version. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | 12 | TARGET_FLAGS = -D$(TARGET) 13 | ifeq ($(TARGET), PPC64) 14 | TARGET_FLAGS += -m64 15 | endif 16 | ifeq ($(TARGET), ARM) 17 | TARGET_FLAGS += -m32 18 | endif 19 | ifeq ($(TARGET), MIPS) 20 | TARGET_FLAGS += -m32 21 | endif 22 | ifeq ($(TARGET), X86) 23 | TARGET_FLAGS += -m32 24 | endif 25 | 26 | APPFILE=eppic/applications/crash/eppic.c 27 | GIT := $(shell which git 2> /dev/null) 28 | # crash 8 with gdb 10 uses new third party callback (tcb) API 29 | EPPIC_BRANCH=v5.0 30 | 31 | all: 32 | @if [ -f /usr/bin/flex ] && [ -f /usr/bin/bison ]; \ 33 | then \ 34 | if [ -f ../$(GDB)/crash.target ]; \ 35 | then \ 36 | if [ ! -f $(APPFILE) ]; \ 37 | then \ 38 | if [ -f "$(GIT)" ]; \ 39 | then \ 40 | if [ -n "$(EPPIC_GIT_URL)" ]; \ 41 | then \ 42 | git clone $(EPPIC_GIT_OPTIONS) $(EPPIC_GIT_URL) eppic; \ 43 | else \ 44 | if ping -c 1 -W 5 github.com >/dev/null ; then \ 45 | git clone -b $(EPPIC_BRANCH) $(EPPIC_GIT_OPTIONS) https://github.com/lucchouina/eppic.git eppic; \ 46 | fi; \ 47 | fi; \ 48 | else \ 49 | if [ ! -f "$(GIT)" ]; then \ 50 | echo "eppic.so: git command is needed for pulling eppic extension code"; \ 51 | fi; \ 52 | fi; \ 53 | fi; \ 54 | if [ -f $(APPFILE) ]; \ 55 | then \ 56 | make -f eppic.mk eppic.so; \ 57 | else \ 58 | echo "eppic.so: failed to pull eppic code from git repo"; \ 59 | fi; \ 60 | else \ 61 | echo "eppic.so: build failed: requires the crash $(GDB) module"; \ 62 | fi ;\ 63 | else \ 64 | echo "eppic.so: build failed: requires /usr/bin/flex and /usr/bin/bison"; \ 65 | fi 66 | 67 | lib-eppic: 68 | cd eppic/libeppic && make 69 | 70 | eppic.so: ../defs.h $(APPFILE) lib-eppic 71 | gcc -g -O0 -Ieppic/libeppic -I.. -nostartfiles -shared -rdynamic -o eppic.so $(APPFILE) -fPIC $(TARGET_FLAGS) $(GDB_FLAGS) -Leppic/libeppic -leppic 72 | 73 | clean: 74 | if [ -d eppic/libeppic ]; \ 75 | then \ 76 | cd eppic/libeppic && make -i clean; \ 77 | fi 78 | rm -f eppic.so 79 | -------------------------------------------------------------------------------- /extensions/snap.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2009, 2011, 2013 David Anderson 3 | # Copyright (C) 2009, 2011, 2013 Red Hat, Inc. All rights reserved. 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | 16 | ifeq ($(shell arch), i686) 17 | TARGET=X86 18 | TARGET_CFLAGS=-D_FILE_OFFSET_BITS=64 19 | endif 20 | ifeq ($(shell arch), ppc64) 21 | TARGET=PPC64 22 | TARGET_CFLAGS=-m64 23 | endif 24 | ifeq ($(shell arch), ppc64le) 25 | TARGET=PPC64 26 | TARGET_CFLAGS=-m64 27 | endif 28 | ifeq ($(shell arch), ia64) 29 | TARGET=IA64 30 | TARGET_CFLAGS= 31 | endif 32 | ifeq ($(shell arch), x86_64) 33 | TARGET=X86_64 34 | TARGET_CFLAGS= 35 | endif 36 | 37 | ifeq ($(shell /bin/ls /usr/include/crash/defs.h 2>/dev/null), /usr/include/crash/defs.h) 38 | INCDIR=/usr/include/crash 39 | endif 40 | ifeq ($(shell /bin/ls ../defs.h 2> /dev/null), ../defs.h) 41 | INCDIR=.. 42 | endif 43 | ifeq ($(shell /bin/ls ./defs.h 2> /dev/null), ./defs.h) 44 | INCDIR=. 45 | endif 46 | 47 | all: snap.so 48 | 49 | snap.so: $(INCDIR)/defs.h snap.c 50 | gcc -Wall -g -I$(INCDIR) -shared -rdynamic -o snap.so snap.c -fPIC -D$(TARGET) $(TARGET_CFLAGS) $(GDB_FLAGS) 51 | -------------------------------------------------------------------------------- /global_data.c: -------------------------------------------------------------------------------- 1 | /* global_data.c - core analysis suite 2 | * 3 | * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. 4 | * Copyright (C) 2002-2006, 2010, 2012-2013, 2018 David Anderson 5 | * Copyright (C) 2002-2006, 2010, 2012-2013, 2018 Red Hat, Inc. All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #include "defs.h" 19 | 20 | /* 21 | * Data output FILE pointer. The contents of fp are changed on the fly 22 | * depending upon whether the output is going to stdout, redirected to a 23 | * user-designated pipe or file, or to the "standard" scrolling pipe. 24 | * Regardless of where it ends up, fprintf(fp, ...) is used throughout 25 | * instead of printf(). 26 | */ 27 | 28 | FILE *fp; 29 | 30 | /* 31 | * The state of the program is kept in the program_context structure. 32 | * Given that it's consulted so often, "pc" is globally available to 33 | * quickly access the structure contents. 34 | */ 35 | struct program_context program_context = { 0 }; 36 | struct program_context *pc = &program_context; 37 | 38 | /* 39 | * The same thing goes for accesses to the frequently-accessed task_table, 40 | * kernel_table, vm_table, symbol_table_data and machdep_table, making the 41 | * "tt", "kt", "vt", "st" and "machdep" pointers globally available. 42 | */ 43 | struct task_table task_table = { 0 }; 44 | struct task_table *tt = &task_table; 45 | 46 | struct kernel_table kernel_table = { 0 }; 47 | struct kernel_table *kt = &kernel_table; 48 | 49 | struct vm_table vm_table = { 0 }; 50 | struct vm_table *vt = &vm_table; 51 | 52 | struct symbol_table_data symbol_table_data = { 0 }; 53 | struct symbol_table_data *st = &symbol_table_data; 54 | 55 | struct machdep_table machdep_table = { 0 }; 56 | struct machdep_table *machdep = &machdep_table; 57 | 58 | /* 59 | * Command functions are entered with the args[] array and argcnt value 60 | * pre-set for issuance to getopt(). 61 | */ 62 | 63 | char *args[MAXARGS]; /* argument array */ 64 | int argcnt; /* argument count */ 65 | int argerrs; /* argument error counter */ 66 | 67 | /* 68 | * To add a new command, declare it in defs.h and enter it in this table. 69 | */ 70 | 71 | struct command_table_entry linux_command_table[] = { 72 | {"*", cmd_pointer, help_pointer, 0}, 73 | {"alias", cmd_alias, help_alias, 0}, 74 | {"ascii", cmd_ascii, help_ascii, 0}, 75 | {"bpf", cmd_bpf, help_bpf, 0}, 76 | {"bt", cmd_bt, help_bt, REFRESH_TASK_TABLE}, 77 | {"btop", cmd_btop, help_btop, 0}, 78 | {"dev", cmd_dev, help_dev, 0}, 79 | {"dis", cmd_dis, help_dis, MINIMAL}, 80 | {"eval", cmd_eval, help_eval, MINIMAL}, 81 | {"exit", cmd_quit, help_exit, MINIMAL}, 82 | {"extend", cmd_extend, help_extend, MINIMAL}, 83 | {"files", cmd_files, help_files, REFRESH_TASK_TABLE}, 84 | {"foreach", cmd_foreach, help_foreach, REFRESH_TASK_TABLE}, 85 | {"fuser", cmd_fuser, help_fuser, REFRESH_TASK_TABLE}, 86 | {"gdb", cmd_gdb, help_gdb, REFRESH_TASK_TABLE}, 87 | {"help", cmd_help, help_help, MINIMAL}, 88 | {"ipcs", cmd_ipcs, help_ipcs, REFRESH_TASK_TABLE}, 89 | {"irq", cmd_irq, help_irq, 0}, 90 | {"kmem", cmd_kmem, help_kmem, 0}, 91 | {"list", cmd_list, help__list, REFRESH_TASK_TABLE}, 92 | {"log", cmd_log, help_log, MINIMAL}, 93 | {"mach", cmd_mach, help_mach, 0}, 94 | {"map", cmd_map, help_map, HIDDEN_COMMAND}, 95 | {"mod", cmd_mod, help_mod, 0}, 96 | {"mount", cmd_mount, help_mount, REFRESH_TASK_TABLE}, 97 | {"net", cmd_net, help_net, REFRESH_TASK_TABLE}, 98 | {"p", cmd_p, help_p, 0}, 99 | {"ps", cmd_ps, help_ps, REFRESH_TASK_TABLE}, 100 | {"pte", cmd_pte, help_pte, 0}, 101 | {"ptob", cmd_ptob, help_ptob, 0}, 102 | {"ptov", cmd_ptov, help_ptov, 0}, 103 | {"q", cmd_quit, help_quit, MINIMAL}, 104 | {"tree", cmd_tree, help_tree, REFRESH_TASK_TABLE}, 105 | {"rd", cmd_rd, help_rd, MINIMAL}, 106 | {"repeat", cmd_repeat, help_repeat, 0}, 107 | {"runq", cmd_runq, help_runq, REFRESH_TASK_TABLE}, 108 | {"sbitmapq", cmd_sbitmapq, help_sbitmapq, 0}, 109 | {"search", cmd_search, help_search, 0}, 110 | {"set", cmd_set, help_set, REFRESH_TASK_TABLE | MINIMAL}, 111 | {"sig", cmd_sig, help_sig, REFRESH_TASK_TABLE}, 112 | {"struct", cmd_struct, help_struct, 0}, 113 | {"swap", cmd_swap, help_swap, 0}, 114 | {"sym", cmd_sym, help_sym, MINIMAL}, 115 | {"sys", cmd_sys, help_sys, REFRESH_TASK_TABLE}, 116 | {"task", cmd_task, help_task, REFRESH_TASK_TABLE}, 117 | {"test", cmd_test, NULL, HIDDEN_COMMAND}, 118 | {"timer", cmd_timer, help_timer, 0}, 119 | {"union", cmd_union, help_union, 0}, 120 | {"vm", cmd_vm, help_vm, REFRESH_TASK_TABLE}, 121 | {"vtop", cmd_vtop, help_vtop, REFRESH_TASK_TABLE}, 122 | {"waitq", cmd_waitq, help_waitq, REFRESH_TASK_TABLE}, 123 | {"whatis", cmd_whatis, help_whatis, 0}, 124 | {"wr", cmd_wr, help_wr, 0}, 125 | #if defined(S390) || defined(S390X) 126 | {"s390dbf", cmd_s390dbf, help_s390dbf, 0}, 127 | #endif 128 | {(char *)NULL} 129 | }; 130 | 131 | struct extension_table *extension_table = NULL; 132 | 133 | /* 134 | * The offset_table and size_table structure contents are referenced 135 | * through several OFFSET- and SIZE-related macros. The array_table 136 | * is a shortcut used by get_array_length(). 137 | */ 138 | struct offset_table offset_table = { 0 }; 139 | struct size_table size_table = { 0 }; 140 | struct array_table array_table = { 0 }; 141 | -------------------------------------------------------------------------------- /ibm_common.h: -------------------------------------------------------------------------------- 1 | /* ibm_common.h - core analysis suite 2 | * 3 | * Copyright (C) 2001, 2002 Mission Critical Linux, Inc. 4 | * Copyright (C) 2002, 2003, 2004, 2005 David Anderson 5 | * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | /* 19 | * header file for zgetdump 20 | * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation 21 | * Author(s): Despina Papadopoulou 22 | */ 23 | 24 | /* This header file holds the architecture specific crash dump header */ 25 | #ifndef _ZGETDUMP_H 26 | #define _ZGETDUMP_H 27 | 28 | /* definitions (this has to match with vmdump.h of lcrash */ 29 | 30 | #define DUMP_MAGIC_S390 0xa8190173618f23fdULL /* s390 magic number */ 31 | #define S390_DUMP_HEADER_SIZE 4096 32 | #define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */ 33 | 34 | /* 35 | * Structure: s390_dump_header_t 36 | * Function: This is the header dumped at the top of every valid s390 crash 37 | * dump. 38 | */ 39 | 40 | typedef struct _s390_dump_header_s { 41 | /* the dump magic number -- unique to verify dump is valid */ 42 | uint64_t dh_magic_number; /* 0x000 */ 43 | 44 | /* the version number of this dump */ 45 | uint32_t dh_version; /* 0x008 */ 46 | 47 | /* the size of this header (in case we can't read it) */ 48 | uint32_t dh_header_size; /* 0x00c */ 49 | 50 | /* the level of this dump (just a header?) */ 51 | uint32_t dh_dump_level; /* 0x010 */ 52 | 53 | /* the size of a Linux memory page (4K, 8K, 16K, etc.) */ 54 | uint32_t dh_page_size; /* 0x014 */ 55 | 56 | /* the size of all physical memory */ 57 | uint64_t dh_memory_size; /* 0x018 */ 58 | 59 | /* the start of physical memory */ 60 | uint64_t dh_memory_start; /* 0x020 */ 61 | 62 | /* the end of physical memory */ 63 | uint64_t dh_memory_end; /* 0x028 */ 64 | 65 | /* the number of pages in this dump specifically */ 66 | uint32_t dh_num_pages; /* 0x030 */ 67 | 68 | /* ensure that dh_tod and dh_cpu_id are 8 byte aligned */ 69 | uint32_t dh_pad; /* 0x034 */ 70 | 71 | /* the time of the dump generation using stck */ 72 | uint64_t dh_tod; /* 0x038 */ 73 | 74 | /* cpu id */ 75 | uint64_t dh_cpu_id; /* 0x040 */ 76 | 77 | /* arch */ 78 | uint32_t dh_arch; /* 0x048 */ 79 | 80 | /* volume number */ 81 | uint32_t dh_volnr; /* 0x04c */ 82 | 83 | /* build arch */ 84 | uint32_t dh_build_arch; /* 0x050 */ 85 | 86 | /* fill up to 4096 byte */ 87 | unsigned char end_pad[0x1000-0x054]; /* 0x054 */ 88 | 89 | } __attribute__((packed)) s390_dump_header_t; 90 | 91 | /* 92 | * Structure: s390_dump_end_marker_t 93 | * Function: This end marker should be at the end of every valid s390 crash 94 | * dump. 95 | */ 96 | 97 | typedef struct _s390_dump_end_marker_{ 98 | char end_string[8]; 99 | unsigned long long end_time; 100 | } __attribute__((packed)) s390_dump_end_marker_t; 101 | 102 | #endif /* _ASM_VMDUMP_H */ 103 | -------------------------------------------------------------------------------- /kvmdump.h: -------------------------------------------------------------------------------- 1 | /* 2 | * kvmdump.h 3 | * 4 | * Copyright (C) 2009, 2010 David Anderson 5 | * Copyright (C) 2009, 2010 Red Hat, Inc. All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | struct mapinfo_trailer { 19 | uint64_t map_start_offset; 20 | uint64_t phys_base; 21 | uint32_t cpu_version_id; 22 | uint32_t ram_version_id; 23 | uint64_t checksum; 24 | uint64_t magic; 25 | }; 26 | 27 | struct register_set { 28 | uint32_t cs; 29 | uint32_t ss; 30 | uint32_t ds; 31 | uint32_t es; 32 | uint32_t fs; 33 | uint32_t gs; 34 | uint64_t ip; 35 | uint64_t flags; 36 | uint64_t regs[16]; 37 | }; 38 | 39 | #define REGS_MAGIC (0xfeedbeefdeadbabeULL) 40 | #define MAPFILE_MAGIC (0xfeedbabedeadbeefULL) 41 | #define CHKSUM_SIZE (4096) 42 | 43 | #define KVMDUMP_CACHED_PAGES 32 44 | 45 | struct kvmdump_data { 46 | ulong flags; 47 | FILE *ofp; 48 | FILE *vmp; 49 | int mapfd; 50 | int vmfd; 51 | struct mapinfo_trailer mapinfo; 52 | /* page cache */ 53 | struct kvm_page_cache_hdr { 54 | uint64_t paddr; 55 | char *bufptr; 56 | } page_cache[KVMDUMP_CACHED_PAGES]; 57 | union { 58 | char *curbufptr; 59 | unsigned char compressed; 60 | } un; 61 | int evict_index; 62 | ulong accesses; 63 | ulong hit_count; 64 | ulong compresses; 65 | uint64_t kvbase; 66 | ulong *debug; 67 | uint64_t cpu_devices; 68 | struct register_set *registers; 69 | uint64_t iohole; 70 | }; 71 | 72 | #define TMPFILE (0x2) 73 | #define MAPFILE (0x4) 74 | #define MAPFILE_FOUND (0x8) 75 | #define MAPFILE_APPENDED (0x10) 76 | #define NO_PHYS_BASE (0x20) 77 | #define KVMHOST_32 (0x40) 78 | #define KVMHOST_64 (0x80) 79 | #define REGS_FROM_DUMPFILE (0x100) 80 | #define REGS_FROM_MAPFILE (0x200) 81 | #define REGS_NOT_AVAIL (0x400) 82 | 83 | extern struct kvmdump_data *kvm; 84 | 85 | #undef dprintf 86 | #define dprintf(x...) do { if (*(kvm->debug)) fprintf(kvm->ofp, x); } while (0) 87 | 88 | int store_mapfile_offset(uint64_t, off_t *); 89 | int load_mapfile_offset(uint64_t, off_t *); 90 | 91 | struct qemu_device_x86; 92 | int kvmdump_regs_store(uint32_t, struct qemu_device_x86 *); 93 | #define KVMDUMP_REGS_START (NR_CPUS+1) 94 | #define KVMDUMP_REGS_END (NR_CPUS+2) 95 | 96 | #define UPPER_32_BITS (0xffffffff00000000ULL) 97 | 98 | enum CPU_REG { 99 | R_EAX, 100 | R_ECX, 101 | R_EDX, 102 | R_EBX, 103 | R_ESP, 104 | R_EBP, 105 | R_ESI, 106 | R_EDI, 107 | R_GP_MAX, 108 | }; 109 | 110 | -------------------------------------------------------------------------------- /lkcd_dump_v5.h: -------------------------------------------------------------------------------- 1 | /* lkcd_dump_v5.h - core analysis suite 2 | * 3 | * Copyright (C) 2001, 2002 Mission Critical Linux, Inc. 4 | * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson 5 | * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | 19 | /* 20 | * Kernel header file for Linux crash dumps. 21 | * 22 | * Created by: Matt Robinson (yakker@sgi.com) 23 | * Copyright 1999 Silicon Graphics, Inc. All rights reserved. 24 | * 25 | * vmdump.h to dump.h by: Matt D. Robinson (yakker@sourceforge.net) 26 | * Copyright 2001 Matt D. Robinson. All rights reserved. 27 | * 28 | * Most of this is the same old stuff from vmdump.h, except now we're 29 | * actually a stand-alone driver plugged into the block layer interface, 30 | * with the exception that we now allow for compression modes externally 31 | * loaded (e.g., someone can come up with their own). 32 | */ 33 | 34 | /* This header file includes all structure definitions for crash dumps. */ 35 | #ifndef _DUMP_H 36 | #define _DUMP_H 37 | 38 | //#include 39 | 40 | /* define TRUE and FALSE for use in our dump modules */ 41 | #ifndef FALSE 42 | #define FALSE 0 43 | #endif 44 | 45 | #ifndef TRUE 46 | #define TRUE 1 47 | #endif 48 | 49 | #ifndef MCLX 50 | 51 | /* 52 | * MCLX NOTE: the architecture-specific headers are being ignored until 53 | * deemed necessary; crash has never used them functionally, and only 54 | * referencing them in the dump_sgi_environment() helper routines. 55 | */ 56 | 57 | /* necessary header files */ 58 | #include /* for architecture-specific header */ 59 | #endif 60 | 61 | #define UTSNAME_ENTRY_SZ 65 62 | 63 | /* necessary header definitions in all cases */ 64 | #define DUMP_KIOBUF_NUMBER 0xdeadbeef /* special number for kiobuf maps */ 65 | 66 | /* size of a dump header page */ 67 | #define DUMP_PAGE_SZ 64 * 1024 /* size of dump page buffer */ 68 | 69 | /* header definitions for s390 dump */ 70 | #define DUMP_MAGIC_S390 0xa8190173618f23fdULL /* s390 magic number */ 71 | #define S390_DUMP_HEADER_SIZE 4096 72 | 73 | /* standard header definitions */ 74 | #define DUMP_MAGIC_NUMBER 0xa8190173618f23edULL /* dump magic number */ 75 | #define DUMP_MAGIC_LIVE 0xa8190173618f23cdULL /* live magic number */ 76 | #define DUMP_VERSION_NUMBER 0x5 /* dump version number */ 77 | #define DUMP_PANIC_LEN 0x100 /* dump panic string length */ 78 | 79 | /* dump levels - type specific stuff added later -- add as necessary */ 80 | #define DUMP_LEVEL_NONE 0x0 /* no dumping at all -- just bail */ 81 | #define DUMP_LEVEL_HEADER 0x1 /* kernel dump header only */ 82 | #define DUMP_LEVEL_KERN 0x2 /* dump header and kernel pages */ 83 | #define DUMP_LEVEL_USED 0x4 /* dump header, kernel/user pages */ 84 | #define DUMP_LEVEL_ALL 0x8 /* dump header, all memory pages */ 85 | 86 | /* dump compression options -- add as necessary */ 87 | #define DUMP_COMPRESS_NONE 0x0 /* don't compress this dump */ 88 | #define DUMP_COMPRESS_RLE 0x1 /* use RLE compression */ 89 | #define DUMP_COMPRESS_GZIP 0x2 /* use GZIP compression */ 90 | 91 | /* dump flags - any dump-type specific flags -- add as necessary */ 92 | #define DUMP_FLAGS_NONE 0x0 /* no flags are set for this dump */ 93 | #define DUMP_FLAGS_NONDISRUPT 0x1 /* try to keep running after dump */ 94 | 95 | /* dump header flags -- add as necessary */ 96 | #define DUMP_DH_FLAGS_NONE 0x0 /* no flags set (error condition!) */ 97 | #define DUMP_DH_RAW 0x1 /* raw page (no compression) */ 98 | #define DUMP_DH_COMPRESSED 0x2 /* page is compressed */ 99 | #define DUMP_DH_END 0x4 /* end marker on a full dump */ 100 | 101 | /* names for various dump tunables (they are now all read-only) */ 102 | #define DUMP_ROOT_NAME "sys/dump" 103 | #define DUMP_DEVICE_NAME "dump_device" 104 | #define DUMP_COMPRESS_NAME "dump_compress" 105 | #define DUMP_LEVEL_NAME "dump_level" 106 | #define DUMP_FLAGS_NAME "dump_flags" 107 | 108 | /* page size for gzip compression -- buffered beyond PAGE_SIZE slightly */ 109 | #define DUMP_DPC_PAGE_SIZE (PAGE_SIZE + 512) 110 | 111 | /* dump ioctl() control options */ 112 | #define DIOSDUMPDEV 1 /* set the dump device */ 113 | #define DIOGDUMPDEV 2 /* get the dump device */ 114 | #define DIOSDUMPLEVEL 3 /* set the dump level */ 115 | #define DIOGDUMPLEVEL 4 /* get the dump level */ 116 | #define DIOSDUMPFLAGS 5 /* set the dump flag parameters */ 117 | #define DIOGDUMPFLAGS 6 /* get the dump flag parameters */ 118 | #define DIOSDUMPCOMPRESS 7 /* set the dump compress level */ 119 | #define DIOGDUMPCOMPRESS 8 /* get the dump compress level */ 120 | 121 | /* the major number used for the dumping device */ 122 | #ifndef DUMP_MAJOR 123 | #define DUMP_MAJOR 227 124 | #endif 125 | 126 | /* 127 | * Structure: dump_header_t 128 | * Function: This is the header dumped at the top of every valid crash 129 | * dump. 130 | * easy reassembly of each crash dump page. The address bits 131 | * are split to make things easier for 64-bit/32-bit system 132 | * conversions. 133 | */ 134 | typedef struct _dump_header_s { 135 | /* the dump magic number -- unique to verify dump is valid */ 136 | uint64_t dh_magic_number; 137 | 138 | /* the version number of this dump */ 139 | uint32_t dh_version; 140 | 141 | /* the size of this header (in case we can't read it) */ 142 | uint32_t dh_header_size; 143 | 144 | /* the level of this dump (just a header?) */ 145 | uint32_t dh_dump_level; 146 | 147 | /* the size of a Linux memory page (4K, 8K, 16K, etc.) */ 148 | uint32_t dh_page_size; 149 | 150 | /* the size of all physical memory */ 151 | uint64_t dh_memory_size; 152 | 153 | /* the start of physical memory */ 154 | uint64_t dh_memory_start; 155 | 156 | /* the end of physical memory */ 157 | uint64_t dh_memory_end; 158 | 159 | /* the number of pages in this dump specifically */ 160 | uint32_t dh_num_pages; 161 | 162 | /* the panic string, if available */ 163 | char dh_panic_string[DUMP_PANIC_LEN]; 164 | 165 | /* the time of the system crash */ 166 | struct timeval dh_time; 167 | 168 | /* the NEW utsname (uname) information -- in character form */ 169 | /* we do this so we don't have to include utsname.h */ 170 | /* plus it helps us be more architecture independent */ 171 | /* now maybe one day soon they'll make the [65] a #define! */ 172 | char dh_utsname_sysname[65]; 173 | char dh_utsname_nodename[65]; 174 | char dh_utsname_release[65]; 175 | char dh_utsname_version[65]; 176 | char dh_utsname_machine[65]; 177 | char dh_utsname_domainname[65]; 178 | 179 | /* the address of current task (OLD = task_struct *, NEW = void *) */ 180 | void *dh_current_task; 181 | 182 | /* what type of compression we're using in this dump (if any) */ 183 | uint32_t dh_dump_compress; 184 | 185 | /* any additional flags */ 186 | uint32_t dh_dump_flags; 187 | 188 | /* any additional flags */ 189 | uint32_t dh_dump_device; 190 | 191 | } dump_header_t; 192 | 193 | /* 194 | * Structure: dump_page_t 195 | * Function: To act as the header associated to each physical page of 196 | * memory saved in the system crash dump. This allows for 197 | * easy reassembly of each crash dump page. The address bits 198 | * are split to make things easier for 64-bit/32-bit system 199 | * conversions. 200 | */ 201 | typedef struct _dump_page_s { 202 | 203 | /* the address of this dump page */ 204 | uint64_t dp_address; 205 | 206 | /* the size of this dump page */ 207 | uint32_t dp_size; 208 | 209 | /* flags (currently DUMP_COMPRESSED, DUMP_RAW or DUMP_END) */ 210 | uint32_t dp_flags; 211 | } dump_page_t; 212 | 213 | /* 214 | * This structure contains information needed for the lkcdutils 215 | * package (particularly lcrash) to determine what information is 216 | * associated to this kernel, specifically. 217 | */ 218 | typedef struct lkcdinfo_s { 219 | int arch; 220 | int ptrsz; 221 | int byte_order; 222 | int linux_release; 223 | int page_shift; 224 | int page_size; 225 | uint64_t page_mask; 226 | uint64_t page_offset; 227 | int stack_offset; 228 | } lkcdinfo_t; 229 | 230 | #ifdef __KERNEL__ 231 | 232 | /* 233 | * Structure: dump_compress_t 234 | * Function: This is what an individual compression mechanism can use 235 | * to plug in their own compression techniques. It's always 236 | * best to build these as individual modules so that people 237 | * can put in whatever they want. 238 | */ 239 | typedef struct dump_compress_s { 240 | /* the list_head structure for list storage */ 241 | struct list_head list; 242 | 243 | /* the type of compression to use (DUMP_COMPRESS_XXX) */ 244 | int compress_type; 245 | 246 | /* the compression function to call */ 247 | int (*compress_func)(char *, int, char *, int); 248 | } dump_compress_t; 249 | 250 | extern int dump_init(void); 251 | extern void dump_execute(char *, struct pt_regs *); 252 | extern int page_is_ram(unsigned long); 253 | 254 | #endif /* __KERNEL__ */ 255 | 256 | #endif /* _DUMP_H */ 257 | -------------------------------------------------------------------------------- /lkcd_fix_mem.c: -------------------------------------------------------------------------------- 1 | /* lkcd_fix_mem.c 2 | * 3 | * Copyright (C) 2004 Hewlett-Packard Development Company, L.P. 4 | * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. 5 | * Copyright (C) 2002, 2003, 2004, 2005 David Anderson 6 | * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | */ 18 | 19 | #ifdef IA64 20 | 21 | #define LKCD_COMMON 22 | #include "defs.h" 23 | #include "lkcd_dump_v8.h" 24 | 25 | static int fix_addr(dump_header_asm_t *); 26 | 27 | int 28 | fix_addr_v8(dump_header_asm_t *dha) 29 | { 30 | fix_addr(dha); 31 | 32 | return 0; 33 | } 34 | 35 | int 36 | fix_addr_v7(int fd) 37 | { 38 | static dump_header_asm_t dump_header_asm_v7 = { 0 }; 39 | dump_header_asm_t *dha; 40 | dha = &dump_header_asm_v7; 41 | 42 | if (read(lkcd->fd, dha, sizeof(dump_header_asm_t)) != 43 | sizeof(dump_header_asm_t)) 44 | return -1; 45 | 46 | fix_addr(dha); 47 | 48 | return 0; 49 | } 50 | 51 | static int 52 | fix_addr(dump_header_asm_t *dha) 53 | { 54 | lkcd->dump_header_asm = dha; 55 | 56 | 57 | if (dha->dha_magic_number == DUMP_ASM_MAGIC_NUMBER && dha->dha_version > 3) { 58 | int num; 59 | int i = 0; 60 | 61 | num = dha->dha_smp_num_cpus; 62 | 63 | 64 | lkcd->fix_addr_num = 0; 65 | if (num && (lkcd->fix_addr = malloc(num * sizeof(struct fix_addrs)))) { 66 | while (i < num) { 67 | if (dha->dha_stack[i] && dha->dha_smp_current_task[i]) { 68 | lkcd->fix_addr[i].task = (ulong)dha->dha_smp_current_task[i]; 69 | lkcd->fix_addr[i].saddr = (ulong)dha->dha_stack[i]; 70 | lkcd->fix_addr[i].sw = (ulong)dha->dha_stack_ptr[i]; 71 | /* remember the highest non-zero entry */ 72 | lkcd->fix_addr_num = i + 1; 73 | } else { 74 | lkcd->fix_addr[i].task = (ulong)0; 75 | } 76 | i++; 77 | } 78 | } 79 | } 80 | 81 | return 0; 82 | } 83 | 84 | ulong 85 | get_lkcd_switch_stack(ulong task) 86 | { 87 | int i; 88 | 89 | if (lkcd->fix_addr_num == 0) 90 | return 0; 91 | 92 | for (i = 0; i < lkcd->fix_addr_num; i++) { 93 | if (task == lkcd->fix_addr[i].task) { 94 | return lkcd->fix_addr[i].sw; 95 | } 96 | } 97 | return 0; 98 | } 99 | 100 | int lkcd_get_kernel_start_v8(ulong *addr) 101 | { 102 | if (!addr) 103 | return 0; 104 | 105 | *addr = ((dump_header_asm_t *)lkcd->dump_header_asm)->dha_kernel_addr; 106 | 107 | return 1; 108 | } 109 | 110 | #endif // IA64 111 | -------------------------------------------------------------------------------- /lkcd_v1.c: -------------------------------------------------------------------------------- 1 | /* lkcd_v1.c - core analysis suite 2 | * 3 | * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. 4 | * Copyright (C) 2002, 2003, 2004, 2005 David Anderson 5 | * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #define LKCD_COMMON 19 | #include "defs.h" 20 | #define CONFIG_VMDUMP 21 | #include "lkcd_vmdump_v1.h" 22 | 23 | static dump_header_t dump_header_v1 = { 0 }; 24 | static dump_page_t dump_page = { 0 }; 25 | 26 | /* 27 | * Verify and initialize the LKCD environment, storing the common data 28 | * in the global lkcd_environment structure. 29 | */ 30 | int 31 | lkcd_dump_init_v1(FILE *fp, int fd) 32 | { 33 | int i; 34 | int eof; 35 | uint32_t pgcnt; 36 | dump_header_t *dh; 37 | dump_page_t *dp; 38 | 39 | lkcd->fd = fd; 40 | lkcd->fp = fp; 41 | 42 | lseek(lkcd->fd, 0, SEEK_SET); 43 | 44 | dh = &dump_header_v1; 45 | dp = &dump_page; 46 | 47 | if (read(lkcd->fd, dh, sizeof(dump_header_t)) != 48 | sizeof(dump_header_t)) 49 | return FALSE; 50 | 51 | lkcd->dump_header = dh; 52 | lkcd->dump_page = dp; 53 | if (lkcd->debug) 54 | dump_lkcd_environment(LKCD_DUMP_HEADER_ONLY); 55 | 56 | /* 57 | * Allocate and clear the benchmark offsets, one per megabyte. 58 | */ 59 | lkcd->page_size = dh->dh_page_size; 60 | lkcd->page_shift = ffs(lkcd->page_size) - 1; 61 | lkcd->bits = sizeof(long) * 8; 62 | lkcd->total_pages = dh->dh_num_pages; 63 | lkcd->benchmark_pages = (dh->dh_num_pages/LKCD_PAGES_PER_MEGABYTE())+1; 64 | lkcd->page_header_size = sizeof(dump_page_t); 65 | 66 | lkcd->zone_shift = ffs(ZONE_SIZE) - 1; 67 | lkcd->zone_mask = ~(ZONE_SIZE - 1); 68 | lkcd->num_zones = 0; 69 | lkcd->max_zones = 0; 70 | 71 | lkcd->get_dp_flags = get_dp_flags_v1; 72 | lkcd->get_dp_address = get_dp_address_v1; 73 | lkcd->get_dp_size = get_dp_size_v1; 74 | lkcd->compression = LKCD_DUMP_COMPRESS_RLE; 75 | 76 | lseek(lkcd->fd, LKCD_OFFSET_TO_FIRST_PAGE, SEEK_SET); 77 | 78 | for (pgcnt = 0, eof = FALSE; !eof; pgcnt++) { 79 | 80 | switch (lkcd_load_dump_page_header(dp, pgcnt)) 81 | { 82 | case LKCD_DUMPFILE_OK: 83 | case LKCD_DUMPFILE_END: 84 | break; 85 | 86 | case LKCD_DUMPFILE_EOF: 87 | eof = TRUE; 88 | continue; 89 | } 90 | 91 | if (!(dp->dp_flags & (DUMP_COMPRESSED|DUMP_RAW|DUMP_END))) { 92 | lkcd_print("unknown page flag in dump: %lx\n", 93 | dp->dp_flags); 94 | } 95 | 96 | if (dp->dp_size > 4096) { 97 | lkcd_print("dp_size > 4096: %d\n", dp->dp_size); 98 | dump_lkcd_environment(LKCD_DUMP_PAGE_ONLY); 99 | } 100 | 101 | if (dp->dp_flags & DUMP_END) { 102 | lkcd_print("found DUMP_END\n"); 103 | break; 104 | } 105 | 106 | lseek(lkcd->fd, dp->dp_size, SEEK_CUR); 107 | 108 | if (!LKCD_DEBUG(1)) 109 | break; 110 | } 111 | 112 | /* 113 | * Allocate space for LKCD_CACHED_PAGES data pages plus one to 114 | * contain a copy of the compressed data of the current page. 115 | */ 116 | if ((lkcd->page_cache_buf = (char *)malloc 117 | (dh->dh_page_size * (LKCD_CACHED_PAGES))) == NULL) 118 | return FALSE; 119 | 120 | /* 121 | * Clear the page data areas. 122 | */ 123 | lkcd_free_memory(); 124 | for (i = 0; i < LKCD_CACHED_PAGES; i++) { 125 | lkcd->page_cache_hdr[i].pg_bufptr = 126 | &lkcd->page_cache_buf[i * dh->dh_page_size]; 127 | } 128 | 129 | if ((lkcd->compressed_page = (char *)malloc(dh->dh_page_size)) == NULL) 130 | return FALSE; 131 | 132 | if ((lkcd->page_hash = (struct page_hash_entry *)calloc 133 | (LKCD_PAGE_HASH, sizeof(struct page_hash_entry))) == NULL) 134 | return FALSE; 135 | 136 | lkcd->total_pages = eof || (pgcnt > dh->dh_num_pages) ? 137 | pgcnt : dh->dh_num_pages; 138 | lkcd->panic_task = (ulong)dh->dh_current_task; 139 | lkcd->panic_string = (char *)&dh->dh_panic_string[0]; 140 | if (!fp) 141 | lkcd->flags |= LKCD_REMOTE; 142 | lkcd->flags |= LKCD_VALID; 143 | 144 | return TRUE; 145 | } 146 | 147 | /* 148 | * Return the current page's dp_size. 149 | */ 150 | uint32_t 151 | get_dp_size_v1(void) 152 | { 153 | dump_page_t *dp; 154 | 155 | dp = (dump_page_t *)lkcd->dump_page; 156 | 157 | return(dp->dp_size); 158 | } 159 | 160 | /* 161 | * Return the current page's dp_flags. 162 | */ 163 | uint32_t 164 | get_dp_flags_v1(void) 165 | { 166 | dump_page_t *dp; 167 | 168 | dp = (dump_page_t *)lkcd->dump_page; 169 | 170 | return(dp->dp_flags); 171 | } 172 | 173 | /* 174 | * Return the current page's dp_address. 175 | */ 176 | uint64_t 177 | get_dp_address_v1(void) 178 | { 179 | dump_page_t *dp; 180 | 181 | dp = (dump_page_t *)lkcd->dump_page; 182 | 183 | return(dp->dp_address); 184 | } 185 | 186 | /* 187 | * console-only output for info regarding current page. 188 | */ 189 | void 190 | dump_dump_page_v1(char *s, void *dpp) 191 | { 192 | dump_page_t *dp; 193 | uint32_t flags; 194 | int others; 195 | 196 | console(s); 197 | 198 | dp = (dump_page_t *)dpp; 199 | others = 0; 200 | 201 | console("dp_address: %llx ", dp->dp_address); 202 | console("dp_size: %ld ", dp->dp_size); 203 | console("dp_flags: %lx (", flags = dp->dp_flags); 204 | 205 | if (flags & DUMP_COMPRESSED) 206 | console("DUMP_COMPRESSED", others++); 207 | if (flags & DUMP_RAW) 208 | console("%sDUMP_RAW", others++ ? "|" : ""); 209 | if (flags & DUMP_END) 210 | console("DUMP_END", others++ ? "|" : ""); 211 | console(")\n"); 212 | } 213 | 214 | /* 215 | * help -S output, or as specified by arg. 216 | */ 217 | void 218 | dump_lkcd_environment_v1(ulong arg) 219 | { 220 | int others; 221 | dump_header_t *dh; 222 | dump_page_t *dp; 223 | 224 | dh = (dump_header_t *)lkcd->dump_header; 225 | dp = (dump_page_t *)lkcd->dump_page; 226 | 227 | if (arg == LKCD_DUMP_HEADER_ONLY) 228 | goto dump_header_only; 229 | if (arg == LKCD_DUMP_PAGE_ONLY) 230 | goto dump_page_only; 231 | 232 | dump_header_only: 233 | 234 | lkcd_print(" dump_header:\n"); 235 | lkcd_print(" dh_magic_number: %llx ", 236 | dh->dh_magic_number); 237 | if (dh->dh_magic_number == DUMP_MAGIC_NUMBER) 238 | lkcd_print("(DUMP_MAGIC_NUMBER)\n"); 239 | else 240 | lkcd_print("(?)\n"); 241 | lkcd_print(" dh_version: %d\n", dh->dh_version); 242 | lkcd_print(" dh_header_size: %d\n", dh->dh_header_size); 243 | lkcd_print(" dh_dump_level: %d\n", dh->dh_dump_level); 244 | lkcd_print(" dh_page_size: %d\n", dh->dh_page_size); 245 | lkcd_print(" dh_memory_size: %lld\n", dh->dh_memory_size); 246 | lkcd_print(" dh_memory_start: %llx\n", dh->dh_memory_start); 247 | lkcd_print(" dh_memory_end: %llx\n", dh->dh_memory_end); 248 | lkcd_print(" dh_esp: %lx\n", dh->dh_esp); 249 | lkcd_print(" dh_eip: %lx\n", dh->dh_eip); 250 | lkcd_print(" dh_num_pages: %d\n", dh->dh_num_pages); 251 | lkcd_print(" dh_panic_string: %s%s", dh->dh_panic_string, 252 | dh && strstr(dh->dh_panic_string, "\n") ? "" : "\n"); 253 | lkcd_print(" dh_time: %s\n", 254 | strip_linefeeds(ctime(&(dh->dh_time.tv_sec)))); 255 | 256 | lkcd_print(" dh_utsname:\n"); 257 | lkcd_print(" sysname: %s\n", dh->dh_utsname.sysname); 258 | lkcd_print(" nodename: %s\n", dh->dh_utsname.nodename); 259 | lkcd_print(" release: %s\n", dh->dh_utsname.release); 260 | lkcd_print(" version: %s\n", dh->dh_utsname.version); 261 | lkcd_print(" machine: %s\n", dh->dh_utsname.machine); 262 | lkcd_print(" domainname: %s\n", dh->dh_utsname.domainname); 263 | 264 | lkcd_print(" dh_current_task: %lx\n", dh->dh_current_task); 265 | 266 | lkcd_print(" dh_regs:\n"); 267 | #ifdef PPC 268 | lkcd_print(" (PowerPC register display TBD)\n"); 269 | #endif 270 | #ifdef X86 271 | lkcd_print(" ebx: %lx\n", dh->dh_regs.ebx); 272 | lkcd_print(" ecx: %lx\n", dh->dh_regs.ecx); 273 | lkcd_print(" edx: %lx\n", dh->dh_regs.edx); 274 | lkcd_print(" esi: %lx\n", dh->dh_regs.esi); 275 | lkcd_print(" edi: %lx\n", dh->dh_regs.edi); 276 | lkcd_print(" eax: %lx\n", dh->dh_regs.eax); 277 | lkcd_print(" xds: %x\n", dh->dh_regs.xds); 278 | lkcd_print(" xes: %x\n", dh->dh_regs.xes); 279 | lkcd_print(" orig_eax: %lx\n", dh->dh_regs.orig_eax); 280 | lkcd_print(" eip: %lx\n", dh->dh_regs.eip); 281 | lkcd_print(" xcs: %x\n", dh->dh_regs.xcs); 282 | lkcd_print(" eflags: %lx\n", dh->dh_regs.eflags); 283 | lkcd_print(" esp: %lx\n", dh->dh_regs.esp); 284 | lkcd_print(" xss: %x\n", dh->dh_regs.xss); 285 | #endif 286 | 287 | if (arg == LKCD_DUMP_HEADER_ONLY) 288 | return; 289 | 290 | dump_page_only: 291 | 292 | lkcd_print(" dump_page:\n"); 293 | lkcd_print(" dp_address: %llx\n", dp->dp_address); 294 | lkcd_print(" dp_size: %ld\n", dp->dp_size); 295 | lkcd_print(" dp_flags: %lx (", dp->dp_flags); 296 | others = 0; 297 | if (dp->dp_flags & DUMP_COMPRESSED) 298 | lkcd_print("DUMP_COMPRESSED", others++); 299 | if (dp->dp_flags & DUMP_RAW) 300 | lkcd_print("%sDUMP_RAW", others++ ? "|" : ""); 301 | if (dp->dp_flags & DUMP_END) 302 | lkcd_print("DUMP_END", others++ ? "|" : ""); 303 | lkcd_print(")\n"); 304 | } 305 | -------------------------------------------------------------------------------- /lkcd_vmdump_v1.h: -------------------------------------------------------------------------------- 1 | /* lkcd_vmdump_v1.h - core analysis suite 2 | * 3 | * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. 4 | * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson 5 | * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | 19 | /* 20 | * Kernel header file for Linux crash dumps. 21 | * 22 | * Created by: Matt Robinson (yakker@sgi.com) 23 | * 24 | * Copyright 1999 Silicon Graphics, Inc. All rights reserved. 25 | * 26 | */ 27 | 28 | /* This header file includes all structure definitions for crash dumps. */ 29 | #ifndef _VMDUMP_H 30 | #define _VMDUMP_H 31 | 32 | /* necessary header files */ 33 | #ifndef MCLX 34 | #include /* for utsname structure */ 35 | #endif 36 | #ifndef IA64 37 | typedef unsigned int u32; 38 | #include /* for pt_regs */ 39 | #endif 40 | 41 | /* necessary header definitions in all cases */ 42 | #define DUMP_KIOBUF_NUMBER 0xdeadbeef /* special number for kiobuf maps */ 43 | 44 | #ifdef CONFIG_VMDUMP 45 | /* size of a dump header page */ 46 | #define DUMP_PAGE_SZ 64 * 1024 /* size of dump page buffer */ 47 | 48 | /* standard header definitions */ 49 | #define DUMP_MAGIC_NUMBER 0xa8190173618f23edULL /* dump magic number */ 50 | #define DUMP_VERSION_NUMBER 0x1 /* dump version number */ 51 | #define DUMP_PANIC_LEN 0x100 /* dump panic string length */ 52 | 53 | /* dump flags -- add as necessary */ 54 | #define DUMP_RAW 0x1 /* raw page (no compression) */ 55 | #define DUMP_COMPRESSED 0x2 /* page is compressed */ 56 | #define DUMP_END 0x4 /* end marker on a full dump */ 57 | 58 | /* dump types - type specific stuff added later for page typing */ 59 | #define DUMP_NONE 0 /* no dumping at all -- just bail */ 60 | #define DUMP_HEADER 1 /* kernel dump header only */ 61 | #define DUMP_KERN 2 /* dump header and kernel pages */ 62 | #define DUMP_USED 3 /* dump header, kernel/user pages */ 63 | #define DUMP_ALL 4 /* dump header, all memory pages */ 64 | 65 | /* 66 | * Structure: dump_header_t 67 | * Function: This is the header dumped at the top of every valid crash 68 | * dump. 69 | * easy reassembly of each crash dump page. The address bits 70 | * are split to make things easier for 64-bit/32-bit system 71 | * conversions. 72 | */ 73 | typedef struct _dump_header_s { 74 | /* the dump magic number -- unique to verify dump is valid */ 75 | uint64_t dh_magic_number; 76 | 77 | /* the version number of this dump */ 78 | uint32_t dh_version; 79 | 80 | /* the size of this header (in case we can't read it) */ 81 | uint32_t dh_header_size; 82 | 83 | /* the level of this dump (just a header?) */ 84 | uint32_t dh_dump_level; 85 | 86 | /* the size of a Linux memory page (4K, 8K, 16K, etc.) */ 87 | uint32_t dh_page_size; 88 | 89 | /* the size of all physical memory */ 90 | uint64_t dh_memory_size; 91 | 92 | /* the start of physical memory */ 93 | uint64_t dh_memory_start; 94 | 95 | /* the end of physical memory */ 96 | uint64_t dh_memory_end; 97 | 98 | /* the esp for i386 systems -- MOVE LATER */ 99 | uint32_t dh_esp; 100 | 101 | /* the eip for i386 systems -- MOVE LATER */ 102 | uint32_t dh_eip; 103 | 104 | /* the number of pages in this dump specifically */ 105 | uint32_t dh_num_pages; 106 | 107 | /* the panic string, if available */ 108 | char dh_panic_string[DUMP_PANIC_LEN]; 109 | 110 | /* the time of the system crash */ 111 | struct timeval dh_time; 112 | 113 | /* the utsname (uname) information */ 114 | struct new_utsname dh_utsname; 115 | 116 | /* the dump registers */ 117 | #if !defined(IA64) && !defined(S390) && !defined(S390X) && !defined(ARM64) && !defined(RISCV64) && !defined(LOONGARCH64) 118 | struct pt_regs dh_regs; 119 | #endif 120 | 121 | /* the address of the current task */ 122 | struct task_struct *dh_current_task; 123 | 124 | } dump_header_t; 125 | 126 | /* 127 | * Structure: dump_page_t 128 | * Function: To act as the header associated to each physical page of 129 | * memory saved in the system crash dump. This allows for 130 | * easy reassembly of each crash dump page. The address bits 131 | * are split to make things easier for 64-bit/32-bit system 132 | * conversions. 133 | */ 134 | typedef struct _dump_page_s { 135 | 136 | /* the address of this dump page */ 137 | uint64_t dp_address; 138 | 139 | /* the size of this dump page */ 140 | uint32_t dp_size; 141 | 142 | /* flags (currently DUMP_COMPRESSED, DUMP_RAW or DUMP_END) */ 143 | uint32_t dp_flags; 144 | } dump_page_t; 145 | 146 | #endif /* CONFIG_VMDUMP */ 147 | 148 | #ifdef __KERNEL__ 149 | extern void dump_init(uint64_t, uint64_t); 150 | extern void dump_open(char *); 151 | extern void dump_execute(char *, struct pt_regs *); 152 | #endif 153 | 154 | #endif /* _VMDUMP_H */ 155 | -------------------------------------------------------------------------------- /lkcd_vmdump_v2_v3.h: -------------------------------------------------------------------------------- 1 | /* lkcd_vmdump_v2_v3.h - core analysis suite 2 | * 3 | * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. 4 | * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson 5 | * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | 19 | /* 20 | * Kernel header file for Linux crash dumps. 21 | * 22 | * Created by: Matt Robinson (yakker@sgi.com) 23 | * 24 | * Copyright 1999 Silicon Graphics, Inc. All rights reserved. 25 | * 26 | */ 27 | 28 | /* This header file includes all structure definitions for crash dumps. */ 29 | #ifndef _VMDUMP_H 30 | #define _VMDUMP_H 31 | 32 | /* necessary header files */ 33 | #ifndef MCLX 34 | #include /* for utsname structure */ 35 | #include /* for architecture-specific header */ 36 | #endif 37 | 38 | #if defined(ARM) || defined(X86) || defined(PPC) || defined(S390) || \ 39 | defined(S390X) || defined(ARM64) || defined(MIPS) || \ 40 | defined(MIPS64) || defined(SPARC64) || defined(RISCV64) || \ 41 | defined(LOONGARCH64) 42 | 43 | /* 44 | * Kernel header file for Linux crash dumps. 45 | * 46 | * Created by: Matt Robinson (yakker@sgi.com) 47 | * 48 | * Copyright 1999 Silicon Graphics, Inc. All rights reserved. 49 | * 50 | */ 51 | 52 | /* This header file holds the architecture specific crash dump header */ 53 | #ifndef _ASM_VMDUMP_H 54 | #define _ASM_VMDUMP_H 55 | 56 | /* necessary header files */ 57 | typedef unsigned int u32; 58 | #include /* for pt_regs */ 59 | 60 | /* definitions */ 61 | #define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */ 62 | #define DUMP_ASM_VERSION_NUMBER 0x1 /* version number */ 63 | 64 | 65 | /* 66 | * Structure: dump_header_asm_t 67 | * Function: This is the header for architecture-specific stuff. It 68 | * follows right after the dump header. 69 | */ 70 | typedef struct _dump_header_asm_s { 71 | 72 | /* the dump magic number -- unique to verify dump is valid */ 73 | uint64_t dha_magic_number; 74 | 75 | /* the version number of this dump */ 76 | uint32_t dha_version; 77 | 78 | /* the size of this header (in case we can't read it) */ 79 | uint32_t dha_header_size; 80 | 81 | /* the esp for i386 systems */ 82 | uint32_t dha_esp; 83 | 84 | /* the eip for i386 systems */ 85 | uint32_t dha_eip; 86 | 87 | /* the dump registers */ 88 | #if !defined(S390) && !defined(S390X) && !defined(ARM64) && !defined(RISCV64) && !defined(LOONGARCH64) 89 | struct pt_regs dha_regs; 90 | #endif 91 | 92 | } dump_header_asm_t; 93 | 94 | #endif /* _ASM_VMDUMP_H */ 95 | 96 | #endif /* ARM || X86 || PPC */ 97 | 98 | #if defined(ALPHA) || defined(IA64) || defined(X86_64) || defined(PPC64) 99 | 100 | /* 101 | * Plug in the real ../arch/alpha/vmdump.h when available. For now the 102 | * data here are just placeholders... 103 | */ 104 | 105 | #ifndef IA64 106 | typedef unsigned int u32; 107 | #include /* for pt_regs */ 108 | #endif 109 | 110 | /* definitions */ 111 | #define DUMP_ASM_MAGIC_NUMBER 0xdeaddeadULL /* magic number */ 112 | #define DUMP_ASM_VERSION_NUMBER 0x1 /* version number */ 113 | 114 | 115 | typedef struct _dump_header_asm_s { 116 | 117 | /* the dump magic number -- unique to verify dump is valid */ 118 | uint64_t dha_magic_number; 119 | 120 | /* the version number of this dump */ 121 | uint32_t dha_version; 122 | 123 | /* the size of this header (in case we can't read it) */ 124 | uint32_t dha_header_size; 125 | 126 | /* the esp for i386 systems */ 127 | uint32_t dha_esp; 128 | 129 | /* the eip for i386 systems */ 130 | uint32_t dha_eip; 131 | 132 | /* the dump registers */ 133 | #ifndef IA64 134 | struct pt_regs dha_regs; 135 | #endif 136 | 137 | } dump_header_asm_t; 138 | 139 | #endif /* ALPHA or IA64 (?) */ 140 | 141 | /* necessary header definitions in all cases */ 142 | #define DUMP_KIOBUF_NUMBER 0xdeadbeef /* special number for kiobuf maps */ 143 | 144 | #ifdef CONFIG_VMDUMP 145 | /* size of a dump header page */ 146 | #define DUMP_PAGE_SZ 64 * 1024 /* size of dump page buffer */ 147 | 148 | /* standard header definitions */ 149 | #define DUMP_MAGIC_NUMBER 0xa8190173618f23edULL /* dump magic number */ 150 | #define DUMP_VERSION_NUMBER 0x2 /* dump version number */ 151 | #define DUMP_PANIC_LEN 0x100 /* dump panic string length */ 152 | 153 | /* dump flags -- add as necessary */ 154 | #define DUMP_RAW 0x1 /* raw page (no compression) */ 155 | #define DUMP_COMPRESSED 0x2 /* page is compressed */ 156 | #define DUMP_END 0x4 /* end marker on a full dump */ 157 | 158 | /* dump types - type specific stuff added later for page typing */ 159 | #define DUMP_NONE 0 /* no dumping at all -- just bail */ 160 | #define DUMP_HEADER 1 /* kernel dump header only */ 161 | #define DUMP_KERN 2 /* dump header and kernel pages */ 162 | #define DUMP_USED 3 /* dump header, kernel/user pages */ 163 | #define DUMP_ALL 4 /* dump header, all memory pages */ 164 | 165 | /* 166 | * Structure: dump_header_t 167 | * Function: This is the header dumped at the top of every valid crash 168 | * dump. 169 | * easy reassembly of each crash dump page. The address bits 170 | * are split to make things easier for 64-bit/32-bit system 171 | * conversions. 172 | */ 173 | typedef struct _dump_header_s { 174 | /* the dump magic number -- unique to verify dump is valid */ 175 | uint64_t dh_magic_number; 176 | 177 | /* the version number of this dump */ 178 | uint32_t dh_version; 179 | 180 | /* the size of this header (in case we can't read it) */ 181 | uint32_t dh_header_size; 182 | 183 | /* the level of this dump (just a header?) */ 184 | uint32_t dh_dump_level; 185 | 186 | /* the size of a Linux memory page (4K, 8K, 16K, etc.) */ 187 | uint32_t dh_page_size; 188 | 189 | /* the size of all physical memory */ 190 | uint64_t dh_memory_size; 191 | 192 | /* the start of physical memory */ 193 | uint64_t dh_memory_start; 194 | 195 | /* the end of physical memory */ 196 | uint64_t dh_memory_end; 197 | 198 | /* the number of pages in this dump specifically */ 199 | uint32_t dh_num_pages; 200 | 201 | /* the panic string, if available */ 202 | char dh_panic_string[DUMP_PANIC_LEN]; 203 | 204 | /* the time of the system crash */ 205 | struct timeval dh_time; 206 | 207 | /* the utsname (uname) information */ 208 | struct new_utsname dh_utsname; 209 | 210 | /* the address of the current task */ 211 | struct task_struct *dh_current_task; 212 | 213 | } dump_header_t; 214 | 215 | /* 216 | * Structure: dump_page_t 217 | * Function: To act as the header associated to each physical page of 218 | * memory saved in the system crash dump. This allows for 219 | * easy reassembly of each crash dump page. The address bits 220 | * are split to make things easier for 64-bit/32-bit system 221 | * conversions. 222 | */ 223 | typedef struct _dump_page_s { 224 | 225 | /* the address of this dump page */ 226 | uint64_t dp_address; 227 | 228 | /* the size of this dump page */ 229 | uint32_t dp_size; 230 | 231 | /* flags (currently DUMP_COMPRESSED, DUMP_RAW or DUMP_END) */ 232 | uint32_t dp_flags; 233 | } dump_page_t; 234 | 235 | #endif /* CONFIG_VMDUMP */ 236 | 237 | #ifdef __KERNEL__ 238 | extern void dump_init(uint64_t, uint64_t); 239 | extern void dump_open(char *); 240 | extern void dump_execute(char *, struct pt_regs *); 241 | #endif 242 | 243 | #endif /* _VMDUMP_H */ 244 | -------------------------------------------------------------------------------- /lzorle_decompress.c: -------------------------------------------------------------------------------- 1 | /* lzorle_decompress.h 2 | * 3 | * from kernel lib/lzo/lzo1x_decompress_safe.c 4 | * 5 | * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer 6 | * Copyright (C) 2024 NIO 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | */ 18 | 19 | #include "defs.h" 20 | #include "lzorle_decompress.h" 21 | 22 | /* This MAX_255_COUNT is the maximum number of times we can add 255 to a base 23 | * count without overflowing an integer. The multiply will overflow when 24 | * multiplying 255 by more than MAXINT/255. The sum will overflow earlier 25 | * depending on the base count. Since the base count is taken from a u8 26 | * and a few bits, it is safe to assume that it will always be lower than 27 | * or equal to 2*255, thus we can always prevent any overflow by accepting 28 | * two less 255 steps. See Documentation/lzo.txt for more information. 29 | */ 30 | #define MAX_255_COUNT ((((ulong)~0) / 255) - 2) 31 | 32 | static inline uint16_t get_unaligned_le16 (const uint8_t *p) { 33 | return p[0] | p[1] << 8; 34 | } 35 | 36 | int lzorle_decompress_safe(const unsigned char *in, ulong in_len, 37 | unsigned char *out, ulong *out_len, void *other/* NOT USED */) { 38 | unsigned char *op; 39 | const unsigned char *ip; 40 | ulong t, next; 41 | ulong state = 0; 42 | const unsigned char *m_pos; 43 | const unsigned char * const ip_end = in + in_len; 44 | unsigned char * const op_end = out + *out_len; 45 | 46 | unsigned char bitstream_version; 47 | 48 | static int efficient_unaligned_access = -1; 49 | 50 | if (efficient_unaligned_access == -1) { 51 | #if defined(ARM) || defined(ARM64) || defined(X86) || defined(X86_64) || defined(PPC) || defined(PPC64) || defined(S390)|| defined(S390X) 52 | efficient_unaligned_access = TRUE; 53 | #else 54 | efficient_unaligned_access = FALSE; 55 | #endif 56 | 57 | if ((kt->ikconfig_flags & IKCONFIG_AVAIL) && 58 | (get_kernel_config("CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS", NULL) == IKCONFIG_Y)) 59 | efficient_unaligned_access = TRUE; 60 | } 61 | 62 | op = out; 63 | ip = in; 64 | 65 | if (in_len < 3) 66 | goto input_overrun; 67 | 68 | if (in_len >= 5 && *ip == 17) { 69 | bitstream_version = ip[1]; 70 | ip += 2; 71 | } else { 72 | bitstream_version = 0; 73 | } 74 | 75 | if (*ip > 17) { 76 | t = *ip++ - 17; 77 | if (t < 4) { 78 | next = t; 79 | goto match_next; 80 | } 81 | goto copy_literal_run; 82 | } 83 | 84 | for (;;) { 85 | t = *ip++; 86 | if (t < 16) { 87 | if (state == 0) { 88 | if (t == 0) { 89 | ulong offset; 90 | const unsigned char *ip_last = ip; 91 | 92 | while (*ip == 0) { 93 | ip++; 94 | NEED_IP(1); 95 | } 96 | offset = ip - ip_last; 97 | if (offset > MAX_255_COUNT) 98 | return LZO_E_ERROR; 99 | 100 | offset = (offset << 8) - offset; 101 | t += offset + 15 + *ip++; 102 | } 103 | t += 3; 104 | copy_literal_run: 105 | if (efficient_unaligned_access && 106 | (HAVE_IP(t + 15) && HAVE_OP(t + 15))) { 107 | const unsigned char *ie = ip + t; 108 | unsigned char *oe = op + t; 109 | do { 110 | COPY8(op, ip); 111 | op += 8; 112 | ip += 8; 113 | COPY8(op, ip); 114 | op += 8; 115 | ip += 8; 116 | } while (ip < ie); 117 | ip = ie; 118 | op = oe; 119 | } else { 120 | NEED_OP(t); 121 | NEED_IP(t + 3); 122 | do { 123 | *op++ = *ip++; 124 | } while (--t > 0); 125 | } 126 | state = 4; 127 | continue; 128 | } else if (state != 4) { 129 | next = t & 3; 130 | m_pos = op - 1; 131 | m_pos -= t >> 2; 132 | m_pos -= *ip++ << 2; 133 | TEST_LB(m_pos); 134 | NEED_OP(2); 135 | op[0] = m_pos[0]; 136 | op[1] = m_pos[1]; 137 | op += 2; 138 | goto match_next; 139 | } else { 140 | next = t & 3; 141 | m_pos = op - (1 + M2_MAX_OFFSET); 142 | m_pos -= t >> 2; 143 | m_pos -= *ip++ << 2; 144 | t = 3; 145 | } 146 | } else if (t >= 64) { 147 | next = t & 3; 148 | m_pos = op - 1; 149 | m_pos -= (t >> 2) & 7; 150 | m_pos -= *ip++ << 3; 151 | t = (t >> 5) - 1 + (3 - 1); 152 | } else if (t >= 32) { 153 | t = (t & 31) + (3 - 1); 154 | if (t == 2) { 155 | ulong offset; 156 | const unsigned char *ip_last = ip; 157 | 158 | while (*ip == 0) { 159 | ip++; 160 | NEED_IP(1); 161 | } 162 | offset = ip - ip_last; 163 | if (offset > MAX_255_COUNT) 164 | return LZO_E_ERROR; 165 | 166 | offset = (offset << 8) - offset; 167 | t += offset + 31 + *ip++; 168 | NEED_IP(2); 169 | } 170 | m_pos = op - 1; 171 | 172 | next = get_unaligned_le16(ip); 173 | ip += 2; 174 | m_pos -= next >> 2; 175 | next &= 3; 176 | } else { 177 | NEED_IP(2); 178 | next = get_unaligned_le16(ip); 179 | if (((next & 0xfffc) == 0xfffc) && 180 | ((t & 0xf8) == 0x18) && 181 | bitstream_version) { 182 | NEED_IP(3); 183 | t &= 7; 184 | t |= ip[2] << 3; 185 | t += MIN_ZERO_RUN_LENGTH; 186 | NEED_OP(t); 187 | memset(op, 0, t); 188 | op += t; 189 | next &= 3; 190 | ip += 3; 191 | goto match_next; 192 | } else { 193 | m_pos = op; 194 | m_pos -= (t & 8) << 11; 195 | t = (t & 7) + (3 - 1); 196 | if (t == 2) { 197 | ulong offset; 198 | const unsigned char *ip_last = ip; 199 | 200 | while (*ip == 0) { 201 | ip++; 202 | NEED_IP(1); 203 | } 204 | offset = ip - ip_last; 205 | if (offset > MAX_255_COUNT) 206 | return LZO_E_ERROR; 207 | 208 | offset = (offset << 8) - offset; 209 | t += offset + 7 + *ip++; 210 | NEED_IP(2); 211 | next = get_unaligned_le16(ip); 212 | } 213 | ip += 2; 214 | m_pos -= next >> 2; 215 | next &= 3; 216 | if (m_pos == op) 217 | goto eof_found; 218 | m_pos -= 0x4000; 219 | } 220 | } 221 | TEST_LB(m_pos); 222 | 223 | if (efficient_unaligned_access && 224 | (op - m_pos >= 8)) { 225 | unsigned char *oe = op + t; 226 | if (HAVE_OP(t + 15)) { 227 | do { 228 | COPY8(op, m_pos); 229 | op += 8; 230 | m_pos += 8; 231 | COPY8(op, m_pos); 232 | op += 8; 233 | m_pos += 8; 234 | } while (op < oe); 235 | op = oe; 236 | if (HAVE_IP(6)) { 237 | state = next; 238 | COPY4(op, ip); 239 | op += next; 240 | ip += next; 241 | continue; 242 | } 243 | } else { 244 | NEED_OP(t); 245 | do { 246 | *op++ = *m_pos++; 247 | } while (op < oe); 248 | } 249 | } else { 250 | unsigned char *oe = op + t; 251 | NEED_OP(t); 252 | op[0] = m_pos[0]; 253 | op[1] = m_pos[1]; 254 | op += 2; 255 | m_pos += 2; 256 | do { 257 | *op++ = *m_pos++; 258 | } while (op < oe); 259 | } 260 | match_next: 261 | state = next; 262 | t = next; 263 | if (efficient_unaligned_access && 264 | (HAVE_IP(6) && HAVE_OP(4))) { 265 | COPY4(op, ip); 266 | op += t; 267 | ip += t; 268 | } else { 269 | NEED_IP(t + 3); 270 | NEED_OP(t); 271 | while (t > 0) { 272 | *op++ = *ip++; 273 | t--; 274 | } 275 | } 276 | } 277 | 278 | eof_found: 279 | *out_len = op - out; 280 | return (t != 3 ? LZO_E_ERROR : 281 | ip == ip_end ? LZO_E_OK : 282 | ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN); 283 | 284 | input_overrun: 285 | *out_len = op - out; 286 | return LZO_E_INPUT_OVERRUN; 287 | 288 | output_overrun: 289 | *out_len = op - out; 290 | return LZO_E_OUTPUT_OVERRUN; 291 | 292 | lookbehind_overrun: 293 | *out_len = op - out; 294 | return LZO_E_LOOKBEHIND_OVERRUN; 295 | } 296 | -------------------------------------------------------------------------------- /lzorle_decompress.h: -------------------------------------------------------------------------------- 1 | /* lzorle_decompress.h 2 | * 3 | * from kernel lib/lzo/lzodefs.h 4 | * 5 | * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer 6 | * Copyright (C) 2024 NIO 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | */ 18 | 19 | #ifndef LZODEFS_H 20 | #define LZODEFS_H 21 | 22 | #define COPY4(dst, src) memcpy((dst), (src), sizeof(uint32_t)) 23 | #define COPY8(dst, src) memcpy((dst), (src), sizeof(uint64_t)) 24 | 25 | #define M1_MAX_OFFSET 0x0400 26 | #define M2_MAX_OFFSET 0x0800 27 | #define M3_MAX_OFFSET 0x4000 28 | #define M4_MAX_OFFSET_V0 0xbfff 29 | #define M4_MAX_OFFSET_V1 0xbffe 30 | 31 | #define M1_MIN_LEN 2 32 | #define M1_MAX_LEN 2 33 | #define M2_MIN_LEN 3 34 | #define M2_MAX_LEN 8 35 | #define M3_MIN_LEN 3 36 | #define M3_MAX_LEN 33 37 | #define M4_MIN_LEN 3 38 | #define M4_MAX_LEN 9 39 | 40 | #define M1_MARKER 0 41 | #define M2_MARKER 64 42 | #define M3_MARKER 32 43 | #define M4_MARKER 16 44 | 45 | #define MIN_ZERO_RUN_LENGTH 4 46 | #define MAX_ZERO_RUN_LENGTH (2047 + MIN_ZERO_RUN_LENGTH) 47 | 48 | #define lzo_dict_t unsigned short 49 | #define D_BITS 13 50 | #define D_SIZE (1u << D_BITS) 51 | #define D_MASK (D_SIZE - 1) 52 | #define D_HIGH ((D_MASK >> 1) + 1) 53 | 54 | #define LZO_E_OK 0 55 | #define LZO_E_ERROR (-1) 56 | #define LZO_E_OUT_OF_MEMORY (-2) 57 | #define LZO_E_NOT_COMPRESSIBLE (-3) 58 | #define LZO_E_INPUT_OVERRUN (-4) 59 | #define LZO_E_OUTPUT_OVERRUN (-5) 60 | #define LZO_E_LOOKBEHIND_OVERRUN (-6) 61 | #define LZO_E_EOF_NOT_FOUND (-7) 62 | #define LZO_E_INPUT_NOT_CONSUMED (-8) 63 | #define LZO_E_NOT_YET_IMPLEMELZO_HFILESNTED (-9) 64 | #define LZO_E_INVALID_ARGUMENT (-10) 65 | 66 | #define HAVE_IP(x) ((unsigned long)(ip_end - ip) >= (unsigned long)(x)) 67 | #define HAVE_OP(x) ((unsigned long)(op_end - op) >= (unsigned long)(x)) 68 | #define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun 69 | #define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun 70 | #define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun 71 | 72 | int lzorle_decompress_safe(const unsigned char *in, unsigned long in_len, 73 | unsigned char *out, unsigned long *out_len, void *other/* NOT USED */); 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /makedumpfile.c: -------------------------------------------------------------------------------- 1 | /* 2 | * makedumpfile.c 3 | * 4 | * This code is for reading a dumpfile ganarated by makedumpfile command. 5 | * 6 | * Copyright (C) 2011 NEC Soft, Ltd. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * Author: Ken'ichi Ohmichi 19 | */ 20 | 21 | #define _LARGEFILE64_SOURCE 1 /* stat64() */ 22 | #include "defs.h" 23 | #include "makedumpfile.h" 24 | #include 25 | 26 | static void flattened_format_get_osrelease(char *); 27 | 28 | int flattened_format = 0; 29 | 30 | struct flat_data { 31 | int64_t off_flattened; 32 | int64_t off_rearranged; /* offset which will be rearranged. */ 33 | int64_t buf_size; 34 | }; 35 | 36 | struct all_flat_data { 37 | unsigned long long num_array; 38 | struct flat_data *array; 39 | size_t file_size; 40 | }; 41 | 42 | struct all_flat_data afd; 43 | 44 | struct makedumpfile_header fh_save; 45 | 46 | static int 47 | is_bigendian(void) 48 | { 49 | int i = 0x12345678; 50 | 51 | if (*(char *)&i == 0x12) 52 | return TRUE; 53 | else 54 | return FALSE; 55 | } 56 | 57 | static unsigned long long 58 | store_flat_data_array(char *file, struct flat_data **fda) 59 | { 60 | int result = FALSE, fd; 61 | int64_t offset_fdh; 62 | int64_t offset_report = 0; 63 | unsigned long long num_allocated = 0; 64 | unsigned long long num_stored = 0; 65 | unsigned long long sort_idx; 66 | unsigned long long size_allocated; 67 | struct flat_data *ptr = NULL, *cur, *new; 68 | struct makedumpfile_data_header fdh; 69 | struct stat64 stat; 70 | ulonglong pct, last_pct; 71 | char buf[BUFSIZE]; 72 | ssize_t bytes_read; 73 | 74 | fd = open(file, O_RDONLY); 75 | if (fd < 0) { 76 | error(INFO, "unable to open dump file %s\n", file); 77 | return -1; 78 | } 79 | if (lseek(fd, MAX_SIZE_MDF_HEADER, SEEK_SET) < 0) { 80 | error(INFO, "%s: seek error (flat format)\n", file); 81 | close(fd); 82 | return -1; 83 | } 84 | if (stat64(file, &stat) < 0) { 85 | error(INFO, "cannot stat64 %s\n", file); 86 | return -1; 87 | } 88 | 89 | please_wait("sorting flat format data"); 90 | pct = last_pct = 0; 91 | while (1) { 92 | if (num_allocated <= num_stored) { 93 | num_allocated += 100; 94 | size_allocated = sizeof(struct flat_data) 95 | * num_allocated; 96 | new = realloc(ptr, size_allocated); 97 | if (new == NULL) { 98 | error(INFO, 99 | "unable to realloc flat_data structures\n"); 100 | break; 101 | } 102 | ptr = new; 103 | } 104 | offset_fdh = lseek(fd, 0x0, SEEK_CUR); 105 | 106 | if ((bytes_read = read(fd, &fdh, sizeof(fdh))) != sizeof(fdh)) { 107 | if (bytes_read >= 0) 108 | error(INFO, 109 | "read error: %s (flat format): truncated/incomplete\n", 110 | file); 111 | else 112 | error(INFO, "read error: %s (flat format)\n", file); 113 | break; 114 | } 115 | if (!is_bigendian()){ 116 | fdh.offset = bswap_64(fdh.offset); 117 | fdh.buf_size = bswap_64(fdh.buf_size); 118 | } 119 | if (fdh.offset == END_FLAG_FLAT_HEADER) { 120 | result = TRUE; 121 | break; 122 | } 123 | cur = ptr + num_stored; 124 | sort_idx = num_stored; 125 | while (sort_idx) { 126 | new = ptr + --sort_idx; 127 | if (new->off_rearranged >= fdh.offset) { 128 | cur->off_flattened = new->off_flattened; 129 | cur->off_rearranged = new->off_rearranged; 130 | cur->buf_size = new->buf_size; 131 | cur = new; 132 | } else { 133 | if (CRASHDEBUG(1) && sort_idx + 1 != num_stored) { 134 | fprintf(fp, 135 | "makedumpfile: Moved from %lld to %lld\n", 136 | num_stored, sort_idx + 1); 137 | } 138 | break; 139 | } 140 | } 141 | cur->off_flattened = offset_fdh + sizeof(fdh); 142 | cur->off_rearranged = fdh.offset; 143 | cur->buf_size = fdh.buf_size; 144 | num_stored++; 145 | 146 | pct = (offset_fdh * 100ULL) / stat.st_size; 147 | if (pct > last_pct) { 148 | sprintf(buf, "sorting flat format data: %lld%%", (ulonglong)pct); 149 | please_wait(buf); 150 | if (CRASHDEBUG(1)) 151 | fprintf(fp, "\n"); 152 | last_pct = pct; 153 | } 154 | 155 | if (CRASHDEBUG(1) && (fdh.offset >> 30) > (offset_report >> 30)) { 156 | fprintf(fp, "makedumpfile: At %lld GiB\n", 157 | (ulonglong)(fdh.offset >> 30)); 158 | offset_report = fdh.offset; 159 | } 160 | 161 | /* seek for next makedumpfile_data_header. */ 162 | if (lseek(fd, fdh.buf_size, SEEK_CUR) < 0) { 163 | error(INFO, "%s: seek error (flat format)\n", file); 164 | break; 165 | } 166 | } 167 | please_wait_done(); 168 | 169 | close(fd); 170 | if (result == FALSE) { 171 | free(ptr); 172 | return -1; 173 | } 174 | *fda = ptr; 175 | 176 | return num_stored; 177 | } 178 | 179 | static int 180 | read_all_makedumpfile_data_header(char *file) 181 | { 182 | unsigned long long num; 183 | struct flat_data *fda = NULL; 184 | long long retval; 185 | 186 | retval = num = store_flat_data_array(file, &fda); 187 | if (retval < 0) 188 | return FALSE; 189 | 190 | afd.num_array = num; 191 | afd.array = fda; 192 | 193 | return TRUE; 194 | } 195 | 196 | void 197 | check_flattened_format(char *file) 198 | { 199 | int fd, get_osrelease; 200 | struct stat stat; 201 | struct makedumpfile_header fh; 202 | 203 | if (pc->flags2 & GET_OSRELEASE) { 204 | get_osrelease = TRUE; 205 | pc->flags2 &= ~GET_OSRELEASE; 206 | } else 207 | get_osrelease = FALSE; 208 | 209 | if (flattened_format) 210 | goto out; 211 | 212 | if (file_exists(file, &stat) && S_ISCHR(stat.st_mode)) 213 | goto out; 214 | 215 | fd = open(file, O_RDONLY); 216 | if (fd < 0) { 217 | error(INFO, "unable to open dump file %s\n", file); 218 | goto out; 219 | } 220 | if (read(fd, &fh, sizeof(fh)) < 0) { 221 | error(INFO, "unable to read dump file %s\n", file); 222 | close(fd); 223 | goto out; 224 | } 225 | close(fd); 226 | 227 | if (!is_bigendian()){ 228 | fh.type = bswap_64(fh.type); 229 | fh.version = bswap_64(fh.version); 230 | } 231 | if ((strncmp(fh.signature, MAKEDUMPFILE_SIGNATURE, sizeof(MAKEDUMPFILE_SIGNATURE)) != 0) || 232 | (fh.type != TYPE_FLAT_HEADER)) 233 | goto out; 234 | 235 | if (get_osrelease) { 236 | flattened_format_get_osrelease(file); 237 | return; 238 | } 239 | 240 | if (!read_all_makedumpfile_data_header(file)) 241 | return; 242 | 243 | if (CRASHDEBUG(1)) 244 | fprintf(fp, "%s: FLAT\n\n", file); 245 | 246 | fh_save = fh; 247 | 248 | flattened_format = TRUE; 249 | return; 250 | 251 | out: 252 | if (get_osrelease) 253 | pc->flags2 |= GET_OSRELEASE; 254 | } 255 | 256 | static int 257 | read_raw_dump_file(int fd, off_t offset, void *buf, size_t size) 258 | { 259 | if (lseek(fd, offset, SEEK_SET) < 0) { 260 | if (CRASHDEBUG(1)) 261 | error(INFO, "read_raw_dump_file: lseek error (flat format)\n"); 262 | return FALSE; 263 | } 264 | if (read(fd, buf, size) < size) { 265 | if (CRASHDEBUG(1)) 266 | error(INFO, "read_raw_dump_file: read error (flat format)\n"); 267 | return FALSE; 268 | } 269 | 270 | return TRUE; 271 | } 272 | 273 | int 274 | read_flattened_format(int fd, off_t offset, void *buf, size_t size) 275 | { 276 | unsigned long long index, index_start, index_end; 277 | int64_t range_start, range_end; 278 | size_t read_size, remain_size; 279 | off_t offset_read; 280 | struct flat_data *ptr; 281 | 282 | index_start = 0; 283 | index_end = afd.num_array; 284 | 285 | while (1) { 286 | index = (index_start + index_end) / 2; 287 | ptr = afd.array + index; 288 | range_start = ptr->off_rearranged; 289 | range_end = ptr->off_rearranged + ptr->buf_size; 290 | 291 | if ((range_start <= offset) && (offset < range_end)) { 292 | /* Found a corresponding array. */ 293 | offset_read = (offset - range_start) + ptr->off_flattened; 294 | 295 | if (offset + size <= range_end) { 296 | if (!read_raw_dump_file(fd, offset_read, buf, size)) 297 | return FALSE; 298 | break; 299 | } 300 | 301 | /* Searh other array corresponding to remaining data. */ 302 | read_size = range_end - offset; 303 | remain_size = size - read_size; 304 | if (!read_raw_dump_file(fd, offset_read, buf, read_size)) 305 | return FALSE; 306 | if (!read_flattened_format(fd, offset + read_size, 307 | (char *)buf + read_size, remain_size)) 308 | return FALSE; 309 | break; 310 | 311 | } else if ((index == index_start) && 312 | (index_start + 1 == index_end)) { 313 | /* 314 | * Try to read not-written area. That is a common case, 315 | * because the area might be skipped by lseek(). 316 | * This area should be the data filled with zero. 317 | */ 318 | ptr = afd.array + index_end; 319 | if (offset + size <= ptr->off_rearranged) { 320 | memset(buf, 0x0, size); 321 | } else { 322 | read_size = ptr->off_rearranged - offset; 323 | remain_size = size - read_size; 324 | memset(buf, 0x0, read_size); 325 | if (!read_flattened_format(fd, 326 | offset + read_size, 327 | (char *)buf + read_size, 328 | remain_size)) 329 | return FALSE; 330 | } 331 | break; 332 | 333 | } else if (offset < ptr->off_rearranged) 334 | index_end = index; 335 | else 336 | index_start = index; 337 | } 338 | return TRUE; 339 | } 340 | 341 | int 342 | is_flattened_format(char *file) 343 | { 344 | check_flattened_format(file); 345 | return flattened_format; 346 | } 347 | 348 | void 349 | dump_flat_header(FILE *ofp) 350 | { 351 | int i; 352 | 353 | fprintf(ofp, "makedumpfile header:\n"); 354 | fprintf(ofp, " signature: \""); 355 | for (i = 0; i < SIG_LEN_MDF; i++) { 356 | if (!fh_save.signature[i]) 357 | break; 358 | fprintf(ofp, "%c", fh_save.signature[i]); 359 | } 360 | fprintf(ofp, "\"\n"); 361 | fprintf(ofp, " type: %llx\n", (ulonglong)fh_save.type); 362 | fprintf(ofp, " version: %llx\n", (ulonglong)fh_save.version); 363 | 364 | fprintf(ofp, " all_flat_data:\n"); 365 | fprintf(ofp, " num_array: %lld\n", (ulonglong)afd.num_array); 366 | fprintf(ofp, " array: %lx\n", (ulong)afd.array); 367 | fprintf(ofp, " file_size: %ld\n\n", (ulong)afd.file_size); 368 | } 369 | 370 | static void 371 | flattened_format_get_osrelease(char *file) 372 | { 373 | int c; 374 | FILE *pipe; 375 | char buf[BUFSIZE], *p1, *p2; 376 | 377 | c = strlen("OSRELEASE="); 378 | sprintf(buf, "/usr/bin/strings -n %d %s", c, file); 379 | 380 | if ((pipe = popen(buf, "r")) == NULL) 381 | return; 382 | 383 | for (c = 0; (c < 100) && fgets(buf, BUFSIZE-1, pipe); c++) { 384 | if ((p1 = strstr(buf, "OSRELEASE="))) { 385 | p2 = strstr(p1, "="); 386 | fprintf(fp, "%s", p2+1); 387 | flattened_format = TRUE; 388 | pc->flags2 |= GET_OSRELEASE; 389 | } 390 | } 391 | 392 | pclose(pipe); 393 | } 394 | -------------------------------------------------------------------------------- /makedumpfile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * makedumpfile.h 3 | * 4 | * This code is for reading a dumpfile ganarated by makedumpfile command. 5 | * 6 | * Copyright (C) 2011 NEC Soft, Ltd. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * Author: Ken'ichi Ohmichi 19 | */ 20 | 21 | /* 22 | * makedumpfile header 23 | * For re-arranging the dump data on different architecture, all the 24 | * variables are defined by 64bits. The size of signature is aligned 25 | * to 64bits, and change the values to big endian. 26 | */ 27 | #define MAKEDUMPFILE_SIGNATURE "makedumpfile" 28 | #define NUM_SIG_MDF (sizeof(MAKEDUMPFILE_SIGNATURE) - 1) 29 | #define SIZE_SIG_MDF roundup(sizeof(char) * NUM_SIG_MDF, 8) 30 | #define SIG_LEN_MDF (SIZE_SIG_MDF / sizeof(char)) 31 | #define MAX_SIZE_MDF_HEADER (4096) /* max size of makedumpfile_header */ 32 | #define TYPE_FLAT_HEADER (1) /* type of flattened format */ 33 | #define VERSION_FLAT_HEADER (1) /* current version of flattened format */ 34 | #define END_FLAG_FLAT_HEADER (-1) 35 | 36 | struct makedumpfile_header { 37 | char signature[SIG_LEN_MDF]; /* = "makedumpfile" */ 38 | int64_t type; 39 | int64_t version; 40 | }; 41 | 42 | struct makedumpfile_data_header { 43 | int64_t offset; 44 | int64_t buf_size; 45 | }; 46 | 47 | -------------------------------------------------------------------------------- /maple_tree.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0+ */ 2 | #ifndef _MAPLE_TREE_H 3 | #define _MAPLE_TREE_H 4 | /* 5 | * Maple Tree - An RCU-safe adaptive tree for storing ranges 6 | * Copyright (c) 2018-2022 Oracle 7 | * Authors: Liam R. Howlett 8 | * Matthew Wilcox 9 | * 10 | * eXtensible Arrays 11 | * Copyright (c) 2017 Microsoft Corporation 12 | * Author: Matthew Wilcox 13 | * 14 | * See Documentation/core-api/xarray.rst for how to use the XArray. 15 | */ 16 | #include 17 | #include 18 | #include 19 | 20 | /* 21 | * The following are copied and modified from include/linux/maple_tree.h 22 | */ 23 | 24 | enum maple_type { 25 | maple_dense, 26 | maple_leaf_64, 27 | maple_range_64, 28 | maple_arange_64, 29 | }; 30 | 31 | #define MAPLE_NODE_MASK 255UL 32 | 33 | #define MT_FLAGS_HEIGHT_OFFSET 0x02 34 | #define MT_FLAGS_HEIGHT_MASK 0x7C 35 | 36 | #define MAPLE_NODE_TYPE_MASK 0x0F 37 | #define MAPLE_NODE_TYPE_SHIFT 0x03 38 | 39 | #define MAPLE_RESERVED_RANGE 4096 40 | 41 | /* 42 | * The following are copied and modified from include/linux/xarray.h 43 | */ 44 | 45 | #define XA_ZERO_ENTRY xa_mk_internal(257) 46 | 47 | static inline ulong xa_mk_internal(ulong v) 48 | { 49 | return (v << 2) | 2; 50 | } 51 | 52 | static inline bool xa_is_internal(ulong entry) 53 | { 54 | return (entry & 3) == 2; 55 | } 56 | 57 | static inline bool xa_is_node(ulong entry) 58 | { 59 | return xa_is_internal(entry) && entry > 4096; 60 | } 61 | 62 | static inline bool xa_is_value(ulong entry) 63 | { 64 | return entry & 1; 65 | } 66 | 67 | static inline bool xa_is_zero(ulong entry) 68 | { 69 | return entry == XA_ZERO_ENTRY; 70 | } 71 | 72 | static inline unsigned long xa_to_internal(ulong entry) 73 | { 74 | return entry >> 2; 75 | } 76 | 77 | static inline unsigned long xa_to_value(ulong entry) 78 | { 79 | return entry >> 1; 80 | } 81 | 82 | #endif /* _MAPLE_TREE_H */ 83 | -------------------------------------------------------------------------------- /memory_driver/Makefile: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU General Public License as published by 3 | # the Free Software Foundation; either version 2 of the License, or 4 | # (at your option) any later version. 5 | # 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | ifneq ($(KERNELRELEASE),) 12 | obj-m := crash.o 13 | else 14 | PWD := $(shell pwd) 15 | KVER ?= $(shell uname -r) 16 | KDIR ?= /lib/modules/${KVER}/build 17 | all: 18 | ${MAKE} -C ${KDIR} M=${PWD} SUBDIRS=${PWD} modules 19 | clean: 20 | test -e ${KDIR}/Makefile && ${MAKE} -C ${KDIR} M=${PWD} SUBDIRS=${PWD} clean || ${RM} *.mod.c *.ko *.o Module.* 21 | endif 22 | -------------------------------------------------------------------------------- /memory_driver/README: -------------------------------------------------------------------------------- 1 | For live system analysis, the physical memory source must be one 2 | of the following devices: 3 | 4 | /dev/mem 5 | /proc/kcore 6 | /dev/crash 7 | 8 | If the live system kernel was configured with CONFIG_STRICT_DEVMEM 9 | or CONFIG_HARDENED_USERCOPY, then /dev/mem cannot be used. 10 | 11 | If the live system kernel was configured without CONFIG_PROC_KCORE, 12 | or if /proc/kcore is non-functional, then /proc/kcore cannot be used. 13 | 14 | The third alternative is this /dev/crash driver. Presuming that 15 | /lib/modules/`uname -r`/build points to a kernel build tree or 16 | kernel "devel" package tree, the module can simply be built and 17 | installed like so: 18 | 19 | # make 20 | ... 21 | # insmod crash.ko 22 | 23 | Once installed, the /dev/crash driver will be used by default for 24 | live system crash sessions. 25 | -------------------------------------------------------------------------------- /memory_driver/crash.c: -------------------------------------------------------------------------------- 1 | /* 2 | * linux/drivers/char/crash.c 3 | * 4 | * Copyright (C) 2004, 2011, 2016 Dave Anderson 5 | * Copyright (C) 2004, 2011, 2016 Red Hat, Inc. 6 | * Copyright (C) 2019 Serapheim Dimitropoulos 7 | */ 8 | 9 | /****************************************************************************** 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2, or (at your option) 14 | * any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program; if not, write to the Free Software 23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 | * 25 | *****************************************************************************/ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | extern int page_is_ram(unsigned long); 40 | 41 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0) 42 | 43 | #define CAN_WRITE_KERNEL 1 44 | 45 | static inline long copy_from_kernel_nofault(void *dst, const void *src, size_t size) 46 | { 47 | return probe_kernel_read(dst, src, size); 48 | } 49 | 50 | static inline long copy_to_kernel_nofault(void *dst, const void *src, size_t size) 51 | { 52 | return probe_kernel_write(dst, src, size); 53 | } 54 | 55 | #endif 56 | 57 | #ifdef CONFIG_S390 58 | /* 59 | * For swapped prefix pages get bounce buffer using xlate_dev_mem_ptr() 60 | */ 61 | static inline void *map_virtual(u64 offset, struct page **pp) 62 | { 63 | struct page *page; 64 | unsigned long pfn; 65 | void *vaddr; 66 | 67 | vaddr = xlate_dev_mem_ptr(offset); 68 | pfn = ((unsigned long) vaddr) >> PAGE_SHIFT; 69 | if ((unsigned long) vaddr != offset) 70 | page = pfn_to_page(pfn); 71 | else 72 | page = NULL; 73 | 74 | if (!page_is_ram(pfn)) { 75 | printk(KERN_INFO 76 | "crash memory driver: !page_is_ram(pfn: %lx)\n", pfn); 77 | return NULL; 78 | } 79 | 80 | if (!pfn_valid(pfn)) { 81 | printk(KERN_INFO 82 | "crash memory driver: invalid pfn: %lx )\n", pfn); 83 | return NULL; 84 | } 85 | 86 | *pp = page; 87 | return vaddr; 88 | } 89 | 90 | /* 91 | * Free bounce buffer if necessary 92 | */ 93 | static inline void unmap_virtual(struct page *page) 94 | { 95 | void *vaddr; 96 | 97 | if (page) { 98 | /* 99 | * Because for bounce buffers vaddr will never be 0 100 | * unxlate_dev_mem_ptr() will always free the bounce buffer. 101 | */ 102 | vaddr = (void *)(page_to_pfn(page) << PAGE_SHIFT); 103 | unxlate_dev_mem_ptr(0, vaddr); 104 | } 105 | } 106 | 107 | #else /* all architectures except s390x */ 108 | 109 | static inline void * 110 | map_virtual(u64 offset, struct page **pp) 111 | { 112 | struct page *page; 113 | unsigned long pfn; 114 | void *vaddr; 115 | 116 | pfn = (unsigned long)(offset >> PAGE_SHIFT); 117 | 118 | #ifdef NOTDEF 119 | /* 120 | * page_is_ram() is typically not exported, but there may 121 | * be another architecture, kernel version, or distribution 122 | * specific mechanism that can be plugged in here if desired. 123 | */ 124 | if (!page_is_ram(pfn)) { 125 | printk(KERN_INFO 126 | "crash memory driver: !page_is_ram(pfn: %lx)\n", pfn); 127 | return NULL; 128 | } 129 | #endif 130 | 131 | if (!pfn_valid(pfn)) { 132 | printk(KERN_INFO 133 | "crash memory driver: invalid pfn: %lx\n", pfn); 134 | return NULL; 135 | } 136 | 137 | page = pfn_to_page(pfn); 138 | 139 | vaddr = kmap(page); 140 | if (!vaddr) { 141 | printk(KERN_INFO 142 | "crash memory driver: pfn: %lx kmap(page: %lx) failed\n", 143 | pfn, (unsigned long)page); 144 | return NULL; 145 | } 146 | 147 | *pp = page; 148 | return (vaddr + (offset & (PAGE_SIZE-1))); 149 | } 150 | 151 | static inline void unmap_virtual(struct page *page) 152 | { 153 | kunmap(page); 154 | } 155 | #endif 156 | 157 | 158 | #define CRASH_VERSION "1.5" 159 | 160 | /* 161 | * These are the file operation functions that allow crash utility 162 | * access to physical memory. 163 | */ 164 | 165 | static loff_t 166 | crash_llseek(struct file * file, loff_t offset, int orig) 167 | { 168 | switch (orig) { 169 | case 0: 170 | file->f_pos = offset; 171 | return file->f_pos; 172 | case 1: 173 | file->f_pos += offset; 174 | return file->f_pos; 175 | default: 176 | return -EINVAL; 177 | } 178 | } 179 | 180 | #ifdef CAN_WRITE_KERNEL 181 | 182 | static ssize_t 183 | crash_write(struct file *file, const char *buf, size_t count, loff_t *poff) 184 | { 185 | void *vaddr; 186 | struct page *page; 187 | u64 offset; 188 | ssize_t written; 189 | char *buffer = file->private_data; 190 | 191 | offset = *poff; 192 | if (offset >> PAGE_SHIFT != (offset+count-1) >> PAGE_SHIFT) 193 | return -EINVAL; 194 | 195 | vaddr = map_virtual(offset, &page); 196 | if (!vaddr) 197 | return -EFAULT; 198 | 199 | /* 200 | * Use bounce buffer to bypass the CONFIG_HARDENED_USERCOPY 201 | * kernel text restriction. 202 | */ 203 | if (copy_from_user(buffer, buf, count)) { 204 | unmap_virtual(page); 205 | return -EFAULT; 206 | } 207 | 208 | if (copy_to_kernel_nofault(vaddr, buffer, count)) { 209 | unmap_virtual(page); 210 | return -EFAULT; 211 | } 212 | unmap_virtual(page); 213 | 214 | written = count; 215 | *poff += written; 216 | return written; 217 | } 218 | 219 | #endif 220 | 221 | /* 222 | * Determine the page address for an address offset value, 223 | * get a virtual address for it, and copy it out. 224 | * Accesses must fit within a page. 225 | */ 226 | static ssize_t 227 | crash_read(struct file *file, char *buf, size_t count, loff_t *poff) 228 | { 229 | void *vaddr; 230 | struct page *page; 231 | u64 offset; 232 | ssize_t read; 233 | char *buffer = file->private_data; 234 | 235 | offset = *poff; 236 | if (offset >> PAGE_SHIFT != (offset+count-1) >> PAGE_SHIFT) 237 | return -EINVAL; 238 | 239 | vaddr = map_virtual(offset, &page); 240 | if (!vaddr) 241 | return -EFAULT; 242 | /* 243 | * Use bounce buffer to bypass the CONFIG_HARDENED_USERCOPY 244 | * kernel text restriction. 245 | */ 246 | if (copy_from_kernel_nofault(buffer, vaddr, count)) { 247 | unmap_virtual(page); 248 | return -EFAULT; 249 | } 250 | if (copy_to_user(buf, buffer, count)) { 251 | unmap_virtual(page); 252 | return -EFAULT; 253 | } 254 | unmap_virtual(page); 255 | 256 | read = count; 257 | *poff += read; 258 | return read; 259 | } 260 | 261 | static int 262 | crash_open(struct inode * inode, struct file * filp) 263 | { 264 | if (!capable(CAP_SYS_RAWIO)) 265 | return -EPERM; 266 | 267 | filp->private_data = (void *)__get_free_page(GFP_KERNEL); 268 | if (!filp->private_data) 269 | return -ENOMEM; 270 | 271 | return 0; 272 | } 273 | 274 | static int 275 | crash_release(struct inode *inode, struct file *filp) 276 | { 277 | free_pages((unsigned long)filp->private_data, 0); 278 | return 0; 279 | } 280 | 281 | /* 282 | * Note: This function is required for Linux 4.6 and later ARM64 kernels. 283 | * For earler kernel versions, remove this CONFIG_ARM64 section. 284 | */ 285 | #ifdef CONFIG_ARM64 286 | 287 | #define DEV_CRASH_ARCH_DATA _IOR('c', 1, long) 288 | 289 | static long 290 | crash_arch_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 291 | { 292 | extern u64 kimage_voffset; 293 | 294 | switch (cmd) 295 | { 296 | case DEV_CRASH_ARCH_DATA: 297 | return put_user(kimage_voffset, (unsigned long __user *)arg); 298 | default: 299 | return -EINVAL; 300 | } 301 | } 302 | #endif 303 | 304 | static long 305 | crash_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 306 | { 307 | #ifdef DEV_CRASH_ARCH_DATA 308 | return crash_arch_ioctl(file, cmd, arg); 309 | #else 310 | return -EINVAL; 311 | #endif 312 | } 313 | 314 | static struct file_operations crash_fops = { 315 | .owner = THIS_MODULE, 316 | .llseek = crash_llseek, 317 | .read = crash_read, 318 | #ifdef CAN_WRITE_KERNEL 319 | .write = crash_write, 320 | #endif 321 | .unlocked_ioctl = crash_ioctl, 322 | .open = crash_open, 323 | .release = crash_release, 324 | }; 325 | 326 | static struct miscdevice crash_dev = { 327 | .minor = MISC_DYNAMIC_MINOR, 328 | .name = "crash", 329 | .fops = &crash_fops 330 | }; 331 | 332 | static int __init 333 | crash_init(void) 334 | { 335 | int ret; 336 | 337 | ret = misc_register(&crash_dev); 338 | if (ret) { 339 | printk(KERN_ERR 340 | "crash memory driver: cannot misc_register (MISC_DYNAMIC_MINOR)\n"); 341 | goto out; 342 | } 343 | 344 | ret = 0; 345 | printk(KERN_INFO "crash memory driver: version %s\n", CRASH_VERSION); 346 | out: 347 | return ret; 348 | } 349 | 350 | static void __exit 351 | crash_cleanup_module(void) 352 | { 353 | misc_deregister(&crash_dev); 354 | } 355 | 356 | module_init(crash_init); 357 | module_exit(crash_cleanup_module); 358 | 359 | MODULE_LICENSE("GPL"); 360 | -------------------------------------------------------------------------------- /netdump.h: -------------------------------------------------------------------------------- 1 | /* netdump.h 2 | * 3 | * Copyright (C) 2002-2009, 2017-2018 David Anderson 4 | * Copyright (C) 2002-2009, 2017-2018 Red Hat, Inc. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * Author: David Anderson 17 | */ 18 | 19 | #include 20 | #include "vmcore.h" 21 | 22 | #define MIN_NETDUMP_ELF32_HEADER_SIZE \ 23 | sizeof(Elf32_Ehdr)+sizeof(Elf32_Phdr)+sizeof(Elf32_Phdr) 24 | #define MIN_NETDUMP_ELF64_HEADER_SIZE \ 25 | sizeof(Elf64_Ehdr)+sizeof(Elf64_Phdr)+sizeof(Elf64_Phdr) 26 | #define MIN_NETDUMP_ELF_HEADER_SIZE \ 27 | MAX(MIN_NETDUMP_ELF32_HEADER_SIZE, MIN_NETDUMP_ELF64_HEADER_SIZE) 28 | 29 | #define NETDUMP_ELF_HEADER_SPARE_SIZE 128 30 | /* 31 | * "Safe" size, as in covering the ELF header and the first two program headers 32 | * plus any "padding" in-between, like section headers. 33 | */ 34 | #define SAFE_NETDUMP_ELF_HEADER_SIZE \ 35 | (MIN_NETDUMP_ELF_HEADER_SIZE+NETDUMP_ELF_HEADER_SPARE_SIZE) 36 | 37 | #define NT_TASKSTRUCT 4 38 | #define NT_DISKDUMP 0x70000001 39 | 40 | #ifdef NOTDEF 41 | /* 42 | * Note: Based upon the original, abandoned, proposal for 43 | * its contents -- keep around for potential future use. 44 | */ 45 | #ifndef NT_KDUMPINFO 46 | #define NT_KDUMPINFO 7 47 | #endif 48 | 49 | #endif /* NOTDEF */ 50 | 51 | struct pt_load_segment { 52 | off_t file_offset; 53 | physaddr_t phys_start; 54 | physaddr_t phys_end; 55 | physaddr_t zero_fill; 56 | }; 57 | 58 | struct vmcore_data { 59 | ulong flags; 60 | int ndfd; 61 | FILE *ofp; 62 | uint header_size; 63 | char *elf_header; 64 | uint num_pt_load_segments; 65 | struct pt_load_segment *pt_load_segments; 66 | Elf32_Ehdr *elf32; 67 | Elf32_Phdr *notes32; 68 | Elf32_Phdr *load32; 69 | Elf64_Ehdr *elf64; 70 | Elf64_Phdr *notes64; 71 | Elf64_Phdr *load64; 72 | Elf64_Shdr *sect0_64; 73 | void *nt_prstatus; 74 | void *nt_prpsinfo; 75 | void *nt_taskstruct; 76 | ulong task_struct; 77 | uint page_size; 78 | ulong switch_stack; 79 | uint num_prstatus_notes; 80 | void *nt_prstatus_percpu[NR_CPUS]; 81 | void *vmcoreinfo; 82 | uint size_vmcoreinfo; 83 | /* Backup Region, first 640K of System RAM. */ 84 | #define KEXEC_BACKUP_SRC_END 0x0009ffff 85 | uint num_qemu_notes; 86 | void *nt_qemu_percpu[NR_CPUS]; 87 | ulonglong backup_src_start; 88 | ulong backup_src_size; 89 | ulonglong backup_offset; 90 | ulong arch_data; 91 | #define arch_data1 arch_data 92 | ulong phys_base; 93 | ulong arch_data2; 94 | void *nt_vmcoredd_array[NR_DEVICE_DUMPS]; 95 | uint num_vmcoredd_notes; 96 | }; 97 | 98 | #define DUMP_ELF_INCOMPLETE 0x1 /* dumpfile is incomplete */ 99 | 100 | /* 101 | * S390 CPU timer ELF note 102 | */ 103 | #ifndef NT_S390_TIMER 104 | #define NT_S390_TIMER 0x301 105 | #endif 106 | 107 | /* 108 | * S390 TOD clock comparator ELF note 109 | */ 110 | #ifndef NT_S390_TODCMP 111 | #define NT_S390_TODCMP 0x302 112 | #endif 113 | 114 | /* 115 | * S390 TOD programmable register ELF note 116 | */ 117 | #ifndef NT_S390_TODPREG 118 | #define NT_S390_TODPREG 0x303 119 | #endif 120 | 121 | /* 122 | * S390 control registers ELF note 123 | */ 124 | #ifndef NT_S390_CTRS 125 | #define NT_S390_CTRS 0x304 126 | #endif 127 | 128 | /* 129 | * S390 prefix ELF note 130 | */ 131 | #ifndef NT_S390_PREFIX 132 | #define NT_S390_PREFIX 0x305 133 | #endif 134 | 135 | /* 136 | * S390 vector registers 0-15 upper half note (16 * u64) 137 | */ 138 | #ifndef NT_S390_VXRS_LOW 139 | #define NT_S390_VXRS_LOW 0x309 140 | #endif 141 | 142 | /* 143 | * S390 vector registers 16-31 note (16 * u128) 144 | */ 145 | #ifndef NT_S390_VXRS_HIGH 146 | #define NT_S390_VXRS_HIGH 0x30a 147 | #endif 148 | 149 | #define MAX_KCORE_ELF_HEADER_SIZE (32768) 150 | 151 | struct proc_kcore_data { 152 | uint flags; 153 | uint segments; 154 | char *elf_header; 155 | size_t header_size; 156 | Elf64_Phdr *load64; 157 | Elf64_Phdr *notes64; 158 | Elf32_Phdr *load32; 159 | Elf32_Phdr *notes32; 160 | void *vmcoreinfo; 161 | uint size_vmcoreinfo; 162 | }; 163 | -------------------------------------------------------------------------------- /printk.c: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | #include 3 | 4 | /* convenience struct for passing many values to helper functions */ 5 | struct prb_map { 6 | char *prb; 7 | 8 | char *desc_ring; 9 | unsigned long desc_ring_count; 10 | char *descs; 11 | char *infos; 12 | unsigned int pid_max_chars; 13 | 14 | char *text_data_ring; 15 | unsigned long text_data_ring_size; 16 | char *text_data; 17 | }; 18 | 19 | /* 20 | * desc_state and DESC_* definitions taken from kernel source: 21 | * 22 | * kernel/printk/printk_ringbuffer.h 23 | */ 24 | 25 | /* The possible responses of a descriptor state-query. */ 26 | enum desc_state { 27 | desc_miss = -1, /* ID mismatch (pseudo state) */ 28 | desc_reserved = 0x0, /* reserved, in use by writer */ 29 | desc_committed = 0x1, /* committed by writer, could get reopened */ 30 | desc_finalized = 0x2, /* committed, no further modification allowed */ 31 | desc_reusable = 0x3, /* free, not yet used by any writer */ 32 | }; 33 | 34 | #define DESC_SV_BITS (sizeof(unsigned long) * 8) 35 | #define DESC_FLAGS_SHIFT (DESC_SV_BITS - 2) 36 | #define DESC_FLAGS_MASK (3UL << DESC_FLAGS_SHIFT) 37 | #define DESC_STATE(sv) (3UL & (sv >> DESC_FLAGS_SHIFT)) 38 | #define DESC_ID_MASK (~DESC_FLAGS_MASK) 39 | #define DESC_ID(sv) ((sv) & DESC_ID_MASK) 40 | 41 | /* 42 | * get_desc_state() taken from kernel source: 43 | * 44 | * kernel/printk/printk_ringbuffer.c 45 | */ 46 | 47 | /* Query the state of a descriptor. */ 48 | static enum desc_state get_desc_state(unsigned long id, 49 | unsigned long state_val) 50 | { 51 | if (id != DESC_ID(state_val)) 52 | return desc_miss; 53 | 54 | return DESC_STATE(state_val); 55 | } 56 | 57 | static void 58 | init_offsets(void) 59 | { 60 | char *n; 61 | 62 | n = "printk_info"; 63 | STRUCT_SIZE_INIT(printk_info, n); 64 | MEMBER_OFFSET_INIT(printk_info_seq, n, "seq"); 65 | MEMBER_OFFSET_INIT(printk_info_ts_nsec, n, "ts_nsec"); 66 | MEMBER_OFFSET_INIT(printk_info_text_len, n, "text_len"); 67 | MEMBER_OFFSET_INIT(printk_info_level, n, "level"); 68 | MEMBER_OFFSET_INIT(printk_info_caller_id, n, "caller_id"); 69 | MEMBER_OFFSET_INIT(printk_info_dev_info, n, "dev_info"); 70 | 71 | n = "dev_printk_info"; 72 | MEMBER_OFFSET_INIT(dev_printk_info_subsystem, n, "subsystem"); 73 | MEMBER_OFFSET_INIT(dev_printk_info_device, n, "device"); 74 | 75 | n = "printk_ringbuffer"; 76 | STRUCT_SIZE_INIT(printk_ringbuffer, n); 77 | MEMBER_OFFSET_INIT(prb_desc_ring, n, "desc_ring"); 78 | MEMBER_OFFSET_INIT(prb_text_data_ring, n, "text_data_ring"); 79 | 80 | n = "prb_desc_ring"; 81 | MEMBER_OFFSET_INIT(prb_desc_ring_count_bits, n, "count_bits"); 82 | MEMBER_OFFSET_INIT(prb_desc_ring_descs, n, "descs"); 83 | MEMBER_OFFSET_INIT(prb_desc_ring_infos, n, "infos"); 84 | MEMBER_OFFSET_INIT(prb_desc_ring_head_id, n, "head_id"); 85 | MEMBER_OFFSET_INIT(prb_desc_ring_tail_id, n, "tail_id"); 86 | 87 | n = "prb_desc"; 88 | STRUCT_SIZE_INIT(prb_desc, n); 89 | MEMBER_OFFSET_INIT(prb_desc_state_var, n, "state_var"); 90 | MEMBER_OFFSET_INIT(prb_desc_text_blk_lpos, n, "text_blk_lpos"); 91 | 92 | n = "prb_data_blk_lpos"; 93 | MEMBER_OFFSET_INIT(prb_data_blk_lpos_begin, n, "begin"); 94 | MEMBER_OFFSET_INIT(prb_data_blk_lpos_next, n, "next"); 95 | 96 | n = "prb_data_ring"; 97 | MEMBER_OFFSET_INIT(prb_data_ring_size_bits, n, "size_bits"); 98 | MEMBER_OFFSET_INIT(prb_data_ring_data, n, "data"); 99 | 100 | n = "atomic_long_t"; 101 | MEMBER_OFFSET_INIT(atomic_long_t_counter, n, "counter"); 102 | } 103 | 104 | static void 105 | dump_record(struct prb_map *m, unsigned long id, int msg_flags) 106 | { 107 | unsigned short text_len; 108 | unsigned long state_var; 109 | unsigned int caller_id; 110 | enum desc_state state; 111 | unsigned char level; 112 | unsigned long begin; 113 | unsigned long next; 114 | char buf[BUFSIZE]; 115 | uint64_t ts_nsec; 116 | ulonglong nanos; 117 | ulonglong seq; 118 | int ilen = 0, i; 119 | char *desc, *info, *text, *p; 120 | ulong rem; 121 | 122 | desc = m->descs + ((id % m->desc_ring_count) * SIZE(prb_desc)); 123 | 124 | /* skip non-committed record */ 125 | state_var = ULONG(desc + OFFSET(prb_desc_state_var) + 126 | OFFSET(atomic_long_t_counter)); 127 | state = get_desc_state(id, state_var); 128 | if (state != desc_committed && state != desc_finalized) 129 | return; 130 | 131 | info = m->infos + ((id % m->desc_ring_count) * SIZE(printk_info)); 132 | 133 | seq = ULONGLONG(info + OFFSET(printk_info_seq)); 134 | caller_id = UINT(info + OFFSET(printk_info_caller_id)); 135 | if (CRASHDEBUG(1)) 136 | fprintf(fp, "seq: %llu caller_id: %x (%s: %u)\n", seq, caller_id, 137 | caller_id & 0x80000000 ? "cpu" : "pid", caller_id & ~0x80000000); 138 | 139 | text_len = USHORT(info + OFFSET(printk_info_text_len)); 140 | 141 | begin = ULONG(desc + OFFSET(prb_desc_text_blk_lpos) + 142 | OFFSET(prb_data_blk_lpos_begin)) % 143 | m->text_data_ring_size; 144 | next = ULONG(desc + OFFSET(prb_desc_text_blk_lpos) + 145 | OFFSET(prb_data_blk_lpos_next)) % 146 | m->text_data_ring_size; 147 | 148 | /* skip data-less text blocks */ 149 | if (begin == next) 150 | goto out; 151 | 152 | if ((msg_flags & SHOW_LOG_TEXT) == 0) { 153 | ts_nsec = ULONGLONG(info + OFFSET(printk_info_ts_nsec)); 154 | nanos = (ulonglong)ts_nsec / (ulonglong)1000000000; 155 | rem = (ulonglong)ts_nsec % (ulonglong)1000000000; 156 | if (msg_flags & SHOW_LOG_CTIME) { 157 | time_t t = kt->boot_date.tv_sec + nanos; 158 | sprintf(buf, "[%s] ", ctime_tz(&t)); 159 | } else 160 | sprintf(buf, "[%5lld.%06ld] ", nanos, rem/1000); 161 | 162 | ilen += strlen(buf); 163 | fprintf(fp, "%s", buf); 164 | } 165 | 166 | /* 167 | * The lockless ringbuffer introduced in Linux-5.10 always has 168 | * the caller_id field available, so if requested, print it. 169 | */ 170 | if (msg_flags & SHOW_LOG_CALLER) { 171 | const unsigned int cpuid = 0x80000000; 172 | char cbuf[PID_CHARS_MAX]; 173 | unsigned int cid; 174 | 175 | /* Get id type, isolate id value in cid for print */ 176 | cid = UINT(info + OFFSET(printk_info_caller_id)); 177 | sprintf(cbuf, "%c%d", (cid & cpuid) ? 'C' : 'T', cid & ~cpuid); 178 | sprintf(buf, "[%*s] ", m->pid_max_chars, cbuf); 179 | 180 | ilen += strlen(buf); 181 | fprintf(fp, "%s", buf); 182 | } 183 | 184 | if (msg_flags & SHOW_LOG_LEVEL) { 185 | level = UCHAR(info + OFFSET(printk_info_level)) >> 5; 186 | sprintf(buf, "<%x>", level); 187 | ilen += strlen(buf); 188 | fprintf(fp, "%s", buf); 189 | } 190 | 191 | /* handle wrapping data block */ 192 | if (begin > next) 193 | begin = 0; 194 | 195 | /* skip over descriptor ID */ 196 | begin += sizeof(unsigned long); 197 | 198 | /* handle truncated messages */ 199 | if (next - begin < text_len) 200 | text_len = next - begin; 201 | 202 | text = m->text_data + begin; 203 | 204 | for (i = 0, p = text; i < text_len; i++, p++) { 205 | if (*p == '\n') 206 | fprintf(fp, "\n%s", space(ilen)); 207 | else if (isprint(*p) || isspace(*p)) 208 | fputc(*p, fp); 209 | else 210 | fputc('.', fp); 211 | } 212 | 213 | if (msg_flags & SHOW_LOG_DICT) { 214 | text = info + OFFSET(printk_info_dev_info) + 215 | OFFSET(dev_printk_info_subsystem); 216 | if (strlen(text)) 217 | fprintf(fp, "\n%sSUBSYSTEM=%s", space(ilen), text); 218 | 219 | text = info + OFFSET(printk_info_dev_info) + 220 | OFFSET(dev_printk_info_device); 221 | if (strlen(text)) 222 | fprintf(fp, "\n%sDEVICE=%s", space(ilen), text); 223 | } 224 | out: 225 | fprintf(fp, "\n"); 226 | } 227 | 228 | /* 229 | * Handle the lockless printk_ringbuffer. 230 | */ 231 | void 232 | dump_lockless_record_log(int msg_flags) 233 | { 234 | unsigned long head_id; 235 | unsigned long tail_id; 236 | unsigned long kaddr; 237 | unsigned long id; 238 | struct prb_map m; 239 | 240 | if (INVALID_SIZE(printk_info)) 241 | init_offsets(); 242 | 243 | /* setup printk_ringbuffer */ 244 | get_symbol_data("prb", sizeof(char *), &kaddr); 245 | m.prb = GETBUF(SIZE(printk_ringbuffer)); 246 | if (!readmem(kaddr, KVADDR, m.prb, SIZE(printk_ringbuffer), 247 | "printk_ringbuffer contents", RETURN_ON_ERROR|QUIET)) { 248 | error(WARNING, "\ncannot read printk_ringbuffer contents\n"); 249 | goto out_prb; 250 | } 251 | 252 | /* setup descriptor ring */ 253 | m.desc_ring = m.prb + OFFSET(prb_desc_ring); 254 | m.desc_ring_count = 1 << UINT(m.desc_ring + OFFSET(prb_desc_ring_count_bits)); 255 | 256 | kaddr = ULONG(m.desc_ring + OFFSET(prb_desc_ring_descs)); 257 | m.descs = GETBUF(SIZE(prb_desc) * m.desc_ring_count); 258 | if (!readmem(kaddr, KVADDR, m.descs, SIZE(prb_desc) * m.desc_ring_count, 259 | "prb_desc_ring contents", RETURN_ON_ERROR|QUIET)) { 260 | error(WARNING, "\ncannot read prb_desc_ring contents\n"); 261 | goto out_descs; 262 | } 263 | 264 | kaddr = ULONG(m.desc_ring + OFFSET(prb_desc_ring_infos)); 265 | m.infos = GETBUF(SIZE(printk_info) * m.desc_ring_count); 266 | if (!readmem(kaddr, KVADDR, m.infos, SIZE(printk_info) * m.desc_ring_count, 267 | "prb_info_ring contents", RETURN_ON_ERROR|QUIET)) { 268 | error(WARNING, "\ncannot read prb_info_ring contents\n"); 269 | goto out_infos; 270 | } 271 | 272 | /* setup text data ring */ 273 | m.text_data_ring = m.prb + OFFSET(prb_text_data_ring); 274 | m.text_data_ring_size = 1 << UINT(m.text_data_ring + OFFSET(prb_data_ring_size_bits)); 275 | 276 | kaddr = ULONG(m.text_data_ring + OFFSET(prb_data_ring_data)); 277 | m.text_data = GETBUF(m.text_data_ring_size); 278 | if (!readmem(kaddr, KVADDR, m.text_data, m.text_data_ring_size, 279 | "prb_text_data_ring contents", RETURN_ON_ERROR|QUIET)) { 280 | error(WARNING, "\ncannot read prb_text_data_ring contents\n"); 281 | goto out_text_data; 282 | } 283 | 284 | /* If caller_id was requested, get the pid_max value for print */ 285 | if (msg_flags & SHOW_LOG_CALLER) { 286 | unsigned int pidmax; 287 | 288 | if (!try_get_symbol_data("pid_max", sizeof(pidmax), &pidmax)) 289 | m.pid_max_chars = PID_CHARS_DEFAULT; 290 | else if (pidmax <= 99999) 291 | m.pid_max_chars = 6; 292 | else if (pidmax <= 999999) 293 | m.pid_max_chars = 7; 294 | else 295 | m.pid_max_chars = PID_CHARS_DEFAULT; 296 | } else { 297 | m.pid_max_chars = PID_CHARS_DEFAULT; 298 | } 299 | 300 | /* ready to go */ 301 | 302 | tail_id = ULONG(m.desc_ring + OFFSET(prb_desc_ring_tail_id) + 303 | OFFSET(atomic_long_t_counter)); 304 | head_id = ULONG(m.desc_ring + OFFSET(prb_desc_ring_head_id) + 305 | OFFSET(atomic_long_t_counter)); 306 | 307 | hq_open(); 308 | 309 | for (id = tail_id; id != head_id; id = (id + 1) & DESC_ID_MASK) 310 | dump_record(&m, id, msg_flags); 311 | 312 | /* dump head record */ 313 | dump_record(&m, id, msg_flags); 314 | 315 | hq_close(); 316 | 317 | out_text_data: 318 | FREEBUF(m.text_data); 319 | out_infos: 320 | FREEBUF(m.infos); 321 | out_descs: 322 | FREEBUF(m.descs); 323 | out_prb: 324 | FREEBUF(m.prb); 325 | } 326 | -------------------------------------------------------------------------------- /qemu-load.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Qemu save VM file description 3 | * 4 | * Copyright (C) 2009 Red Hat, Inc. 5 | * Written by Paolo Bonzini. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #ifndef QEMU_LOAD_H 19 | #define QEMU_LOAD_H 1 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | enum qemu_save_section { 27 | QEMU_VM_EOF, 28 | QEMU_VM_SECTION_START, 29 | QEMU_VM_SECTION_PART, 30 | QEMU_VM_SECTION_END, 31 | QEMU_VM_SECTION_FULL, 32 | QEMU_VM_SUBSECTION, 33 | QEMU_VM_CONFIGURATION = 0x07, 34 | QEMU_VM_SECTION_FOOTER = 0x7e 35 | }; 36 | 37 | enum qemu_features { 38 | QEMU_FEATURE_RAM = 1, 39 | QEMU_FEATURE_CPU = 2, 40 | QEMU_FEATURE_TIMER = 4, 41 | QEMU_FEATURE_KVM = 8 42 | }; 43 | 44 | struct qemu_device_list { 45 | struct qemu_device *head, *tail; 46 | uint32_t features; 47 | }; 48 | 49 | struct qemu_device_loader { 50 | const char *name; 51 | struct qemu_device *(*init_load) (struct qemu_device_list *, uint32_t, 52 | uint32_t, uint32_t, bool, FILE *); 53 | }; 54 | 55 | struct qemu_device_vtbl { 56 | const char *name; 57 | uint32_t (*load) (struct qemu_device *, FILE *, 58 | enum qemu_save_section); 59 | void (*free) (struct qemu_device *, 60 | struct qemu_device_list *); 61 | }; 62 | 63 | struct qemu_device { 64 | struct qemu_device_vtbl *vtbl; 65 | struct qemu_device_list *list; 66 | struct qemu_device *next; 67 | struct qemu_device *prev; 68 | uint32_t section_id; 69 | uint32_t instance_id; 70 | uint32_t version_id; 71 | }; 72 | 73 | struct qemu_device_ram { 74 | struct qemu_device dev_base; 75 | uint64_t last_ram_offset; 76 | FILE *fp; 77 | off_t *offsets; 78 | }; 79 | 80 | union qemu_uint128_t { 81 | uint32_t i[4]; 82 | unsigned i128 __attribute__ ((vector_size (16))); 83 | }; 84 | 85 | struct qemu_x86_seg { 86 | uint64_t base; 87 | uint32_t selector; 88 | uint32_t limit; 89 | uint32_t flags; 90 | }; 91 | 92 | struct qemu_x86_sysenter { 93 | uint32_t cs; 94 | uint64_t esp; 95 | uint64_t eip; 96 | }; 97 | 98 | union qemu_fpu_reg { 99 | long double ld; 100 | char bytes[10]; 101 | uint64_t mmx; 102 | }; 103 | 104 | 105 | struct qemu_x86_vmtrr { 106 | uint64_t base; 107 | uint64_t mask; 108 | }; 109 | 110 | struct qemu_x86_svm { 111 | uint64_t hsave; 112 | uint64_t vmcb; 113 | uint64_t tsc_offset; 114 | uint8_t in_vmm : 1; 115 | uint8_t guest_if_mask : 1; 116 | uint8_t guest_intr_masking : 1; 117 | uint16_t cr_read_mask; 118 | uint16_t cr_write_mask; 119 | uint16_t dr_read_mask; 120 | uint16_t dr_write_mask; 121 | uint32_t exception_intercept_mask; 122 | uint64_t intercept_mask; 123 | }; 124 | 125 | struct qemu_x86_kvm { 126 | uint64_t int_bitmap[4]; 127 | uint64_t tsc; 128 | uint32_t mp_state; 129 | uint32_t exception_injected; 130 | uint8_t soft_interrupt; 131 | uint8_t nmi_injected; 132 | uint8_t nmi_pending; 133 | uint8_t has_error_code; 134 | uint32_t sipi_vector; 135 | uint64_t system_time_msr; 136 | uint64_t wall_clock_msr; 137 | }; 138 | 139 | struct qemu_x86_mce { 140 | uint64_t mcg_cap; 141 | uint64_t mcg_status; 142 | uint64_t mcg_ctl; 143 | uint64_t mce_banks[10 * 4]; 144 | }; 145 | 146 | struct qemu_device_x86 { 147 | struct qemu_device dev_base; 148 | 149 | uint32_t halted; 150 | uint32_t irq; 151 | 152 | uint64_t regs[16]; 153 | uint64_t eip; 154 | uint64_t eflags; 155 | uint16_t fpucw; 156 | uint16_t fpusw; 157 | uint16_t fpu_free; 158 | union qemu_fpu_reg st[8]; 159 | struct qemu_x86_seg cs; 160 | struct qemu_x86_seg ds; 161 | struct qemu_x86_seg es; 162 | struct qemu_x86_seg ss; 163 | struct qemu_x86_seg fs; 164 | struct qemu_x86_seg gs; 165 | struct qemu_x86_seg ldt; 166 | struct qemu_x86_seg tr; 167 | struct qemu_x86_seg gdt; 168 | struct qemu_x86_seg idt; 169 | struct qemu_x86_sysenter sysenter; 170 | uint64_t cr0; 171 | uint64_t cr2; 172 | uint64_t cr3; 173 | uint64_t cr4; 174 | uint64_t dr[8]; 175 | uint8_t cr8; 176 | uint8_t soft_mmu : 1; 177 | uint8_t smm : 1; 178 | uint8_t a20_masked : 1; 179 | uint8_t global_if : 1; 180 | uint8_t in_nmi : 1; 181 | uint32_t mxcsr; 182 | union qemu_uint128_t xmm[16]; 183 | uint64_t efer; 184 | uint64_t star; 185 | uint64_t lstar; 186 | uint64_t cstar; 187 | uint64_t fmask; 188 | uint64_t kernel_gs_base; 189 | uint64_t pat; 190 | uint32_t smbase; 191 | struct qemu_x86_svm svm; 192 | uint64_t fixed_mtrr[11]; 193 | uint64_t deftype_mtrr; 194 | struct qemu_x86_vmtrr variable_mtrr[8]; 195 | struct qemu_x86_kvm kvm; 196 | struct qemu_x86_mce mce; 197 | uint64_t tsc_aux; 198 | uint64_t xcr0; 199 | uint64_t xstate_bv; 200 | union qemu_uint128_t ymmh_regs[16]; 201 | }; 202 | 203 | struct qemu_timer { 204 | uint64_t cpu_ticks_offset; 205 | uint64_t ticks_per_sec; 206 | uint64_t cpu_clock_offset; 207 | }; 208 | 209 | struct qemu_device *device_alloc (struct qemu_device_list *, size_t, 210 | struct qemu_device_vtbl *, uint32_t, 211 | uint32_t, uint32_t); 212 | void device_free (struct qemu_device *); 213 | void device_list_free (struct qemu_device_list *); 214 | struct qemu_device *device_find (struct qemu_device_list *, uint32_t); 215 | struct qemu_device *device_find_instance (struct qemu_device_list *, 216 | const char *, uint32_t); 217 | 218 | struct qemu_device_list *qemu_load (const struct qemu_device_loader *, 219 | uint32_t, FILE *); 220 | 221 | int ram_read_phys_page (struct qemu_device_ram *, void *, uint64_t); 222 | 223 | /* For a 32-bit KVM host. */ 224 | extern const struct qemu_device_loader devices_x86_32[]; 225 | 226 | /* For a 64-bit KVM host. */ 227 | extern const struct qemu_device_loader devices_x86_64[]; 228 | 229 | #endif 230 | -------------------------------------------------------------------------------- /qemu.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Derive kernel base from a QEMU saved VM file 3 | * 4 | * Copyright (C) 2009, 2010 Red Hat, Inc. 5 | * Written by Paolo Bonzini. 6 | * 7 | * Portions Copyright (C) 2009 David Anderson 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "qemu-load.h" 26 | 27 | #include "kvmdump.h" 28 | 29 | /* 30 | * Some bits we need to access in the control registers and page tables. 31 | */ 32 | 33 | #define MSR_EFER_LMA (1 << 10) 34 | #define PG_PRESENT_MASK (1 << 0) 35 | #define PG_PSE_MASK (1 << 7) 36 | #define CR0_PG_MASK (1 << 31) 37 | #define CR4_PAE_MASK (1 << 31) 38 | #define CR4_PSE_MASK (1 << 31) 39 | 40 | static uint32_t 41 | ldl (struct qemu_device_x86 *dx86, struct qemu_device_ram *dram, uint64_t addr) 42 | { 43 | char buf[4096]; 44 | if (dx86->a20_masked) 45 | addr &= ~(1LL<<20); 46 | if (!ram_read_phys_page (dram, buf, addr & ~0xfff)) 47 | return 0; 48 | 49 | assert ((addr & 0xfff) <= 0xffc); 50 | return *(uint32_t *)(buf + (addr & 0xfff)); 51 | } 52 | 53 | static uint64_t 54 | ldq (struct qemu_device_x86 *dx86, struct qemu_device_ram *dram, uint64_t addr) 55 | { 56 | char buf[4096]; 57 | if (dx86->a20_masked) 58 | addr &= ~(1LL<<20); 59 | if (!ram_read_phys_page (dram, buf, addr & ~0xfff)) 60 | return 0; 61 | 62 | assert ((addr & 0xfff) <= 0xff8); 63 | return *(uint64_t *)(buf + (addr & 0xfff)); 64 | } 65 | 66 | /* 67 | * Messy x86 TLB fault logic, walking the page tables to find the physical 68 | * address corresponding to ADDR. Taken from QEMU. 69 | */ 70 | 71 | static uint64_t 72 | get_phys_page(struct qemu_device_x86 *dx86, struct qemu_device_ram *dram, 73 | uint64_t addr) 74 | { 75 | uint64_t pde_addr, pte_addr; 76 | uint64_t pte, paddr; 77 | uint32_t page_offset; 78 | int page_size; 79 | 80 | if ((dx86->cr4 & CR4_PAE_MASK) || (dx86->efer & MSR_EFER_LMA)) { 81 | uint64_t pdpe_addr; 82 | uint64_t pde, pdpe; 83 | 84 | if (dx86->cr4 & CR4_PAE_MASK) 85 | dprintf ("PAE active\n"); 86 | if (dx86->efer & MSR_EFER_LMA) { 87 | uint64_t pml4e_addr, pml4e; 88 | int32_t sext; 89 | 90 | dprintf ("long mode active\n"); 91 | 92 | /* test virtual address sign extension */ 93 | sext = (int64_t) addr >> 47; 94 | if (sext != 0 && sext != -1) 95 | return -1; 96 | 97 | pml4e_addr = ((dx86->cr3 & ~0xfff) 98 | + (((addr >> 39) & 0x1ff) << 3)); 99 | pml4e = ldq (dx86, dram, pml4e_addr); 100 | if (!(pml4e & PG_PRESENT_MASK)) 101 | return -1; 102 | dprintf ("PML4 page present\n"); 103 | 104 | pdpe_addr = ((pml4e & ~0xfff) 105 | + (((addr >> 30) & 0x1ff) << 3)); 106 | pdpe = ldq (dx86, dram, pdpe_addr); 107 | if (!(pdpe & PG_PRESENT_MASK)) 108 | return -1; 109 | dprintf ("PDPE page present\n"); 110 | } else { 111 | dprintf ("long mode inactive\n"); 112 | 113 | pdpe_addr = ((dx86->cr3 & ~0x1f) 114 | + ((addr >> 27) & 0x18)); 115 | pdpe = ldq (dx86, dram, pdpe_addr); 116 | if (!(pdpe & PG_PRESENT_MASK)) 117 | return -1; 118 | dprintf ("PDPE page present\n"); 119 | } 120 | 121 | pde_addr = (pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3); 122 | pde = ldq (dx86, dram, pde_addr); 123 | if (!(pde & PG_PRESENT_MASK)) 124 | return -1; 125 | dprintf ("PDE page present\n"); 126 | 127 | if (pde & PG_PSE_MASK) { 128 | /* 2 MB page */ 129 | dprintf ("2MB page\n"); 130 | 131 | page_size = 2048 * 1024; 132 | pte = pde & ~((page_size - 1) & ~0xfff); 133 | } else { 134 | /* 4 KB page */ 135 | dprintf ("4 KB PAE page\n"); 136 | 137 | pte_addr = ((pde & ~0xfff) 138 | + (((addr >> 12) & 0x1ff) << 3)); 139 | page_size = 4096; 140 | pte = ldq (dx86, dram, pte_addr); 141 | if (!(pte & PG_PRESENT_MASK)) 142 | return -1; 143 | dprintf ("PTE page present\n"); 144 | } 145 | 146 | } else { 147 | /* Not PAE. */ 148 | 149 | uint32_t pde; 150 | if (!(dx86->cr0 & CR0_PG_MASK)) { 151 | dprintf ("Paging inactive\n"); 152 | 153 | pte = addr; 154 | page_size = 4096; 155 | } else { 156 | /* page directory entry */ 157 | pde_addr = ((dx86->cr3 & ~0xfff) 158 | + ((addr >> 20) & 0xffc)); 159 | pde = ldl (dx86, dram, pde_addr); 160 | if (!(pde & PG_PRESENT_MASK)) 161 | return -1; 162 | dprintf ("PDE page present\n"); 163 | if ((pde & PG_PSE_MASK) && (dx86->cr4 & CR4_PSE_MASK)) { 164 | page_size = 4096 * 1024; 165 | pte = pde & ~((page_size - 1) & ~0xfff); 166 | } else { 167 | page_size = 4096; 168 | pte_addr = ((pde & ~0xfff) 169 | + ((addr >> 10) & 0xffc)); 170 | pte = ldl (dx86, dram, pte_addr); 171 | if (!(pte & PG_PRESENT_MASK)) 172 | return -1; 173 | dprintf ("PTE page present\n"); 174 | } 175 | } 176 | } 177 | 178 | page_offset = (addr & 0xfff) & (page_size - 1); 179 | paddr = (pte & ~0xfff) + page_offset; 180 | return paddr; 181 | } 182 | 183 | /* 184 | * I'm using the IDT base as a quick way to find the bottom of the 185 | * kernel memory. 186 | */ 187 | static uint64_t 188 | get_idt_base(struct qemu_device_list *dl) 189 | { 190 | struct qemu_device_x86 *dx86 = (struct qemu_device_x86 *) 191 | device_find_instance (dl, "cpu", 0); 192 | 193 | return dx86->idt.base; 194 | } 195 | 196 | static uint64_t 197 | get_kernel_base(struct qemu_device_list *dl) 198 | { 199 | int i; 200 | uint64_t kernel_base = -1; 201 | uint64_t base_vaddr, last, mask; 202 | struct qemu_device_x86 *dx86 = (struct qemu_device_x86 *) 203 | device_find_instance (dl, "cpu", 0); 204 | struct qemu_device_ram *dram = (struct qemu_device_ram *) 205 | device_find_instance (dl, "ram", 0); 206 | 207 | for (i = 30, last = -1; (kernel_base == -1) && (i >= 20); i--) 208 | { 209 | mask = ~((1LL << i) - 1); 210 | base_vaddr = dx86->idt.base & mask; 211 | if (base_vaddr == last) 212 | continue; 213 | if (base_vaddr < kvm->kvbase) { 214 | fprintf(stderr, 215 | "WARNING: IDT base contains: %llx\n " 216 | "cannot determine physical base address: defaulting to 0\n\n", 217 | (unsigned long long)base_vaddr); 218 | return 0; 219 | } 220 | dprintf("get_kernel_base: %llx\n", (unsigned long long)base_vaddr); 221 | kernel_base = get_phys_page(dx86, dram, base_vaddr); 222 | last = base_vaddr; 223 | } 224 | 225 | if (kernel_base != -1) { 226 | dprintf("kvbase: %llx vaddr used: %llx physical: %llx\n", 227 | (unsigned long long)kvm->kvbase, 228 | (unsigned long long)base_vaddr, 229 | (unsigned long long)kernel_base); 230 | /* 231 | * Subtract the offset between the virtual address used 232 | * and the kernel's base virtual address. 233 | */ 234 | kernel_base -= (base_vaddr - kvm->kvbase); 235 | } else { 236 | dprintf("WARNING: cannot determine physical base address:" 237 | " defaulting to 0\n\n"); 238 | kernel_base = 0; 239 | kvm->flags |= NO_PHYS_BASE; 240 | } 241 | 242 | return kernel_base; 243 | } 244 | 245 | 246 | #ifdef MAIN_FROM_TEST_C 247 | int main (int argc, char **argv) 248 | { 249 | struct qemu_device_list *dl; 250 | FILE *fp; 251 | 252 | if (argc != 2) { 253 | fprintf (stderr, "Usage: test SAVE-FILE\n"); 254 | exit (1); 255 | } 256 | 257 | fp = fopen(argv[1], "r"); 258 | if (!fp) { 259 | fprintf (stderr, "Error: %s\n", strerror (errno)); 260 | exit (1); 261 | } 262 | 263 | #ifdef HOST_32BIT 264 | dl = qemu_load (devices_x86_32, QEMU_FEATURE_CPU|QEMU_FEATURE_RAM, fp); 265 | #else 266 | dl = qemu_load (devices_x86_64, QEMU_FEATURE_CPU|QEMU_FEATURE_RAM, fp); 267 | #endif 268 | printf ("IDT at %llx\n", get_idt_base (dl)); 269 | printf ("Physical kernel base at %llx\n", get_kernel_base (dl)); 270 | device_list_free (dl); 271 | fclose (fp); 272 | exit (0); 273 | } 274 | #endif 275 | 276 | 277 | /* 278 | * crash utility adaptation 279 | */ 280 | 281 | #include "defs.h" 282 | 283 | int 284 | qemu_init(char *filename) 285 | { 286 | struct qemu_device_list *dl; 287 | struct qemu_device_ram *dram; 288 | uint64_t idt = 0; 289 | 290 | if (CRASHDEBUG(1)) 291 | dump_qemu_header(kvm->ofp); 292 | 293 | rewind(kvm->vmp); 294 | 295 | if (kvm->flags & (MAPFILE|MAPFILE_APPENDED)) 296 | return TRUE; 297 | 298 | please_wait("scanning KVM dumpfile"); 299 | 300 | if (kvm->flags & KVMHOST_32) 301 | dl = qemu_load(devices_x86_32, 302 | QEMU_FEATURE_CPU|QEMU_FEATURE_RAM, kvm->vmp); 303 | else 304 | dl = qemu_load(devices_x86_64, 305 | QEMU_FEATURE_CPU|QEMU_FEATURE_RAM, kvm->vmp); 306 | 307 | please_wait_done(); 308 | 309 | if (dl) { 310 | if (machine_type("X86_64")) { 311 | idt = get_idt_base(dl); 312 | kvm->mapinfo.phys_base = get_kernel_base(dl); 313 | } 314 | 315 | dram = (struct qemu_device_ram *) 316 | device_find_instance (dl, "ram", 0); 317 | 318 | if (CRASHDEBUG(1)) { 319 | if (machine_type("X86_64")) { 320 | fprintf(kvm->ofp, "IDT: %llx\n", 321 | (ulonglong)idt); 322 | fprintf(kvm->ofp, "physical kernel base: %llx\n", 323 | (ulonglong)kvm->mapinfo.phys_base); 324 | } 325 | fprintf(kvm->ofp, "last RAM offset: %llx\n", 326 | (ulonglong)dram->last_ram_offset); 327 | } 328 | 329 | device_list_free (dl); 330 | } else 331 | fclose(kvm->vmp); 332 | 333 | return dl ? TRUE : FALSE; 334 | } 335 | -------------------------------------------------------------------------------- /ramdump.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ramdump.c - core analysis suite 3 | * 4 | * Copyright (c) 2014 Broadcom Corporation 5 | * Oza Pawandeep 6 | * Vikram Prakash 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * Author: Oza Pawandeep 19 | */ 20 | 21 | #define _LARGEFILE64_SOURCE 1 /* stat64() */ 22 | #include "defs.h" 23 | #include 24 | 25 | struct ramdump_def { 26 | char *path; 27 | int rfd; 28 | ulonglong start_paddr; 29 | ulonglong end_paddr; 30 | }; 31 | 32 | static struct ramdump_def *ramdump; 33 | static int nodes; 34 | static char *user_elf = NULL; 35 | static char elf_default[] = "/var/tmp/ramdump_elf_XXXXXX"; 36 | 37 | static void alloc_elf_header(Elf64_Ehdr *ehdr, ushort e_machine) 38 | { 39 | memcpy(ehdr->e_ident, ELFMAG, SELFMAG); 40 | ehdr->e_ident[EI_CLASS] = ELFCLASS64; 41 | ehdr->e_ident[EI_DATA] = ELFDATA2LSB; 42 | ehdr->e_ident[EI_VERSION] = EV_CURRENT; 43 | ehdr->e_ident[EI_OSABI] = ELFOSABI_LINUX; 44 | ehdr->e_ident[EI_ABIVERSION] = 0; 45 | memset(ehdr->e_ident+EI_PAD, 0, 46 | EI_NIDENT-EI_PAD); 47 | ehdr->e_type = ET_CORE; 48 | ehdr->e_machine = e_machine; 49 | ehdr->e_version = EV_CURRENT; 50 | ehdr->e_entry = 0; 51 | ehdr->e_phoff = sizeof(Elf64_Ehdr); 52 | ehdr->e_shoff = 0; 53 | ehdr->e_flags = 0; 54 | ehdr->e_ehsize = sizeof(Elf64_Ehdr); 55 | ehdr->e_phentsize = sizeof(Elf64_Phdr); 56 | ehdr->e_phnum = 1 + nodes; 57 | ehdr->e_shentsize = 0; 58 | ehdr->e_shnum = 0; 59 | ehdr->e_shstrndx = 0; 60 | } 61 | 62 | static void alloc_program_headers(Elf64_Phdr *phdr) 63 | { 64 | unsigned int i; 65 | 66 | for (i = 0; i < nodes; i++) { 67 | phdr[i].p_type = PT_LOAD; 68 | phdr[i].p_filesz = ramdump[i].end_paddr + 1 - ramdump[i].start_paddr; 69 | phdr[i].p_memsz = phdr[i].p_filesz; 70 | phdr[i].p_vaddr = 0; 71 | phdr[i].p_paddr = ramdump[i].start_paddr; 72 | phdr[i].p_flags = PF_R | PF_W | PF_X; 73 | phdr[i].p_align = 0; 74 | } 75 | } 76 | 77 | static char *write_elf(Elf64_Phdr *load, Elf64_Ehdr *e_head, size_t data_offset) 78 | { 79 | #define CPY_BUF_SZ 4096 80 | int fd1, fd2, i, err = 1; 81 | char *buf; 82 | char *out_elf; 83 | size_t offset; 84 | ssize_t rd, len; 85 | 86 | buf = (char *)malloc(CPY_BUF_SZ); 87 | 88 | offset = data_offset; 89 | 90 | if (user_elf) { 91 | fd2 = open(user_elf, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); 92 | if (fd2 < 0) { 93 | error(INFO, "%s open error, %s\n", 94 | user_elf, strerror(errno)); 95 | goto end1; 96 | } 97 | out_elf = user_elf; 98 | } else { 99 | fd2 = mkstemp(elf_default); 100 | if (fd2 < 0) { 101 | error(INFO, "%s open error, %s\n", 102 | elf_default, strerror(errno)); 103 | goto end1; 104 | } 105 | out_elf = elf_default; 106 | pc->flags2 |= RAMDUMP; 107 | } 108 | 109 | if (user_elf) { 110 | sprintf(buf, "creating ELF dumpfile: %s", out_elf); 111 | please_wait(buf); 112 | } else if (CRASHDEBUG(1)) 113 | fprintf(fp, "creating temporary ELF header: %s\n\n", 114 | elf_default); 115 | 116 | while (offset > 0) { 117 | len = write(fd2, e_head + (data_offset - offset), offset); 118 | if (len < 0) { 119 | error(INFO, "ramdump write error, %s\n", 120 | strerror(errno)); 121 | goto end; 122 | } 123 | offset -= len; 124 | } 125 | 126 | if (user_elf) { 127 | for (i = 0; i < nodes; i++) { 128 | offset = load[i].p_offset; 129 | 130 | fd1 = open(ramdump[i].path, O_RDONLY, S_IRUSR); 131 | if (fd1 < 0) { 132 | error(INFO, "%s open error, %s\n", 133 | ramdump[i].path, strerror(errno)); 134 | goto end; 135 | } 136 | 137 | lseek(fd2, (off_t)offset, SEEK_SET); 138 | while ((rd = read(fd1, buf, CPY_BUF_SZ)) > 0) { 139 | if (write(fd2, buf, rd) != rd) { 140 | error(INFO, "%s write error, %s\n", 141 | ramdump[i].path, 142 | strerror(errno)); 143 | close(fd1); 144 | goto end; 145 | } 146 | } 147 | close(fd1); 148 | } 149 | please_wait_done(); 150 | } 151 | 152 | err = 0; 153 | end: 154 | close(fd2); 155 | end1: 156 | free(buf); 157 | return err ? NULL : out_elf; 158 | } 159 | 160 | static void alloc_notes(Elf64_Phdr *notes) 161 | { 162 | /* Nothing filled in as of now */ 163 | notes->p_type = PT_NOTE; 164 | notes->p_offset = 0; 165 | notes->p_vaddr = 0; 166 | notes->p_paddr = 0; 167 | notes->p_filesz = 0; 168 | notes->p_memsz = 0; 169 | notes->p_flags = 0; 170 | notes->p_align = 0; 171 | } 172 | 173 | char *ramdump_to_elf(void) 174 | { 175 | int i; 176 | char *ptr, *e_file = NULL; 177 | ushort e_machine = 0; 178 | size_t offset, data_offset; 179 | size_t l_offset; 180 | Elf64_Phdr *notes, *load; 181 | Elf64_Ehdr *e_head; 182 | 183 | if (machine_type("ARM")) 184 | e_machine = EM_ARM; 185 | else if (machine_type("ARM64")) 186 | e_machine = EM_AARCH64; 187 | else if (machine_type("MIPS") || machine_type("MIPS64")) 188 | e_machine = EM_MIPS; 189 | else if (machine_type("X86_64")) 190 | e_machine = EM_X86_64; 191 | else if (machine_type("RISCV64")) 192 | e_machine = EM_RISCV; 193 | else if (machine_type("LOONGARCH64")) 194 | e_machine = EM_LOONGARCH; 195 | else 196 | error(FATAL, "ramdump: unsupported machine type: %s\n", 197 | MACHINE_TYPE); 198 | 199 | e_head = (Elf64_Ehdr *)malloc(sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) + 200 | (nodes * sizeof(Elf64_Phdr)) + (CPY_BUF_SZ * 2)); 201 | ptr = (char *)e_head; 202 | offset = 0; 203 | 204 | alloc_elf_header(e_head, e_machine); 205 | 206 | ptr += sizeof(Elf64_Ehdr); 207 | offset += sizeof(Elf64_Ehdr); 208 | 209 | notes = (Elf64_Phdr *)ptr; 210 | 211 | alloc_notes(notes); 212 | 213 | offset += sizeof(Elf64_Phdr); 214 | ptr += sizeof(Elf64_Phdr); 215 | 216 | load = (Elf64_Phdr *)ptr; 217 | 218 | alloc_program_headers(load); 219 | 220 | offset += sizeof(Elf64_Phdr) * nodes; 221 | ptr += sizeof(Elf64_Phdr) * nodes; 222 | 223 | /* Empty note */ 224 | notes->p_offset = offset; 225 | 226 | l_offset = offset; 227 | 228 | data_offset = offset; 229 | 230 | for (i = 0; i < nodes; i++) { 231 | load[i].p_offset = l_offset; 232 | l_offset += load[i].p_filesz; 233 | } 234 | 235 | e_file = write_elf(load, e_head, data_offset); 236 | 237 | free(e_head); 238 | return e_file; 239 | } 240 | 241 | #define PREFIX(ptr, pat) \ 242 | (strncmp((ptr), (pat), sizeof(pat)-1) ? 0 : \ 243 | ((ptr) += sizeof(pat)-1, 1)) 244 | 245 | int is_ramdump(char *p) 246 | { 247 | char *x = NULL, *y = NULL, *pat; 248 | size_t len; 249 | char *pattern; 250 | struct stat64 st; 251 | int is_live; 252 | int err = 0; 253 | 254 | is_live = PREFIX(p, "live:"); 255 | 256 | if (nodes || !strchr(p, '@')) 257 | return 0; 258 | 259 | len = strlen(p); 260 | pattern = (char *)malloc(len + 1); 261 | strlcpy(pattern, p, len + 1); 262 | 263 | pat = pattern; 264 | while ((pat = strtok_r(pat, ",", &x))) { 265 | if ((pat = strtok_r(pat, "@", &y))) { 266 | nodes++; 267 | ramdump = realloc(ramdump, 268 | sizeof(struct ramdump_def) * nodes); 269 | if (!ramdump) 270 | error(FATAL, "realloc failure\n"); 271 | ramdump[nodes - 1].path = pat; 272 | pat = strtok_r(NULL, "@", &y); 273 | ramdump[nodes - 1].start_paddr = 274 | htoll(pat, RETURN_ON_ERROR, &err); 275 | if (err == TRUE) 276 | error(FATAL, "Invalid ramdump address\n"); 277 | if ((ramdump[nodes - 1].rfd = 278 | open(ramdump[nodes - 1].path, O_RDONLY)) < 0) 279 | error(FATAL, 280 | "ramdump %s open failed:%s\n", 281 | ramdump[nodes - 1].path, 282 | strerror(errno)); 283 | if (fstat64(ramdump[nodes - 1].rfd, &st) < 0) 284 | error(FATAL, "ramdump stat failed\n"); 285 | ramdump[nodes - 1].end_paddr = 286 | ramdump[nodes - 1].start_paddr + st.st_size - 1; 287 | } 288 | 289 | pat = NULL; 290 | } 291 | 292 | if (nodes && is_live) { 293 | pc->flags |= LIVE_SYSTEM; 294 | pc->dumpfile = ramdump[0].path; 295 | pc->live_memsrc = pc->dumpfile; 296 | } 297 | return nodes; 298 | } 299 | 300 | void ramdump_elf_output_file(char *opt) 301 | { 302 | user_elf = opt; 303 | } 304 | 305 | void ramdump_cleanup(void) 306 | { 307 | if (!user_elf) 308 | unlink(elf_default); 309 | } 310 | 311 | int 312 | read_ramdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) 313 | { 314 | off_t offset; 315 | int i, found; 316 | struct ramdump_def *r = &ramdump[0]; 317 | 318 | offset = 0; 319 | 320 | for (i = found = 0; i < nodes; i++) { 321 | r = &ramdump[i]; 322 | 323 | if ((paddr >= r->start_paddr) && 324 | (paddr <= r->end_paddr)) { 325 | offset = (off_t)paddr - (off_t)r->start_paddr; 326 | found++; 327 | break; 328 | } 329 | } 330 | 331 | if (!found) { 332 | if (CRASHDEBUG(8)) 333 | fprintf(fp, "read_ramdump: READ_ERROR: " 334 | "offset not found for paddr: %llx\n", 335 | (ulonglong)paddr); 336 | return READ_ERROR; 337 | } 338 | 339 | if (CRASHDEBUG(8)) 340 | fprintf(fp, 341 | "read_ramdump: addr: %lx paddr: %llx cnt: %d offset: %llx\n", 342 | addr, (ulonglong)paddr, cnt, (ulonglong)offset); 343 | 344 | if (lseek(r->rfd, offset, SEEK_SET) == -1) { 345 | if (CRASHDEBUG(8)) 346 | fprintf(fp, "read_ramdump: SEEK_ERROR: " 347 | "offset: %llx\n", (ulonglong)offset); 348 | return SEEK_ERROR; 349 | } 350 | 351 | if (read(r->rfd, bufptr, cnt) != cnt) { 352 | if (CRASHDEBUG(8)) 353 | fprintf(fp, "read_ramdump: READ_ERROR: " 354 | "offset: %llx\n", (ulonglong)offset); 355 | return READ_ERROR; 356 | } 357 | 358 | return cnt; 359 | } 360 | 361 | void 362 | show_ramdump_files(void) 363 | { 364 | int i; 365 | 366 | fprintf(fp, "%s [temporary ELF header]\n", elf_default); 367 | for (i = 0; i < nodes; i++) { 368 | fprintf(fp, "%s %s", 369 | i ? "\n" : "", ramdump[i].path); 370 | } 371 | } 372 | 373 | void 374 | dump_ramdump_data() 375 | { 376 | int i; 377 | 378 | if (!user_elf && !is_ramdump_image()) 379 | return; 380 | 381 | fprintf(fp, "\nramdump data:\n"); 382 | 383 | fprintf(fp, " user_elf: %s\n", 384 | user_elf ? user_elf : "(unused)"); 385 | fprintf(fp, " elf_default: %s\n", 386 | user_elf ? "(unused)" : elf_default); 387 | fprintf(fp, " nodes: %d\n", nodes); 388 | 389 | for (i = 0; i < nodes; i++) { 390 | fprintf(fp, " ramdump[%d]:\n", i); 391 | fprintf(fp, " path: %s\n", 392 | ramdump[i].path); 393 | fprintf(fp, " rfd: %d\n", 394 | ramdump[i].rfd); 395 | fprintf(fp, " start_paddr: %llx\n", 396 | (ulonglong)ramdump[i].start_paddr); 397 | fprintf(fp, " end_paddr: %llx\n", 398 | (ulonglong)ramdump[i].end_paddr); 399 | } 400 | 401 | fprintf(fp, "\n"); 402 | } 403 | 404 | int 405 | is_ramdump_image(void) 406 | { 407 | return (pc->flags2 & RAMDUMP ? TRUE : FALSE); 408 | } 409 | -------------------------------------------------------------------------------- /rse.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_IA64_RSE_H 2 | #define _ASM_IA64_RSE_H 3 | 4 | /* 5 | * Copyright (C) 1998, 1999 Hewlett-Packard Co 6 | * Copyright (C) 1998, 1999 David Mosberger-Tang 7 | */ 8 | 9 | /* 10 | * rse.h 11 | * 12 | * Copyright (C) 2002, 2003, 2004, 2005 David Anderson 13 | * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. 14 | * 15 | * This program is free software; you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * This program is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * Adapted from: 26 | * 27 | * include/asm-ia64/rse.h (2.4.9-e.3) 28 | */ 29 | 30 | /* 31 | * Register stack engine related helper functions. This file may be 32 | * used in applications, so be careful about the name-space and give 33 | * some consideration to non-GNU C compilers (though __inline__ is 34 | * fine). 35 | */ 36 | 37 | static __inline__ unsigned long 38 | ia64_rse_slot_num (unsigned long *addr) 39 | { 40 | return (((unsigned long) addr) >> 3) & 0x3f; 41 | } 42 | 43 | /* 44 | * Return TRUE if ADDR is the address of an RNAT slot. 45 | */ 46 | static __inline__ unsigned long 47 | ia64_rse_is_rnat_slot (unsigned long *addr) 48 | { 49 | return ia64_rse_slot_num(addr) == 0x3f; 50 | } 51 | 52 | /* 53 | * Returns the address of the RNAT slot that covers the slot at 54 | * address SLOT_ADDR. 55 | */ 56 | static __inline__ unsigned long * 57 | ia64_rse_rnat_addr (unsigned long *slot_addr) 58 | { 59 | return (unsigned long *) ((unsigned long) slot_addr | (0x3f << 3)); 60 | } 61 | 62 | /* 63 | * Calcuate the number of registers in the dirty partition starting at 64 | * BSPSTORE with a size of DIRTY bytes. This isn't simply DIRTY 65 | * divided by eight because the 64th slot is used to store ar.rnat. 66 | */ 67 | static __inline__ unsigned long 68 | ia64_rse_num_regs (unsigned long *bspstore, unsigned long *bsp) 69 | { 70 | unsigned long slots = (bsp - bspstore); 71 | 72 | return slots - (ia64_rse_slot_num(bspstore) + slots)/0x40; 73 | } 74 | 75 | /* 76 | * The inverse of the above: given bspstore and the number of 77 | * registers, calculate ar.bsp. 78 | */ 79 | static __inline__ unsigned long * 80 | ia64_rse_skip_regs (unsigned long *addr, long num_regs) 81 | { 82 | long delta = ia64_rse_slot_num(addr) + num_regs; 83 | 84 | if (num_regs < 0) 85 | delta -= 0x3e; 86 | return addr + num_regs + delta/0x3f; 87 | } 88 | 89 | #endif /* _ASM_IA64_RSE_H */ 90 | -------------------------------------------------------------------------------- /s390_dump.c: -------------------------------------------------------------------------------- 1 | /* s390_dump.c - core analysis suite 2 | * 3 | * Copyright (C) 2001, 2002 Mission Critical Linux, Inc. 4 | * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson 5 | * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. 6 | * Copyright (C) 2005 Michael Holzheu, IBM Corporation 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | */ 18 | #include "defs.h" 19 | //#include 20 | #include "ibm_common.h" 21 | 22 | static FILE * s390_file; 23 | 24 | int 25 | is_s390_dump(char *file) 26 | { 27 | FILE* fh; 28 | long long int magic; 29 | size_t items ATTRIBUTE_UNUSED; 30 | int rc; 31 | 32 | fh = fopen(file,"r"); 33 | if (fh == NULL) { 34 | error(INFO, "is_s390_dump: cannot open %s: %s\n", file); 35 | return FALSE; 36 | } 37 | items = fread(&magic, sizeof(magic), 1,fh); 38 | if(magic == 0xa8190173618f23fdLL) 39 | rc = TRUE; 40 | else 41 | rc = FALSE; 42 | fclose(fh); 43 | return rc; 44 | } 45 | 46 | FILE* 47 | s390_dump_init(char *file) 48 | { 49 | if ((s390_file = fopen(file, "r+")) == NULL) { 50 | if ((s390_file = fopen(file, "r")) == NULL) 51 | return NULL; 52 | } 53 | 54 | return s390_file; 55 | } 56 | 57 | int 58 | read_s390_dumpfile(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) 59 | { 60 | paddr += S390_DUMP_HEADER_SIZE; 61 | 62 | if (fseek(s390_file, (ulong)paddr, SEEK_SET) != 0) 63 | return SEEK_ERROR; 64 | 65 | if (fread(bufptr, 1 , cnt, s390_file) != cnt) 66 | return READ_ERROR; 67 | 68 | return 0; 69 | } 70 | 71 | int 72 | write_s390_dumpfile(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) 73 | { 74 | return WRITE_ERROR; 75 | } 76 | 77 | #define S390_PAGE_SHIFT 12 78 | #define S390_PAGE_SIZE (1UL << S390_PAGE_SHIFT) 79 | 80 | uint 81 | s390_page_size(void) 82 | { 83 | return S390_PAGE_SIZE; 84 | } 85 | 86 | int 87 | s390_memory_used(void) 88 | { 89 | return 0; 90 | } 91 | 92 | int 93 | s390_free_memory(void) 94 | { 95 | return 0; 96 | } 97 | 98 | int 99 | s390_memory_dump(FILE *fp) 100 | { 101 | return 0; 102 | } 103 | 104 | ulong 105 | get_s390_panic_task(void) 106 | { 107 | return BADVAL; 108 | } 109 | 110 | void 111 | get_s390_panicmsg(char *buf) 112 | { 113 | return; 114 | } 115 | -------------------------------------------------------------------------------- /sadump.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sadump.h - core analysis suite 3 | * 4 | * Copyright (c) 2011 FUJITSU LIMITED 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * Author: HATAYAMA Daisuke 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | typedef struct efi_time { 23 | uint16_t year; 24 | uint8_t month; 25 | uint8_t day; 26 | uint8_t hour; 27 | uint8_t minute; 28 | uint8_t second; 29 | uint8_t pad1; 30 | uint32_t nanosecond; 31 | #define EFI_UNSPECIFIED_TIMEZONE 2047 32 | int16_t timezone; 33 | uint8_t daylight; 34 | uint8_t pad2; 35 | } efi_time_t; 36 | 37 | typedef struct { 38 | uint32_t data1; 39 | uint16_t data2; 40 | uint16_t data3; 41 | uint8_t data4[8]; 42 | } efi_guid_t; 43 | 44 | #define SADUMP_EFI_GUID_TEXT_REPR_LEN 36 45 | 46 | struct sadump_part_header { 47 | #define SADUMP_SIGNATURE1 0x75646173 48 | #define SADUMP_SIGNATURE2 0x0000706d 49 | uint32_t signature1; /* sadu */ 50 | uint32_t signature2; /* mp\0\0 */ 51 | uint32_t enable; /* set sadump service */ 52 | uint32_t reboot; /* number of seconds until reboot. 1-3600 */ 53 | uint32_t compress; /* memory image format. */ 54 | uint32_t recycle; /* dump device recycle */ 55 | uint32_t label[16]; /* reserve */ 56 | efi_guid_t sadump_id; /* system UUID */ 57 | efi_guid_t disk_set_id; /* disk set UUID */ 58 | efi_guid_t vol_id; /* device UUID */ 59 | efi_time_t time_stamp; /* time stamp */ 60 | uint32_t set_disk_set; /* device type */ 61 | #define SADUMP_MAX_DISK_SET_NUM 16 62 | uint32_t reserve; /* Padding for Alignment */ 63 | uint64_t used_device; /* used device */ 64 | #define DUMP_PART_HEADER_MAGICNUM_SIZE 982 65 | uint32_t magicnum[DUMP_PART_HEADER_MAGICNUM_SIZE]; /* magic number */ 66 | }; 67 | 68 | struct sadump_volume_info { 69 | efi_guid_t id; /* volume id */ 70 | uint64_t vol_size; /* device size */ 71 | uint32_t status; /* device status */ 72 | uint32_t cache_size; /* cache size */ 73 | }; 74 | 75 | struct sadump_disk_set_header { 76 | uint32_t disk_set_header_size; /* disk set header size */ 77 | uint32_t disk_num; /* disk number */ 78 | uint64_t disk_set_size; /* disk set size */ 79 | #define DUMP_DEVICE_MAX 16 80 | struct sadump_volume_info vol_info[DUMP_DEVICE_MAX - 1]; 81 | /* struct VOL_INFO array */ 82 | }; 83 | 84 | struct sadump_header { 85 | #define SADUMP_SIGNATURE "sadump\0\0" 86 | char signature[8]; /* = "sadump\0\0" */ 87 | uint32_t header_version; /* Dump header version */ 88 | uint32_t reserve; /* Padding for Alignment */ 89 | efi_time_t timestamp; /* Time stamp */ 90 | uint32_t status; /* Above flags */ 91 | uint32_t compress; /* Above flags */ 92 | uint32_t block_size; /* Size of a block in byte */ 93 | #define SADUMP_DEFAULT_BLOCK_SIZE 4096 94 | uint32_t extra_hdr_size; /* Size of host dependent 95 | * header in blocks (reserve) 96 | */ 97 | uint32_t sub_hdr_size; /* Size of arch dependent header in blocks */ 98 | uint32_t bitmap_blocks; /* Size of Memory bitmap in block */ 99 | uint32_t dumpable_bitmap_blocks; /* Size of Memory bitmap in block */ 100 | uint32_t max_mapnr; /* = max_mapnr */ 101 | uint32_t total_ram_blocks; /* Size of Memory in block */ 102 | uint32_t device_blocks; /* Number of total blocks in the dump device */ 103 | uint32_t written_blocks; /* Number of written blocks */ 104 | uint32_t current_cpu; /* CPU# which handles dump */ 105 | uint32_t nr_cpus; /* Number of CPUs */ 106 | /* 107 | * The members from below are supported in header version 1 108 | * and later. 109 | */ 110 | uint64_t max_mapnr_64; 111 | uint64_t total_ram_blocks_64; 112 | uint64_t device_blocks_64; 113 | uint64_t written_blocks_64; 114 | }; 115 | 116 | struct sadump_apic_state { 117 | uint64_t ApicId; /* Local Apic ID register */ 118 | uint64_t Ldr; /* Logical Destination Register */ 119 | }; 120 | 121 | struct sadump_smram_cpu_state { 122 | uint64_t Reserved1[58]; 123 | uint32_t GdtUpper, LdtUpper, IdtUpper; 124 | uint32_t Reserved2[3]; 125 | uint64_t IoEip; 126 | uint64_t Reserved3[10]; 127 | uint32_t Cr4; 128 | uint32_t Reserved4[18]; 129 | uint32_t GdtLower; 130 | uint32_t GdtLimit; 131 | uint32_t IdtLower; 132 | uint32_t IdtLimit; 133 | uint32_t LdtLower; 134 | uint32_t LdtLimit; 135 | uint32_t LdtInfo; 136 | uint64_t Reserved5[6]; 137 | uint64_t Eptp; 138 | uint32_t EptpSetting; 139 | uint32_t Reserved6[5]; 140 | uint32_t Smbase; 141 | uint32_t SmmRevisionId; 142 | uint16_t IoInstructionRestart; 143 | uint16_t AutoHaltRestart; 144 | uint32_t Reserved7[6]; 145 | uint32_t R15Lower, R15Upper, R14Lower, R14Upper; 146 | uint32_t R13Lower, R13Upper, R12Lower, R12Upper; 147 | uint32_t R11Lower, R11Upper, R10Lower, R10Upper; 148 | uint32_t R9Lower, R9Upper, R8Lower, R8Upper; 149 | uint32_t RaxLower, RaxUpper, RcxLower, RcxUpper; 150 | uint32_t RdxLower, RdxUpper, RbxLower, RbxUpper; 151 | uint32_t RspLower, RspUpper, RbpLower, RbpUpper; 152 | uint32_t RsiLower, RsiUpper, RdiLower, RdiUpper; 153 | uint32_t IoMemAddrLower, IoMemAddrUpper; 154 | uint32_t IoMisc, Es, Cs, Ss, Ds, Fs, Gs; 155 | uint32_t Ldtr, Tr; 156 | uint64_t Dr7, Dr6, Rip, Ia32Efer, Rflags; 157 | uint64_t Cr3, Cr0; 158 | }; 159 | 160 | struct sadump_page_header { 161 | uint64_t page_flags; 162 | uint32_t size; 163 | uint32_t flags; 164 | }; 165 | 166 | struct sadump_media_header { 167 | efi_guid_t sadump_id; // system UUID 168 | efi_guid_t disk_set_id; // disk set UUID 169 | efi_time_t time_stamp; /* time stamp */ 170 | char sequential_num; // Medium sequential number 171 | char term_cord; // Termination cord 172 | char disk_set_header_size; // Size of original disk set header 173 | char disks_in_use; // Number of used disks of original dump device 174 | char reserve[4044]; // reserve feild 175 | }; 176 | 177 | #define divideup(x, y) (((x) + ((y) - 1)) / (y)) 178 | 179 | #define SADUMP_PF_SECTION_NUM 4096 180 | 181 | struct sadump_diskset_data { 182 | char *filename; 183 | int dfd; 184 | struct sadump_part_header *header; 185 | ulong data_offset; 186 | }; 187 | 188 | struct sadump_data { 189 | char *filename; 190 | ulong flags; 191 | int dfd; /* dumpfile file descriptor */ 192 | int machine_type; /* machine type identifier */ 193 | 194 | struct sadump_part_header *header; 195 | struct sadump_header *dump_header; 196 | struct sadump_disk_set_header *diskset_header; 197 | struct sadump_media_header *media_header; 198 | 199 | char *bitmap; 200 | char *dumpable_bitmap; 201 | 202 | size_t sub_hdr_offset; 203 | uint32_t smram_cpu_state_size; 204 | 205 | ulong data_offset; 206 | int block_size; 207 | int block_shift; 208 | 209 | char *page_buf; 210 | uint64_t *block_table; 211 | 212 | int sd_list_len; 213 | struct sadump_diskset_data **sd_list; 214 | 215 | /* Backup Region, First 640K of System RAM. */ 216 | #define KEXEC_BACKUP_SRC_END 0x0009ffff 217 | ulonglong backup_src_start; 218 | ulong backup_src_size; 219 | ulonglong backup_offset; 220 | 221 | uint64_t max_mapnr; 222 | ulong phys_base; 223 | }; 224 | 225 | struct sadump_data *sadump_get_sadump_data(void); 226 | int sadump_cleanup_sadump_data(void); 227 | ulong sadump_identify_format(int *block_size); 228 | int sadump_get_smram_cpu_state(int apicid, 229 | struct sadump_smram_cpu_state *smram); 230 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | /* test.c - core analysis suite 2 | * 3 | * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. 4 | * Copyright (C) 2002, 2003, 2004, 2005, 2011 David Anderson 5 | * Copyright (C) 2002, 2003, 2004, 2005, 2011 Red Hat, Inc. All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | 18 | #include "defs.h" 19 | #include 20 | 21 | static struct option test_long_options[] = { 22 | {"no", no_argument, 0, 0}, 23 | {"req", required_argument, 0, 0}, 24 | {0, 0, 0, 0} 25 | }; 26 | 27 | /* 28 | * Test your stuff here first if you'd like. If anything's being done 29 | * below in this routine, consider it leftover trash... 30 | */ 31 | void 32 | cmd_test(void) 33 | { 34 | int c; 35 | int option_index; 36 | 37 | while ((c = getopt_long(argcnt, args, "", 38 | test_long_options, &option_index)) != EOF) { 39 | switch(c) 40 | { 41 | case 0: 42 | if (STREQ(test_long_options[option_index].name, "no")) 43 | fprintf(fp, "no argument\n"); 44 | if (STREQ(test_long_options[option_index].name, "req")) 45 | fprintf(fp, "required argument: %s\n", optarg); 46 | break; 47 | 48 | default: 49 | argerrs++; 50 | break; 51 | } 52 | } 53 | 54 | if (argerrs) 55 | cmd_usage(pc->curcmd, SYNOPSIS); 56 | 57 | while (args[optind]) { 58 | ; 59 | optind++; 60 | } 61 | } 62 | 63 | /* 64 | * Scratch routine for testing a feature on a per-task basis by entering 65 | * the "foreach test" command. Like cmd_test(), anything that's being done 66 | * below in this routine can be considered trash. 67 | */ 68 | void 69 | foreach_test(ulong task, ulong flags) 70 | { 71 | 72 | } 73 | 74 | /* 75 | * Template for building a new command. 76 | */ 77 | void 78 | cmd_template(void) 79 | { 80 | int c; 81 | 82 | while ((c = getopt(argcnt, args, "")) != EOF) { 83 | switch(c) 84 | { 85 | default: 86 | argerrs++; 87 | break; 88 | } 89 | } 90 | 91 | if (argerrs) 92 | cmd_usage(pc->curcmd, SYNOPSIS); 93 | 94 | while (args[optind]) { 95 | ; 96 | optind++; 97 | } 98 | } 99 | 100 | -------------------------------------------------------------------------------- /unwind_i.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2000, 2002 Hewlett-Packard Co 3 | * David Mosberger-Tang 4 | */ 5 | 6 | /* 7 | * unwind_i.h 8 | * 9 | * Copyright (C) 2002, 2003, 2004, 2005 David Anderson 10 | * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. 11 | * 12 | * This program is free software; you can redistribute it and/or modify 13 | * it under the terms of the GNU General Public License as published by 14 | * the Free Software Foundation; either version 2 of the License, or 15 | * (at your option) any later version. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU General Public License for more details. 21 | * 22 | * Adapted from: 23 | * 24 | * arch/ia64/kernel/unwind_i.h (kernel-2.4.18-6.23) 25 | */ 26 | 27 | /* 28 | * Kernel unwind support. 29 | */ 30 | 31 | #define UNW_VER(x) ((x) >> 48) 32 | #define UNW_FLAG_MASK 0x0000ffff00000000 33 | #define UNW_FLAG_OSMASK 0x0000f00000000000 34 | #define UNW_FLAG_EHANDLER(x) ((x) & 0x0000000100000000L) 35 | #define UNW_FLAG_UHANDLER(x) ((x) & 0x0000000200000000L) 36 | #define UNW_LENGTH(x) ((x) & 0x00000000ffffffffL) 37 | 38 | enum unw_register_index { 39 | /* primary unat: */ 40 | UNW_REG_PRI_UNAT_GR, 41 | UNW_REG_PRI_UNAT_MEM, 42 | 43 | /* register stack */ 44 | UNW_REG_BSP, /* register stack pointer */ 45 | UNW_REG_BSPSTORE, 46 | UNW_REG_PFS, /* previous function state */ 47 | UNW_REG_RNAT, 48 | /* memory stack */ 49 | UNW_REG_PSP, /* previous memory stack pointer */ 50 | /* return pointer: */ 51 | UNW_REG_RP, 52 | 53 | /* preserved registers: */ 54 | UNW_REG_R4, UNW_REG_R5, UNW_REG_R6, UNW_REG_R7, 55 | UNW_REG_UNAT, UNW_REG_PR, UNW_REG_LC, UNW_REG_FPSR, 56 | UNW_REG_B1, UNW_REG_B2, UNW_REG_B3, UNW_REG_B4, UNW_REG_B5, 57 | UNW_REG_F2, UNW_REG_F3, UNW_REG_F4, UNW_REG_F5, 58 | UNW_REG_F16, UNW_REG_F17, UNW_REG_F18, UNW_REG_F19, 59 | UNW_REG_F20, UNW_REG_F21, UNW_REG_F22, UNW_REG_F23, 60 | UNW_REG_F24, UNW_REG_F25, UNW_REG_F26, UNW_REG_F27, 61 | UNW_REG_F28, UNW_REG_F29, UNW_REG_F30, UNW_REG_F31, 62 | UNW_NUM_REGS 63 | }; 64 | 65 | struct unw_info_block { 66 | u64 header; 67 | u64 desc[0]; /* unwind descriptors */ 68 | /* personality routine and language-specific data follow behind descriptors */ 69 | }; 70 | 71 | struct unw_table_entry { 72 | u64 start_offset; 73 | u64 end_offset; 74 | u64 info_offset; 75 | }; 76 | 77 | struct unw_table { 78 | struct unw_table *next; /* must be first member! */ 79 | const char *name; 80 | unsigned long gp; /* global pointer for this load-module */ 81 | unsigned long segment_base; /* base for offsets in the unwind table entries */ 82 | unsigned long start; 83 | unsigned long end; 84 | const struct unw_table_entry *array; 85 | unsigned long length; 86 | }; 87 | 88 | enum unw_where { 89 | UNW_WHERE_NONE, /* register isn't saved at all */ 90 | UNW_WHERE_GR, /* register is saved in a general register */ 91 | UNW_WHERE_FR, /* register is saved in a floating-point register */ 92 | UNW_WHERE_BR, /* register is saved in a branch register */ 93 | UNW_WHERE_SPREL, /* register is saved on memstack (sp-relative) */ 94 | UNW_WHERE_PSPREL, /* register is saved on memstack (psp-relative) */ 95 | /* 96 | * At the end of each prologue these locations get resolved to 97 | * UNW_WHERE_PSPREL and UNW_WHERE_GR, respectively: 98 | */ 99 | UNW_WHERE_SPILL_HOME, /* register is saved in its spill home */ 100 | UNW_WHERE_GR_SAVE /* register is saved in next general register */ 101 | }; 102 | 103 | #define UNW_WHEN_NEVER 0x7fffffff 104 | 105 | struct unw_reg_info { 106 | unsigned long val; /* save location: register number or offset */ 107 | enum unw_where where; /* where the register gets saved */ 108 | int when; /* when the register gets saved */ 109 | }; 110 | 111 | struct unw_reg_state { 112 | struct unw_reg_state *next; /* next (outer) element on state stack */ 113 | struct unw_reg_info reg[UNW_NUM_REGS]; /* register save locations */ 114 | }; 115 | 116 | struct unw_labeled_state { 117 | struct unw_labeled_state *next; /* next labeled state (or NULL) */ 118 | unsigned long label; /* label for this state */ 119 | struct unw_reg_state saved_state; 120 | }; 121 | 122 | struct unw_state_record { 123 | unsigned int first_region : 1; /* is this the first region? */ 124 | unsigned int done : 1; /* are we done scanning descriptors? */ 125 | unsigned int any_spills : 1; /* got any register spills? */ 126 | unsigned int in_body : 1; /* are we inside a body (as opposed to a prologue)? */ 127 | unsigned long flags; /* see UNW_FLAG_* in unwind.h */ 128 | 129 | u8 *imask; /* imask of spill_mask record or NULL */ 130 | unsigned long pr_val; /* predicate values */ 131 | unsigned long pr_mask; /* predicate mask */ 132 | long spill_offset; /* psp-relative offset for spill base */ 133 | int region_start; 134 | int region_len; 135 | int epilogue_start; 136 | int epilogue_count; 137 | int when_target; 138 | 139 | u8 gr_save_loc; /* next general register to use for saving a register */ 140 | u8 return_link_reg; /* branch register in which the return link is passed */ 141 | 142 | struct unw_labeled_state *labeled_states; /* list of all labeled states */ 143 | struct unw_reg_state curr; /* current state */ 144 | }; 145 | 146 | enum unw_nat_type { 147 | UNW_NAT_NONE, /* NaT not represented */ 148 | UNW_NAT_VAL, /* NaT represented by NaT value (fp reg) */ 149 | UNW_NAT_MEMSTK, /* NaT value is in unat word at offset OFF */ 150 | UNW_NAT_REGSTK /* NaT is in rnat */ 151 | }; 152 | 153 | enum unw_insn_opcode { 154 | UNW_INSN_ADD, /* s[dst] += val */ 155 | UNW_INSN_ADD_PSP, /* s[dst] = (s.psp + val) */ 156 | UNW_INSN_ADD_SP, /* s[dst] = (s.sp + val) */ 157 | UNW_INSN_MOVE, /* s[dst] = s[val] */ 158 | UNW_INSN_MOVE2, /* s[dst] = s[val]; s[dst+1] = s[val+1] */ 159 | UNW_INSN_MOVE_STACKED, /* s[dst] = ia64_rse_skip(*s.bsp, val) */ 160 | UNW_INSN_SETNAT_MEMSTK, /* s[dst+1].nat.type = MEMSTK; 161 | s[dst+1].nat.off = *s.pri_unat - s[dst] */ 162 | UNW_INSN_SETNAT_TYPE, /* s[dst+1].nat.type = val */ 163 | UNW_INSN_LOAD, /* s[dst] = *s[val] */ 164 | UNW_INSN_MOVE_SCRATCH, /* s[dst] = scratch reg "val" */ 165 | }; 166 | 167 | struct unw_insn { 168 | unsigned int opc : 4; 169 | unsigned int dst : 9; 170 | signed int val : 19; 171 | }; 172 | 173 | /* 174 | * Preserved general static registers (r2-r5) give rise to two script 175 | * instructions; everything else yields at most one instruction; at 176 | * the end of the script, the psp gets popped, accounting for one more 177 | * instruction. 178 | */ 179 | #define UNW_MAX_SCRIPT_LEN (UNW_NUM_REGS + 5) 180 | 181 | struct unw_script { 182 | unsigned long ip; /* ip this script is for */ 183 | unsigned long pr_mask; /* mask of predicates script depends on */ 184 | unsigned long pr_val; /* predicate values this script is for */ 185 | #ifndef REDHAT 186 | rwlock_t lock; 187 | #endif /* !REDHAT */ 188 | unsigned int flags; /* see UNW_FLAG_* in unwind.h */ 189 | #ifndef REDHAT 190 | unsigned short lru_chain; /* used for least-recently-used chain */ 191 | unsigned short coll_chain; /* used for hash collisions */ 192 | unsigned short hint; /* hint for next script to try (or -1) */ 193 | #endif /* !REDHAT */ 194 | unsigned short count; /* number of instructions in script */ 195 | struct unw_insn insn[UNW_MAX_SCRIPT_LEN]; 196 | }; 197 | -------------------------------------------------------------------------------- /unwind_x86.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software; you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation; either version 2 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | */ 12 | 13 | -------------------------------------------------------------------------------- /unwind_x86_64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software; you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation; either version 2 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | */ 12 | 13 | #define CONFIG_64BIT 1 14 | #define NULL ((void *)0) 15 | 16 | typedef unsigned long size_t; 17 | typedef unsigned char u8; 18 | typedef signed short s16; 19 | typedef unsigned short u16; 20 | typedef signed int s32; 21 | typedef unsigned int u32; 22 | typedef unsigned long long u64; 23 | 24 | struct pt_regs { 25 | unsigned long r15; 26 | unsigned long r14; 27 | unsigned long r13; 28 | unsigned long r12; 29 | unsigned long rbp; 30 | unsigned long rbx; 31 | /* arguments: non interrupts/non tracing syscalls only save upto here*/ 32 | unsigned long r11; 33 | unsigned long r10; 34 | unsigned long r9; 35 | unsigned long r8; 36 | unsigned long rax; 37 | unsigned long rcx; 38 | unsigned long rdx; 39 | unsigned long rsi; 40 | unsigned long rdi; 41 | unsigned long orig_rax; 42 | /* end of arguments */ 43 | /* cpu exception frame or undefined */ 44 | unsigned long rip; 45 | unsigned long cs; 46 | unsigned long eflags; 47 | unsigned long rsp; 48 | unsigned long ss; 49 | /* top of stack page */ 50 | }; 51 | 52 | struct unwind_frame_info 53 | { 54 | struct pt_regs regs; 55 | }; 56 | 57 | extern int unwind(struct unwind_frame_info *, int); 58 | extern void init_unwind_table(void); 59 | extern void free_unwind_table(void); 60 | 61 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 62 | #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) 63 | #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) 64 | #define get_unaligned(ptr) (*(ptr)) 65 | //#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr))) 66 | #define THREAD_ORDER 1 67 | #define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER) 68 | 69 | #define UNW_PC(frame) (frame)->regs.rip 70 | #define UNW_SP(frame) (frame)->regs.rsp 71 | #ifdef CONFIG_FRAME_POINTER 72 | #define UNW_FP(frame) (frame)->regs.rbp 73 | #define FRAME_RETADDR_OFFSET 8 74 | #define FRAME_LINK_OFFSET 0 75 | #define STACK_BOTTOM(tsk) (((tsk)->thread.rsp0 - 1) & ~(THREAD_SIZE - 1)) 76 | #define STACK_TOP(tsk) ((tsk)->thread.rsp0) 77 | #endif 78 | 79 | 80 | #define EXTRA_INFO(f) { BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) % FIELD_SIZEOF(struct unwind_frame_info, f)) + offsetof(struct unwind_frame_info, f)/ FIELD_SIZEOF(struct unwind_frame_info, f), FIELD_SIZEOF(struct unwind_frame_info, f) } 81 | 82 | #define PTREGS_INFO(f) EXTRA_INFO(regs.f) 83 | 84 | #define UNW_REGISTER_INFO \ 85 | PTREGS_INFO(rax),\ 86 | PTREGS_INFO(rdx),\ 87 | PTREGS_INFO(rcx),\ 88 | PTREGS_INFO(rbx), \ 89 | PTREGS_INFO(rsi), \ 90 | PTREGS_INFO(rdi), \ 91 | PTREGS_INFO(rbp), \ 92 | PTREGS_INFO(rsp), \ 93 | PTREGS_INFO(r8), \ 94 | PTREGS_INFO(r9), \ 95 | PTREGS_INFO(r10),\ 96 | PTREGS_INFO(r11), \ 97 | PTREGS_INFO(r12), \ 98 | PTREGS_INFO(r13), \ 99 | PTREGS_INFO(r14), \ 100 | PTREGS_INFO(r15), \ 101 | PTREGS_INFO(rip) 102 | 103 | -------------------------------------------------------------------------------- /va_server.h: -------------------------------------------------------------------------------- 1 | /* va_server.h - kernel crash dump file translation library 2 | * 3 | * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. 4 | * Copyright (C) 2002, 2003, 2004, 2005 David Anderson 5 | * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * 10/99, Dave Winchell, Initial release for kernel crash dump support. 18 | * 11/12/99, Dave Winchell, Add support for in memory dumps. 19 | */ 20 | 21 | #include "vas_crash.h" 22 | 23 | extern int vas_page_size; 24 | extern u_long vas_base_va; 25 | 26 | int va_server_init(char *crash_file, u_long *start, u_long *end, u_long *stride); 27 | int va_server_init_v1(char *crash_file, u_long *start, u_long *end, u_long *stride); 28 | int vas_lseek(u_long position, int whence); 29 | int vas_lseek_v1(u_long position, int whence); 30 | size_t vas_read(void *buf_in, size_t count); 31 | size_t vas_read_v1(void *buf_in, size_t count); 32 | size_t vas_write(void *buf_in, size_t count); 33 | size_t vas_write_v1(void *buf_in, size_t count); 34 | void vas_free_data(u_long va); 35 | void vas_free_data_v1(u_long va); 36 | 37 | 38 | /* in-memory formats */ 39 | 40 | struct map_hdr { 41 | struct crash_map_entry *map; /* array of map entries */ 42 | int blk_size; /* blocksize for this map */ 43 | }; 44 | 45 | 46 | 47 | struct map_hdr_v1 { 48 | u_long start_va; 49 | u_long end_va; 50 | 51 | struct crash_map_entry_v1 *map; /* array of map entries */ 52 | int map_entries; /* entries in array pointed to by map */ 53 | u_long va_per_entry; /* va covered by each map_entry */ 54 | int blk_offset; /* add this to start_blk in map_entry 55 | * this allows relocation of compressed data 56 | * while using original maps 57 | */ 58 | int blk_size; /* blocksize for this map */ 59 | 60 | struct map_hdr_v1 *next; 61 | }; 62 | 63 | extern int clean_exit(int); 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /va_server_v1.c: -------------------------------------------------------------------------------- 1 | /* va_server_v1.c - kernel crash dump file translation library 2 | * 3 | * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. 4 | * Copyright (C) 2002, 2003, 2004, 2005 David Anderson 5 | * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * 11/12/99, Dave Winchell, Preserve V1 interface. 18 | */ 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "va_server.h" 28 | #include 29 | #include 30 | #include 31 | 32 | struct map_hdr_v1 *vas_map_base_v1 = (struct map_hdr_v1 *)0; /* base of tree */ 33 | 34 | 35 | #ifdef NOT_DEF 36 | #define trunc_page(x) ((void *)(((unsigned long)(x)) & ~((unsigned long)(page_size - 1)))) 37 | #define round_page(x) trunc_page(((unsigned long)(x)) + ((unsigned long)(page_size - 1))) 38 | #endif 39 | 40 | extern u_long vas_base_va; 41 | extern u_long vas_start_va; 42 | u_long vas_end_va; 43 | 44 | void find_data_v1(u_long va, u_long *buf, u_long *len, u_long *offset); 45 | void load_data_v1(struct map_hdr_v1 *hdr, u_long index, u_long *buf, u_long *len); 46 | struct map_hdr_v1 *find_header_v1(u_long va); 47 | u_long vas_find_start_v1(void); 48 | u_long vas_find_end_v1(void); 49 | int read_maps_v1(char *crash_file); 50 | int read_map_v1(int blk_pos); 51 | 52 | extern int Page_Size; 53 | 54 | extern FILE *vas_file_p; 55 | 56 | extern void *malloc(size_t); 57 | 58 | 59 | int va_server_init_v1(char *crash_file, u_long *start, u_long *end, u_long *stride) 60 | { 61 | if(read_maps_v1(crash_file)) 62 | return -1; 63 | 64 | vas_base_va = vas_start_va = vas_find_start_v1(); 65 | vas_end_va = vas_find_end_v1(); 66 | 67 | if(start) 68 | *start = vas_start_va; 69 | if(end) 70 | *end = vas_end_va; 71 | if(stride) 72 | *stride = vas_map_base_v1->va_per_entry; 73 | return 0; 74 | } 75 | 76 | int vas_lseek_v1(u_long position, int whence) 77 | { 78 | if(whence != SEEK_SET) 79 | return -1; 80 | if(position > (vas_end_va - vas_start_va)) { 81 | printf("position 0x%lx beyond dump range of 0x%lx\n", 82 | position, (vas_end_va - vas_start_va)); 83 | return -1; 84 | } 85 | vas_base_va = vas_start_va + position; 86 | return 0; 87 | } 88 | size_t vas_read_v1(void *buf_in, size_t count) 89 | { 90 | u_long len, offset, buf, va; 91 | u_long num, output, remaining; 92 | 93 | 94 | if(count > (vas_end_va - vas_base_va)) { 95 | printf("count 0x%lx greater than remaining dump of 0x%lx\n", 96 | (ulong)count, (vas_end_va - vas_base_va)); 97 | return -1; 98 | } 99 | va = vas_base_va; 100 | remaining = count; 101 | output = (u_long)buf_in; 102 | 103 | while(remaining) { 104 | find_data_v1(va, &buf, &len, &offset); 105 | num = (remaining > (len - offset)) ? (len - offset) : remaining; 106 | bcopy((const void *)(buf+offset), (void *)output, num); 107 | remaining -= num; 108 | va += num; 109 | output += num; 110 | } 111 | vas_base_va += count; 112 | return count; 113 | } 114 | size_t vas_write_v1(void *buf_in, size_t count) 115 | { 116 | u_long len, offset, buf, va; 117 | 118 | if(count != sizeof(u_long)) { 119 | printf("count %d not %d\n", (int)count, (int)sizeof(u_long)); 120 | return -1; 121 | } 122 | va = vas_base_va; 123 | find_data_v1(va, &buf, &len, &offset); 124 | *(u_long *)(buf+offset) = *(u_long *)buf_in; 125 | 126 | vas_base_va += count; 127 | return count; 128 | } 129 | 130 | 131 | void find_data_v1(u_long va, u_long *buf, u_long *len, u_long *offset) 132 | { 133 | struct map_hdr_v1 *hdr; 134 | u_long index, off; 135 | 136 | hdr = find_header_v1(va); 137 | index = (va - hdr->start_va) / hdr->va_per_entry; 138 | off = (va - hdr->start_va) % hdr->va_per_entry; 139 | load_data_v1(hdr, index, buf, len); 140 | if(offset) 141 | *offset = off; 142 | } 143 | void vas_free_data_v1(u_long va) 144 | { 145 | struct map_hdr_v1 *hdr; 146 | u_long index; 147 | 148 | hdr = find_header_v1(va); 149 | index = (va - hdr->start_va) / hdr->va_per_entry; 150 | 151 | if(hdr->map[index].exp_data) { 152 | free((void *)hdr->map[index].exp_data); 153 | hdr->map[index].exp_data = 0; 154 | } 155 | } 156 | void load_data_v1(struct map_hdr_v1 *hdr, u_long index, u_long *buf, u_long *len) 157 | { 158 | char *compr_buf; 159 | char *exp_buf; 160 | int ret, items; 161 | uLongf destLen; 162 | 163 | if(hdr->map[index].exp_data) 164 | goto out; 165 | ret = fseek(vas_file_p, (long)((hdr->blk_offset + hdr->map[index].start_blk) * hdr->blk_size), 166 | SEEK_SET); 167 | 168 | if(ret == -1) { 169 | printf("load_data: unable to fseek, errno = %d\n", ferror(vas_file_p)); 170 | clean_exit(1); 171 | } 172 | compr_buf = (char *)malloc(2*hdr->va_per_entry); 173 | if(!compr_buf) { 174 | printf("load_data: bad ret from malloc, errno = %d\n", ferror(vas_file_p)); 175 | clean_exit(1); 176 | } 177 | items = fread((void *)compr_buf, sizeof(char), hdr->map[index].num_blks * hdr->blk_size, vas_file_p); 178 | if(items != hdr->map[index].num_blks * hdr->blk_size) { 179 | printf("unable to read blocks from errno = %d\n", ferror(vas_file_p)); 180 | clean_exit(1); 181 | } 182 | hdr->map[index].exp_data = exp_buf = (char *)malloc(hdr->va_per_entry); 183 | if(!exp_buf) { 184 | printf("load_data: bad ret from malloc, errno = %d\n", ferror(vas_file_p)); 185 | clean_exit(1); 186 | } 187 | destLen = (uLongf)(2*hdr->va_per_entry); 188 | ret = uncompress((Bytef *)exp_buf, &destLen, (const Bytef *)compr_buf, (uLong)items); 189 | /* if(destLen != hdr->va_per_entry) { 190 | printf("uncompress error\n"); 191 | exit(1); 192 | } 193 | */ 194 | if(ret) { 195 | if(ret == Z_MEM_ERROR) 196 | printf("load_data, bad ret Z_MEM_ERROR from uncompress\n"); 197 | else if(ret == Z_BUF_ERROR) 198 | printf("load_data, bad ret Z_BUF_ERROR from uncompress\n"); 199 | else if(ret == Z_DATA_ERROR) 200 | printf("load_data, bad ret Z_DATA_ERROR from uncompress\n"); 201 | else 202 | printf("load_data, bad ret %d from uncompress\n", ret); 203 | 204 | clean_exit(1); 205 | } 206 | free((void *)compr_buf); 207 | out: 208 | if(buf) 209 | *buf = (u_long)hdr->map[index].exp_data; 210 | if(len) 211 | *len = hdr->va_per_entry; 212 | return; 213 | } 214 | 215 | struct map_hdr_v1 *find_header_v1(u_long va) 216 | { 217 | struct map_hdr_v1 *hdr; 218 | int found = 0; 219 | 220 | for(hdr = vas_map_base_v1; hdr; hdr = hdr->next) 221 | if((va >= hdr->start_va) && (va < hdr->end_va)) { 222 | found = 1; 223 | break; 224 | } 225 | if(found) 226 | return hdr; 227 | else 228 | return (struct map_hdr_v1 *)0; 229 | } 230 | u_long vas_find_start_v1(void) 231 | { 232 | struct map_hdr_v1 *hdr; 233 | u_long start; 234 | 235 | start = vas_map_base_v1->start_va; 236 | for(hdr = vas_map_base_v1; hdr; hdr = hdr->next) 237 | if(hdr->start_va < start) 238 | start = hdr->start_va; 239 | 240 | return start; 241 | } 242 | u_long vas_find_end_v1(void) 243 | { 244 | struct map_hdr_v1 *hdr; 245 | u_long end; 246 | 247 | end = vas_map_base_v1->end_va; 248 | for(hdr = vas_map_base_v1; hdr; hdr = hdr->next) 249 | if(hdr->end_va > end) 250 | end = hdr->end_va; 251 | 252 | return end; 253 | } 254 | int read_maps_v1(char *crash_file) 255 | { 256 | int *cur_entry_p, *cp; 257 | int ret, items, blk_pos; 258 | 259 | cur_entry_p = (int *)malloc(Page_Size); 260 | if(!cur_entry_p) { 261 | printf("read_maps: bad ret from malloc, errno = %d\n", ferror(vas_file_p)); 262 | clean_exit(1); 263 | } 264 | bzero((void *)cur_entry_p, Page_Size); 265 | 266 | vas_file_p = fopen(crash_file, "r"); 267 | if(vas_file_p == (FILE *)0) { 268 | printf("read_maps: bad ret from fopen for %s: %s\n", crash_file, strerror(errno)); 269 | free(cur_entry_p); 270 | return -1; 271 | } 272 | ret = fseek(vas_file_p, (long)0, SEEK_SET); 273 | if(ret == -1) { 274 | printf("read_maps: unable to fseek in %s, errno = %d\n", crash_file, ferror(vas_file_p)); 275 | free(cur_entry_p); 276 | return -1; 277 | } 278 | items = fread((void *)cur_entry_p, 1, Page_Size, vas_file_p); 279 | if(items != Page_Size) { 280 | printf("read_maps: unable to read header from %s, errno = %d\n", crash_file, ferror(vas_file_p)); 281 | free(cur_entry_p); 282 | return -1; 283 | } 284 | ret = -1; 285 | cp = cur_entry_p; 286 | while ((blk_pos = *cp++)) { 287 | if (read_map_v1(blk_pos)) { 288 | free(cur_entry_p); 289 | return -1; 290 | } 291 | ret = 0; 292 | } 293 | 294 | free(cur_entry_p); 295 | return ret; 296 | } 297 | 298 | 299 | 300 | 301 | int read_map_v1(int blk_pos) 302 | { 303 | struct crash_map_hdr_v1 *disk_hdr; 304 | int ret, items; 305 | struct map_hdr_v1 *hdr, *hdr1; 306 | extern int console(char *, ...); 307 | 308 | hdr = (struct map_hdr_v1 *)malloc(sizeof(struct map_hdr_v1)); 309 | if(!hdr) { 310 | printf("read_map: unable to malloc mem\n"); 311 | return -1; 312 | } 313 | bzero((void *)hdr, sizeof(struct map_hdr_v1)); 314 | disk_hdr = (struct crash_map_hdr_v1 *)malloc(Page_Size); 315 | ret = fseek(vas_file_p, (long)(blk_pos*Page_Size), SEEK_SET); 316 | if(ret == -1) { 317 | console("va_server: unable to fseek, err = %d\n", ferror(vas_file_p)); 318 | free(hdr); 319 | free(disk_hdr); 320 | return -1; 321 | } 322 | items = fread((void *)disk_hdr, 1, Page_Size, vas_file_p); 323 | if(items != Page_Size) { 324 | free(hdr); 325 | free(disk_hdr); 326 | return -1; 327 | } 328 | if(disk_hdr->magic[0] != CRASH_MAGIC) { 329 | console("va_server: bad magic 0x%lx\n", disk_hdr->magic[0]); 330 | free(hdr); 331 | free(disk_hdr); 332 | return -1; 333 | } 334 | ret = fseek(vas_file_p, (long)((blk_pos + disk_hdr->map_block) * disk_hdr->blk_size), SEEK_SET); 335 | 336 | if(ret == -1) { 337 | printf("va_server: unable to fseek, err = %d\n", ferror(vas_file_p)); 338 | free(hdr); 339 | free(disk_hdr); 340 | return -1; 341 | } 342 | 343 | hdr->map_entries = disk_hdr->map_entries; 344 | hdr->va_per_entry = disk_hdr->va_per_entry; 345 | hdr->blk_offset = blk_pos - CRASH_OFFSET_BLKS; 346 | hdr->blk_size = disk_hdr->blk_size; 347 | Page_Size = disk_hdr->blk_size; /* over-ride PAGE_SIZE */ 348 | 349 | hdr->map = (struct crash_map_entry_v1 *)malloc(hdr->map_entries * 350 | sizeof(struct crash_map_entry_v1)); 351 | items = fread((void *)hdr->map, sizeof(struct crash_map_entry_v1), hdr->map_entries, 352 | vas_file_p); 353 | if(items != hdr->map_entries) { 354 | printf("unable to read map entries, err = %d\n", errno); 355 | free(hdr); 356 | free(disk_hdr); 357 | return -1; 358 | } 359 | 360 | hdr->start_va = hdr->map[0].start_va; 361 | hdr->end_va = hdr->start_va + hdr->map_entries * hdr->va_per_entry; 362 | 363 | if(!vas_map_base_v1) { 364 | vas_map_base_v1 = hdr; 365 | hdr->next = (struct map_hdr_v1 *)0; 366 | } 367 | else { 368 | hdr1 = vas_map_base_v1; 369 | while(hdr1->next) 370 | hdr1 = hdr1->next; 371 | hdr1->next = hdr; 372 | hdr->next = (struct map_hdr_v1 *)0; 373 | } 374 | 375 | free((void *)disk_hdr); 376 | return 0; 377 | 378 | } 379 | 380 | 381 | 382 | 383 | -------------------------------------------------------------------------------- /vas_crash.h: -------------------------------------------------------------------------------- 1 | /* vas_crash.h - kernel crash dump file format (on swap) 2 | * 3 | * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. 4 | * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson 5 | * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * 10/99, Dave Winchell, Initial release for kernel crash dump support. 18 | * 11/12/99, Dave Winchell, Add support for in memory dumps. 19 | */ 20 | 21 | #include 22 | //#include 23 | 24 | void save_core(void); 25 | 26 | 27 | /* struct crash_map_hdr located at byte offset 0 */ 28 | /* on-disk formats */ 29 | 30 | #define trunc_page(x) ((void *)(((unsigned long)(x)) & ~((unsigned long)(Page_Size - 1)))) 31 | #define round_page(x) trunc_page(((unsigned long)(x)) + ((unsigned long)(Page_Size - 1))) 32 | 33 | #define CRASH_MAGIC 0x9a8bccdd 34 | #define CRASH_SOURCE_PAGES 128 35 | #define CRASH_SUB_MAP_BYTES ((u_long)round_page((CRASH_SOURCE_PAGES+1)*sizeof(u_long))) 36 | #define CRASH_SUB_MAP_PAGES (CRASH_SUB_MAP_BYTES / Page_Size) 37 | #define CRASH_UNCOMPR_BUF_PAGES (CRASH_SOURCE_PAGES + CRASH_SUB_MAP_PAGES) 38 | #define CRASH_COMPR_BUF_PAGES (CRASH_UNCOMPR_BUF_PAGES + (CRASH_UNCOMPR_BUF_PAGES/4)) 39 | #define CRASH_COMPESS_PRIME_PAGES (2*CRASH_COMPR_BUF_PAGES) 40 | #define CRASH_ZALLOC_PAGES 16*5*2 /* 2 to handle crash in crash */ 41 | #define CRASH_LOW_WATER_PAGES 100 42 | 43 | #define HP_BIOS_HIGH_PAGES_USED 2000 44 | 45 | #define CRASH_MARK_RESERVED(addr) (set_bit(PG_reserved,&mem_map[MAP_NR(addr)].flags)) 46 | #define CRASH_CLEAR_RESERVED(addr) (clear_bit(PG_reserved,&mem_map[MAP_NR(addr)].flags)) 47 | 48 | #ifdef NOT_DEF 49 | typedef int boolean_t; 50 | #endif 51 | 52 | #define TRUE 1 53 | #define FALSE 0 54 | 55 | 56 | 57 | /* mem structure */ 58 | 59 | struct mem_crash_map_hdr { 60 | long magic[4]; /* identify crash dump */ 61 | u_long map; /* location of map */ 62 | u_long map_pages; 63 | u_long data_pages; 64 | u_long compr_units; 65 | }; 66 | struct mem_crash_map_entry { 67 | u_long src_va; /* source start of larger non-contig block */ 68 | /* a src_va of -1 means that the dest_page_va 69 | * is the location of the next map page */ 70 | u_long dest_page_va; /* dest of this sub block */ 71 | u_long check_sum; /* check_sum for dest data */ 72 | }; 73 | 74 | 75 | /* file structure */ 76 | 77 | struct crash_map_hdr { 78 | long magic[4]; /* identify crash dump */ 79 | int blk_size; /* block size for this device */ 80 | int map_block; /* location of map */ 81 | int map_blocks; /* number of blocks for map */ 82 | }; 83 | struct crash_map_entry { 84 | u_long start_va; /* virtual address */ 85 | char *exp_data; /* expanded data in memory */ 86 | int start_blk; /* device location */ 87 | int num_blks; 88 | }; 89 | 90 | #define CRASH_OFFSET_BLKS 100 91 | #define CRASH_MAGIC 0x9a8bccdd 92 | struct crash_map_hdr_v1 { 93 | long magic[4]; /* identify crash dump */ 94 | int blk_size; /* block size for this device */ 95 | int map_block; /* location of map */ 96 | int map_blocks; /* number of blocks for map */ 97 | int map_entries; 98 | u_long va_per_entry; /* va covered by each map_entry */ 99 | u_long bytes_not_dumped; /* ran out of swap space */ 100 | int total_blocks; /* CRASH_OFFSET_BLKS + header + map + data */ 101 | }; 102 | struct crash_map_entry_v1 { 103 | u_long start_va; /* virtual address */ 104 | char *exp_data; /* expanded data in memory */ 105 | int start_blk; /* device location */ 106 | int num_blks; 107 | int chk_sum; /* check sum */ 108 | }; 109 | -------------------------------------------------------------------------------- /vmcore.h: -------------------------------------------------------------------------------- 1 | /* 2 | * vmcore.h 3 | * 4 | * Copyright (C) 2019 Chelsio Communications. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | */ 16 | #ifndef _VMCORE_H 17 | #define _VMCORE_H 18 | 19 | #include 20 | 21 | #ifndef NT_VMCOREDD 22 | #define NT_VMCOREDD 0x700 23 | #endif 24 | 25 | #define VMCOREDD_NOTE_NAME "LINUX" 26 | #define VMCOREDD_MAX_NAME_BYTES 44 27 | 28 | struct vmcoredd_header { 29 | __u32 n_namesz; /* Name size */ 30 | __u32 n_descsz; /* Content size */ 31 | __u32 n_type; /* NT_VMCOREDD */ 32 | __u8 name[8]; /* LINUX\0\0\0 */ 33 | __u8 dump_name[VMCOREDD_MAX_NAME_BYTES]; /* Device dump's name */ 34 | }; 35 | 36 | #endif /* _VMCORE_H */ 37 | -------------------------------------------------------------------------------- /vmware_vmss.h: -------------------------------------------------------------------------------- 1 | /* 2 | * vmware_vmss.h 3 | * 4 | * Copyright (c) 2015 VMware, Inc. 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * Author: Dyno Hongjun Fu 17 | */ 18 | 19 | #define CPTDUMP_OLD_MAGIC_NUMBER 0xbed0bed0 20 | #define CPTDUMP_MAGIC_NUMBER 0xbed2bed2 21 | #define CPTDUMP_PARTIAL_MAGIC_NUMBER 0xbed3bed3 22 | 23 | #define CPTDUMP_RESTORED_MAGIC_NUMBER 0xbad1bad1 24 | #define CPTDUMP_NORESTORE_MAGIC_NUMBER 0xbad2bad2 25 | /* 26 | * Poor man's bit fields 27 | * TAG: | NAMELEN | NINDX | VALSIZE | 28 | * bits |15 8|7 6|5 0| 29 | * size | 8 | 2 | 6 | 30 | */ 31 | #define TAG_NAMELEN_MASK 0xFF 32 | #define TAG_NAMELEN_OFFSET 8 33 | #define TAG_NINDX_MASK 0x3 34 | #define TAG_NINDX_OFFSET 6 35 | #define TAG_VALSIZE_MASK 0x3F 36 | #define TAG_VALSIZE_OFFSET 0 37 | #define TAG_SIZE 2 38 | 39 | /* 40 | * The value size has two special values to indicate blocks and compressed 41 | * blocks. 42 | */ 43 | #define TAG_ISBLOCK TAG_VALSIZE_MASK 44 | #define TAG_ISBLOCK_COMPRESSED (TAG_VALSIZE_MASK-1) 45 | 46 | #define MAKE_TAG(_nl, _nidx, _nb) \ 47 | (((_nl) & TAG_NAMELEN_MASK) << TAG_NAMELEN_OFFSET | \ 48 | ((_nidx) & TAG_NINDX_MASK) << TAG_NINDX_OFFSET | \ 49 | ((_nb) & TAG_VALSIZE_MASK) << TAG_VALSIZE_OFFSET) 50 | 51 | #define TAG_NAMELEN(_tag) (((_tag) >> TAG_NAMELEN_OFFSET) & TAG_NAMELEN_MASK) 52 | #define TAG_NINDX(_tag) (((_tag) >> TAG_NINDX_OFFSET) & TAG_NINDX_MASK) 53 | #define TAG_VALSIZE(_tag) (((_tag) >> TAG_VALSIZE_OFFSET) & TAG_VALSIZE_MASK) 54 | 55 | #define NULL_TAG MAKE_TAG(0, 0, 0) 56 | #define NO_INDEX (-1) 57 | 58 | /* 59 | * TRUE iff it's a (optionally compressed) block 60 | */ 61 | #define IS_BLOCK_TAG(_tag) (TAG_VALSIZE(_tag) == TAG_ISBLOCK || \ 62 | TAG_VALSIZE(_tag) == TAG_ISBLOCK_COMPRESSED) 63 | 64 | /* 65 | * TRUE iff it's a compressed block. 66 | */ 67 | #define IS_BLOCK_COMPRESSED_TAG(_tag) (TAG_VALSIZE(_tag) == TAG_ISBLOCK_COMPRESSED) 68 | 69 | struct cptdumpheader { 70 | uint32_t id; 71 | uint32_t version; 72 | uint32_t numgroups; 73 | }; 74 | typedef struct cptdumpheader cptdumpheader; 75 | 76 | 77 | #define MAX_LENGTH 64 78 | struct cptgroupdesc { 79 | char name[MAX_LENGTH]; 80 | uint64_t position; 81 | uint64_t size; 82 | }; 83 | typedef struct cptgroupdesc cptgroupdesc; 84 | 85 | struct memregion { 86 | uint32_t startpagenum; 87 | uint32_t startppn; 88 | uint32_t size; 89 | }; 90 | typedef struct memregion memregion; 91 | 92 | #define VMW_GPREGS_SIZE (128) 93 | #define VMW_CR64_SIZE (72) 94 | #define VMW_IDTR_SIZE (10) 95 | struct vmssregs64 { 96 | /* read from vmss */ 97 | uint64_t rax; 98 | uint64_t rcx; 99 | uint64_t rdx; 100 | uint64_t rbx; 101 | uint64_t rbp; 102 | uint64_t rsp; 103 | uint64_t rsi; 104 | uint64_t rdi; 105 | uint64_t r8; 106 | uint64_t r9; 107 | uint64_t r10; 108 | uint64_t r11; 109 | uint64_t r12; 110 | uint64_t r13; 111 | uint64_t r14; 112 | uint64_t r15; 113 | /* manually managed */ 114 | uint64_t idtr; 115 | uint64_t cr[VMW_CR64_SIZE / 8]; 116 | uint64_t rip; 117 | uint64_t rflags; 118 | }; 119 | typedef struct vmssregs64 vmssregs64; 120 | 121 | #define REGS_PRESENT_RAX 1<<0 122 | #define REGS_PRESENT_RCX 1<<1 123 | #define REGS_PRESENT_RDX 1<<2 124 | #define REGS_PRESENT_RBX 1<<3 125 | #define REGS_PRESENT_RBP 1<<4 126 | #define REGS_PRESENT_RSP 1<<5 127 | #define REGS_PRESENT_RSI 1<<6 128 | #define REGS_PRESENT_RDI 1<<7 129 | #define REGS_PRESENT_R8 1<<8 130 | #define REGS_PRESENT_R9 1<<9 131 | #define REGS_PRESENT_R10 1<<10 132 | #define REGS_PRESENT_R11 1<<11 133 | #define REGS_PRESENT_R12 1<<12 134 | #define REGS_PRESENT_R13 1<<13 135 | #define REGS_PRESENT_R14 1<<14 136 | #define REGS_PRESENT_R15 1<<15 137 | #define REGS_PRESENT_IDTR 1<<16 138 | #define REGS_PRESENT_CR0 1<<17 139 | #define REGS_PRESENT_CR1 1<<18 140 | #define REGS_PRESENT_CR2 1<<19 141 | #define REGS_PRESENT_CR3 1<<20 142 | #define REGS_PRESENT_CR4 1<<21 143 | #define REGS_PRESENT_RIP 1<<22 144 | #define REGS_PRESENT_RFLAGS 1<<23 145 | #define REGS_PRESENT_GPREGS 65535 146 | #define REGS_PRESENT_CRS 4063232 147 | #define REGS_PRESENT_ALL 16777215 148 | 149 | #define MAX_REGIONS 3 150 | struct vmssdata { 151 | int32_t cpt64bit; 152 | FILE *dfp; 153 | char *filename; 154 | /* about the memory */ 155 | uint32_t alignmask; 156 | uint32_t regionscount; 157 | memregion regions[MAX_REGIONS]; 158 | uint64_t memoffset; 159 | uint64_t memsize; 160 | ulong phys_base; 161 | int separate_vmem; 162 | uint32_t *vcpu_regs; 163 | uint64_t num_vcpus; 164 | vmssregs64 **regs64; 165 | }; 166 | typedef struct vmssdata vmssdata; 167 | 168 | /* VMware only supports X86/X86_64 virtual machines. */ 169 | #define VMW_PAGE_SIZE (4096) 170 | #define VMW_PAGE_SHIFT (12) 171 | 172 | #define MAX_BLOCK_DUMP (128) 173 | 174 | extern vmssdata vmss; 175 | 176 | #define DEBUG_PARSE_PRINT(x) \ 177 | do { \ 178 | if (CRASHDEBUG(1)) { \ 179 | fprintf x; \ 180 | } \ 181 | } while(0) 182 | 183 | -------------------------------------------------------------------------------- /xen_dom0.c: -------------------------------------------------------------------------------- 1 | /* xen_dom0.c 2 | * 3 | * Copyright (C) 2015 David Anderson 4 | * Copyright (C) 2015 Red Hat, Inc. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * Author: David Anderson 17 | */ 18 | 19 | #include "defs.h" 20 | #include "xen_dom0.h" 21 | 22 | static struct xen_kdump_data xen_kdump_data = { 0 }; 23 | 24 | struct xen_kdump_data *xkd = &xen_kdump_data; 25 | 26 | void 27 | dump_xen_kdump_data(FILE *fp) 28 | { 29 | int i, others; 30 | 31 | fprintf(fp, " xen_kdump_data: %s\n", 32 | XEN_CORE_DUMPFILE() ? " " : "(unused)"); 33 | if (!XEN_CORE_DUMPFILE()) 34 | return; 35 | fprintf(fp, " flags: %lx (", xkd->flags); 36 | others = 0; 37 | if (xkd->flags & KDUMP_P2M_INIT) 38 | fprintf(fp, "%sKDUMP_P2M_INIT", others++ ? "|" : ""); 39 | if (xkd->flags & KDUMP_CR3) 40 | fprintf(fp, "%sKDUMP_CR3", others++ ? "|" : ""); 41 | if (xkd->flags & KDUMP_MFN_LIST) 42 | fprintf(fp, "%sKDUMP_MFN_LIST", others++ ? "|" : ""); 43 | fprintf(fp, ")\n"); 44 | fprintf(fp, " p2m_mfn: %lx\n", 45 | xkd->p2m_mfn); 46 | fprintf(fp, " cr3: %lx\n", 47 | xkd->cr3); 48 | fprintf(fp, " last_mfn_read: %lx\n", 49 | xkd->last_mfn_read); 50 | fprintf(fp, " last_pmd_read: %lx\n", 51 | xkd->last_pmd_read); 52 | fprintf(fp, " page: %lx\n", 53 | (ulong)xkd->page); 54 | fprintf(fp, " accesses: %ld\n", 55 | xkd->accesses); 56 | fprintf(fp, " cache_hits: %ld ", 57 | xkd->cache_hits); 58 | if (xkd->accesses) 59 | fprintf(fp, "(%ld%%)", 60 | xkd->cache_hits * 100 / xkd->accesses); 61 | fprintf(fp, "\n p2m_frames: %d\n", 62 | xkd->p2m_frames); 63 | fprintf(fp, " xen_phys_start: %lx\n", 64 | xkd->xen_phys_start); 65 | fprintf(fp, " xen_major_version: %d\n", 66 | xkd->xen_major_version); 67 | fprintf(fp, " xen_minor_version: %d\n", 68 | xkd->xen_minor_version); 69 | fprintf(fp, " p2m_mfn_frame_list: %lx\n", 70 | (ulong)xkd->p2m_mfn_frame_list); 71 | for (i = 0; i < xkd->p2m_frames; i++) 72 | fprintf(fp, "%lx ", xkd->p2m_mfn_frame_list[i]); 73 | if (i) fprintf(fp, "\n"); 74 | } 75 | 76 | void 77 | process_xen_note(ulong type, void *data, size_t sz) 78 | { 79 | ulong *up = (ulong*) data; 80 | unsigned words = sz / sizeof(ulong); 81 | 82 | pc->flags |= XEN_CORE; 83 | xkd->last_mfn_read = UNINITIALIZED; 84 | xkd->last_pmd_read = UNINITIALIZED; 85 | 86 | if (type == NT_XEN_KDUMP_CR3) 87 | error(WARNING, 88 | "obsolete Xen n_type: %lx (NT_XEN_KDUMP_CR3)\n\n", 89 | type); 90 | 91 | if (type == NT_XEN_KDUMP_CR3 && words == 1) { 92 | xkd->flags |= KDUMP_CR3; 93 | /* 94 | * Use the first cr3 found. 95 | */ 96 | if (!xkd->cr3) 97 | xkd->cr3 = *up; 98 | } else { 99 | xkd->flags |= KDUMP_MFN_LIST; 100 | /* 101 | * If already set, overridden with --pfm_mfn 102 | */ 103 | if (!xkd->p2m_mfn) 104 | xkd->p2m_mfn = up[words-1]; 105 | if (words > 9 && !xkd->xen_phys_start) 106 | xkd->xen_phys_start = up[words-2]; 107 | xkd->xen_major_version = up[0]; 108 | xkd->xen_minor_version = up[1]; 109 | } 110 | } 111 | 112 | /* 113 | * Override the dom0 p2m mfn in the XEN_ELFNOTE_CRASH_INFO note 114 | * in order to initiate a crash session of a guest kernel. 115 | */ 116 | void 117 | xen_kdump_p2m_mfn(char *arg) 118 | { 119 | ulong value; 120 | int errflag; 121 | 122 | errflag = 0; 123 | value = htol(arg, RETURN_ON_ERROR|QUIET, &errflag); 124 | if (!errflag) { 125 | xen_kdump_data.p2m_mfn = value; 126 | if (CRASHDEBUG(1)) 127 | error(INFO, 128 | "xen_kdump_data.p2m_mfn override: %lx\n", 129 | value); 130 | } else 131 | error(WARNING, "invalid p2m_mfn argument: %s\n", arg); 132 | } 133 | 134 | /* 135 | * Fujitsu dom0/HV sadump-generated dumpfile, which requires 136 | * the --p2m_mfn command line argument. 137 | */ 138 | int 139 | is_sadump_xen(void) 140 | { 141 | if (xen_kdump_data.p2m_mfn) { 142 | if (!XEN_CORE_DUMPFILE()) { 143 | pc->flags |= XEN_CORE; 144 | xkd->last_mfn_read = UNINITIALIZED; 145 | xkd->last_pmd_read = UNINITIALIZED; 146 | xkd->flags |= KDUMP_MFN_LIST; 147 | } 148 | return TRUE; 149 | } 150 | 151 | return FALSE; 152 | } 153 | 154 | void 155 | set_xen_phys_start(char *arg) 156 | { 157 | ulong value; 158 | int errflag = 0; 159 | 160 | value = htol(arg, RETURN_ON_ERROR|QUIET, &errflag); 161 | if (!errflag) 162 | xen_kdump_data.xen_phys_start = value; 163 | else 164 | error(WARNING, "invalid xen_phys_start argument: %s\n", arg); 165 | } 166 | 167 | ulong 168 | xen_phys_start(void) 169 | { 170 | return xkd->xen_phys_start; 171 | } 172 | 173 | int 174 | xen_major_version(void) 175 | { 176 | return xkd->xen_major_version; 177 | } 178 | 179 | int 180 | xen_minor_version(void) 181 | { 182 | return xkd->xen_minor_version; 183 | } 184 | 185 | struct xen_kdump_data * 186 | get_xen_kdump_data(void) 187 | { 188 | return xkd; 189 | } 190 | 191 | /* 192 | * Translate a xen domain's pseudo-physical address into the 193 | * xen machine address. Since there's no compression involved, 194 | * just the last phys_to_machine_mapping[] page read is cached, 195 | * which essentially caches 1024 p2m translations. 196 | */ 197 | physaddr_t 198 | xen_kdump_p2m(physaddr_t pseudo) 199 | { 200 | ulong pfn, mfn_frame; 201 | ulong *mfnptr; 202 | ulong mfn_idx, frame_idx; 203 | physaddr_t paddr; 204 | 205 | if (pc->curcmd_flags & XEN_MACHINE_ADDR) 206 | return pseudo; 207 | 208 | if (!(xkd->flags & KDUMP_P2M_INIT)) { 209 | if (!machdep->xen_kdump_p2m_create) 210 | error(FATAL, 211 | "xen kdump dumpfiles not supported on this architecture\n"); 212 | 213 | if ((xkd->page = 214 | (char *)malloc(PAGESIZE())) == NULL) 215 | error(FATAL, 216 | "cannot malloc xen kdump data page\n"); 217 | 218 | if (!machdep->xen_kdump_p2m_create(xkd)) 219 | error(FATAL, 220 | "cannot create xen kdump pfn-to-mfn mapping\n"); 221 | 222 | xkd->flags |= KDUMP_P2M_INIT; 223 | } 224 | 225 | #ifdef IA64 226 | return ia64_xen_kdump_p2m(xkd, pseudo); 227 | #endif 228 | 229 | xkd->accesses++; 230 | 231 | pfn = (ulong)BTOP(pseudo); 232 | mfn_idx = pfn / (PAGESIZE()/sizeof(ulong)); 233 | frame_idx = pfn % (PAGESIZE()/sizeof(ulong)); 234 | if (mfn_idx >= xkd->p2m_frames) { 235 | if (CRASHDEBUG(8)) 236 | fprintf(fp, "xen_kdump_p2m: paddr/pfn: %llx/%lx: " 237 | "mfn_idx nonexistent\n", 238 | (ulonglong)pseudo, pfn); 239 | return P2M_FAILURE; 240 | } 241 | mfn_frame = xkd->p2m_mfn_frame_list[mfn_idx]; 242 | 243 | if (mfn_frame == xkd->last_mfn_read) 244 | xkd->cache_hits++; 245 | else { 246 | int res; 247 | 248 | if (CRASHDEBUG(8)) 249 | fprintf(fp, "xen_kdump_p2m: paddr/pfn: %llx/%lx: " 250 | "read mfn_frame: %llx\n", 251 | (ulonglong)pseudo, pfn, PTOB(mfn_frame)); 252 | 253 | pc->curcmd_flags |= XEN_MACHINE_ADDR; 254 | res = readmem((physaddr_t)PTOB(mfn_frame), PHYSADDR, 255 | xkd->page, PAGESIZE(), 256 | "xen_kdump_p2m mfn frame", RETURN_ON_ERROR); 257 | pc->curcmd_flags &= ~XEN_MACHINE_ADDR; 258 | 259 | if (!res) 260 | return P2M_FAILURE; 261 | } 262 | 263 | xkd->last_mfn_read = mfn_frame; 264 | 265 | mfnptr = ((ulong *)(xkd->page)) + frame_idx; 266 | paddr = (physaddr_t)PTOB((ulonglong)(*mfnptr)); 267 | paddr |= PAGEOFFSET(pseudo); 268 | 269 | if (CRASHDEBUG(7)) 270 | fprintf(fp, 271 | "xen_kdump_p2m(%llx): mfn_idx: %ld frame_idx: %ld" 272 | " mfn_frame: %lx mfn: %lx => %llx\n", 273 | (ulonglong)pseudo, mfn_idx, frame_idx, 274 | mfn_frame, *mfnptr, (ulonglong)paddr); 275 | 276 | return paddr; 277 | } 278 | -------------------------------------------------------------------------------- /xen_dom0.h: -------------------------------------------------------------------------------- 1 | /* xen_dom0.h 2 | * 3 | * Copyright (C) 2015 David Anderson 4 | * Copyright (C) 2015 Red Hat, Inc. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * Author: David Anderson 17 | */ 18 | 19 | /* 20 | * ELF note types for Xen dom0/hypervisor kdumps. 21 | * The comments below are from xen/include/public/elfnote.h. 22 | */ 23 | 24 | /* 25 | * System information exported through crash notes. 26 | * 27 | * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_INFO 28 | * note in case of a system crash. This note will contain various 29 | * information about the system, see xen/include/xen/elfcore.h. 30 | */ 31 | #define XEN_ELFNOTE_CRASH_INFO 0x1000001 32 | 33 | /* 34 | * System registers exported through crash notes. 35 | * 36 | * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_REGS 37 | * note per cpu in case of a system crash. This note is architecture 38 | * specific and will contain registers not saved in the "CORE" note. 39 | * See xen/include/xen/elfcore.h for more information. 40 | */ 41 | #define XEN_ELFNOTE_CRASH_REGS 0x1000002 42 | 43 | 44 | /* 45 | * For (temporary) backwards compatibility. 46 | */ 47 | #define NT_XEN_KDUMP_CR3 0x10000001 48 | 49 | struct xen_kdump_data { 50 | ulong flags; 51 | ulong cr3; 52 | ulong p2m_mfn; 53 | char *page; 54 | ulong last_mfn_read; 55 | ulong last_pmd_read; 56 | ulong cache_hits; 57 | ulong accesses; 58 | int p2m_frames; 59 | ulong *p2m_mfn_frame_list; 60 | ulong xen_phys_start; 61 | int xen_major_version; 62 | int xen_minor_version; 63 | }; 64 | 65 | #define KDUMP_P2M_INIT (0x1) 66 | #define KDUMP_CR3 (0x2) 67 | #define KDUMP_MFN_LIST (0x4) 68 | 69 | #define P2M_FAILURE ((physaddr_t)(0xffffffffffffffffLL)) 70 | 71 | extern struct xen_kdump_data *xkd; 72 | 73 | void dump_xen_kdump_data(FILE *); 74 | struct xen_kdump_data *get_xen_kdump_data(void); 75 | 76 | void process_xen_note(ulong, void *, size_t); 77 | physaddr_t xen_kdump_p2m(physaddr_t); 78 | -------------------------------------------------------------------------------- /xendump.h: -------------------------------------------------------------------------------- 1 | /* 2 | * xendump.h 3 | * 4 | * Copyright (C) 2006, 2007, 2009, 2010, 2014 David Anderson 5 | * Copyright (C) 2006, 2007, 2009, 2010, 2014 Red Hat, Inc. All rights reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | */ 17 | #include 18 | #include 19 | 20 | #define XC_SAVE_SIGNATURE "LinuxGuestRecord" 21 | #define XC_CORE_MAGIC 0xF00FEBED 22 | #define XC_CORE_MAGIC_HVM 0xF00FEBEE 23 | 24 | /* 25 | * From xenctrl.h, but probably not on most host machines. 26 | */ 27 | typedef struct xc_core_header { 28 | unsigned int xch_magic; 29 | unsigned int xch_nr_vcpus; 30 | unsigned int xch_nr_pages; 31 | unsigned int xch_ctxt_offset; 32 | unsigned int xch_index_offset; 33 | unsigned int xch_pages_offset; 34 | } xc_core_header_t; 35 | 36 | /* 37 | * Based upon the original xensource xc_core_header struct above, 38 | * but with unsigned long offset values so that it can be used 39 | * with the original dumpfile format and new ELF-style format. 40 | */ 41 | struct xen_core_header { 42 | unsigned int xch_magic; 43 | unsigned int xch_nr_vcpus; 44 | unsigned int xch_nr_pages; 45 | off_t xch_ctxt_offset; 46 | off_t xch_index_offset; 47 | off_t xch_pages_offset; 48 | }; 49 | 50 | struct pfn_offset_cache { 51 | off_t file_offset; 52 | ulong pfn; 53 | ulong cnt; 54 | }; 55 | #define PFN_TO_OFFSET_CACHE_ENTRIES (5000) 56 | 57 | struct elf_index_pfn { 58 | ulong index; 59 | ulong pfn; 60 | }; 61 | #define INDEX_PFN_COUNT (128) 62 | 63 | struct last_batch { 64 | ulong index; 65 | ulong start; 66 | ulong end; 67 | ulong accesses; 68 | ulong duplicates; 69 | }; 70 | 71 | struct xendump_data { 72 | ulong flags; /* XENDUMP_LOCAL, plus anything else... */ 73 | int xfd; 74 | int pc_next; 75 | uint page_size; 76 | FILE *ofp; 77 | char *page; 78 | ulong accesses; 79 | ulong cache_hits; 80 | ulong redundant; 81 | ulong last_pfn; 82 | struct pfn_offset_cache *poc; 83 | 84 | struct xc_core_data { 85 | int p2m_frames; 86 | ulong *p2m_frame_index_list; 87 | struct xen_core_header header; 88 | int elf_class; 89 | uint64_t format_version; 90 | off_t elf_strtab_offset; 91 | off_t shared_info_offset; 92 | off_t ia64_mapped_regs_offset; 93 | struct elf_index_pfn elf_index_pfn[INDEX_PFN_COUNT]; 94 | struct last_batch last_batch; 95 | Elf32_Ehdr *elf32; 96 | Elf64_Ehdr *elf64; 97 | } xc_core; 98 | 99 | struct xc_save_data { 100 | ulong nr_pfns; 101 | int vmconfig_size; 102 | char *vmconfig_buf; 103 | ulong *p2m_frame_list; 104 | uint pfns_not; 105 | off_t pfns_not_offset; 106 | off_t vcpu_ctxt_offset; 107 | off_t shared_info_page_offset; 108 | off_t *batch_offsets; 109 | ulong batch_count; 110 | ulong *region_pfn_type; 111 | ulong ia64_version; 112 | ulong *ia64_page_offsets; 113 | } xc_save; 114 | 115 | ulong panic_pc; 116 | ulong panic_sp; 117 | }; 118 | 119 | #define XC_SAVE (XENDUMP_LOCAL << 1) 120 | #define XC_CORE_ORIG (XENDUMP_LOCAL << 2) 121 | #define XC_CORE_P2M_CREATE (XENDUMP_LOCAL << 3) 122 | #define XC_CORE_PFN_CREATE (XENDUMP_LOCAL << 4) 123 | #define XC_CORE_NO_P2M (XENDUMP_LOCAL << 5) 124 | #define XC_SAVE_IA64 (XENDUMP_LOCAL << 6) 125 | #define XC_CORE_64BIT_HOST (XENDUMP_LOCAL << 7) 126 | #define XC_CORE_ELF (XENDUMP_LOCAL << 8) 127 | 128 | #define MACHINE_BYTE_ORDER() \ 129 | (machine_type("X86") || \ 130 | machine_type("X86_64") || \ 131 | machine_type("IA64") ? __LITTLE_ENDIAN : __BIG_ENDIAN) 132 | 133 | #define BYTE_SWAP_REQUIRED(endian) (endian != MACHINE_BYTE_ORDER()) 134 | 135 | static inline uint32_t 136 | swab32(uint32_t x) 137 | { 138 | return (((x & 0x000000ffU) << 24) | 139 | ((x & 0x0000ff00U) << 8) | 140 | ((x & 0x00ff0000U) >> 8) | 141 | ((x & 0xff000000U) >> 24)); 142 | } 143 | 144 | #define MFN_NOT_FOUND (-1) 145 | #define PFN_NOT_FOUND (-1) 146 | 147 | #define INVALID_MFN (~0UL) 148 | 149 | /* 150 | * ia64 "xm save" format is completely different than the others. 151 | */ 152 | typedef struct xen_domctl_arch_setup { 153 | uint64_t flags; /* XEN_DOMAINSETUP_* */ 154 | /* #ifdef __ia64__ */ 155 | uint64_t bp; /* mpaddr of boot param area */ 156 | uint64_t maxmem; /* Highest memory address for MDT. */ 157 | uint64_t xsi_va; /* Xen shared_info area virtual address. */ 158 | uint32_t hypercall_imm; /* Break imm for Xen hypercalls. */ 159 | /* #endif */ 160 | } xen_domctl_arch_setup_t; 161 | 162 | /* 163 | * xc_core ELF note, which differs from the standard Elf[32|64]_Nhdr 164 | * structure by the additional name field. 165 | */ 166 | struct elfnote { 167 | uint32_t namesz; 168 | uint32_t descsz; 169 | uint32_t type; 170 | char name[4]; 171 | }; 172 | 173 | #define XEN_ELFNOTE_DUMPCORE_NONE 0x2000000 174 | #define XEN_ELFNOTE_DUMPCORE_HEADER 0x2000001 175 | #define XEN_ELFNOTE_DUMPCORE_XEN_VERSION 0x2000002 176 | #define XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION 0x2000003 177 | 178 | struct xen_dumpcore_elfnote_header_desc { 179 | uint64_t xch_magic; 180 | uint64_t xch_nr_vcpus; 181 | uint64_t xch_nr_pages; 182 | uint64_t xch_page_size; 183 | }; 184 | 185 | #define FORMAT_VERSION_0000000000000001 0x0000000000000001ULL 186 | 187 | struct xen_dumpcore_elfnote_format_version_desc { 188 | uint64_t version; 189 | }; 190 | 191 | struct xen_dumpcore_p2m { 192 | uint64_t pfn; 193 | uint64_t gmfn; 194 | }; 195 | 196 | extern struct xendump_data *xd; 197 | --------------------------------------------------------------------------------